Merge pull request #592 from Atmosphere-NX/boot_refactor

Refactor boot sysmodule to use sts::boot namespace.
This commit is contained in:
SciresM authored and GitHub committed 2019-06-23 20:39:39 -07:00
commit 6bbece39bc
151 files changed
+4269 -5598

No files matched your search

+1 -1
View File
@@ -33,7 +33,7 @@ endef
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR)) TARGET := $(notdir $(CURDIR))
BUILD := build BUILD := build
SOURCES := source source/i2c_driver source/updater SOURCES := source source/i2c source/i2c/driver source/i2c/driver/impl source/gpio source/pinmux
DATA := data DATA := data
INCLUDES := include ../../common/include INCLUDES := include ../../common/include
EXEFS_SRC := exefs_src EXEFS_SRC := exefs_src
@@ -14,14 +14,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <switch.h>
#include <stratosphere.hpp>
#include "boot_functions.hpp"
#include "boot_battery_driver.hpp" #include "boot_battery_driver.hpp"
#include "boot_calibration.hpp"
#include "boot_i2c_utils.hpp"
const Max17050Parameters *BatteryDriver::GetBatteryParameters() { namespace sts::boot {
const u32 battery_version = Boot::GetBatteryVersion();
const u32 battery_vendor = Boot::GetBatteryVendor(); /* Include configuration into anonymous namespace. */
namespace {
#include "boot_battery_parameters.inc"
const Max17050Parameters *GetBatteryParameters() {
const u32 battery_version = GetBatteryVersion();
const u32 battery_vendor = GetBatteryVendor();
if (battery_version == 2) { if (battery_version == 2) {
if (battery_vendor == 'M') { if (battery_vendor == 'M') {
@@ -44,12 +50,14 @@ const Max17050Parameters *BatteryDriver::GetBatteryParameters() {
} }
} }
}
Result BatteryDriver::Read(u8 addr, u16 *out) { Result BatteryDriver::Read(u8 addr, u16 *out) {
return Boot::ReadI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(out), sizeof(*out), &addr, sizeof(addr)); return ReadI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(out), sizeof(*out), &addr, sizeof(addr));
} }
Result BatteryDriver::Write(u8 addr, u16 val) { Result BatteryDriver::Write(u8 addr, u16 val) {
return Boot::WriteI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(&val), sizeof(val), &addr, sizeof(addr)); return WriteI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(&val), sizeof(val), &addr, sizeof(addr));
} }
Result BatteryDriver::ReadWrite(u8 addr, u16 mask, u16 val) { Result BatteryDriver::ReadWrite(u8 addr, u16 mask, u16 val) {
@@ -287,3 +295,5 @@ Result BatteryDriver::GetShutdownEnabled(bool *out) {
Result BatteryDriver::SetShutdownEnabled(bool enabled) { Result BatteryDriver::SetShutdownEnabled(bool enabled) {
return this->ReadWrite(Max17050Config, 0x0040, enabled ? 0x0040 : 0x0000); return this->ReadWrite(Max17050Config, 0x0040, enabled ? 0x0040 : 0x0000);
} }
}
@@ -18,25 +18,24 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "i2c_driver/i2c_api.hpp" #include "i2c/driver/i2c_api.hpp"
#include "boot_battery_parameters.hpp"
namespace sts::boot {
class BatteryDriver { class BatteryDriver {
private: private:
I2cSessionImpl i2c_session; i2c::driver::Session i2c_session;
public: public:
BatteryDriver() { BatteryDriver() {
I2cDriver::Initialize(); i2c::driver::Initialize();
I2cDriver::OpenSession(&this->i2c_session, I2cDevice_Max17050); i2c::driver::OpenSession(&this->i2c_session, I2cDevice_Max17050);
} }
~BatteryDriver() { ~BatteryDriver() {
I2cDriver::CloseSession(this->i2c_session); i2c::driver::CloseSession(this->i2c_session);
I2cDriver::Finalize(); i2c::driver::Finalize();
} }
private: private:
static const Max17050Parameters *GetBatteryParameters();
Result Read(u8 addr, u16 *out_data); Result Read(u8 addr, u16 *out_data);
Result Write(u8 addr, u16 val); Result Write(u8 addr, u16 val);
Result ReadWrite(u8 addr, u16 mask, u16 val); Result ReadWrite(u8 addr, u16 mask, u16 val);
@@ -62,3 +61,5 @@ class BatteryDriver {
Result GetShutdownEnabled(bool *out); Result GetShutdownEnabled(bool *out);
Result SetShutdownEnabled(bool enabled); Result SetShutdownEnabled(bool enabled);
}; };
}
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
constexpr size_t ChargingBatteryX = 26;
constexpr size_t ChargingBatteryY = 28;
constexpr size_t ChargingBatteryW = 76;
constexpr size_t ChargingBatteryH = 28;
constexpr size_t ChargingBatteryMeterX = 7;
constexpr size_t ChargingBatteryMeterY = 8;
constexpr size_t ChargingBatteryMeterW = 31;
constexpr size_t ChargingBatteryMeterH = 12;
static_assert(ChargingBatteryMeterX + ChargingBatteryMeterW < ChargingBatteryW && ChargingBatteryMeterY + ChargingBatteryMeterH < ChargingBatteryH, "Incorrect ChargingBatteryMeter definition!");
constexpr u32 ChargingBattery[] = {0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF3D3D3D, 0xFFB2B2B2, 0xFFE6E6E6, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFE6E6E6, 0xFFB2B2B2, 0xFF3D3D3D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF7A7A7A, 0xFFFEFEFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFDFDFD, 0xFF7A7A7A, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF3D3D3D, 0xFFFDFDFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFDFDFD, 0xFF3D3D3D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFB2B2B2, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFB2B2B2, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF494949, 0xFFE2E2E2, 0xFFE3E3E3, 0xFF494949, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFE6E6E6, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF4A4A4A, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF0000Line truncated
static_assert(sizeof(ChargingBattery) == sizeof(u32) * ChargingBatteryW * ChargingBatteryH, "Incorrect ChargingBattery definition!");
@@ -1,34 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include "boot_types.hpp"
static constexpr size_t ChargingRedBatteryX = 26;
static constexpr size_t ChargingRedBatteryY = 28;
static constexpr size_t ChargingRedBatteryW = 76;
static constexpr size_t ChargingRedBatteryH = 28;
static constexpr size_t ChargingRedBatteryMeterX = 7;
static constexpr size_t ChargingRedBatteryMeterY = 8;
static constexpr size_t ChargingRedBatteryMeterW = 31;
static constexpr size_t ChargingRedBatteryMeterH = 12;
static_assert(ChargingRedBatteryMeterX + ChargingRedBatteryMeterW < ChargingRedBatteryW && ChargingRedBatteryMeterY + ChargingRedBatteryMeterH < ChargingRedBatteryH, "Incorrect ChargingRedBatteryMeter definition!");
static constexpr u32 ChargingRedBattery[] = {0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF3D3D3D, 0xFFB2B2B2, 0xFFE6E6E6, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFE6E6E6, 0xFFB2B2B2, 0xFF3D3D3D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF7A7A7A, 0xFFFEFEFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFDFDFD, 0xFF7A7A7A, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF3D3D3D, 0xFFFDFDFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFDFDFD, 0xFF3D3D3D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFB2B2B2, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFB2B2B2, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF494949, 0xFFE2E2E2, 0xFFE3E3E3, 0xFF494949, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFE6E6E6, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF4A4A4A, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000Line truncated
static_assert(sizeof(ChargingRedBattery) == sizeof(u32) * ChargingRedBatteryW * ChargingRedBatteryH, "Incorrect ChargingRedBattery definition!");
@@ -14,21 +14,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once constexpr size_t ChargingRedBatteryX = 26;
#include <switch.h> constexpr size_t ChargingRedBatteryY = 28;
constexpr size_t ChargingRedBatteryW = 76;
constexpr size_t ChargingRedBatteryH = 28;
#include "boot_types.hpp" constexpr size_t ChargingRedBatteryMeterX = 7;
constexpr size_t ChargingRedBatteryMeterY = 8;
constexpr size_t ChargingRedBatteryMeterW = 31;
constexpr size_t ChargingRedBatteryMeterH = 12;
static_assert(ChargingRedBatteryMeterX + ChargingRedBatteryMeterW < ChargingRedBatteryW && ChargingRedBatteryMeterY + ChargingRedBatteryMeterH < ChargingRedBatteryH, "Incorrect ChargingRedBatteryMeter definition!");
static constexpr size_t ChargingBatteryX = 26; constexpr u32 ChargingRedBattery[] = {0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF3D3D3D, 0xFFB2B2B2, 0xFFE6E6E6, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFE6E6E6, 0xFFB2B2B2, 0xFF3D3D3D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF7A7A7A, 0xFFFEFEFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFDFDFD, 0xFF7A7A7A, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF3D3D3D, 0xFFFDFDFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFDFDFD, 0xFF3D3D3D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFB2B2B2, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFB2B2B2, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF494949, 0xFFE2E2E2, 0xFFE3E3E3, 0xFF494949, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFE6E6E6, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF4A4A4A, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF0Line truncated
static constexpr size_t ChargingBatteryY = 28; static_assert(sizeof(ChargingRedBattery) == sizeof(u32) * ChargingRedBatteryW * ChargingRedBatteryH, "Incorrect ChargingRedBattery definition!");
static constexpr size_t ChargingBatteryW = 76;
static constexpr size_t ChargingBatteryH = 28;
static constexpr size_t ChargingBatteryMeterX = 7;
static constexpr size_t ChargingBatteryMeterY = 8;
static constexpr size_t ChargingBatteryMeterW = 31;
static constexpr size_t ChargingBatteryMeterH = 12;
static_assert(ChargingBatteryMeterX + ChargingBatteryMeterW < ChargingBatteryW && ChargingBatteryMeterY + ChargingBatteryMeterH < ChargingBatteryH, "Incorrect ChargingBatteryMeter definition!");
static constexpr u32 ChargingBattery[] = {0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF3D3D3D, 0xFFB2B2B2, 0xFFE6E6E6, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFE6E6E6, 0xFFB2B2B2, 0xFF3D3D3D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF7A7A7A, 0xFFFEFEFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFDFDFD, 0xFF7A7A7A, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF3D3D3D, 0xFFFDFDFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFDFDFD, 0xFF3D3D3D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFB2B2B2, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFB2B2B2, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF494949, 0xFFE2E2E2, 0xFFE3E3E3, 0xFF494949, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFE6E6E6, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF4A4A4A, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0Line truncated
static_assert(sizeof(ChargingBattery) == sizeof(u32) * ChargingBatteryW * ChargingBatteryH, "Incorrect ChargingBattery definition!");
@@ -1,28 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include "boot_types.hpp"
static constexpr size_t LowBatteryX = 26;
static constexpr size_t LowBatteryY = 28;
static constexpr size_t LowBatteryW = 52;
static constexpr size_t LowBatteryH = 28;
static constexpr u32 LowBattery[] = {0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF3D3D3D, 0xFFB2B2B2, 0xFFE6E6E6, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFE6E6E6, 0xFFB2B2B2, 0xFF3D3D3D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF7A7A7A, 0xFFFEFEFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFDFDFD, 0xFF7A7A7A, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF3D3D3D, 0xFFFDFDFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFDFDFD, 0xFF3D3D3D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFB2B2B2, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFB2B2B2, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFE6E6E6, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF4A4A4A, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF4B4B4B, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFE6E6E6, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF00Line truncated
static_assert(sizeof(LowBattery) == sizeof(u32) * LowBatteryW * LowBatteryH, "Incorrect LowBattery definition!");
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
constexpr size_t LowBatteryX = 26;
constexpr size_t LowBatteryY = 28;
constexpr size_t LowBatteryW = 52;
constexpr size_t LowBatteryH = 28;
constexpr u32 LowBattery[] = {0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF3D3D3D, 0xFFB2B2B2, 0xFFE6E6E6, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFE6E6E6, 0xFFB2B2B2, 0xFF3D3D3D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF7A7A7A, 0xFFFEFEFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFDFDFD, 0xFF7A7A7A, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF3D3D3D, 0xFFFDFDFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFDFDFD, 0xFF3D3D3D, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFB2B2B2, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFB2B2B2, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFE6E6E6, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF4A4A4A, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF4B4B4B, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFE6E6E6, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0Line truncated
static_assert(sizeof(LowBattery) == sizeof(u32) * LowBatteryW * LowBatteryH, "Incorrect LowBattery definition!");
+31 -19
View File
@@ -14,22 +14,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp" #include "boot_battery_icons.hpp"
#include "boot_battery_icon_low.hpp" #include "boot_display.hpp"
#include "boot_battery_icon_charging.hpp"
#include "boot_battery_icon_charging_red.hpp"
void Boot::ShowLowBatteryIcon() { namespace sts::boot {
Boot::InitializeDisplay();
{
/* Low battery icon is shown for 5 seconds. */
Boot::ShowDisplay(LowBatteryX, LowBatteryY, LowBatteryW, LowBatteryH, LowBattery);
svcSleepThread(5'000'000'000ul);
}
Boot::FinalizeDisplay();
}
static void FillBatteryMeter(u32 *icon, const size_t icon_w, const size_t icon_h, const size_t meter_x, const size_t meter_y, const size_t meter_w, const size_t meter_h, const size_t fill_w) { 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; 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) { if (fill_x + fill_w > icon_w || meter_y + meter_h > icon_h || fill_x == 0) {
@@ -49,7 +47,19 @@ static void FillBatteryMeter(u32 *icon, const size_t icon_w, const size_t icon_h
} }
} }
void Boot::StartShowChargingIcon(size_t battery_percentage, bool wait) { }
void ShowLowBatteryIcon() {
InitializeDisplay();
{
/* Low battery icon is shown for 5 seconds. */
ShowDisplay(LowBatteryX, LowBatteryY, LowBatteryW, LowBatteryH, LowBattery);
svcSleepThread(5'000'000'000ul);
}
FinalizeDisplay();
}
void StartShowChargingIcon(size_t battery_percentage, bool wait) {
const bool is_red = battery_percentage <= 15; const bool is_red = battery_percentage <= 15;
const size_t IconX = is_red ? ChargingRedBatteryX : ChargingBatteryX; const size_t IconX = is_red ? ChargingRedBatteryX : ChargingBatteryX;
@@ -68,8 +78,8 @@ void Boot::StartShowChargingIcon(size_t battery_percentage, bool wait) {
std::memcpy(Icon, is_red ? ChargingRedBattery : ChargingBattery, sizeof(Icon)); std::memcpy(Icon, is_red ? ChargingRedBattery : ChargingBattery, sizeof(Icon));
FillBatteryMeter(Icon, IconW, IconH, IconMeterX, IconMeterY, IconMeterW, IconMeterH, MeterFillW); FillBatteryMeter(Icon, IconW, IconH, IconMeterX, IconMeterY, IconMeterW, IconMeterH, MeterFillW);
Boot::InitializeDisplay(); InitializeDisplay();
Boot::ShowDisplay(IconX, IconY, IconW, IconH, Icon); ShowDisplay(IconX, IconY, IconW, IconH, Icon);
} }
/* Wait for 2 seconds if we're supposed to. */ /* Wait for 2 seconds if we're supposed to. */
@@ -78,6 +88,8 @@ void Boot::StartShowChargingIcon(size_t battery_percentage, bool wait) {
} }
} }
void Boot::EndShowChargingIcon() { void EndShowChargingIcon() {
Boot::FinalizeDisplay(); FinalizeDisplay();
}
} }
@@ -18,13 +18,11 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#define IRAM_BASE 0x40000000ull namespace sts::boot {
#define IRAM_SIZE 0x40000
#define IRAM_PAYLOAD_MAX_SIZE 0x2E000
#define IRAM_PAYLOAD_BASE 0x40010000ull
class BootRebootManager { /* Battery Display utilities. */
public: void ShowLowBatteryIcon();
static Result PerformReboot(); void StartShowChargingIcon(size_t battery_percentage, bool wait);
static void RebootForFatalError(AtmosphereFatalErrorContext *ctx); void EndShowChargingIcon();
};
}
@@ -14,99 +14,96 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once constexpr u8 Max17050Status = 0x00;
#include <switch.h> constexpr u8 Max17050VAlrtThreshold = 0x01;
constexpr u8 Max17050TAlrtThreshold = 0x02;
constexpr u8 Max17050SocAlrtThreshold = 0x03;
constexpr u8 Max17050AtRate = 0x04;
constexpr u8 Max17050RemCapRep = 0x05;
constexpr u8 Max17050SocRep = 0x06;
constexpr u8 Max17050Age = 0x07;
constexpr u8 Max17050Temperature = 0x08;
constexpr u8 Max17050VCell = 0x09;
constexpr u8 Max17050Current = 0x0A;
constexpr u8 Max17050AverageCurrent = 0x0B;
static constexpr u8 Max17050Status = 0x00; constexpr u8 Max17050SocMix = 0x0D;
static constexpr u8 Max17050VAlrtThreshold = 0x01; constexpr u8 Max17050SocAv = 0x0E;
static constexpr u8 Max17050TAlrtThreshold = 0x02; constexpr u8 Max17050RemCapMix = 0x0F;
static constexpr u8 Max17050SocAlrtThreshold = 0x03; constexpr u8 Max17050FullCap = 0x10;
static constexpr u8 Max17050AtRate = 0x04; constexpr u8 Max17050Tte = 0x11;
static constexpr u8 Max17050RemCapRep = 0x05; constexpr u8 Max17050QResidual00 = 0x12;
static constexpr u8 Max17050SocRep = 0x06; constexpr u8 Max17050FullSocThr = 0x13;
static constexpr u8 Max17050Age = 0x07;
static constexpr u8 Max17050Temperature = 0x08;
static constexpr u8 Max17050VCell = 0x09;
static constexpr u8 Max17050Current = 0x0A;
static constexpr u8 Max17050AverageCurrent = 0x0B;
static constexpr u8 Max17050SocMix = 0x0D;
static constexpr u8 Max17050SocAv = 0x0E;
static constexpr u8 Max17050RemCapMix = 0x0F;
static constexpr u8 Max17050FullCap = 0x10;
static constexpr u8 Max17050Tte = 0x11;
static constexpr u8 Max17050QResidual00 = 0x12;
static constexpr u8 Max17050FullSocThr = 0x13;
static constexpr u8 Max17050AverageTemp = 0x16; constexpr u8 Max17050AverageTemp = 0x16;
static constexpr u8 Max17050Cycles = 0x17; constexpr u8 Max17050Cycles = 0x17;
static constexpr u8 Max17050DesignCap = 0x18; constexpr u8 Max17050DesignCap = 0x18;
static constexpr u8 Max17050AverageVCell = 0x19; constexpr u8 Max17050AverageVCell = 0x19;
static constexpr u8 Max17050MaxMinTemp = 0x1A; constexpr u8 Max17050MaxMinTemp = 0x1A;
static constexpr u8 Max17050MaxMinVoltage = 0x1B; constexpr u8 Max17050MaxMinVoltage = 0x1B;
static constexpr u8 Max17050MaxMinCurrent = 0x1C; constexpr u8 Max17050MaxMinCurrent = 0x1C;
static constexpr u8 Max17050Config = 0x1D; constexpr u8 Max17050Config = 0x1D;
static constexpr u8 Max17050IChgTerm = 0x1E; constexpr u8 Max17050IChgTerm = 0x1E;
static constexpr u8 Max17050RemCapAv = 0x1F; constexpr u8 Max17050RemCapAv = 0x1F;
static constexpr u8 Max17050Version = 0x21; constexpr u8 Max17050Version = 0x21;
static constexpr u8 Max17050QResidual10 = 0x22; constexpr u8 Max17050QResidual10 = 0x22;
static constexpr u8 Max17050FullCapNom = 0x23; constexpr u8 Max17050FullCapNom = 0x23;
static constexpr u8 Max17050TempNom = 0x24; constexpr u8 Max17050TempNom = 0x24;
static constexpr u8 Max17050TempLim = 0x25; constexpr u8 Max17050TempLim = 0x25;
static constexpr u8 Max17050Ain = 0x27; constexpr u8 Max17050Ain = 0x27;
static constexpr u8 Max17050LearnCfg = 0x28; constexpr u8 Max17050LearnCfg = 0x28;
static constexpr u8 Max17050FilterCfg = 0x29; constexpr u8 Max17050FilterCfg = 0x29;
static constexpr u8 Max17050RelaxCfg = 0x2A; constexpr u8 Max17050RelaxCfg = 0x2A;
static constexpr u8 Max17050MiscCfg = 0x2B; constexpr u8 Max17050MiscCfg = 0x2B;
static constexpr u8 Max17050TGain = 0x2C; constexpr u8 Max17050TGain = 0x2C;
static constexpr u8 Max17050TOff = 0x2D; constexpr u8 Max17050TOff = 0x2D;
static constexpr u8 Max17050CGain = 0x2E; constexpr u8 Max17050CGain = 0x2E;
static constexpr u8 Max17050COff = 0x2F; constexpr u8 Max17050COff = 0x2F;
static constexpr u8 Max17050QResidual20 = 0x32; constexpr u8 Max17050QResidual20 = 0x32;
static constexpr u8 Max17050IAvgEmpty = 0x36; constexpr u8 Max17050IAvgEmpty = 0x36;
static constexpr u8 Max17050FCtc = 0x37; constexpr u8 Max17050FCtc = 0x37;
static constexpr u8 Max17050RComp0 = 0x38; constexpr u8 Max17050RComp0 = 0x38;
static constexpr u8 Max17050TempCo = 0x39; constexpr u8 Max17050TempCo = 0x39;
static constexpr u8 Max17050VEmpty = 0x3A; constexpr u8 Max17050VEmpty = 0x3A;
static constexpr u8 Max17050FStat = 0x3D; constexpr u8 Max17050FStat = 0x3D;
static constexpr u8 Max17050Timer = 0x3E; constexpr u8 Max17050Timer = 0x3E;
static constexpr u8 Max17050ShdnTimer = 0x3F; constexpr u8 Max17050ShdnTimer = 0x3F;
static constexpr u8 Max17050QResidual30 = 0x42; constexpr u8 Max17050QResidual30 = 0x42;
static constexpr u8 Max17050DQAcc = 0x45; constexpr u8 Max17050DQAcc = 0x45;
static constexpr u8 Max17050DPAcc = 0x46; constexpr u8 Max17050DPAcc = 0x46;
static constexpr u8 Max17050SocVf0 = 0x48; constexpr u8 Max17050SocVf0 = 0x48;
static constexpr u8 Max17050Qh0 = 0x4C; constexpr u8 Max17050Qh0 = 0x4C;
static constexpr u8 Max17050Qh = 0x4D; constexpr u8 Max17050Qh = 0x4D;
static constexpr u8 Max17050SocVfAccess = 0x60; constexpr u8 Max17050SocVfAccess = 0x60;
static constexpr u8 Max17050ModelAccess0 = 0x62; constexpr u8 Max17050ModelAccess0 = 0x62;
static constexpr u8 Max17050ModelAccess1 = 0x63; constexpr u8 Max17050ModelAccess1 = 0x63;
static constexpr u8 Max17050ModelChrTblStart = 0x80; constexpr u8 Max17050ModelChrTblStart = 0x80;
static constexpr u8 Max17050ModelChrTblEnd = 0xB0; constexpr u8 Max17050ModelChrTblEnd = 0xB0;
static constexpr u8 Max17050VFocV = 0xFB; constexpr u8 Max17050VFocV = 0xFB;
static constexpr u8 Max17050SocVf = 0xFF; constexpr u8 Max17050SocVf = 0xFF;
static constexpr size_t Max17050ModelChrTblSize = Max17050ModelChrTblEnd - Max17050ModelChrTblStart; constexpr size_t Max17050ModelChrTblSize = Max17050ModelChrTblEnd - Max17050ModelChrTblStart;
struct Max17050Parameters { struct Max17050Parameters {
u16 relaxcfg; u16 relaxcfg;
@@ -129,7 +126,7 @@ struct Max17050Parameters {
static_assert(sizeof(Max17050Parameters) == 0x7E, "Max17050Parameters definition!"); static_assert(sizeof(Max17050Parameters) == 0x7E, "Max17050Parameters definition!");
static constexpr Max17050Parameters Max17050ParamsA = { constexpr Max17050Parameters Max17050ParamsA = {
0x203B, /* relaxcfg */ 0x203B, /* relaxcfg */
0x0053, /* rcomp0 */ 0x0053, /* rcomp0 */
0x1C22, /* tempco */ 0x1C22, /* tempco */
@@ -155,7 +152,7 @@ static constexpr Max17050Parameters Max17050ParamsA = {
0x1D2A /* iavgempty */ 0x1D2A /* iavgempty */
}; };
static constexpr Max17050Parameters Max17050ParamsM = { constexpr Max17050Parameters Max17050ParamsM = {
0x203B, /* relaxcfg */ 0x203B, /* relaxcfg */
0x0085, /* rcomp0 */ 0x0085, /* rcomp0 */
0x1625, /* tempco */ 0x1625, /* tempco */
@@ -181,7 +178,7 @@ static constexpr Max17050Parameters Max17050ParamsM = {
0x1D2A /* iavgempty */ 0x1D2A /* iavgempty */
}; };
static constexpr Max17050Parameters Max17050ParamsR = { constexpr Max17050Parameters Max17050ParamsR = {
0x203B, /* relaxcfg */ 0x203B, /* relaxcfg */
0x0048, /* rcomp0 */ 0x0048, /* rcomp0 */
0x2034, /* tempco */ 0x2034, /* tempco */
@@ -207,7 +204,7 @@ static constexpr Max17050Parameters Max17050ParamsR = {
0x1D2A /* iavgempty */ 0x1D2A /* iavgempty */
}; };
static constexpr Max17050Parameters Max17050Params1 = { constexpr Max17050Parameters Max17050Params1 = {
0x203B, /* relaxcfg */ 0x203B, /* relaxcfg */
0x0040, /* rcomp0 */ 0x0040, /* rcomp0 */
0x1624, /* tempco */ 0x1624, /* tempco */
@@ -233,7 +230,7 @@ static constexpr Max17050Parameters Max17050Params1 = {
0x1584 /* iavgempty */ 0x1584 /* iavgempty */
}; };
static constexpr Max17050Parameters Max17050Params2 = { constexpr Max17050Parameters Max17050Params2 = {
0x203B, /* relaxcfg */ 0x203B, /* relaxcfg */
0x004A, /* rcomp0 */ 0x004A, /* rcomp0 */
0x1D23, /* tempco */ 0x1D23, /* tempco */
@@ -259,7 +256,7 @@ static constexpr Max17050Parameters Max17050Params2 = {
0x1680 /* iavgempty */ 0x1680 /* iavgempty */
}; };
static constexpr Max17050Parameters Max17050Params2M = { constexpr Max17050Parameters Max17050Params2M = {
0x203B, /* relaxcfg */ 0x203B, /* relaxcfg */
0x0049, /* rcomp0 */ 0x0049, /* rcomp0 */
0x222A, /* tempco */ 0x222A, /* tempco */
+20 -7
View File
@@ -14,13 +14,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp" #include <stratosphere/spl.hpp>
#include "boot_boot_reason.hpp"
#include "boot_pmic_driver.hpp" #include "boot_pmic_driver.hpp"
#include "boot_rtc_driver.hpp" #include "boot_rtc_driver.hpp"
static u32 g_boot_reason = 0; namespace sts::boot {
static bool g_detected_boot_reason = false;
namespace {
/* Types. */
struct BootReasonValue { struct BootReasonValue {
union { union {
struct { struct {
@@ -33,7 +37,12 @@ struct BootReasonValue {
}; };
}; };
static u32 MakeBootReason(u32 power_intr, u8 rtc_intr, u8 nv_erc, bool ac_ok) { /* Globals. */
u32 g_boot_reason = 0;
bool g_detected_boot_reason = false;
/* Helpers. */
u32 MakeBootReason(u32 power_intr, u8 rtc_intr, u8 nv_erc, bool ac_ok) {
if (power_intr & 0x08) { if (power_intr & 0x08) {
return 2; return 2;
} }
@@ -44,7 +53,7 @@ static u32 MakeBootReason(u32 power_intr, u8 rtc_intr, u8 nv_erc, bool ac_ok) {
return 1; return 1;
} }
if (rtc_intr & 0x04) { if (rtc_intr & 0x04) {
if (nv_erc != 0x80 && !Boot::IsRecoveryBoot()) { if (nv_erc != 0x80 && !spl::IsRecoveryBoot()) {
return 4; return 4;
} }
} }
@@ -54,7 +63,9 @@ static u32 MakeBootReason(u32 power_intr, u8 rtc_intr, u8 nv_erc, bool ac_ok) {
return 0; return 0;
} }
void Boot::DetectBootReason() { }
void DetectBootReason() {
u8 power_intr; u8 power_intr;
u8 rtc_intr; u8 rtc_intr;
u8 rtc_intr_m; u8 rtc_intr_m;
@@ -104,10 +115,12 @@ void Boot::DetectBootReason() {
g_detected_boot_reason = true; g_detected_boot_reason = true;
} }
u32 Boot::GetBootReason() { u32 GetBootReason() {
if (!g_detected_boot_reason) { if (!g_detected_boot_reason) {
std::abort(); std::abort();
} }
return g_boot_reason; return g_boot_reason;
} }
}
@@ -18,16 +18,10 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
/* pcv isn't alive at the time boot runs, but nn::i2c::driver needs nn::pcv. */ namespace sts::boot {
/* These are the overrides N puts in boot. */
class Pcv { /* Boot Reason utilities. */
public: void DetectBootReason();
static void Initialize(); u32 GetBootReason();
static void Finalize();
static Result SetClockRate(PcvModule module, u32 hz); }
static Result SetClockEnabled(PcvModule module, bool enabled);
static Result SetVoltageEnabled(u32 domain, bool enabled);
static Result SetVoltageValue(u32 domain, u32 voltage);
static Result SetReset(PcvModule module, bool reset);
};
@@ -14,20 +14,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once namespace sts::boot::bq24193 {
#include <switch.h>
static constexpr u8 Bq24193InputSourceControl = 0x00; constexpr u8 InputSourceControl = 0x00;
static constexpr u8 Bq24193PowerOnConfiguration = 0x01; constexpr u8 PowerOnConfiguration = 0x01;
static constexpr u8 Bq24193ChargeCurrentControl = 0x02; constexpr u8 ChargeCurrentControl = 0x02;
static constexpr u8 Bq24193PreChargeTerminationCurrentControl = 0x03; constexpr u8 PreChargeTerminationCurrentControl = 0x03;
static constexpr u8 Bq24193ChargeVoltageControl = 0x04; constexpr u8 ChargeVoltageControl = 0x04;
static constexpr u8 Bq24193ChargeTerminationTimerControl = 0x05; constexpr u8 ChargeTerminationTimerControl = 0x05;
static constexpr u8 Bq24193IrCompensationThermalRegulationControl = 0x06; constexpr u8 IrCompensationThermalRegulationControl = 0x06;
static constexpr u8 Bq24193MiscOperationControl = 0x07; constexpr u8 MiscOperationControl = 0x07;
static constexpr u8 Bq24193SystemStatus = 0x08; constexpr u8 SystemStatus = 0x08;
static constexpr u8 Bq24193Fault = 0x09; constexpr u8 Fault = 0x09;
static constexpr u8 Bq24193VendorPartRevisionStatus = 0x0A; constexpr u8 VendorPartRevisionStatus = 0x0A;
enum ChargerConfiguration : u8 { enum ChargerConfiguration : u8 {
ChargerConfiguration_ChargeDisable = (0 << 4), ChargerConfiguration_ChargeDisable = (0 << 4),
@@ -35,10 +34,10 @@ enum ChargerConfiguration : u8 {
ChargerConfiguration_Otg = (2 << 4), ChargerConfiguration_Otg = (2 << 4),
}; };
static constexpr u32 ChargeVoltageLimitMin = 3504; constexpr u32 ChargeVoltageLimitMin = 3504;
static constexpr u32 ChargeVoltageLimitMax = 4208; constexpr u32 ChargeVoltageLimitMax = 4208;
static inline u8 EncodeChargeVoltageLimit(u32 voltage) { inline u8 EncodeChargeVoltageLimit(u32 voltage) {
if (voltage < ChargeVoltageLimitMin || voltage > ChargeVoltageLimitMax) { if (voltage < ChargeVoltageLimitMin || voltage > ChargeVoltageLimitMax) {
std::abort(); std::abort();
} }
@@ -47,14 +46,14 @@ static inline u8 EncodeChargeVoltageLimit(u32 voltage) {
return static_cast<u8>(voltage << 2); return static_cast<u8>(voltage << 2);
} }
static inline u32 DecodeChargeVoltageLimit(u8 reg) { inline u32 DecodeChargeVoltageLimit(u8 reg) {
return ChargeVoltageLimitMin + (static_cast<u32>(reg & 0xFC) << 2); return ChargeVoltageLimitMin + (static_cast<u32>(reg & 0xFC) << 2);
} }
static constexpr u32 FastChargeCurrentLimitMin = 512; constexpr u32 FastChargeCurrentLimitMin = 512;
static constexpr u32 FastChargeCurrentLimitMax = 4544; constexpr u32 FastChargeCurrentLimitMax = 4544;
static inline u8 EncodeFastChargeCurrentLimit(u32 current) { inline u8 EncodeFastChargeCurrentLimit(u32 current) {
if (current < FastChargeCurrentLimitMin || current > FastChargeCurrentLimitMax) { if (current < FastChargeCurrentLimitMin || current > FastChargeCurrentLimitMax) {
std::abort(); std::abort();
} }
@@ -63,7 +62,7 @@ static inline u8 EncodeFastChargeCurrentLimit(u32 current) {
return static_cast<u8>(current << 2); return static_cast<u8>(current << 2);
} }
static inline u32 DecodeFastChargeCurrentLimit(u8 reg) { inline u32 DecodeFastChargeCurrentLimit(u8 reg) {
return FastChargeCurrentLimitMin + (static_cast<u32>(reg & 0xFC) << 4); return FastChargeCurrentLimitMin + (static_cast<u32>(reg & 0xFC) << 4);
} }
@@ -78,10 +77,10 @@ enum InputCurrentLimit : u8 {
InputCurrentLimit_3000mA = 7, InputCurrentLimit_3000mA = 7,
}; };
static constexpr u32 PreChargeCurrentLimitMin = 128; constexpr u32 PreChargeCurrentLimitMin = 128;
static constexpr u32 PreChargeCurrentLimitMax = 2048; constexpr u32 PreChargeCurrentLimitMax = 2048;
static inline u8 EncodePreChargeCurrentLimit(u32 current) { inline u8 EncodePreChargeCurrentLimit(u32 current) {
if (current < PreChargeCurrentLimitMin || current > PreChargeCurrentLimitMax) { if (current < PreChargeCurrentLimitMin || current > PreChargeCurrentLimitMax) {
std::abort(); std::abort();
} }
@@ -90,14 +89,14 @@ static inline u8 EncodePreChargeCurrentLimit(u32 current) {
return static_cast<u8>(current << 4); return static_cast<u8>(current << 4);
} }
static inline u32 DecodePreChargeCurrentLimit(u8 reg) { inline u32 DecodePreChargeCurrentLimit(u8 reg) {
return PreChargeCurrentLimitMin + (static_cast<u32>(reg & 0xF0) << 3); return PreChargeCurrentLimitMin + (static_cast<u32>(reg & 0xF0) << 3);
} }
static constexpr u32 TerminationCurrentLimitMin = 128; constexpr u32 TerminationCurrentLimitMin = 128;
static constexpr u32 TerminationCurrentLimitMax = 2048; constexpr u32 TerminationCurrentLimitMax = 2048;
static inline u8 EncodeTerminationCurrentLimit(u32 current) { inline u8 EncodeTerminationCurrentLimit(u32 current) {
if (current < TerminationCurrentLimitMin || current > TerminationCurrentLimitMax) { if (current < TerminationCurrentLimitMin || current > TerminationCurrentLimitMax) {
std::abort(); std::abort();
} }
@@ -106,14 +105,14 @@ static inline u8 EncodeTerminationCurrentLimit(u32 current) {
return static_cast<u8>(current); return static_cast<u8>(current);
} }
static inline u32 DecodeTerminationCurrentLimit(u8 reg) { inline u32 DecodeTerminationCurrentLimit(u8 reg) {
return TerminationCurrentLimitMin + (static_cast<u32>(reg & 0xF) << 7); return TerminationCurrentLimitMin + (static_cast<u32>(reg & 0xF) << 7);
} }
static constexpr u32 MinimumSystemVoltageLimitMin = 3000; constexpr u32 MinimumSystemVoltageLimitMin = 3000;
static constexpr u32 MinimumSystemVoltageLimitMax = 3700; constexpr u32 MinimumSystemVoltageLimitMax = 3700;
static inline u8 EncodeMinimumSystemVoltageLimit(u32 voltage) { inline u8 EncodeMinimumSystemVoltageLimit(u32 voltage) {
if (voltage < MinimumSystemVoltageLimitMin || voltage > MinimumSystemVoltageLimitMax) { if (voltage < MinimumSystemVoltageLimitMin || voltage > MinimumSystemVoltageLimitMax) {
std::abort(); std::abort();
} }
@@ -122,7 +121,7 @@ static inline u8 EncodeMinimumSystemVoltageLimit(u32 voltage) {
return static_cast<u8>(voltage << 1); return static_cast<u8>(voltage << 1);
} }
static inline u32 DecodeMinimumSystemVoltageLimit(u8 reg) { inline u32 DecodeMinimumSystemVoltageLimit(u8 reg) {
return MinimumSystemVoltageLimitMin + (static_cast<u32>(reg & 0x0E) * 50); return MinimumSystemVoltageLimitMin + (static_cast<u32>(reg & 0x0E) * 50);
} }
@@ -137,3 +136,5 @@ enum BoostModeCurrentLimit : u8 {
BoostModeCurrentLimit_500mA = 0, BoostModeCurrentLimit_500mA = 0,
BoostModeCurrentLimit_1300mA = 1, BoostModeCurrentLimit_1300mA = 1,
}; };
}
+26 -16
View File
@@ -14,20 +14,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp" #include "boot_calibration.hpp"
static constexpr size_t BatteryLotOffset = 0x2CE0; namespace sts::boot {
static constexpr size_t BatteryLotSize = 0x20;
static constexpr size_t BatteryVersionOffset = 0x4310;
static constexpr size_t BatteryVersionSize = 0x10;
static constexpr u32 DefaultBatteryVendor = static_cast<u32>('A'); namespace {
static constexpr u32 DefaultBatteryVersion = 0;
static constexpr Result ResultCalInvalidCrc = 0xCAC6; /* TODO: Verify this really is cal, move to libstrat results. */ /* Convenience definitions. */
constexpr size_t BatteryLotOffset = 0x2CE0;
constexpr size_t BatteryLotSize = 0x20;
constexpr size_t BatteryVersionOffset = 0x4310;
constexpr size_t BatteryVersionSize = 0x10;
u16 Boot::GetCrc16(const void *data, size_t size) { constexpr u32 DefaultBatteryVendor = static_cast<u32>('A');
static constexpr u16 s_crc_table[0x10] = { constexpr u32 DefaultBatteryVersion = 0;
constexpr Result ResultCalInvalidCrc = 0xCAC6; /* TODO: Verify this really is cal, move to libstrat results. */
/* Helpers. */
constexpr u16 GetCrc16(const void *data, size_t size) {
constexpr u16 s_crc_table[0x10] = {
0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
}; };
@@ -45,15 +51,15 @@ u16 Boot::GetCrc16(const void *data, size_t size) {
return crc16; return crc16;
} }
static Result ValidateCalibrationCrc16(const void *data, size_t size) { Result ValidateCalibrationCrc16(const void *data, size_t size) {
const u8 *data_u8 = reinterpret_cast<const u8 *>(data); const u8 *data_u8 = reinterpret_cast<const u8 *>(data);
if (Boot::GetCrc16(data, size - sizeof(u16)) != *(reinterpret_cast<const u16 *>(&data_u8[size - sizeof(u16)]))) { if (GetCrc16(data, size - sizeof(u16)) != *(reinterpret_cast<const u16 *>(&data_u8[size - sizeof(u16)]))) {
return ResultCalInvalidCrc; return ResultCalInvalidCrc;
} }
return ResultSuccess; return ResultSuccess;
} }
static Result GetBatteryVendorImpl(u32 *vendor) { Result GetBatteryVendorImpl(u32 *vendor) {
FsStorage s; FsStorage s;
R_TRY(fsOpenBisStorage(&s, FsBisStorageId_CalibrationBinary)); R_TRY(fsOpenBisStorage(&s, FsBisStorageId_CalibrationBinary));
ON_SCOPE_EXIT { fsStorageClose(&s); }; ON_SCOPE_EXIT { fsStorageClose(&s); };
@@ -67,7 +73,7 @@ static Result GetBatteryVendorImpl(u32 *vendor) {
return ResultSuccess; return ResultSuccess;
} }
static Result GetBatteryVersionImpl(u32 *version) { Result GetBatteryVersionImpl(u32 *version) {
FsStorage s; FsStorage s;
R_TRY(fsOpenBisStorage(&s, FsBisStorageId_CalibrationBinary)); R_TRY(fsOpenBisStorage(&s, FsBisStorageId_CalibrationBinary));
ON_SCOPE_EXIT { fsStorageClose(&s); }; ON_SCOPE_EXIT { fsStorageClose(&s); };
@@ -81,7 +87,9 @@ static Result GetBatteryVersionImpl(u32 *version) {
return ResultSuccess; return ResultSuccess;
} }
u32 Boot::GetBatteryVendor() { }
u32 GetBatteryVendor() {
u32 vendor; u32 vendor;
if (R_FAILED(GetBatteryVendorImpl(&vendor))) { if (R_FAILED(GetBatteryVendorImpl(&vendor))) {
return DefaultBatteryVendor; return DefaultBatteryVendor;
@@ -89,10 +97,12 @@ u32 Boot::GetBatteryVendor() {
return vendor; return vendor;
} }
u32 Boot::GetBatteryVersion() { u32 GetBatteryVersion() {
u32 version; u32 version;
if (R_FAILED(GetBatteryVersionImpl(&version))) { if (R_FAILED(GetBatteryVersionImpl(&version))) {
return DefaultBatteryVersion; return DefaultBatteryVersion;
} }
return version; return version;
} }
}
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::boot {
/* Calibration utilities. */
u32 GetBatteryVersion();
u32 GetBatteryVendor();
}
@@ -14,19 +14,27 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp" #include "boot_change_voltage.hpp"
#include "boot_pmc_wrapper.hpp"
static constexpr u32 Sdmmc3VoltageBit = (1 << 13); /* SDMMC3 */ namespace sts::boot {
static constexpr u32 AudioVoltageBit = (1 << 18); /* AUDIO_HV */
static constexpr u32 GpioVoltageBit = (1 << 21); /* GPIO */
static constexpr u32 SpiVoltageBit = (1 << 23); /* SPI_HV */
static constexpr u32 VoltageChangeMask = SpiVoltageBit | GpioVoltageBit | AudioVoltageBit | Sdmmc3VoltageBit; namespace {
static constexpr u32 PmcPwrDet = 0x7000E448; /* Convenience definitions. */
static constexpr u32 PmcPwrDetVal = 0x7000E4E4; 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 */
void Boot::ChangeGpioVoltageTo1_8v() { 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. */ /* Write mask to APBDEV_PMC_PWR_DET, then clear APBDEV_PMC_PWR_DET_VAL. */
WritePmcRegister(PmcPwrDet, VoltageChangeMask, VoltageChangeMask); WritePmcRegister(PmcPwrDet, VoltageChangeMask, VoltageChangeMask);
WritePmcRegister(PmcPwrDetVal, 0, VoltageChangeMask); WritePmcRegister(PmcPwrDetVal, 0, VoltageChangeMask);
@@ -34,3 +42,5 @@ void Boot::ChangeGpioVoltageTo1_8v() {
/* Sleep for 100 us. */ /* Sleep for 100 us. */
svcSleepThread(100'000ul); svcSleepThread(100'000ul);
} }
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::boot {
void ChangeGpioVoltageTo1_8v();;
}
@@ -16,14 +16,17 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "boot_charger_driver.hpp" #include "boot_charger_driver.hpp"
namespace sts::boot {
Result ChargerDriver::Read(u8 addr, u8 *out) { Result ChargerDriver::Read(u8 addr, u8 *out) {
return Boot::ReadI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(out), sizeof(*out), &addr, sizeof(addr)); return ReadI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(out), sizeof(*out), &addr, sizeof(addr));
} }
Result ChargerDriver::Write(u8 addr, u8 val) { Result ChargerDriver::Write(u8 addr, u8 val) {
return Boot::WriteI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(&val), sizeof(val), &addr, sizeof(addr)); return WriteI2cRegister(this->i2c_session, reinterpret_cast<u8 *>(&val), sizeof(val), &addr, sizeof(addr));
} }
Result ChargerDriver::ReadWrite(u8 addr, u8 mask, u8 val) { Result ChargerDriver::ReadWrite(u8 addr, u8 mask, u8 val) {
@@ -41,7 +44,7 @@ Result ChargerDriver::Initialize() {
Result ChargerDriver::Initialize(bool set_input_current_limit) { Result ChargerDriver::Initialize(bool set_input_current_limit) {
if (set_input_current_limit) { if (set_input_current_limit) {
R_TRY(this->SetInputCurrentLimit(InputCurrentLimit_500mA)); R_TRY(this->SetInputCurrentLimit(bq24193::InputCurrentLimit_500mA));
} }
R_TRY(this->SetChargeVoltageLimit(4208)); R_TRY(this->SetChargeVoltageLimit(4208));
@@ -50,82 +53,84 @@ Result ChargerDriver::Initialize(bool set_input_current_limit) {
R_TRY(this->SetPreChargeCurrentLimit(128)); R_TRY(this->SetPreChargeCurrentLimit(128));
R_TRY(this->SetTerminationCurrentLimit(128)); R_TRY(this->SetTerminationCurrentLimit(128));
R_TRY(this->SetMinimumSystemVoltageLimit(3000)); R_TRY(this->SetMinimumSystemVoltageLimit(3000));
R_TRY(this->SetWatchdogTimerSetting(WatchdogTimerSetting_Disabled)); R_TRY(this->SetWatchdogTimerSetting(bq24193::WatchdogTimerSetting_Disabled));
R_TRY(this->SetChargingSafetyTimerEnabled(false)); R_TRY(this->SetChargingSafetyTimerEnabled(false));
R_TRY(this->ResetWatchdogTimer()); R_TRY(this->ResetWatchdogTimer());
R_TRY(this->SetBoostModeCurrentLimit(BoostModeCurrentLimit_500mA)); R_TRY(this->SetBoostModeCurrentLimit(bq24193::BoostModeCurrentLimit_500mA));
R_TRY(this->SetHiZEnabled(false)); R_TRY(this->SetHiZEnabled(false));
return ResultSuccess; return ResultSuccess;
} }
Result ChargerDriver::SetChargeEnabled(bool enabled) { Result ChargerDriver::SetChargeEnabled(bool enabled) {
Boot::GpioSetValue(GpioPadName_Bq24193Charger, enabled ? GpioValue_Low : GpioValue_High); gpio::SetValue(GpioPadName_Bq24193Charger, enabled ? GpioValue_Low : GpioValue_High);
return this->SetChargerConfiguration(ChargerConfiguration_ChargeBattery); return this->SetChargerConfiguration(bq24193::ChargerConfiguration_ChargeBattery);
} }
Result ChargerDriver::SetChargerConfiguration(ChargerConfiguration config) { Result ChargerDriver::SetChargerConfiguration(bq24193::ChargerConfiguration config) {
return this->ReadWrite(Bq24193PowerOnConfiguration, 0x30, config); return this->ReadWrite(bq24193::PowerOnConfiguration, 0x30, config);
} }
Result ChargerDriver::SetChargeVoltageLimit(u32 voltage) { Result ChargerDriver::SetChargeVoltageLimit(u32 voltage) {
return this->ReadWrite(Bq24193ChargeVoltageControl, 0xFC, EncodeChargeVoltageLimit(voltage)); return this->ReadWrite(bq24193::ChargeVoltageControl, 0xFC, bq24193::EncodeChargeVoltageLimit(voltage));
} }
Result ChargerDriver::SetFastChargeCurrentLimit(u32 current) { Result ChargerDriver::SetFastChargeCurrentLimit(u32 current) {
return this->ReadWrite(Bq24193ChargeCurrentControl, 0xFC, EncodeFastChargeCurrentLimit(current)); return this->ReadWrite(bq24193::ChargeCurrentControl, 0xFC, bq24193::EncodeFastChargeCurrentLimit(current));
} }
Result ChargerDriver::SetInputCurrentLimit(InputCurrentLimit current) { Result ChargerDriver::SetInputCurrentLimit(bq24193::InputCurrentLimit current) {
return this->ReadWrite(Bq24193InputSourceControl, 0x07, current); return this->ReadWrite(bq24193::InputSourceControl, 0x07, current);
} }
Result ChargerDriver::SetForce20PercentChargeCurrent(bool force) { Result ChargerDriver::SetForce20PercentChargeCurrent(bool force) {
return this->ReadWrite(Bq24193ChargeCurrentControl, 0x01, force ? 1 : 0); return this->ReadWrite(bq24193::ChargeCurrentControl, 0x01, force ? 1 : 0);
} }
Result ChargerDriver::SetPreChargeCurrentLimit(u32 current) { Result ChargerDriver::SetPreChargeCurrentLimit(u32 current) {
return this->ReadWrite(Bq24193PreChargeTerminationCurrentControl, 0xF0, EncodePreChargeCurrentLimit(current)); return this->ReadWrite(bq24193::PreChargeTerminationCurrentControl, 0xF0, bq24193::EncodePreChargeCurrentLimit(current));
} }
Result ChargerDriver::SetTerminationCurrentLimit(u32 current) { Result ChargerDriver::SetTerminationCurrentLimit(u32 current) {
return this->ReadWrite(Bq24193PreChargeTerminationCurrentControl, 0x0F, EncodeTerminationCurrentLimit(current)); return this->ReadWrite(bq24193::PreChargeTerminationCurrentControl, 0x0F, bq24193::EncodeTerminationCurrentLimit(current));
} }
Result ChargerDriver::SetMinimumSystemVoltageLimit(u32 voltage) { Result ChargerDriver::SetMinimumSystemVoltageLimit(u32 voltage) {
return this->ReadWrite(Bq24193PowerOnConfiguration, 0x0E, EncodeMinimumSystemVoltageLimit(voltage)); return this->ReadWrite(bq24193::PowerOnConfiguration, 0x0E, bq24193::EncodeMinimumSystemVoltageLimit(voltage));
} }
Result ChargerDriver::SetWatchdogTimerSetting(WatchdogTimerSetting setting) { Result ChargerDriver::SetWatchdogTimerSetting(bq24193::WatchdogTimerSetting setting) {
return this->ReadWrite(Bq24193ChargeTerminationTimerControl, 0x30, setting); return this->ReadWrite(bq24193::ChargeTerminationTimerControl, 0x30, setting);
} }
Result ChargerDriver::SetChargingSafetyTimerEnabled(bool enabled) { Result ChargerDriver::SetChargingSafetyTimerEnabled(bool enabled) {
return this->ReadWrite(Bq24193ChargeTerminationTimerControl, 0x08, enabled ? 0x08 : 0); return this->ReadWrite(bq24193::ChargeTerminationTimerControl, 0x08, enabled ? 0x08 : 0);
} }
Result ChargerDriver::ResetWatchdogTimer() { Result ChargerDriver::ResetWatchdogTimer() {
return this->ReadWrite(Bq24193PowerOnConfiguration, 0x40, 0x40); return this->ReadWrite(bq24193::PowerOnConfiguration, 0x40, 0x40);
} }
Result ChargerDriver::SetBoostModeCurrentLimit(BoostModeCurrentLimit current) { Result ChargerDriver::SetBoostModeCurrentLimit(bq24193::BoostModeCurrentLimit current) {
return this->ReadWrite(Bq24193PowerOnConfiguration, 0x01, current); return this->ReadWrite(bq24193::PowerOnConfiguration, 0x01, current);
} }
Result ChargerDriver::SetHiZEnabled(bool enabled) { Result ChargerDriver::SetHiZEnabled(bool enabled) {
return this->ReadWrite(Bq24193InputSourceControl, 0x80, enabled ? 0x80 : 0); return this->ReadWrite(bq24193::InputSourceControl, 0x80, enabled ? 0x80 : 0);
} }
Result ChargerDriver::GetInputCurrentLimit(InputCurrentLimit *out) { Result ChargerDriver::GetInputCurrentLimit(bq24193::InputCurrentLimit *out) {
u8 limit; u8 limit;
R_TRY(this->Read(Bq24193InputSourceControl, &limit)); R_TRY(this->Read(bq24193::InputSourceControl, &limit));
*out = static_cast<InputCurrentLimit>(limit); *out = static_cast<bq24193::InputCurrentLimit>(limit);
return ResultSuccess; return ResultSuccess;
} }
Result ChargerDriver::GetChargeVoltageLimit(u32 *out) { Result ChargerDriver::GetChargeVoltageLimit(u32 *out) {
u8 reg; u8 reg;
R_TRY(this->Read(Bq24193ChargeVoltageControl, &reg)); R_TRY(this->Read(bq24193::ChargeVoltageControl, &reg));
*out = DecodeChargeVoltageLimit(reg); *out = bq24193::DecodeChargeVoltageLimit(reg);
return ResultSuccess; return ResultSuccess;
} }
}
@@ -18,42 +18,45 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "i2c_driver/i2c_api.hpp"
#include "boot_functions.hpp"
#include "boot_bq24193_charger.hpp" #include "boot_bq24193_charger.hpp"
#include "boot_i2c_utils.hpp"
#include "gpio/gpio_utils.hpp"
namespace sts::boot {
class ChargerDriver { class ChargerDriver {
private: private:
static constexpr u32 GpioPadName_Bq24193Charger = 0xA; static constexpr u32 GpioPadName_Bq24193Charger = 0xA;
private: private:
I2cSessionImpl i2c_session; i2c::driver::Session i2c_session;
public: public:
ChargerDriver() { ChargerDriver() {
I2cDriver::Initialize(); i2c::driver::Initialize();
I2cDriver::OpenSession(&this->i2c_session, I2cDevice_Bq24193); i2c::driver::OpenSession(&this->i2c_session, I2cDevice_Bq24193);
Boot::GpioConfigure(GpioPadName_Bq24193Charger); gpio::Configure(GpioPadName_Bq24193Charger);
Boot::GpioSetDirection(GpioPadName_Bq24193Charger, GpioDirection_Output); gpio::SetDirection(GpioPadName_Bq24193Charger, GpioDirection_Output);
} }
~ChargerDriver() { ~ChargerDriver() {
I2cDriver::CloseSession(this->i2c_session); i2c::driver::CloseSession(this->i2c_session);
I2cDriver::Finalize(); i2c::driver::Finalize();
} }
private: private:
Result Read(u8 addr, u8 *out_data); Result Read(u8 addr, u8 *out_data);
Result Write(u8 addr, u8 val); Result Write(u8 addr, u8 val);
Result ReadWrite(u8 addr, u8 mask, u8 val); Result ReadWrite(u8 addr, u8 mask, u8 val);
Result SetInputCurrentLimit(InputCurrentLimit current); Result SetInputCurrentLimit(bq24193::InputCurrentLimit current);
Result SetForce20PercentChargeCurrent(bool force); Result SetForce20PercentChargeCurrent(bool force);
Result SetPreChargeCurrentLimit(u32 current); Result SetPreChargeCurrentLimit(u32 current);
Result SetTerminationCurrentLimit(u32 current); Result SetTerminationCurrentLimit(u32 current);
Result SetMinimumSystemVoltageLimit(u32 voltage); Result SetMinimumSystemVoltageLimit(u32 voltage);
Result SetWatchdogTimerSetting(WatchdogTimerSetting setting); Result SetWatchdogTimerSetting(bq24193::WatchdogTimerSetting setting);
Result SetChargingSafetyTimerEnabled(bool enabled); Result SetChargingSafetyTimerEnabled(bool enabled);
Result ResetWatchdogTimer(); Result ResetWatchdogTimer();
Result SetBoostModeCurrentLimit(BoostModeCurrentLimit current); Result SetBoostModeCurrentLimit(bq24193::BoostModeCurrentLimit current);
Result SetHiZEnabled(bool enabled); Result SetHiZEnabled(bool enabled);
public: public:
@@ -62,7 +65,9 @@ class ChargerDriver {
Result SetChargeVoltageLimit(u32 voltage); Result SetChargeVoltageLimit(u32 voltage);
Result SetFastChargeCurrentLimit(u32 current); Result SetFastChargeCurrentLimit(u32 current);
Result SetChargeEnabled(bool enabled); Result SetChargeEnabled(bool enabled);
Result SetChargerConfiguration(ChargerConfiguration config); Result SetChargerConfiguration(bq24193::ChargerConfiguration config);
Result GetInputCurrentLimit(InputCurrentLimit *out); Result GetInputCurrentLimit(bq24193::InputCurrentLimit *out);
Result GetChargeVoltageLimit(u32 *out); Result GetChargeVoltageLimit(u32 *out);
}; };
}
+51 -37
View File
@@ -14,15 +14,24 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp"
#include "boot_pmic_driver.hpp"
#include "boot_battery_driver.hpp" #include "boot_battery_driver.hpp"
#include "boot_battery_icons.hpp"
#include "boot_boot_reason.hpp"
#include "boot_calibration.hpp"
#include "boot_charger_driver.hpp" #include "boot_charger_driver.hpp"
#include "boot_check_battery.hpp"
#include "boot_pmic_driver.hpp"
#include "boot_power_utils.hpp"
enum CheckBatteryResult { namespace sts::boot {
CheckBatteryResult_Success = 0,
CheckBatteryResult_Shutdown = 1, namespace {
CheckBatteryResult_Reboot = 2,
/* Types. */
enum class CheckBatteryResult {
Success,
Shutdown,
Reboot,
}; };
struct BatteryChargeParameters { struct BatteryChargeParameters {
@@ -40,7 +49,8 @@ struct BatteryChargeParameters {
u32 fast_charge_current_limit_low_voltage; u32 fast_charge_current_limit_low_voltage;
}; };
static constexpr BatteryChargeParameters BatteryChargeParameters0 = { /* Battery parameters. */
constexpr BatteryChargeParameters BatteryChargeParameters0 = {
.temp_min = 4, .temp_min = 4,
.temp_low = 17, .temp_low = 17,
.temp_high = 51, .temp_high = 51,
@@ -54,7 +64,7 @@ static constexpr BatteryChargeParameters BatteryChargeParameters0 = {
.fast_charge_current_limit_low_voltage = 0x200, .fast_charge_current_limit_low_voltage = 0x200,
}; };
static constexpr BatteryChargeParameters BatteryChargeParameters1 = { constexpr BatteryChargeParameters BatteryChargeParameters1 = {
.temp_min = 4, .temp_min = 4,
.temp_low = 17, .temp_low = 17,
.temp_high = 51, .temp_high = 51,
@@ -68,7 +78,7 @@ static constexpr BatteryChargeParameters BatteryChargeParameters1 = {
.fast_charge_current_limit_low_voltage = 0x600, .fast_charge_current_limit_low_voltage = 0x600,
}; };
static constexpr BatteryChargeParameters BatteryChargeParameters2 = { constexpr BatteryChargeParameters BatteryChargeParameters2 = {
.temp_min = 4, .temp_min = 4,
.temp_low = 17, .temp_low = 17,
.temp_high = 51, .temp_high = 51,
@@ -82,7 +92,7 @@ static constexpr BatteryChargeParameters BatteryChargeParameters2 = {
.fast_charge_current_limit_low_voltage = 0x680, .fast_charge_current_limit_low_voltage = 0x680,
}; };
static const BatteryChargeParameters *GetBatteryChargeParameters(u32 battery_version) { constexpr const BatteryChargeParameters *GetBatteryChargeParameters(u32 battery_version) {
switch (battery_version) { switch (battery_version) {
case 0: case 0:
return &BatteryChargeParameters0; return &BatteryChargeParameters0;
@@ -95,7 +105,8 @@ static const BatteryChargeParameters *GetBatteryChargeParameters(u32 battery_ver
} }
} }
static void UpdateCharger(PmicDriver *pmic_driver, ChargerDriver *charger_driver, BatteryDriver *battery_driver, const BatteryChargeParameters *params, u32 charge_voltage_limit) { /* Helpers. */
void UpdateCharger(PmicDriver *pmic_driver, ChargerDriver *charger_driver, BatteryDriver *battery_driver, const BatteryChargeParameters *params, u32 charge_voltage_limit) {
double temperature; double temperature;
u32 battery_voltage; u32 battery_voltage;
@@ -138,38 +149,38 @@ static void UpdateCharger(PmicDriver *pmic_driver, ChargerDriver *charger_driver
} }
} }
static bool IsSufficientBattery(u32 battery_voltage, bool ac_ok) { bool IsSufficientBattery(u32 battery_voltage, bool ac_ok) {
/* Nintendo has stuff for updating a static variable every 10 seconds here, but this seems, again, to be debug leftovers. */ /* Nintendo has stuff for updating a static variable every 10 seconds here, but this seems, again, to be debug leftovers. */
const u32 required_voltage = ac_ok ? 4000 : 3650; const u32 required_voltage = ac_ok ? 4000 : 3650;
return battery_voltage >= required_voltage; return battery_voltage >= required_voltage;
} }
static CheckBatteryResult LoopCheckBattery(PmicDriver *pmic_driver, ChargerDriver *charger_driver, BatteryDriver *battery_driver, const BatteryChargeParameters *params, u32 charge_voltage_limit, bool reboot_on_power_button_pressed, bool succeed_on_sufficient_battery, bool shutdown_on_full_battery, bool can_show_battery_icon, bool can_show_charging_icon) { CheckBatteryResult LoopCheckBattery(PmicDriver *pmic_driver, ChargerDriver *charger_driver, BatteryDriver *battery_driver, const BatteryChargeParameters *params, u32 charge_voltage_limit, bool reboot_on_power_button_pressed, bool succeed_on_sufficient_battery, bool shutdown_on_full_battery, bool can_show_battery_icon, bool can_show_charging_icon) {
bool is_showing_charging_icon = false; bool is_showing_charging_icon = false;
ON_SCOPE_EXIT { ON_SCOPE_EXIT {
if (is_showing_charging_icon) { if (is_showing_charging_icon) {
Boot::EndShowChargingIcon(); EndShowChargingIcon();
} }
}; };
if (can_show_charging_icon) { if (can_show_charging_icon) {
size_t battery_percentage; size_t battery_percentage;
if (R_FAILED(battery_driver->GetBatteryPercentage(&battery_percentage))) { if (R_FAILED(battery_driver->GetBatteryPercentage(&battery_percentage))) {
return CheckBatteryResult_Shutdown; return CheckBatteryResult::Shutdown;
} }
Boot::StartShowChargingIcon(battery_percentage, true); StartShowChargingIcon(battery_percentage, true);
is_showing_charging_icon = true; is_showing_charging_icon = true;
} }
while (true) { while (true) {
double battery_charge; double battery_charge;
if (R_FAILED(battery_driver->GetSocRep(&battery_charge))) { if (R_FAILED(battery_driver->GetSocRep(&battery_charge))) {
return CheckBatteryResult_Shutdown; return CheckBatteryResult::Shutdown;
} }
if (succeed_on_sufficient_battery && battery_charge >= 3.0) { if (succeed_on_sufficient_battery && battery_charge >= 3.0) {
return CheckBatteryResult_Success; return CheckBatteryResult::Success;
} else if (shutdown_on_full_battery && battery_charge >= 99.0) { } else if (shutdown_on_full_battery && battery_charge >= 99.0) {
return CheckBatteryResult_Shutdown; return CheckBatteryResult::Shutdown;
} else { } else {
/* Nintendo has logic for checking a value every 10 seconds. */ /* Nintendo has logic for checking a value every 10 seconds. */
/* They never do anything with this value though, so it's probably just leftovers from debug? */ /* They never do anything with this value though, so it's probably just leftovers from debug? */
@@ -177,37 +188,37 @@ static CheckBatteryResult LoopCheckBattery(PmicDriver *pmic_driver, ChargerDrive
bool ac_ok; bool ac_ok;
if (R_FAILED(pmic_driver->GetAcOk(&ac_ok))) { if (R_FAILED(pmic_driver->GetAcOk(&ac_ok))) {
return CheckBatteryResult_Shutdown; return CheckBatteryResult::Shutdown;
} }
u32 battery_voltage; u32 battery_voltage;
if (R_FAILED(battery_driver->GetAverageVCell(&battery_voltage))) { if (R_FAILED(battery_driver->GetAverageVCell(&battery_voltage))) {
return CheckBatteryResult_Shutdown; return CheckBatteryResult::Shutdown;
} }
if (succeed_on_sufficient_battery && IsSufficientBattery(battery_voltage, ac_ok)) { if (succeed_on_sufficient_battery && IsSufficientBattery(battery_voltage, ac_ok)) {
return CheckBatteryResult_Success; return CheckBatteryResult::Success;
} }
if (!ac_ok) { if (!ac_ok) {
if (can_show_battery_icon && !is_showing_charging_icon) { if (can_show_battery_icon && !is_showing_charging_icon) {
Boot::ShowLowBatteryIcon(); ShowLowBatteryIcon();
} }
return CheckBatteryResult_Shutdown; return CheckBatteryResult::Shutdown;
} }
if (reboot_on_power_button_pressed) { if (reboot_on_power_button_pressed) {
bool power_button_pressed; bool power_button_pressed;
if (R_FAILED(pmic_driver->GetPowerButtonPressed(&power_button_pressed))) { if (R_FAILED(pmic_driver->GetPowerButtonPressed(&power_button_pressed))) {
return CheckBatteryResult_Shutdown; return CheckBatteryResult::Shutdown;
} }
if (power_button_pressed) { if (power_button_pressed) {
return CheckBatteryResult_Reboot; return CheckBatteryResult::Reboot;
} }
} }
if (can_show_battery_icon && !is_showing_charging_icon) { if (can_show_battery_icon && !is_showing_charging_icon) {
Boot::StartShowChargingIcon(1, false); StartShowChargingIcon(1, false);
is_showing_charging_icon = true; is_showing_charging_icon = true;
} }
@@ -215,8 +226,9 @@ static CheckBatteryResult LoopCheckBattery(PmicDriver *pmic_driver, ChargerDrive
UpdateCharger(pmic_driver, charger_driver, battery_driver, params, charge_voltage_limit); UpdateCharger(pmic_driver, charger_driver, battery_driver, params, charge_voltage_limit);
} }
} }
}
void Boot::CheckBatteryCharge() { void CheckBatteryCharge() {
PmicDriver pmic_driver; PmicDriver pmic_driver;
BatteryDriver battery_driver; BatteryDriver battery_driver;
ChargerDriver charger_driver; ChargerDriver charger_driver;
@@ -231,18 +243,18 @@ void Boot::CheckBatteryCharge() {
} }
} }
const u32 boot_reason = Boot::GetBootReason(); const u32 boot_reason = GetBootReason();
InputCurrentLimit input_current_limit; bq24193::InputCurrentLimit input_current_limit;
if (R_FAILED(charger_driver.Initialize(boot_reason != 4)) || R_FAILED(charger_driver.GetInputCurrentLimit(&input_current_limit))) { if (R_FAILED(charger_driver.Initialize(boot_reason != 4)) || R_FAILED(charger_driver.GetInputCurrentLimit(&input_current_limit))) {
pmic_driver.ShutdownSystem(); pmic_driver.ShutdownSystem();
} }
if (input_current_limit <= InputCurrentLimit_150mA) { if (input_current_limit <= bq24193::InputCurrentLimit_150mA) {
charger_driver.SetChargerConfiguration(ChargerConfiguration_ChargeDisable); charger_driver.SetChargerConfiguration(bq24193::ChargerConfiguration_ChargeDisable);
pmic_driver.ShutdownSystem(); pmic_driver.ShutdownSystem();
} }
const BatteryChargeParameters *params = GetBatteryChargeParameters(Boot::GetBatteryVersion()); const BatteryChargeParameters *params = GetBatteryChargeParameters(GetBatteryVersion());
u32 charge_voltage_limit = params->charge_voltage_limit_default; u32 charge_voltage_limit = params->charge_voltage_limit_default;
CheckBatteryResult check_result; CheckBatteryResult check_result;
if (boot_reason == 4) { if (boot_reason == 4) {
@@ -261,15 +273,17 @@ void Boot::CheckBatteryCharge() {
} }
switch (check_result) { switch (check_result) {
case CheckBatteryResult_Success: case CheckBatteryResult::Success:
break; break;
case CheckBatteryResult_Shutdown: case CheckBatteryResult::Shutdown:
pmic_driver.ShutdownSystem(); pmic_driver.ShutdownSystem();
break; break;
case CheckBatteryResult_Reboot: case CheckBatteryResult::Reboot:
Boot::RebootSystem(); RebootSystem();
break; break;
default: default:
std::abort(); std::abort();
} }
} }
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::boot {
void CheckBatteryCharge();
}
+28 -20
View File
@@ -14,35 +14,43 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp" #include <stratosphere/reg.hpp>
#include "boot_check_clock.hpp"
#include "boot_power_utils.hpp"
static constexpr u32 ExpectedPlluDivP = (1 << 16); namespace sts::boot {
static constexpr u32 ExpectedPlluDivN = (25 << 8);
static constexpr u32 ExpectedPlluDivM = (2 << 0);
static constexpr u32 ExpectedPlluVal = (ExpectedPlluDivP | ExpectedPlluDivN | ExpectedPlluDivM);
static constexpr u32 ExpectedPlluMask = 0x1FFFFF;
static constexpr u32 ExpectedUtmipDivN = (25 << 16); namespace {
static constexpr u32 ExpectedUtmipDivM = (1 << 8);
static constexpr u32 ExpectedUtmipVal = (ExpectedUtmipDivN | ExpectedUtmipDivM);
static constexpr u32 ExpectedUtmipMask = 0xFFFF00;
static bool IsUsbClockValid() { /* Convenience definitions. */
u64 _vaddr; constexpr u32 ExpectedPlluDivP = (1 << 16);
if (R_FAILED(svcQueryIoMapping(&_vaddr, 0x60006000ul, 0x1000))) { constexpr u32 ExpectedPlluDivN = (25 << 8);
std::abort(); constexpr u32 ExpectedPlluDivM = (2 << 0);
} constexpr u32 ExpectedPlluVal = (ExpectedPlluDivP | ExpectedPlluDivN | ExpectedPlluDivM);
volatile u32 *car_regs = reinterpret_cast<volatile u32 *>(_vaddr); constexpr u32 ExpectedPlluMask = 0x1FFFFF;
const u32 pllu = car_regs[0xC0 >> 2]; constexpr u32 ExpectedUtmipDivN = (25 << 16);
const u32 utmip = car_regs[0x480 >> 2]; constexpr u32 ExpectedUtmipDivM = (1 << 8);
constexpr u32 ExpectedUtmipVal = (ExpectedUtmipDivN | ExpectedUtmipDivM);
constexpr u32 ExpectedUtmipMask = 0xFFFF00;
/* Helpers. */
bool IsUsbClockValid() {
uintptr_t car_regs = GetIoMapping(0x60006000ul, 0x1000);
const u32 pllu = reg::Read(car_regs + 0xC0);
const u32 utmip = reg::Read(car_regs + 0x480);
return ((pllu & ExpectedPlluMask) == ExpectedPlluVal) && ((utmip & ExpectedUtmipMask) == ExpectedUtmipVal); return ((pllu & ExpectedPlluMask) == ExpectedPlluVal) && ((utmip & ExpectedUtmipMask) == ExpectedUtmipVal);
} }
void Boot::CheckClock() { }
void CheckClock() {
if (!IsUsbClockValid()) { if (!IsUsbClockValid()) {
/* Sleep for 1s, then reboot. */ /* Sleep for 1s, then reboot. */
svcSleepThread(1'000'000'000ul); svcSleepThread(1'000'000'000ul);
Boot::RebootSystem(); RebootSystem();
} }
} }
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::boot {
void CheckClock();
}
@@ -14,15 +14,25 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp" #include "boot_clock_initial_configuration.hpp"
#include "boot_pmc_wrapper.hpp"
#include "boot_registers_pmc.hpp" #include "boot_registers_pmc.hpp"
static constexpr u32 PmcClkOutCntrl = PmcBase + APBDEV_PMC_CLK_OUT_CNTRL; namespace sts::boot {
static constexpr u32 InitialClockOutMask1x = 0x00C4;
static constexpr u32 InitialClockOutMask6x = 0xC4C4;
void Boot::SetInitialClockConfiguration() { namespace {
/* Convenience definitions. */
constexpr u32 PmcClkOutCntrl = PmcBase + APBDEV_PMC_CLK_OUT_CNTRL;
constexpr u32 InitialClockOutMask1x = 0x00C4;
constexpr u32 InitialClockOutMask6x = 0xC4C4;
}
void SetInitialClockConfiguration() {
/* Write mask to APBDEV_PMC_PWR_DET, then clear APBDEV_PMC_PWR_DET_VAL. */ /* Write mask to APBDEV_PMC_PWR_DET, then clear APBDEV_PMC_PWR_DET_VAL. */
const u32 mask = GetRuntimeFirmwareVersion() >= FirmwareVersion_600 ? InitialClockOutMask6x : InitialClockOutMask1x; const u32 mask = GetRuntimeFirmwareVersion() >= FirmwareVersion_600 ? InitialClockOutMask6x : InitialClockOutMask1x;
WritePmcRegister(PmcClkOutCntrl, mask, mask); WritePmcRegister(PmcClkOutCntrl, mask, mask);
} }
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::boot {
void SetInitialClockConfiguration();
}
+167 -193
View File
@@ -14,9 +14,29 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp" #include <stratosphere/reg.hpp>
#include "boot_display_config.hpp" #include <stratosphere/spl.hpp>
#include "i2c_driver/i2c_api.hpp"
#include "boot_display.hpp"
#include "boot_i2c_utils.hpp"
#include "boot_pmc_wrapper.hpp"
#include "boot_registers_clkrst.hpp"
#include "boot_registers_di.hpp"
#include "boot_registers_gpio.hpp"
#include "boot_registers_pinmux.hpp"
#include "boot_registers_pmc.hpp"
namespace sts::boot {
/* Display configuration included into anonymous namespace. */
namespace {
#include "boot_display_config.inc"
}
namespace {
/* Helpful defines. */ /* Helpful defines. */
constexpr size_t DeviceAddressSpaceAlignSize = 0x400000; constexpr size_t DeviceAddressSpaceAlignSize = 0x400000;
@@ -42,87 +62,37 @@ constexpr size_t MipiCalSize = 0x1000;
/* Types. */ /* Types. */
/* Globals. */ /* Globals. */
static bool g_is_display_intialized = false; bool g_is_display_intialized = false;
static u32 *g_frame_buffer = nullptr; u32 *g_frame_buffer = nullptr;
static bool g_is_mariko = false; bool g_is_mariko = false;
static u32 g_lcd_vendor = 0; u32 g_lcd_vendor = 0;
static Handle g_dc_das_hnd = INVALID_HANDLE; Handle g_dc_das_hnd = INVALID_HANDLE;
static u8 g_frame_buffer_storage[DeviceAddressSpaceAlignSize + FrameBufferSize]; u8 g_frame_buffer_storage[DeviceAddressSpaceAlignSize + FrameBufferSize];
static uintptr_t g_disp1_regs = 0; uintptr_t g_disp1_regs = 0;
static uintptr_t g_dsi_regs = 0; uintptr_t g_dsi_regs = 0;
static uintptr_t g_clk_rst_regs = 0; uintptr_t g_clk_rst_regs = 0;
static uintptr_t g_gpio_regs = 0; uintptr_t g_gpio_regs = 0;
static uintptr_t g_apb_misc_regs = 0; uintptr_t g_apb_misc_regs = 0;
static uintptr_t g_mipi_cal_regs = 0; uintptr_t g_mipi_cal_regs = 0;
static inline uintptr_t QueryVirtualAddress(uintptr_t phys, size_t size) { /* Helper functions. */
uintptr_t aligned_phys = phys & ~0xFFFul; void InitializeRegisterBaseAddresses() {
size_t aligned_size = size + (phys - aligned_phys); g_disp1_regs = GetIoMapping(Disp1Base, Disp1Size);
uintptr_t aligned_virt; g_dsi_regs = GetIoMapping(DsiBase, DsiSize);
if (R_FAILED(svcQueryIoMapping(&aligned_virt, aligned_phys, aligned_size))) { g_clk_rst_regs = GetIoMapping(ClkRstBase, ClkRstSize);
std::abort(); g_gpio_regs = GetIoMapping(GpioBase, GpioSize);
} g_apb_misc_regs = GetIoMapping(ApbMiscBase, ApbMiscSize);
return aligned_virt + (phys - aligned_phys); g_mipi_cal_regs = GetIoMapping(MipiCalBase, MipiCalSize);
} }
static inline void WriteRegister(volatile u32 *reg, u32 val) { inline void DoRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes, size_t num_writes) {
*reg = val;
}
static inline void WriteRegister(uintptr_t reg, u32 val) {
WriteRegister(reinterpret_cast<volatile u32 *>(reg), val);
}
static inline u32 ReadRegister(volatile u32 *reg) {
u32 val = *reg;
return val;
}
static inline u32 ReadRegister(uintptr_t reg) {
return ReadRegister(reinterpret_cast<volatile u32 *>(reg));
}
static inline void SetRegisterBits(volatile u32 *reg, u32 mask) {
*reg |= mask;
}
static inline void SetRegisterBits(uintptr_t reg, u32 mask) {
SetRegisterBits(reinterpret_cast<volatile u32 *>(reg), mask);
}
static inline void ClearRegisterBits(volatile u32 *reg, u32 mask) {
*reg &= mask;
}
static inline void ClearRegisterBits(uintptr_t reg, u32 mask) {
ClearRegisterBits(reinterpret_cast<volatile u32 *>(reg), mask);
}
static inline void ReadWriteRegisterBits(volatile u32 *reg, u32 val, u32 mask) {
*reg = (*reg & (~mask)) | (val & mask);
}
static inline void ReadWriteRegisterBits(uintptr_t reg, u32 val, u32 mask) {
ReadWriteRegisterBits(reinterpret_cast<volatile u32 *>(reg), val, mask);
}
static void InitializeRegisterBaseAddresses() {
g_disp1_regs = QueryVirtualAddress(Disp1Base, Disp1Size);
g_dsi_regs = QueryVirtualAddress(DsiBase, DsiSize);
g_clk_rst_regs = QueryVirtualAddress(ClkRstBase, ClkRstSize);
g_gpio_regs = QueryVirtualAddress(GpioBase, GpioSize);
g_apb_misc_regs = QueryVirtualAddress(ApbMiscBase, ApbMiscSize);
g_mipi_cal_regs = QueryVirtualAddress(MipiCalBase, MipiCalSize);
}
static inline void DoRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes, size_t num_writes) {
for (size_t i = 0; i < num_writes; i++) { for (size_t i = 0; i < num_writes; i++) {
*(reinterpret_cast<volatile u32 *>(base_address + reg_writes[i].offset)) = reg_writes[i].value; reg::Write(base_address + reg_writes[i].offset, reg_writes[i].value);
} }
} }
static inline void DoSocDependentRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes_erista, size_t num_writes_erista, const RegisterWrite *reg_writes_mariko, size_t num_writes_mariko) { inline void DoSocDependentRegisterWrites(uintptr_t base_address, const RegisterWrite *reg_writes_erista, size_t num_writes_erista, const RegisterWrite *reg_writes_mariko, size_t num_writes_mariko) {
if (g_is_mariko) { if (g_is_mariko) {
DoRegisterWrites(base_address, reg_writes_mariko, num_writes_mariko); DoRegisterWrites(base_address, reg_writes_mariko, num_writes_mariko);
} else { } else {
@@ -130,10 +100,10 @@ static inline void DoSocDependentRegisterWrites(uintptr_t base_address, const Re
} }
} }
static inline void DoDsiSleepOrRegisterWrites(const DsiSleepOrRegisterWrite *reg_writes, size_t num_writes) { inline void DoDsiSleepOrRegisterWrites(const DsiSleepOrRegisterWrite *reg_writes, size_t num_writes) {
for (size_t i = 0; i < num_writes; i++) { for (size_t i = 0; i < num_writes; i++) {
if (reg_writes[i].kind == DsiSleepOrRegisterWriteKind_Write) { if (reg_writes[i].kind == DsiSleepOrRegisterWriteKind_Write) {
*(reinterpret_cast<volatile u32 *>(g_dsi_regs + sizeof(u32) * reg_writes[i].offset)) = reg_writes[i].value; reg::Write(g_dsi_regs + sizeof(u32) * reg_writes[i].offset, reg_writes[i].value);
} else if (reg_writes[i].kind == DsiSleepOrRegisterWriteKind_Sleep) { } else if (reg_writes[i].kind == DsiSleepOrRegisterWriteKind_Sleep) {
svcSleepThread(1'000'000ul * u64(reg_writes[i].offset)); svcSleepThread(1'000'000ul * u64(reg_writes[i].offset));
} else { } else {
@@ -146,7 +116,7 @@ static inline void DoDsiSleepOrRegisterWrites(const DsiSleepOrRegisterWrite *reg
#define DO_SOC_DEPENDENT_REGISTER_WRITES(base_address, writes) DoSocDependentRegisterWrites(base_address, writes##Erista, sizeof(writes##Erista) / sizeof(writes##Erista[0]), writes##Mariko, sizeof(writes##Mariko) / sizeof(writes##Mariko[0])) #define DO_SOC_DEPENDENT_REGISTER_WRITES(base_address, writes) DoSocDependentRegisterWrites(base_address, writes##Erista, sizeof(writes##Erista) / sizeof(writes##Erista[0]), writes##Mariko, sizeof(writes##Mariko) / sizeof(writes##Mariko[0]))
#define DO_DSI_SLEEP_OR_REGISTER_WRITES(writes) DoDsiSleepOrRegisterWrites(writes, sizeof(writes) / sizeof(writes[0])) #define DO_DSI_SLEEP_OR_REGISTER_WRITES(writes) DoDsiSleepOrRegisterWrites(writes, sizeof(writes) / sizeof(writes[0]))
static void InitializeFrameBuffer() { void InitializeFrameBuffer() {
if (g_frame_buffer != nullptr) { if (g_frame_buffer != nullptr) {
std::memset(g_frame_buffer, 0x00, FrameBufferSize); std::memset(g_frame_buffer, 0x00, FrameBufferSize);
armDCacheFlush(g_frame_buffer, FrameBufferSize); armDCacheFlush(g_frame_buffer, FrameBufferSize);
@@ -174,7 +144,7 @@ static void InitializeFrameBuffer() {
} }
} }
static void FinalizeFrameBuffer() { void FinalizeFrameBuffer() {
if (g_frame_buffer != nullptr) { if (g_frame_buffer != nullptr) {
const uintptr_t frame_buffer_aligned = reinterpret_cast<uintptr_t>(g_frame_buffer); const uintptr_t frame_buffer_aligned = reinterpret_cast<uintptr_t>(g_frame_buffer);
constexpr u64 DeviceName_DC = 2; constexpr u64 DeviceName_DC = 2;
@@ -196,14 +166,14 @@ static void FinalizeFrameBuffer() {
} }
} }
static void WaitDsiTrigger() { void WaitDsiTrigger() {
TimeoutHelper timeout_helper(250'000'000ul); TimeoutHelper timeout_helper(250'000'000ul);
while (true) { while (true) {
if (timeout_helper.TimedOut()) { if (timeout_helper.TimedOut()) {
break; break;
} }
if (ReadRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER) == 0) { if (reg::Read(g_dsi_regs + sizeof(u32) * DSI_TRIGGER) == 0) {
break; break;
} }
} }
@@ -211,79 +181,81 @@ static void WaitDsiTrigger() {
svcSleepThread(5'000'000ul); svcSleepThread(5'000'000ul);
} }
static void WaitDsiHostControl() { void WaitDsiHostControl() {
TimeoutHelper timeout_helper(150'000'000ul); TimeoutHelper timeout_helper(150'000'000ul);
while (true) { while (true) {
if (timeout_helper.TimedOut()) { if (timeout_helper.TimedOut()) {
break; break;
} }
if ((ReadRegister(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL) & DSI_HOST_CONTROL_IMM_BTA) == 0) { if ((reg::Read(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL) & DSI_HOST_CONTROL_IMM_BTA) == 0) {
break; break;
} }
} }
} }
void Boot::InitializeDisplay() { }
void InitializeDisplay() {
/* Setup globals. */ /* Setup globals. */
InitializeRegisterBaseAddresses(); InitializeRegisterBaseAddresses();
g_is_mariko = Boot::IsMariko(); g_is_mariko = spl::IsMariko();
InitializeFrameBuffer(); InitializeFrameBuffer();
/* Turn on DSI/voltage rail. */ /* Turn on DSI/voltage rail. */
{ {
I2cSessionImpl i2c_session; i2c::driver::Session i2c_session;
I2cDriver::Initialize(); i2c::driver::Initialize();
I2cDriver::OpenSession(&i2c_session, I2cDevice_Max77620Pmic); ON_SCOPE_EXIT { i2c::driver::Finalize(); };
i2c::driver::OpenSession(&i2c_session, I2cDevice_Max77620Pmic);
if (g_is_mariko) { if (g_is_mariko) {
Boot::WriteI2cRegister(i2c_session, 0x18, 0x3A); WriteI2cRegister(i2c_session, 0x18, 0x3A);
Boot::WriteI2cRegister(i2c_session, 0x1F, 0x71); WriteI2cRegister(i2c_session, 0x1F, 0x71);
} }
Boot::WriteI2cRegister(i2c_session, 0x23, 0xD0); WriteI2cRegister(i2c_session, 0x23, 0xD0);
I2cDriver::Finalize();
} }
/* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */ /* Enable MIPI CAL, DSI, DISP1, HOST1X, UART_FST_MIPI_CAL, DSIA LP clocks. */
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_CLR, 0x1010000); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_CLR, 0x1010000);
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_SET, 0x1010000); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_SET, 0x1010000);
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_CLR, 0x18000000); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_CLR, 0x18000000);
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_SET, 0x18000000); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_SET, 0x18000000);
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_X_SET, 0x20000); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_X_SET, 0x20000);
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL, 0xA); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL, 0xA);
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_W_SET, 0x80000); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_W_SET, 0x80000);
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP, 0xA); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP, 0xA);
/* DPD idle. */ /* DPD idle. */
WritePmcRegister(PmcBase + APBDEV_PMC_IO_DPD_REQ, 0x40000000); WritePmcRegister(PmcBase + APBDEV_PMC_IO_DPD_REQ, 0x40000000);
WritePmcRegister(PmcBase + APBDEV_PMC_IO_DPD2_REQ, 0x40000000); WritePmcRegister(PmcBase + APBDEV_PMC_IO_DPD2_REQ, 0x40000000);
/* Configure LCD pinmux tristate + passthrough. */ /* Configure LCD pinmux tristate + passthrough. */
ClearRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_NFC_EN, ~PINMUX_TRISTATE); reg::ClearBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_NFC_EN, PINMUX_TRISTATE);
ClearRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_NFC_INT, ~PINMUX_TRISTATE); reg::ClearBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_NFC_INT, PINMUX_TRISTATE);
ClearRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_BL_PWM, ~PINMUX_TRISTATE); reg::ClearBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_BL_PWM, PINMUX_TRISTATE);
ClearRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_BL_EN, ~PINMUX_TRISTATE); reg::ClearBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_BL_EN, PINMUX_TRISTATE);
ClearRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_RST, ~PINMUX_TRISTATE); reg::ClearBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_RST, PINMUX_TRISTATE);
/* Configure LCD power, VDD. */ /* Configure LCD power, VDD. */
SetRegisterBits(g_gpio_regs + GPIO_PORT3_CNF_0, 0x3); reg::SetBits(g_gpio_regs + GPIO_PORT3_CNF_0, 0x3);
SetRegisterBits(g_gpio_regs + GPIO_PORT3_OE_0, 0x3); reg::SetBits(g_gpio_regs + GPIO_PORT3_OE_0, 0x3);
SetRegisterBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1); reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1);
svcSleepThread(10'000'000ul); svcSleepThread(10'000'000ul);
SetRegisterBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2); reg::SetBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2);
svcSleepThread(10'000'000ul); svcSleepThread(10'000'000ul);
/* Configure LCD backlight. */ /* Configure LCD backlight. */
SetRegisterBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x7); reg::SetBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x7);
SetRegisterBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x7); reg::SetBits(g_gpio_regs + GPIO_PORT6_OE_1, 0x7);
SetRegisterBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x2); reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x2);
/* Configure display interface and display. */ /* Configure display interface and display. */
WriteRegister(g_mipi_cal_regs + 0x060, 0); reg::Write(g_mipi_cal_regs + 0x060, 0);
if (g_is_mariko) { if (g_is_mariko) {
WriteRegister(g_mipi_cal_regs + 0x058, 0); reg::Write(g_mipi_cal_regs + 0x058, 0);
WriteRegister(g_apb_misc_regs + 0xAC0, 0); reg::Write(g_apb_misc_regs + 0xAC0, 0);
} }
/* Execute configs. */ /* Execute configs. */
@@ -305,19 +277,19 @@ void Boot::InitializeDisplay() {
svcSleepThread(10'000'000ul); svcSleepThread(10'000'000ul);
/* Enable backlight reset. */ /* Enable backlight reset. */
SetRegisterBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4); reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4);
svcSleepThread(60'000'000ul); svcSleepThread(60'000'000ul);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_BTA_TIMING, 0x50204); reg::Write(g_dsi_regs + sizeof(u32) * DSI_BTA_TIMING, 0x50204);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x337); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x337);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
WaitDsiTrigger(); WaitDsiTrigger();
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x406); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x406);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
WaitDsiTrigger(); WaitDsiTrigger();
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_TX_TRIG_HOST | DSI_HOST_CONTROL_IMM_BTA | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC); 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(); WaitDsiHostControl();
svcSleepThread(5'000'000ul); svcSleepThread(5'000'000ul);
@@ -325,7 +297,7 @@ void Boot::InitializeDisplay() {
{ {
u32 host_response[3]; u32 host_response[3];
for (size_t i = 0; i < sizeof(host_response) / sizeof(host_response[0]); i++) { for (size_t i = 0; i < sizeof(host_response) / sizeof(host_response[0]); i++) {
host_response[i] = ReadRegister(g_dsi_regs + sizeof(u32) * DSI_RD_DATA); host_response[i] = reg::Read(g_dsi_regs + sizeof(u32) * DSI_RD_DATA);
} }
if ((host_response[2] & 0xFF) == 0x10) { if ((host_response[2] & 0xFF) == 0x10) {
@@ -339,47 +311,47 @@ void Boot::InitializeDisplay() {
/* LCD vendor specific configuration. */ /* LCD vendor specific configuration. */
switch (g_lcd_vendor) { switch (g_lcd_vendor) {
case 0xF30: /* TODO: What's this? */ case 0xF30: /* TODO: What's this? */
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
svcSleepThread(180'000'000ul); svcSleepThread(180'000'000ul);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
svcSleepThread(5'000'000ul); svcSleepThread(5'000'000ul);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x711148B1); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x711148B1);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
svcSleepThread(5'000'000ul); svcSleepThread(5'000'000ul);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
break; break;
case 0xF20: /* TODO: What's this? */ case 0xF20: /* TODO: What's this? */
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
svcSleepThread(180'000'000ul); svcSleepThread(180'000'000ul);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
svcSleepThread(5'000'000ul); svcSleepThread(5'000'000ul);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x739);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x751548B1); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x751548B1);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x143209);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
svcSleepThread(5'000'000ul); svcSleepThread(5'000'000ul);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
break; break;
case 0x10: /* Japan Display Inc screens. */ case 0x10: /* Japan Display Inc screens. */
DO_DSI_SLEEP_OR_REGISTER_WRITES(DisplayConfigJdiSpecificInit01); DO_DSI_SLEEP_OR_REGISTER_WRITES(DisplayConfigJdiSpecificInit01);
break; break;
default: default:
if ((g_lcd_vendor | 0x10) == 0x1030) { if ((g_lcd_vendor | 0x10) == 0x1030) {
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1105);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
svcSleepThread(120'000'000ul); svcSleepThread(120'000'000ul);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x2905);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
} }
break; break;
} }
@@ -390,7 +362,7 @@ void Boot::InitializeDisplay() {
DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming); DO_SOC_DEPENDENT_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsiPhyTiming);
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init09); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init09);
WriteRegister(g_disp1_regs + sizeof(u32) * DC_DISP_DISP_CLOCK_CONTROL, SHIFT_CLK_DIVIDER(4)); reg::Write(g_disp1_regs + sizeof(u32) * DC_DISP_DISP_CLOCK_CONTROL, SHIFT_CLK_DIVIDER(4));
DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init10); DO_REGISTER_WRITES(g_dsi_regs, DisplayConfigDsi01Init10);
svcSleepThread(10'000'000ul); svcSleepThread(10'000'000ul);
@@ -416,7 +388,7 @@ void Boot::InitializeDisplay() {
g_is_display_intialized = true; g_is_display_intialized = true;
} }
void Boot::ShowDisplay(size_t x, size_t y, size_t width, size_t height, const u32 *img) { void ShowDisplay(size_t x, size_t y, size_t width, size_t height, const u32 *img) {
if (!g_is_display_intialized) { if (!g_is_display_intialized) {
return; return;
} }
@@ -433,31 +405,31 @@ void Boot::ShowDisplay(size_t x, size_t y, size_t width, size_t height, const u3
armDCacheFlush(g_frame_buffer, FrameBufferSize); armDCacheFlush(g_frame_buffer, FrameBufferSize);
/* Enable backlight. */ /* Enable backlight. */
SetRegisterBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1); reg::SetBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1);
} }
void Boot::FinalizeDisplay() { void FinalizeDisplay() {
if (!g_is_display_intialized) { if (!g_is_display_intialized) {
return; return;
} }
/* Disable backlight. */ /* Disable backlight. */
ClearRegisterBits(g_gpio_regs + GPIO_PORT6_OUT_1, ~0x1); reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x1);
WriteRegister(g_disp1_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 1); reg::Write(g_disp1_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 1);
WriteRegister(g_disp1_regs + sizeof(u32) * DSI_WR_DATA, 0x2805); reg::Write(g_disp1_regs + sizeof(u32) * DSI_WR_DATA, 0x2805);
/* Nintendo waits 5 frames before continuing. */ /* Nintendo waits 5 frames before continuing. */
{ {
const uintptr_t host1x_vaddr = QueryVirtualAddress(0x500030a4, 4); const uintptr_t host1x_vaddr = GetIoMapping(0x500030a4, 4);
const u32 start_val = ReadRegister(host1x_vaddr); const u32 start_val = reg::Read(host1x_vaddr);
while (ReadRegister(host1x_vaddr) < start_val + 5) { while (reg::Read(host1x_vaddr) < start_val + 5) {
/* spinlock here. */ /* spinlock here. */
} }
} }
WriteRegister(g_disp1_regs + sizeof(u32) * DC_CMD_STATE_ACCESS, (READ_MUX | WRITE_MUX)); reg::Write(g_disp1_regs + sizeof(u32) * DC_CMD_STATE_ACCESS, (READ_MUX | WRITE_MUX));
WriteRegister(g_disp1_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 0); reg::Write(g_disp1_regs + sizeof(u32) * DSI_VIDEO_MODE_CONTROL, 0);
DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld01); DO_SOC_DEPENDENT_REGISTER_WRITES(g_clk_rst_regs, DisplayConfigPlld01);
@@ -477,27 +449,27 @@ void Boot::FinalizeDisplay() {
svcSleepThread(5'000'000ul); svcSleepThread(5'000'000ul);
break; break;
case 0x1020: /* TODO: What's this? */ case 0x1020: /* TODO: What's this? */
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
svcSleepThread(5'000'000ul); svcSleepThread(5'000'000ul);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xB39); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xB39);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x751548B1); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x751548B1);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x71143209); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x71143209);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x115631); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x115631);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
svcSleepThread(5'000'000ul); svcSleepThread(5'000'000ul);
break; break;
case 0x1030: /* TODO: What's this? */ case 0x1030: /* TODO: What's this? */
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x439);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x9483FFB9);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
svcSleepThread(5'000'000ul); svcSleepThread(5'000'000ul);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xB39); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0xB39);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x711148B1); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x711148B1);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x71143209); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x71143209);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x114D31); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x114D31);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
svcSleepThread(5'000'000ul); svcSleepThread(5'000'000ul);
break; break;
default: default:
@@ -505,32 +477,34 @@ void Boot::FinalizeDisplay() {
} }
svcSleepThread(5'000'000ul); svcSleepThread(5'000'000ul);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1005); reg::Write(g_dsi_regs + sizeof(u32) * DSI_WR_DATA, 0x1005);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST); reg::Write(g_dsi_regs + sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST);
svcSleepThread(50'000'000ul); svcSleepThread(50'000'000ul);
/* Disable backlight RST/Voltage. */ /* Disable backlight RST/Voltage. */
ClearRegisterBits(g_gpio_regs + GPIO_PORT6_OUT_1, ~0x4); reg::ClearBits(g_gpio_regs + GPIO_PORT6_OUT_1, 0x4);
svcSleepThread(10'000'000ul); svcSleepThread(10'000'000ul);
ClearRegisterBits(g_gpio_regs + GPIO_PORT3_OUT_0, ~0x2); reg::ClearBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x2);
svcSleepThread(10'000'000ul); svcSleepThread(10'000'000ul);
ClearRegisterBits(g_gpio_regs + GPIO_PORT3_OUT_0, ~0x1); reg::ClearBits(g_gpio_regs + GPIO_PORT3_OUT_0, 0x1);
svcSleepThread(10'000'000ul); svcSleepThread(10'000'000ul);
/* Cut clock to DSI. */ /* Cut clock to DSI. */
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_SET, 0x1010000); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_H_SET, 0x1010000);
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, 0x1010000); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, 0x1010000);
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_SET, 0x18000000); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_RST_DEV_L_SET, 0x18000000);
WriteRegister(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, 0x18000000); reg::Write(g_clk_rst_regs + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, 0x18000000);
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_PAD_CONTROL_0, (DSI_PAD_CONTROL_VS1_PULLDN_CLK | DSI_PAD_CONTROL_VS1_PULLDN(0xF) | DSI_PAD_CONTROL_VS1_PDIO_CLK | DSI_PAD_CONTROL_VS1_PDIO(0xF))); 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)));
WriteRegister(g_dsi_regs + sizeof(u32) * DSI_POWER_CONTROL, 0); reg::Write(g_dsi_regs + sizeof(u32) * DSI_POWER_CONTROL, 0);
/* Final LCD config for PWM */ /* Final LCD config for PWM */
ClearRegisterBits(g_gpio_regs + GPIO_PORT6_CNF_1, ~0x1); reg::ClearBits(g_gpio_regs + GPIO_PORT6_CNF_1, 0x1);
SetRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_BL_PWM, PINMUX_TRISTATE); reg::SetBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_BL_PWM, PINMUX_TRISTATE);
ReadWriteRegisterBits(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_BL_PWM, 1, 0x3); reg::ReadWrite(g_apb_misc_regs + 0x3000 + PINMUX_AUX_LCD_BL_PWM, 1, 0x3);
/* Unmap framebuffer from DC virtual address space. */ /* Unmap framebuffer from DC virtual address space. */
FinalizeFrameBuffer(); FinalizeFrameBuffer();
g_is_display_intialized = false; g_is_display_intialized = false;
} }
}
+28
View File
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::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();
}
@@ -14,17 +14,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once
#include <switch.h>
#include "boot_types.hpp"
#include "boot_registers_clkrst.hpp"
#include "boot_registers_di.hpp"
#include "boot_registers_gpio.hpp"
#include "boot_registers_pinmux.hpp"
#include "boot_registers_pmc.hpp"
struct RegisterWrite { struct RegisterWrite {
u32 offset; u32 offset;
u32 value; u32 value;
@@ -41,21 +30,21 @@ struct DsiSleepOrRegisterWrite {
u32 value; u32 value;
}; };
static constexpr RegisterWrite DisplayConfigPlld01Erista[] = { constexpr RegisterWrite DisplayConfigPlld01Erista[] = {
{CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000}, {CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000},
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001}, {CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001},
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020}, {CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020},
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA}, {CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA},
}; };
static constexpr RegisterWrite DisplayConfigPlld01Mariko[] = { constexpr RegisterWrite DisplayConfigPlld01Mariko[] = {
{CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000}, {CLK_RST_CONTROLLER_CLK_SOURCE_DISP1, 0x40000000},
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001}, {CLK_RST_CONTROLLER_PLLD_BASE, 0x4830A001},
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000}, {CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000},
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00}, {CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00},
}; };
static constexpr RegisterWrite DisplayConfigDc01[] = { constexpr RegisterWrite DisplayConfigDc01[] = {
{sizeof(u32) * DC_CMD_STATE_ACCESS, 0}, {sizeof(u32) * DC_CMD_STATE_ACCESS, 0},
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE}, {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_UPDATE},
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ}, {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ},
@@ -158,7 +147,7 @@ static constexpr RegisterWrite DisplayConfigDc01[] = {
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ} {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ | WIN_B_ACT_REQ | WIN_C_ACT_REQ}
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init01[] = { constexpr RegisterWrite DisplayConfigDsi01Init01[] = {
{sizeof(u32) * DSI_WR_DATA, 0x0}, {sizeof(u32) * DSI_WR_DATA, 0x0},
{sizeof(u32) * DSI_INT_ENABLE, 0x0}, {sizeof(u32) * DSI_INT_ENABLE, 0x0},
{sizeof(u32) * DSI_INT_STATUS, 0x0}, {sizeof(u32) * DSI_INT_STATUS, 0x0},
@@ -169,15 +158,15 @@ static constexpr RegisterWrite DisplayConfigDsi01Init01[] = {
{sizeof(u32) * DSI_INIT_SEQ_DATA_3, 0x0}, {sizeof(u32) * DSI_INIT_SEQ_DATA_3, 0x0},
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init02Erista[] = { constexpr RegisterWrite DisplayConfigDsi01Init02Erista[] = {
{sizeof(u32) * DSI_INIT_SEQ_DATA_15, 0x0}, {sizeof(u32) * DSI_INIT_SEQ_DATA_15, 0x0},
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init02Mariko[] = { constexpr RegisterWrite DisplayConfigDsi01Init02Mariko[] = {
{sizeof(u32) * DSI_INIT_SEQ_DATA_15_MARIKO, 0x0}, {sizeof(u32) * DSI_INIT_SEQ_DATA_15_MARIKO, 0x0},
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init03[] = { constexpr RegisterWrite DisplayConfigDsi01Init03[] = {
{sizeof(u32) * DSI_DCS_CMDS, 0}, {sizeof(u32) * DSI_DCS_CMDS, 0},
{sizeof(u32) * DSI_PKT_SEQ_0_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_0_LO, 0},
{sizeof(u32) * DSI_PKT_SEQ_1_LO, 0}, {sizeof(u32) * DSI_PKT_SEQ_1_LO, 0},
@@ -193,11 +182,11 @@ static constexpr RegisterWrite DisplayConfigDsi01Init03[] = {
{sizeof(u32) * DSI_PKT_SEQ_5_HI, 0}, {sizeof(u32) * DSI_PKT_SEQ_5_HI, 0},
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init04Erista[] = { constexpr RegisterWrite DisplayConfigDsi01Init04Erista[] = {
/* No register writes. */ /* No register writes. */
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init04Mariko[] = { constexpr RegisterWrite DisplayConfigDsi01Init04Mariko[] = {
{sizeof(u32) * DSI_PAD_CONTROL_1, 0}, {sizeof(u32) * DSI_PAD_CONTROL_1, 0},
{sizeof(u32) * DSI_PAD_CONTROL_2, 0}, {sizeof(u32) * DSI_PAD_CONTROL_2, 0},
{sizeof(u32) * DSI_PAD_CONTROL_3, 0}, {sizeof(u32) * DSI_PAD_CONTROL_3, 0},
@@ -207,7 +196,7 @@ static constexpr RegisterWrite DisplayConfigDsi01Init04Mariko[] = {
{sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0}, {sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0},
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init05[] = { constexpr RegisterWrite DisplayConfigDsi01Init05[] = {
{sizeof(u32) * DSI_PAD_CONTROL_CD, 0}, {sizeof(u32) * DSI_PAD_CONTROL_CD, 0},
{sizeof(u32) * DSI_SOL_DELAY, 0x18}, {sizeof(u32) * DSI_SOL_DELAY, 0x18},
{sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0}, {sizeof(u32) * DSI_MAX_THRESHOLD, 0x1E0},
@@ -220,7 +209,7 @@ static constexpr RegisterWrite DisplayConfigDsi01Init05[] = {
{sizeof(u32) * DSI_PAD_CONTROL_1, 0}, {sizeof(u32) * DSI_PAD_CONTROL_1, 0},
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init06[] = { constexpr RegisterWrite DisplayConfigDsi01Init06[] = {
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05}, {sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30109}, {sizeof(u32) * DSI_PHY_TIMING_2, 0x30109},
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14}, {sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
@@ -236,7 +225,7 @@ static constexpr RegisterWrite DisplayConfigDsi01Init06[] = {
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init07[] = { constexpr RegisterWrite DisplayConfigDsi01Init07[] = {
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05}, {sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30118}, {sizeof(u32) * DSI_PHY_TIMING_2, 0x30118},
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14}, {sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
@@ -253,15 +242,15 @@ static constexpr RegisterWrite DisplayConfigDsi01Init07[] = {
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0} {sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0}
}; };
static constexpr RegisterWrite DisplayConfigDsiPhyTimingErista[] = { constexpr RegisterWrite DisplayConfigDsiPhyTimingErista[] = {
{sizeof(u32) * DSI_PHY_TIMING_0, 0x6070601}, {sizeof(u32) * DSI_PHY_TIMING_0, 0x6070601},
}; };
static constexpr RegisterWrite DisplayConfigDsiPhyTimingMariko[] = { constexpr RegisterWrite DisplayConfigDsiPhyTimingMariko[] = {
{sizeof(u32) * DSI_PHY_TIMING_0, 0x6070603}, {sizeof(u32) * DSI_PHY_TIMING_0, 0x6070603},
}; };
static constexpr DsiSleepOrRegisterWrite DisplayConfigJdiSpecificInit01[] = { constexpr DsiSleepOrRegisterWrite DisplayConfigJdiSpecificInit01[] = {
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439}, {DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x439},
{DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9}, {DsiSleepOrRegisterWriteKind_Write, DSI_WR_DATA, 0x9483FFB9},
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
@@ -312,23 +301,23 @@ static constexpr DsiSleepOrRegisterWrite DisplayConfigJdiSpecificInit01[] = {
{DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST}, {DsiSleepOrRegisterWriteKind_Write, DSI_TRIGGER, DSI_TRIGGER_HOST},
}; };
static constexpr RegisterWrite DisplayConfigPlld02Erista[] = { constexpr RegisterWrite DisplayConfigPlld02Erista[] = {
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001}, {CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001},
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020}, {CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000020},
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA}, {CLK_RST_CONTROLLER_PLLD_MISC, 0x002D0AAA},
}; };
static constexpr RegisterWrite DisplayConfigPlld02Mariko[] = { constexpr RegisterWrite DisplayConfigPlld02Mariko[] = {
{CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001}, {CLK_RST_CONTROLLER_PLLD_BASE, 0x4810c001},
{CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000}, {CLK_RST_CONTROLLER_PLLD_MISC1, 0x00000000},
{CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00}, {CLK_RST_CONTROLLER_PLLD_MISC, 0x002DFC00},
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init08[] = { constexpr RegisterWrite DisplayConfigDsi01Init08[] = {
{sizeof(u32) * DSI_PAD_CONTROL_1, 0}, {sizeof(u32) * DSI_PAD_CONTROL_1, 0},
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init09[] = { constexpr RegisterWrite DisplayConfigDsi01Init09[] = {
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05}, {sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30172}, {sizeof(u32) * DSI_PHY_TIMING_2, 0x30172},
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14}, {sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
@@ -350,7 +339,7 @@ static constexpr RegisterWrite DisplayConfigDsi01Init09[] = {
{sizeof(u32) * DSI_HOST_CONTROL, 0}, {sizeof(u32) * DSI_HOST_CONTROL, 0},
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init10[] = { constexpr RegisterWrite DisplayConfigDsi01Init10[] = {
{sizeof(u32) * DSI_TRIGGER, 0}, {sizeof(u32) * DSI_TRIGGER, 0},
{sizeof(u32) * DSI_CONTROL, 0}, {sizeof(u32) * DSI_CONTROL, 0},
{sizeof(u32) * DSI_SOL_DELAY, 6}, {sizeof(u32) * DSI_SOL_DELAY, 6},
@@ -363,14 +352,14 @@ static constexpr RegisterWrite DisplayConfigDsi01Init10[] = {
{sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC} {sizeof(u32) * DSI_HOST_CONTROL, DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC}
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init11Erista[] = { constexpr RegisterWrite DisplayConfigDsi01Init11Erista[] = {
{sizeof(u32) * DSI_PAD_CONTROL_1, 0}, {sizeof(u32) * DSI_PAD_CONTROL_1, 0},
{sizeof(u32) * DSI_PAD_CONTROL_2, 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_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} {sizeof(u32) * DSI_PAD_CONTROL_4, 0}
}; };
static constexpr RegisterWrite DisplayConfigDsi01Init11Mariko[] = { constexpr RegisterWrite DisplayConfigDsi01Init11Mariko[] = {
{sizeof(u32) * DSI_PAD_CONTROL_1, 0}, {sizeof(u32) * DSI_PAD_CONTROL_1, 0},
{sizeof(u32) * DSI_PAD_CONTROL_2, 0}, {sizeof(u32) * DSI_PAD_CONTROL_2, 0},
{sizeof(u32) * DSI_PAD_CONTROL_3, 0}, {sizeof(u32) * DSI_PAD_CONTROL_3, 0},
@@ -380,24 +369,24 @@ static constexpr RegisterWrite DisplayConfigDsi01Init11Mariko[] = {
{sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0}, {sizeof(u32) * DSI_PAD_CONTROL_7_MARIKO, 0},
}; };
static constexpr RegisterWrite DisplayConfigMipiCal01[] = { constexpr RegisterWrite DisplayConfigMipiCal01[] = {
{0x60, 0}, {0x60, 0},
{0x08, 0xF3F10000}, {0x08, 0xF3F10000},
{0x58, 1}, {0x58, 1},
{0x60, 0}, {0x60, 0},
}; };
static constexpr RegisterWrite DisplayConfigMipiCal02Erista[] = { constexpr RegisterWrite DisplayConfigMipiCal02Erista[] = {
{0x60, 0x10010}, {0x60, 0x10010},
{0x5C, 0x300}, {0x5C, 0x300},
}; };
static constexpr RegisterWrite DisplayConfigMipiCal02Mariko[] = { constexpr RegisterWrite DisplayConfigMipiCal02Mariko[] = {
{0x60, 0x10010}, {0x60, 0x10010},
{0x5C, 0}, {0x5C, 0},
}; };
static constexpr RegisterWrite DisplayConfigMipiCal03Erista[] = { constexpr RegisterWrite DisplayConfigMipiCal03Erista[] = {
{0x38, 0x200200}, {0x38, 0x200200},
{0x3C, 0x200200}, {0x3C, 0x200200},
{0x64, 0x200002}, {0x64, 0x200002},
@@ -406,7 +395,7 @@ static constexpr RegisterWrite DisplayConfigMipiCal03Erista[] = {
{0x18, 0}, {0x18, 0},
}; };
static constexpr RegisterWrite DisplayConfigMipiCal03Mariko[] = { constexpr RegisterWrite DisplayConfigMipiCal03Mariko[] = {
{0x38, 0x200006}, {0x38, 0x200006},
{0x3C, 0x200006}, {0x3C, 0x200006},
{0x64, 0x260000}, {0x64, 0x260000},
@@ -415,7 +404,7 @@ static constexpr RegisterWrite DisplayConfigMipiCal03Mariko[] = {
{0x18, 0}, {0x18, 0},
}; };
static constexpr RegisterWrite DisplayConfigMipiCal04[] = { constexpr RegisterWrite DisplayConfigMipiCal04[] = {
{0x1C, 0}, {0x1C, 0},
{0x20, 0}, {0x20, 0},
{0x24, 0}, {0x24, 0},
@@ -428,7 +417,7 @@ static constexpr RegisterWrite DisplayConfigMipiCal04[] = {
{0x00, 0x2A000001}, {0x00, 0x2A000001},
}; };
static constexpr RegisterWrite DisplayConfigDc02[] = { constexpr RegisterWrite DisplayConfigDc02[] = {
{sizeof(u32) * DC_CMD_STATE_ACCESS, 0}, {sizeof(u32) * DC_CMD_STATE_ACCESS, 0},
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT}, {sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT},
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0}, {sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
@@ -552,9 +541,9 @@ static constexpr RegisterWrite DisplayConfigDc02[] = {
{sizeof(u32) * DC_CMD_DISPLAY_COMMAND_OPTION0, 0} {sizeof(u32) * DC_CMD_DISPLAY_COMMAND_OPTION0, 0}
}; };
static constexpr u32 DisplayConfigFrameBufferAddress = 0xC0000000; constexpr u32 DisplayConfigFrameBufferAddress = 0xC0000000;
static constexpr RegisterWrite DisplayConfigFrameBuffer[] = { constexpr RegisterWrite DisplayConfigFrameBuffer[] = {
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C. {sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_C_SELECT}, //Enable window C.
{sizeof(u32) * DC_WIN_WIN_OPTIONS, 0}, {sizeof(u32) * DC_WIN_WIN_OPTIONS, 0},
{sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B. {sizeof(u32) * DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_B_SELECT}, //Enable window B.
@@ -589,12 +578,12 @@ static constexpr RegisterWrite DisplayConfigFrameBuffer[] = {
{sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request. {sizeof(u32) * DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ} //General activation request; window A activation request.
}; };
static constexpr RegisterWrite DisplayConfigDsi01Fini01[] = { constexpr RegisterWrite DisplayConfigDsi01Fini01[] = {
{sizeof(u32) * DSI_POWER_CONTROL, 0}, {sizeof(u32) * DSI_POWER_CONTROL, 0},
{sizeof(u32) * DSI_PAD_CONTROL_1, 0}, {sizeof(u32) * DSI_PAD_CONTROL_1, 0},
}; };
static constexpr RegisterWrite DisplayConfigDsi01Fini02[] = { constexpr RegisterWrite DisplayConfigDsi01Fini02[] = {
{sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05}, {sizeof(u32) * DSI_PHY_TIMING_1, 0x40A0E05},
{sizeof(u32) * DSI_PHY_TIMING_2, 0x30109}, {sizeof(u32) * DSI_PHY_TIMING_2, 0x30109},
{sizeof(u32) * DSI_BTA_TIMING, 0x190A14}, {sizeof(u32) * DSI_BTA_TIMING, 0x190A14},
@@ -610,7 +599,7 @@ static constexpr RegisterWrite DisplayConfigDsi01Fini02[] = {
{sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0} {sizeof(u32) * DSI_INIT_SEQ_CONTROL, 0}
}; };
static constexpr RegisterWrite DisplayConfigJdiSpecificFini01[] = { constexpr RegisterWrite DisplayConfigJdiSpecificFini01[] = {
{sizeof(u32) * DSI_WR_DATA, 0x439}, {sizeof(u32) * DSI_WR_DATA, 0x439},
{sizeof(u32) * DSI_WR_DATA, 0x9483FFB9}, {sizeof(u32) * DSI_WR_DATA, 0x9483FFB9},
{sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST}, {sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST},
@@ -635,7 +624,7 @@ static constexpr RegisterWrite DisplayConfigJdiSpecificFini01[] = {
{sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST}, {sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST},
}; };
static constexpr RegisterWrite DisplayConfigF30SpecificFini01[] = { constexpr RegisterWrite DisplayConfigF30SpecificFini01[] = {
{sizeof(u32) * DSI_WR_DATA, 0x439}, {sizeof(u32) * DSI_WR_DATA, 0x439},
{sizeof(u32) * DSI_WR_DATA, 0x9483FFB9}, {sizeof(u32) * DSI_WR_DATA, 0x9483FFB9},
{sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST}, {sizeof(u32) * DSI_TRIGGER, DSI_TRIGGER_HOST},
+20 -7
View File
@@ -14,14 +14,27 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp" #include <stratosphere/spl.hpp>
static constexpr u32 GpioPadName_FanEnable = 0x4B; #include "boot_fan_enable.hpp"
void Boot::SetFanEnabled() { #include "gpio/gpio_utils.hpp"
if (Boot::GetHardwareType() == HardwareType_Copper) {
Boot::GpioConfigure(GpioPadName_FanEnable); namespace sts::boot {
Boot::GpioSetDirection(GpioPadName_FanEnable, GpioDirection_Output);
Boot::GpioSetValue(GpioPadName_FanEnable, GpioValue_High); namespace {
/* Convenience definitions. */
constexpr u32 GpioPadName_FanEnable = 0x4B;
}
void SetFanEnabled() {
if (spl::GetHardwareType() == spl::HardwareType::Copper) {
gpio::Configure(GpioPadName_FanEnable);
gpio::SetDirection(GpioPadName_FanEnable, GpioDirection_Output);
gpio::SetValue(GpioPadName_FanEnable, GpioValue_High);
} }
} }
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::boot {
void SetFanEnabled();
}
@@ -1,92 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "boot_types.hpp"
#include "i2c_driver/i2c_types.hpp"
class Boot {
public:
static constexpr u32 GpioPhysicalBase = 0x6000D000;
static constexpr u32 ApbMiscPhysicalBase = 0x70000000;
public:
/* Functions for actually booting. */
static void ChangeGpioVoltageTo1_8v();
static void SetInitialGpioConfiguration();
static void CheckClock();
static void DetectBootReason();
static void ShowSplashScreen();
static void CheckBatteryCharge();
static void SetInitialClockConfiguration();
static void ConfigurePinmux();
static void SetInitialWakePinConfiguration();
static void SetFanEnabled();
static void CheckAndRepairBootImages();
/* Power utilities. */
static void RebootSystem();
static void ShutdownSystem();
/* Register Utilities. */
static u32 ReadPmcRegister(u32 phys_addr);
static void WritePmcRegister(u32 phys_addr, u32 value, u32 mask = UINT32_MAX);
/* GPIO Utilities. */
static u32 GpioConfigure(u32 gpio_pad_name);
static u32 GpioSetDirection(u32 gpio_pad_name, GpioDirection dir);
static u32 GpioSetValue(u32 gpio_pad_name, GpioValue val);
/* Pinmux Utilities. */
static u32 PinmuxUpdatePark(u32 pinmux_name);
static u32 PinmuxUpdatePad(u32 pinmux_name, u32 config_val, u32 config_mask);
static u32 PinmuxUpdateDrivePad(u32 pinmux_drivepad_name, u32 config_val, u32 config_mask);
static u32 PinmuxDummyReadDrivePad(u32 pinmux_drivepad_name);
static void ConfigurePinmuxInitialPads();
static void ConfigurePinmuxInitialDrivePads();
/* SPL Utilities. */
static HardwareType GetHardwareType();
static u32 GetBootReason();
static bool IsRecoveryBoot();
static bool IsMariko();
/* I2C Utilities. */
static Result ReadI2cRegister(I2cSessionImpl &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size);
static Result WriteI2cRegister(I2cSessionImpl &session, const u8 *src, size_t src_size, const u8 *cmd, size_t cmd_size);
static Result WriteI2cRegister(I2cSessionImpl &session, const u8 address, const u8 value);
/* Splash Screen/Display utilities. */
static void InitializeDisplay();
static void ShowDisplay(size_t x, size_t y, size_t width, size_t height, const u32 *img);
static void FinalizeDisplay();
/* Battery Display utilities. */
static void ShowLowBatteryIcon();
static void StartShowChargingIcon(size_t battery_percentage, bool wait);
static void EndShowChargingIcon();
/* Calibration utilities. */
static u16 GetCrc16(const void *data, size_t size);
static u32 GetBatteryVersion();
static u32 GetBatteryVendor();
/* Wake pin utiliies. */
static void SetWakeEventLevel(u32 index, u32 level);
static void SetWakeEventEnabled(u32 index, bool enabled);
};
@@ -1,82 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "boot_functions.hpp"
#include "boot_gpio_initial_configuration_icosa.hpp"
#include "boot_gpio_initial_configuration_copper.hpp"
#include "boot_gpio_initial_configuration_hoag.hpp"
#include "boot_gpio_initial_configuration_iowa.hpp"
void Boot::SetInitialGpioConfiguration() {
const GpioInitialConfig *configs = nullptr;
size_t num_configs = 0;
const HardwareType hw_type = Boot::GetHardwareType();
const FirmwareVersion fw_ver = GetRuntimeFirmwareVersion();
/* Choose GPIO map. */
if (fw_ver >= FirmwareVersion_200) {
switch (hw_type) {
case HardwareType_Icosa:
{
if (fw_ver >= FirmwareVersion_400) {
configs = GpioInitialConfigsIcosa4x;
num_configs = GpioNumInitialConfigsIcosa4x;
} else {
configs = GpioInitialConfigsIcosa;
num_configs = GpioNumInitialConfigsIcosa;
}
}
break;
case HardwareType_Copper:
configs = GpioInitialConfigsCopper;
num_configs = GpioNumInitialConfigsCopper;
break;
case HardwareType_Hoag:
configs = GpioInitialConfigsHoag;
num_configs = GpioNumInitialConfigsHoag;
break;
case HardwareType_Iowa:
configs = GpioInitialConfigsIowa;
num_configs = GpioNumInitialConfigsIowa;
break;
default:
/* Unknown hardware type, we can't proceed. */
std::abort();
}
} else {
/* Until 2.0.0, the GPIO map for Icosa was used for all hardware types. */
configs = GpioInitialConfigsIcosa;
num_configs = GpioNumInitialConfigsIcosa;
}
/* Ensure we found an appropriate config. */
if (configs == nullptr) {
std::abort();
}
for (size_t i = 0; i < num_configs; i++) {
/* Configure the GPIO. */
Boot::GpioConfigure(configs[i].pad_name);
/* Set the GPIO's direction. */
Boot::GpioSetDirection(configs[i].pad_name, configs[i].direction);
if (configs[i].direction == GpioDirection_Output) {
/* Set the GPIO's value. */
Boot::GpioSetValue(configs[i].pad_name, configs[i].value);
}
}
}
@@ -1,119 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "boot_functions.hpp"
#include "boot_gpio_map.hpp"
static bool g_initialized_gpio_vaddr = false;
static uintptr_t g_gpio_vaddr = 0;
static inline u32 GetGpioPadDescriptor(u32 gpio_pad_name) {
if (gpio_pad_name >= GpioPadNameMax) {
std::abort();
}
return GpioMap[gpio_pad_name];
}
static uintptr_t GetGpioBaseAddress() {
if (!g_initialized_gpio_vaddr) {
u64 vaddr;
if (R_FAILED(svcQueryIoMapping(&vaddr, Boot::GpioPhysicalBase, 0x1000))) {
std::abort();
}
g_gpio_vaddr = vaddr;
g_initialized_gpio_vaddr = true;
}
return g_gpio_vaddr;
}
u32 Boot::GpioConfigure(u32 gpio_pad_name) {
uintptr_t gpio_base_vaddr = GetGpioBaseAddress();
/* Fetch this GPIO's pad descriptor */
const u32 gpio_pad_desc = GetGpioPadDescriptor(gpio_pad_name);
/* Discard invalid GPIOs */
if (gpio_pad_desc == GpioInvalid) {
return GpioInvalid;
}
/* Convert the GPIO pad descriptor into its register offset */
u32 gpio_reg_offset = (((gpio_pad_desc << 0x03) & 0xFFFFFF00) | ((gpio_pad_desc >> 0x01) & 0x0C));
/* Extract the bit and lock values from the GPIO pad descriptor */
u32 gpio_cnf_val = ((0x01 << ((gpio_pad_desc & 0x07) | 0x08)) | (0x01 << (gpio_pad_desc & 0x07)));
/* Write to the appropriate GPIO_CNF_x register (upper offset) */
*(reinterpret_cast<volatile u32 *>(gpio_base_vaddr + gpio_reg_offset + 0x80)) = gpio_cnf_val;
/* Do a dummy read from GPIO_CNF_x register (lower offset) */
gpio_cnf_val = *(reinterpret_cast<volatile u32 *>(gpio_base_vaddr + gpio_reg_offset));
return gpio_cnf_val;
}
u32 Boot::GpioSetDirection(u32 gpio_pad_name, GpioDirection dir) {
uintptr_t gpio_base_vaddr = GetGpioBaseAddress();
/* Fetch this GPIO's pad descriptor */
const u32 gpio_pad_desc = GetGpioPadDescriptor(gpio_pad_name);
/* Discard invalid GPIOs */
if (gpio_pad_desc == GpioInvalid) {
return GpioInvalid;
}
/* Convert the GPIO pad descriptor into its register offset */
u32 gpio_reg_offset = (((gpio_pad_desc << 0x03) & 0xFFFFFF00) | ((gpio_pad_desc >> 0x01) & 0x0C));
/* Set the direction bit and lock values */
u32 gpio_oe_val = ((0x01 << ((gpio_pad_desc & 0x07) | 0x08)) | (static_cast<u32>(dir) << (gpio_pad_desc & 0x07)));
/* Write to the appropriate GPIO_OE_x register (upper offset) */
*(reinterpret_cast<volatile u32 *>(gpio_base_vaddr + gpio_reg_offset + 0x90)) = gpio_oe_val;
/* Do a dummy read from GPIO_OE_x register (lower offset) */
gpio_oe_val = *(reinterpret_cast<volatile u32 *>(gpio_base_vaddr + gpio_reg_offset + 0x10));
return gpio_oe_val;
}
u32 Boot::GpioSetValue(u32 gpio_pad_name, GpioValue val) {
uintptr_t gpio_base_vaddr = GetGpioBaseAddress();
/* Fetch this GPIO's pad descriptor */
const u32 gpio_pad_desc = GetGpioPadDescriptor(gpio_pad_name);
/* Discard invalid GPIOs */
if (gpio_pad_desc == GpioInvalid) {
return GpioInvalid;
}
/* Convert the GPIO pad descriptor into its register offset */
u32 gpio_reg_offset = (((gpio_pad_desc << 0x03) & 0xFFFFFF00) | ((gpio_pad_desc >> 0x01) & 0x0C));
/* Set the output bit and lock values */
u32 gpio_out_val = ((0x01 << ((gpio_pad_desc & 0x07) | 0x08)) | (static_cast<u32>(val) << (gpio_pad_desc & 0x07)));
/* Write to the appropriate GPIO_OUT_x register (upper offset) */
*(reinterpret_cast<volatile u32 *>(gpio_base_vaddr + gpio_reg_offset + 0xA0)) = gpio_out_val;
/* Do a dummy read from GPIO_OUT_x register (lower offset) */
gpio_out_val = *(reinterpret_cast<volatile u32 *>(gpio_base_vaddr + gpio_reg_offset + 0x20));
return gpio_out_val;
}
+18 -11
View File
@@ -14,11 +14,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp" #include "boot_i2c_utils.hpp"
#include "i2c_driver/i2c_api.hpp"
namespace sts::boot {
namespace {
template<typename F> template<typename F>
static Result RetryUntilSuccess(F f) { constexpr Result RetryUntilSuccess(F f) {
constexpr u64 timeout = 10'000'000'000ul; constexpr u64 timeout = 10'000'000'000ul;
constexpr u64 retry_interval = 20'000'000ul; constexpr u64 retry_interval = 20'000'000ul;
@@ -35,21 +38,23 @@ static Result RetryUntilSuccess(F f) {
} }
} }
Result Boot::ReadI2cRegister(I2cSessionImpl &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size) { }
Result ReadI2cRegister(i2c::driver::Session &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size) {
if (dst == nullptr || dst_size == 0 || cmd == nullptr || cmd_size == 0) { if (dst == nullptr || dst_size == 0 || cmd == nullptr || cmd_size == 0) {
std::abort(); std::abort();
} }
u8 cmd_list[I2cCommandListFormatter::MaxCommandListSize]; u8 cmd_list[i2c::CommandListFormatter::MaxCommandListSize];
I2cCommandListFormatter formatter(cmd_list, sizeof(cmd_list)); i2c::CommandListFormatter formatter(cmd_list, sizeof(cmd_list));
R_ASSERT(formatter.EnqueueSendCommand(I2cTransactionOption_Start, cmd, cmd_size)); R_ASSERT(formatter.EnqueueSendCommand(I2cTransactionOption_Start, cmd, cmd_size));
R_ASSERT(formatter.EnqueueReceiveCommand(static_cast<I2cTransactionOption>(I2cTransactionOption_Start | I2cTransactionOption_Stop), dst_size)); R_ASSERT(formatter.EnqueueReceiveCommand(static_cast<I2cTransactionOption>(I2cTransactionOption_Start | I2cTransactionOption_Stop), dst_size));
return RetryUntilSuccess([&]() { return I2cDriver::ExecuteCommandList(session, dst, dst_size, cmd_list, formatter.GetCurrentSize()); }); return RetryUntilSuccess([&]() { return i2c::driver::ExecuteCommandList(session, dst, dst_size, cmd_list, formatter.GetCurrentSize()); });
} }
Result Boot::WriteI2cRegister(I2cSessionImpl &session, const u8 *src, size_t src_size, const u8 *cmd, size_t cmd_size) { Result WriteI2cRegister(i2c::driver::Session &session, const u8 *src, size_t src_size, const u8 *cmd, size_t cmd_size) {
if (src == nullptr || src_size == 0 || cmd == nullptr || cmd_size == 0) { if (src == nullptr || src_size == 0 || cmd == nullptr || cmd_size == 0) {
std::abort(); std::abort();
} }
@@ -60,9 +65,11 @@ Result Boot::WriteI2cRegister(I2cSessionImpl &session, const u8 *src, size_t src
std::memcpy(&cmd_list[0], cmd, cmd_size); std::memcpy(&cmd_list[0], cmd, cmd_size);
std::memcpy(&cmd_list[cmd_size], src, src_size); std::memcpy(&cmd_list[cmd_size], src, src_size);
return RetryUntilSuccess([&]() { return I2cDriver::Send(session, cmd_list, src_size + cmd_size, static_cast<I2cTransactionOption>(I2cTransactionOption_Start | I2cTransactionOption_Stop)); }); return RetryUntilSuccess([&]() { return i2c::driver::Send(session, cmd_list, src_size + cmd_size, static_cast<I2cTransactionOption>(I2cTransactionOption_Start | I2cTransactionOption_Stop)); });
}
Result WriteI2cRegister(i2c::driver::Session &session, const u8 address, const u8 value) {
return WriteI2cRegister(session, &value, sizeof(value), &address, sizeof(address));
} }
Result Boot::WriteI2cRegister(I2cSessionImpl &session, const u8 address, const u8 value) {
return Boot::WriteI2cRegister(session, &value, sizeof(value), &address, sizeof(address));
} }
@@ -18,25 +18,13 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
/* TODO: Better way to do this? */ #include "i2c/driver/i2c_api.hpp"
#include "../boot_types.hpp"
enum BootImageUpdateType { namespace sts::boot {
BootImageUpdateType_Erista,
BootImageUpdateType_Mariko,
};
enum BootModeType { /* I2C Utilities. */
BootModeType_Normal, Result ReadI2cRegister(i2c::driver::Session &session, u8 *dst, size_t dst_size, const u8 *cmd, size_t cmd_size);
BootModeType_Safe, Result WriteI2cRegister(i2c::driver::Session &session, const u8 *src, size_t src_size, const u8 *cmd, size_t cmd_size);
}; Result WriteI2cRegister(i2c::driver::Session &session, const u8 address, const u8 value);
static constexpr size_t BctSize = 0x4000; }
static constexpr size_t EksSize = 0x4000;
static constexpr size_t EksEntrySize = 0x200;
static constexpr size_t EksBlobSize = 0xB0;
struct VerificationState {
bool needs_verify_normal;
bool needs_verify_safe;
};
+33 -20
View File
@@ -22,9 +22,24 @@
#include <switch.h> #include <switch.h>
#include <atmosphere.h> #include <atmosphere.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include <stratosphere/spl.hpp>
#include "boot_functions.hpp" #include "boot_boot_reason.hpp"
#include "boot_reboot_manager.hpp" #include "boot_change_voltage.hpp"
#include "boot_check_battery.hpp"
#include "boot_check_clock.hpp"
#include "boot_clock_initial_configuration.hpp"
#include "boot_fan_enable.hpp"
#include "boot_repair_boot_images.hpp"
#include "boot_splash_screen.hpp"
#include "boot_wake_pins.hpp"
#include "gpio/gpio_initial_configuration.hpp"
#include "pinmux/pinmux_initial_configuration.hpp"
#include "boot_power_utils.hpp"
using namespace sts;
extern "C" { extern "C" {
extern u32 __start__; extern u32 __start__;
@@ -53,7 +68,7 @@ void __libnx_exception_handler(ThreadExceptionDump *ctx) {
void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx) { void __libstratosphere_exception_handler(AtmosphereFatalErrorContext *ctx) {
/* We're boot sysmodule, so manually reboot to fatal error. */ /* We're boot sysmodule, so manually reboot to fatal error. */
BootRebootManager::RebootForFatalError(ctx); boot::RebootForFatalError(ctx);
} }
void __libnx_initheap(void) { void __libnx_initheap(void) {
@@ -94,47 +109,45 @@ int main(int argc, char **argv)
consoleDebugInit(debugDevice_SVC); consoleDebugInit(debugDevice_SVC);
/* Change voltage from 3.3v to 1.8v for select devices. */ /* Change voltage from 3.3v to 1.8v for select devices. */
Boot::ChangeGpioVoltageTo1_8v(); boot::ChangeGpioVoltageTo1_8v();
/* Setup GPIO. */ /* Setup GPIO. */
Boot::SetInitialGpioConfiguration(); gpio::SetInitialConfiguration();
/* Check USB PLL/UTMIP clock. */ /* Check USB PLL/UTMIP clock. */
Boot::CheckClock(); boot::CheckClock();
/* Talk to PMIC/RTC, set boot reason with SPL. */ /* Talk to PMIC/RTC, set boot reason with SPL. */
Boot::DetectBootReason(); boot::DetectBootReason();
const HardwareType hw_type = Boot::GetHardwareType(); const auto hw_type = spl::GetHardwareType();
if (hw_type != HardwareType_Copper) { if (hw_type != spl::HardwareType::Copper) {
/* Display splash screen for two seconds. */ /* Display splash screen for two seconds. */
Boot::ShowSplashScreen(); boot::ShowSplashScreen();
/* Check that the battery has enough to boot. */ /* Check that the battery has enough to boot. */
Boot::CheckBatteryCharge(); boot::CheckBatteryCharge();
} }
/* Configure pinmux + drive pads. */ /* Configure pinmux + drive pads. */
Boot::ConfigurePinmux(); pinmux::SetInitialConfiguration();
/* Configure the PMC wake pin settings. */ /* Configure the PMC wake pin settings. */
Boot::SetInitialWakePinConfiguration(); boot::SetInitialWakePinConfiguration();
/* Configure output clock. */ /* Configure output clock. */
if (hw_type != HardwareType_Copper) { if (hw_type != spl::HardwareType::Copper) {
Boot::SetInitialClockConfiguration(); boot::SetInitialClockConfiguration();
} }
/* Set Fan enable config (Copper only). */ /* Set Fan enable config (Copper only). */
Boot::SetFanEnabled(); boot::SetFanEnabled();
/* Repair boot partitions in NAND if needed. */ /* Repair boot partitions in NAND if needed. */
Boot::CheckAndRepairBootImages(); boot::CheckAndRepairBootImages();
/* Tell PM to start boot2. */ /* Tell PM to start boot2. */
if (R_FAILED(pmshellNotifyBootFinished())) { R_ASSERT(pmshellNotifyBootFinished());
std::abort();
}
return 0; return 0;
} }
+77
View File
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c/i2c_types.hpp"
#include "i2c/driver/impl/i2c_pcv.hpp"
#include "i2c/driver/impl/i2c_registers.hpp"
using namespace sts::i2c::driver::impl;
namespace sts::pcv {
void Initialize() {
/* Don't do anything. */
}
void Finalize() {
/* Don't do anything. */
}
Result SetClockRate(PcvModule module, u32 hz) {
/* Get clock/reset registers. */
ClkRstRegisters regs;
regs.SetBus(ConvertFromPcvModule(module));
/* Set clock enabled/source. */
reg::SetBits(regs.clk_en_reg, regs.mask);
reg::ReadWrite(regs.clk_src_reg, 0x4, 0xFF);
svcSleepThread(1000ul);
reg::ReadWrite(regs.clk_src_reg, 0, 0xE0000000);
svcSleepThread(2000ul);
return ResultSuccess;
}
Result SetClockEnabled(PcvModule module, bool enabled) {
return ResultSuccess;
}
Result SetVoltageEnabled(u32 domain, bool enabled) {
return ResultSuccess;
}
Result SetVoltageValue(u32 domain, u32 voltage) {
return ResultSuccess;
}
Result SetReset(PcvModule module, bool reset) {
/* Get clock/reset registers. */
ClkRstRegisters regs;
regs.SetBus(ConvertFromPcvModule(module));
/* Set/clear reset. */
if (reset) {
reg::SetBits(regs.rst_reg, regs.mask);
} else {
reg::ClearBits(regs.rst_reg, regs.mask);
}
return ResultSuccess;
}
}
@@ -1,95 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "boot_functions.hpp"
#include "boot_pinmux_map.hpp"
#include "boot_pinmux_initial_configuration_icosa.hpp"
#include "boot_pinmux_initial_configuration_copper.hpp"
#include "boot_pinmux_initial_configuration_hoag.hpp"
#include "boot_pinmux_initial_configuration_iowa.hpp"
#include "boot_pinmux_initial_drive_pad_configuration.hpp"
void Boot::ConfigurePinmux() {
/* Update parks. */
for (size_t i = 0; i < PinmuxPadNameMax; i++) {
Boot::PinmuxUpdatePark(static_cast<u32>(i));
}
/* Dummy read all drive pads. */
for (size_t i = 0; i < PinmuxDrivePadNameMax; i++) {
Boot::PinmuxDummyReadDrivePad(static_cast<u32>(i));
}
/* Set initial pad configs. */
Boot::ConfigurePinmuxInitialPads();
/* Set initial drive pad configs. */
Boot::ConfigurePinmuxInitialDrivePads();
}
void Boot::ConfigurePinmuxInitialPads() {
const PinmuxInitialConfig *configs = nullptr;
size_t num_configs = 0;
const HardwareType hw_type = Boot::GetHardwareType();
switch (hw_type) {
case HardwareType_Icosa:
configs = PinmuxInitialConfigsIcosa;
num_configs = PinmuxNumInitialConfigsIcosa;
break;
case HardwareType_Copper:
configs = PinmuxInitialConfigsCopper;
num_configs = PinmuxNumInitialConfigsCopper;
break;
case HardwareType_Hoag:
configs = PinmuxInitialConfigsHoag;
num_configs = PinmuxNumInitialConfigsHoag;
break;
case HardwareType_Iowa:
configs = PinmuxInitialConfigsIowa;
num_configs = PinmuxNumInitialConfigsIowa;
break;
default:
/* Unknown hardware type, we can't proceed. */
std::abort();
}
/* Ensure we found an appropriate config. */
if (configs == nullptr) {
std::abort();
}
for (size_t i = 0; i < num_configs - 1; i++) {
Boot::PinmuxUpdatePad(configs[i].name, configs[i].val, configs[i].mask);
}
/* Extra configs for iowa only. */
if (hw_type == HardwareType_Iowa) {
static constexpr u32 ExtraIowaPinmuxPadNames[] = {
0xAA, 0xAC, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9
};
for (size_t i = 0; i < sizeof(ExtraIowaPinmuxPadNames) / sizeof(ExtraIowaPinmuxPadNames[0]); i++) {
Boot::PinmuxUpdatePad(ExtraIowaPinmuxPadNames[i], 0x2000, 0x2000);
}
}
}
void Boot::ConfigurePinmuxInitialDrivePads() {
const PinmuxInitialConfig *configs = PinmuxInitialDrivePadConfigs;
for (size_t i = 0; i < PinmuxNumInitialDrivePadConfigs; i++) {
Boot::PinmuxUpdateDrivePad(configs[i].name, configs[i].val, configs[i].mask);
}
}
@@ -1,505 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "boot_functions.hpp"
#include "boot_pinmux_map.hpp"
static bool g_initialized_pinmux_vaddr = false;
static uintptr_t g_pinmux_vaddr = 0;
static inline const PinmuxDefinition *GetPinmuxDefinition(u32 pinmux_name) {
if (pinmux_name >= PinmuxPadNameMax) {
std::abort();
}
return &PinmuxMap[pinmux_name];
}
static inline const PinmuxDrivePadDefinition *GetPinmuxDrivePadDefinition(u32 pinmux_name) {
if (pinmux_name >= PinmuxDrivePadNameMax) {
std::abort();
}
return &PinmuxDrivePadMap[pinmux_name];
}
static uintptr_t GetPinmuxBaseAddress() {
if (!g_initialized_pinmux_vaddr) {
u64 vaddr;
if (R_FAILED(svcQueryIoMapping(&vaddr, Boot::ApbMiscPhysicalBase, 0x4000))) {
std::abort();
}
g_pinmux_vaddr = vaddr;
g_initialized_pinmux_vaddr = true;
}
return g_pinmux_vaddr;
}
u32 Boot::PinmuxUpdatePark(u32 pinmux_name) {
const uintptr_t pinmux_base_vaddr = GetPinmuxBaseAddress();
const PinmuxDefinition *pinmux_def = GetPinmuxDefinition(pinmux_name);
/* Fetch this PINMUX's register offset */
u32 pinmux_reg_offset = pinmux_def->reg_offset;
/* Fetch this PINMUX's mask value */
u32 pinmux_mask_val = pinmux_def->mask_val;
/* Get current register ptr. */
volatile u32 *pinmux_reg = reinterpret_cast<volatile u32 *>(pinmux_base_vaddr + pinmux_reg_offset);
/* Read from the PINMUX register */
u32 pinmux_val = *pinmux_reg;
/* This PINMUX supports park change */
if (pinmux_mask_val & 0x20) {
/* Clear park status if set */
if (pinmux_val & 0x20) {
pinmux_val &= ~(0x20);
}
}
/* Write to the appropriate PINMUX register */
*pinmux_reg = pinmux_val;
/* Do a dummy read from the PINMUX register */
pinmux_val = *pinmux_reg;
return pinmux_val;
}
u32 Boot::PinmuxUpdatePad(u32 pinmux_name, u32 pinmux_config_val, u32 pinmux_config_mask_val) {
const uintptr_t pinmux_base_vaddr = GetPinmuxBaseAddress();
const PinmuxDefinition *pinmux_def = GetPinmuxDefinition(pinmux_name);
/* Fetch this PINMUX's register offset */
u32 pinmux_reg_offset = pinmux_def->reg_offset;
/* Fetch this PINMUX's mask value */
u32 pinmux_mask_val = pinmux_def->mask_val;
/* Get current register ptr. */
volatile u32 *pinmux_reg = reinterpret_cast<volatile u32 *>(pinmux_base_vaddr + pinmux_reg_offset);
/* Read from the PINMUX register */
u32 pinmux_val = *pinmux_reg;
/* This PINMUX register is locked */
if (pinmux_val & 0x80) {
std::abort();
}
u32 pm_val = (pinmux_config_val & 0x07);
/* Adjust PM */
if (pinmux_config_mask_val & 0x07) {
/* Apply additional changes first */
if (pm_val == 0x05) {
/* This pin supports PUPD change */
if (pinmux_mask_val & 0x0C) {
/* Change PUPD */
if ((pinmux_val & 0x0C) != 0x04) {
pinmux_val &= 0xFFFFFFF3;
pinmux_val |= 0x04;
}
}
/* This pin supports Tristate change */
if (pinmux_mask_val & 0x10) {
/* Change Tristate */
if (!(pinmux_val & 0x10)) {
pinmux_val |= 0x10;
}
}
/* This pin supports EInput change */
if (pinmux_mask_val & 0x40) {
/* Change EInput */
if (pinmux_val & 0x40) {
pinmux_val &= 0xFFFFFFBF;
}
}
} else if (pm_val >= 0x06) {
/* Default to safe value */
pm_val = 0x04;
}
/* Translate PM value if necessary */
if (pm_val == 0x04 || pm_val == 0x05) {
pm_val = pinmux_def->pm_val;
}
/* This pin supports PM change */
if (pinmux_mask_val & 0x03) {
/* Change PM */
if ((pinmux_val & 0x03) != (pm_val & 0x03)) {
pinmux_val &= 0xFFFFFFFC;
pinmux_val |= (pm_val & 0x03);
}
}
}
u32 pupd_config_val = (pinmux_config_val & 0x18);
/* Adjust PUPD */
if (pinmux_config_mask_val & 0x18) {
if (pupd_config_val < 0x11) {
/* This pin supports PUPD change */
if (pinmux_mask_val & 0x0C) {
/* Change PUPD */
if (((pinmux_val >> 0x02) & 0x03) != (pupd_config_val >> 0x03)) {
pinmux_val &= 0xFFFFFFF3;
pinmux_val |= (pupd_config_val >> 0x01);
}
}
}
}
u32 eod_config_val = (pinmux_config_val & 0x60);
/* Adjust EOd field */
if (pinmux_config_mask_val & 0x60) {
if (eod_config_val == 0x20) {
/* This pin supports Tristate change */
if (pinmux_mask_val & 0x10) {
/* Change Tristate */
if (!(pinmux_val & 0x10)) {
pinmux_val |= 0x10;
}
}
/* This pin supports EInput change */
if (pinmux_mask_val & 0x40) {
/* Change EInput */
if (!(pinmux_val & 0x40)) {
pinmux_val |= 0x40;
}
}
/* This pin supports EOd change */
if (pinmux_mask_val & 0x800) {
/* Change EOd */
if (pinmux_val & 0x800) {
pinmux_val &= 0xFFFFF7FF;
}
}
} else if (eod_config_val == 0x40) {
/* This pin supports Tristate change */
if (pinmux_mask_val & 0x10) {
/* Change Tristate */
if (pinmux_val & 0x10) {
pinmux_val &= 0xFFFFFFEF;
}
}
/* This pin supports EInput change */
if (pinmux_mask_val & 0x40) {
/* Change EInput */
if (!(pinmux_val & 0x40)) {
pinmux_val |= 0x40;
}
}
/* This pin supports EOd change */
if (pinmux_mask_val & 0x800) {
/* Change EOd */
if (pinmux_val & 0x800) {
pinmux_val &= 0xFFFFF7FF;
}
}
} else if (eod_config_val == 0x60) {
/* This pin supports Tristate change */
if (pinmux_mask_val & 0x10) {
/* Change Tristate */
if (pinmux_val & 0x10) {
pinmux_val &= 0xFFFFFFEF;
}
}
/* This pin supports EInput change */
if (pinmux_mask_val & 0x40) {
/* Change EInput */
if (!(pinmux_val & 0x40)) {
pinmux_val |= 0x40;
}
}
/* This pin supports EOd change */
if (pinmux_mask_val & 0x800) {
/* Change EOd */
if (!(pinmux_val & 0x800)) {
pinmux_val |= 0x800;
}
}
} else {
/* This pin supports Tristate change */
if (pinmux_mask_val & 0x10) {
/* Change Tristate */
if (pinmux_val & 0x10) {
pinmux_val &= 0xFFFFFFEF;
}
}
/* This pin supports EInput change */
if (pinmux_mask_val & 0x40) {
/* Change EInput */
if (pinmux_val & 0x40) {
pinmux_val &= 0xFFFFFFBF;
}
}
/* This pin supports EOd change */
if (pinmux_mask_val & 0x800) {
/* Change EOd */
if (pinmux_val & 0x800) {
pinmux_val &= 0xFFFFF7FF;
}
}
}
}
u32 lock_config_val = (pinmux_config_val & 0x80);
/* Adjust Lock */
if (pinmux_config_mask_val & 0x80) {
/* This pin supports Lock change */
if (pinmux_mask_val & 0x80) {
/* Change Lock */
if ((pinmux_val ^ pinmux_config_val) & 0x80) {
pinmux_val &= 0xFFFFFF7F;
pinmux_val |= lock_config_val;
}
}
}
u32 ioreset_config_val = (((pinmux_config_val >> 0x08) & 0x1) << 0x10);
/* Adjust IoReset */
if (pinmux_config_mask_val & 0x100) {
/* This pin supports IoReset change */
if (pinmux_mask_val & 0x10000) {
/* Change IoReset */
if (((pinmux_val >> 0x10) ^ (pinmux_config_val >> 0x08)) & 0x01) {
pinmux_val &= 0xFFFEFFFF;
pinmux_val |= ioreset_config_val;
}
}
}
u32 park_config_val = (((pinmux_config_val >> 0x0A) & 0x1) << 0x5);
/* Adjust Park */
if (pinmux_config_mask_val & 0x400) {
/* This pin supports Park change */
if (pinmux_mask_val & 0x20) {
/* Change Park */
if (((pinmux_val >> 0x05) ^ (pinmux_config_val >> 0x0A)) & 0x01) {
pinmux_val &= 0xFFFFFFDF;
pinmux_val |= park_config_val;
}
}
}
u32 elpdr_config_val = (((pinmux_config_val >> 0x0B) & 0x1) << 0x08);
/* Adjust ELpdr */
if (pinmux_config_mask_val & 0x800) {
/* This pin supports ELpdr change */
if (pinmux_mask_val & 0x100) {
/* Change ELpdr */
if (((pinmux_val >> 0x08) ^ (pinmux_config_val >> 0x0B)) & 0x01) {
pinmux_val &= 0xFFFFFEFF;
pinmux_val |= elpdr_config_val;
}
}
}
u32 ehsm_config_val = (((pinmux_config_val >> 0x0C) & 0x1) << 0x09);
/* Adjust EHsm */
if (pinmux_config_mask_val & 0x1000) {
/* This pin supports EHsm change */
if (pinmux_mask_val & 0x200) {
/* Change EHsm */
if (((pinmux_val >> 0x09) ^ (pinmux_config_val >> 0x0C)) & 0x01) {
pinmux_val &= 0xFFFFFDFF;
pinmux_val |= ehsm_config_val;
}
}
}
u32 eiohv_config_val = (((pinmux_config_val >> 0x09) & 0x1) << 0x0A);
/* Adjust EIoHv */
if (pinmux_config_mask_val & 0x200) {
/* This pin supports EIoHv change */
if (pinmux_mask_val & 0x400) {
/* Change EIoHv */
if (((pinmux_val >> 0x0A) ^ (pinmux_config_val >> 0x09)) & 0x01) {
pinmux_val &= 0xFFFFFBFF;
pinmux_val |= eiohv_config_val;
}
}
}
u32 eschmt_config_val = (((pinmux_config_val >> 0x0D) & 0x1) << 0x0C);
/* Adjust ESchmt */
if (pinmux_config_mask_val & 0x2000) {
/* This pin supports ESchmt change */
if (pinmux_mask_val & 0x1000) {
/* Change ESchmt */
if (((pinmux_val >> 0x0C) ^ (pinmux_config_val >> 0x0D)) & 0x01) {
pinmux_val &= 0xFFFFEFFF;
pinmux_val |= eschmt_config_val;
}
}
}
u32 preemp_config_val = (((pinmux_config_val >> 0x10) & 0x1) << 0xF);
/* Adjust Preemp */
if (pinmux_config_mask_val & 0x10000) {
/* This pin supports Preemp change */
if (pinmux_mask_val & 0x8000) {
/* Change Preemp */
if (((pinmux_val >> 0x0F) ^ (pinmux_config_val >> 0x10)) & 0x01) {
pinmux_val &= 0xFFFF7FFF;
pinmux_val |= preemp_config_val;
}
}
}
u32 drvtype_config_val = (((pinmux_config_val >> 0x0E) & 0x3) << 0xD);
/* Adjust DrvType */
if (pinmux_config_mask_val & 0xC000) {
/* This pin supports DrvType change */
if (pinmux_mask_val & 0x6000) {
/* Change DrvType */
if (((pinmux_val >> 0x0D) ^ (pinmux_config_val >> 0x0E)) & 0x03) {
pinmux_val &= 0xFFFF9FFF;
pinmux_val |= drvtype_config_val;
}
}
}
/* Write to the appropriate PINMUX register */
*pinmux_reg = pinmux_val;
/* Do a dummy read from the PINMUX register */
pinmux_val = *pinmux_reg;
return pinmux_val;
}
u32 Boot::PinmuxUpdateDrivePad(u32 pinmux_drivepad_name, u32 pinmux_drivepad_config_val, u32 pinmux_drivepad_config_mask_val) {
const uintptr_t pinmux_base_vaddr = GetPinmuxBaseAddress();
const PinmuxDrivePadDefinition *pinmux_drivepad_def = GetPinmuxDrivePadDefinition(pinmux_drivepad_name);
/* Fetch this PINMUX drive group's register offset */
u32 pinmux_drivepad_reg_offset = pinmux_drivepad_def->reg_offset;
/* Fetch this PINMUX drive group's mask value */
u32 pinmux_drivepad_mask_val = pinmux_drivepad_def->mask_val;
/* Get current register ptr. */
volatile u32 *pinmux_drivepad_reg = reinterpret_cast<volatile u32 *>(pinmux_base_vaddr + pinmux_drivepad_reg_offset);
/* Read from the PINMUX drive group register */
u32 pinmux_drivepad_val = *pinmux_drivepad_reg;
/* Adjust DriveDownStrength */
if (pinmux_drivepad_config_mask_val & 0x1F000) {
u32 mask_val = 0x7F000;
/* Adjust mask value */
if ((pinmux_drivepad_mask_val & 0x7F000) != 0x7F000)
mask_val = 0x1F000;
/* This drive group supports DriveDownStrength change */
if (pinmux_drivepad_mask_val & mask_val) {
/* Change DriveDownStrength */
if (((pinmux_drivepad_config_val & 0x7F000) & mask_val) != (pinmux_drivepad_val & mask_val)) {
pinmux_drivepad_val &= ~(mask_val);
pinmux_drivepad_val |= ((pinmux_drivepad_config_val & 0x7F000) & mask_val);
}
}
}
/* Adjust DriveUpStrength */
if (pinmux_drivepad_config_mask_val & 0x1F00000) {
u32 mask_val = 0x7F00000;
/* Adjust mask value */
if ((pinmux_drivepad_mask_val & 0x7F00000) != 0x7F00000)
mask_val = 0x1F00000;
/* This drive group supports DriveUpStrength change */
if (pinmux_drivepad_mask_val & mask_val) {
/* Change DriveUpStrength */
if (((pinmux_drivepad_config_val & 0x7F00000) & mask_val) != (pinmux_drivepad_val & mask_val)) {
pinmux_drivepad_val &= ~(mask_val);
pinmux_drivepad_val |= ((pinmux_drivepad_config_val & 0x7F00000) & mask_val);
}
}
}
/* Adjust DriveDownSlew */
if (pinmux_drivepad_config_mask_val & 0x30000000) {
/* This drive group supports DriveDownSlew change */
if (pinmux_drivepad_mask_val & 0x30000000) {
/* Change DriveDownSlew */
if ((pinmux_drivepad_val ^ pinmux_drivepad_config_val) & 0x30000000) {
pinmux_drivepad_val &= 0xCFFFFFFF;
pinmux_drivepad_val |= (pinmux_drivepad_config_val & 0x30000000);
}
}
}
/* Adjust DriveUpSlew */
if (pinmux_drivepad_config_mask_val & 0xC0000000) {
/* This drive group supports DriveUpSlew change */
if (pinmux_drivepad_mask_val & 0xC0000000) {
/* Change DriveUpSlew */
if ((pinmux_drivepad_val ^ pinmux_drivepad_config_val) & 0xC0000000) {
pinmux_drivepad_val &= 0x3FFFFFFF;
pinmux_drivepad_val |= (pinmux_drivepad_config_val & 0xC0000000);
}
}
}
/* Write to the appropriate PINMUX drive group register */
*pinmux_drivepad_reg = pinmux_drivepad_val;
/* Do a dummy read from the PINMUX drive group register */
pinmux_drivepad_val = *pinmux_drivepad_reg;
return pinmux_drivepad_val;
}
u32 Boot::PinmuxDummyReadDrivePad(u32 pinmux_drivepad_name) {
const uintptr_t pinmux_base_vaddr = GetPinmuxBaseAddress();
const PinmuxDrivePadDefinition *pinmux_drivepad_def = GetPinmuxDrivePadDefinition(pinmux_drivepad_name);
/* Fetch this PINMUX drive group's register offset */
u32 pinmux_drivepad_reg_offset = pinmux_drivepad_def->reg_offset;
/* Get current register ptr. */
volatile u32 *pinmux_drivepad_reg = reinterpret_cast<volatile u32 *>(pinmux_base_vaddr + pinmux_drivepad_reg_offset);
return *pinmux_drivepad_reg;
}
+19 -9
View File
@@ -14,25 +14,31 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp" #include "boot_pmc_wrapper.hpp"
static constexpr u32 SmcFunctionId_AtmosphereReadWriteRegister = 0xF0000002; namespace sts::boot {
static constexpr u32 PmcPhysStart = 0x7000E400; namespace {
static constexpr u32 PmcPhysEnd = 0x7000EFFF;
static inline bool IsValidPmcAddress(u32 phys_addr) { /* Convenience definitions. */
constexpr u32 SmcFunctionId_AtmosphereReadWriteRegister = 0xF0000002;
constexpr u32 PmcPhysStart = 0x7000E400;
constexpr u32 PmcPhysEnd = 0x7000EFFF;
/* Helpers. */
bool IsValidPmcAddress(u32 phys_addr) {
return (phys_addr & 3) == 0 && PmcPhysStart <= phys_addr && phys_addr <= PmcPhysEnd; return (phys_addr & 3) == 0 && PmcPhysStart <= phys_addr && phys_addr <= PmcPhysEnd;
} }
static inline u32 SmcAtmosphereReadWriteRegister(u32 phys_addr, u32 value, u32 mask) { inline u32 SmcAtmosphereReadWriteRegister(u32 phys_addr, u32 value, u32 mask) {
SecmonArgs args; SecmonArgs args;
args.X[0] = SmcFunctionId_AtmosphereReadWriteRegister; args.X[0] = SmcFunctionId_AtmosphereReadWriteRegister;
args.X[1] = phys_addr; args.X[1] = phys_addr;
args.X[2] = mask; args.X[2] = mask;
args.X[3] = value; args.X[3] = value;
svcCallSecureMonitor(&args); R_ASSERT(svcCallSecureMonitor(&args));
if (args.X[0] != 0) { if (args.X[0] != 0) {
std::abort(); std::abort();
} }
@@ -40,7 +46,9 @@ static inline u32 SmcAtmosphereReadWriteRegister(u32 phys_addr, u32 value, u32 m
return static_cast<u32>(args.X[1]); return static_cast<u32>(args.X[1]);
} }
u32 Boot::ReadPmcRegister(u32 phys_addr) { }
u32 ReadPmcRegister(u32 phys_addr) {
if (!IsValidPmcAddress(phys_addr)) { if (!IsValidPmcAddress(phys_addr)) {
std::abort(); std::abort();
} }
@@ -48,10 +56,12 @@ u32 Boot::ReadPmcRegister(u32 phys_addr) {
return SmcAtmosphereReadWriteRegister(phys_addr, 0, 0); return SmcAtmosphereReadWriteRegister(phys_addr, 0, 0);
} }
void Boot::WritePmcRegister(u32 phys_addr, u32 value, u32 mask) { void WritePmcRegister(u32 phys_addr, u32 value, u32 mask) {
if (!IsValidPmcAddress(phys_addr)) { if (!IsValidPmcAddress(phys_addr)) {
std::abort(); std::abort();
} }
SmcAtmosphereReadWriteRegister(phys_addr, value, mask); SmcAtmosphereReadWriteRegister(phys_addr, value, mask);
} }
}
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::boot {
/* PMC Access Utilities. */
u32 ReadPmcRegister(u32 phys_addr);
void WritePmcRegister(u32 phys_addr, u32 value, u32 mask = UINT32_MAX);
}
+15 -22
View File
@@ -16,19 +16,18 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "boot_functions.hpp"
#include "boot_i2c_utils.hpp"
#include "boot_pmic_driver.hpp" #include "boot_pmic_driver.hpp"
namespace sts::boot {
void PmicDriver::ShutdownSystem() { void PmicDriver::ShutdownSystem() {
if (R_FAILED(this->ShutdownSystem(false))) { R_ASSERT(this->ShutdownSystem(false));
std::abort();
}
} }
void PmicDriver::RebootSystem() { void PmicDriver::RebootSystem() {
if (R_FAILED(this->ShutdownSystem(true))) { R_ASSERT(this->ShutdownSystem(true));
std::abort();
}
} }
Result PmicDriver::GetAcOk(bool *out) { Result PmicDriver::GetAcOk(bool *out) {
@@ -40,17 +39,17 @@ Result PmicDriver::GetAcOk(bool *out) {
Result PmicDriver::GetPowerIntr(u8 *out) { Result PmicDriver::GetPowerIntr(u8 *out) {
const u8 addr = 0x0B; const u8 addr = 0x0B;
return Boot::ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr)); return ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr));
} }
Result PmicDriver::GetPowerStatus(u8 *out) { Result PmicDriver::GetPowerStatus(u8 *out) {
const u8 addr = 0x15; const u8 addr = 0x15;
return Boot::ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr)); return ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr));
} }
Result PmicDriver::GetNvErc(u8 *out) { Result PmicDriver::GetNvErc(u8 *out) {
const u8 addr = 0x0C; const u8 addr = 0x0C;
return Boot::ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr)); return ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr));
} }
Result PmicDriver::GetPowerButtonPressed(bool *out) { Result PmicDriver::GetPowerButtonPressed(bool *out) {
@@ -66,23 +65,17 @@ Result PmicDriver::ShutdownSystem(bool reboot) {
/* Get value, set or clear software reset mask. */ /* Get value, set or clear software reset mask. */
u8 on_off_2_val = 0; u8 on_off_2_val = 0;
if (R_FAILED(Boot::ReadI2cRegister(this->i2c_session, &on_off_2_val, sizeof(on_off_2_val), &on_off_2_addr, sizeof(on_off_2_addr)))) { R_ASSERT(ReadI2cRegister(this->i2c_session, &on_off_2_val, sizeof(on_off_2_val), &on_off_2_addr, sizeof(on_off_2_addr)));
std::abort();
}
if (reboot) { if (reboot) {
on_off_2_val |= 0x80; on_off_2_val |= 0x80;
} else { } else {
on_off_2_val &= ~0x80; on_off_2_val &= ~0x80;
} }
if (R_FAILED(Boot::WriteI2cRegister(this->i2c_session, &on_off_2_val, sizeof(on_off_2_val), &on_off_2_addr, sizeof(on_off_2_addr)))) { R_ASSERT(WriteI2cRegister(this->i2c_session, &on_off_2_val, sizeof(on_off_2_val), &on_off_2_addr, sizeof(on_off_2_addr)));
std::abort();
}
/* Get value, set software reset mask. */ /* Get value, set software reset mask. */
u8 on_off_1_val = 0; u8 on_off_1_val = 0;
if (R_FAILED(Boot::ReadI2cRegister(this->i2c_session, &on_off_1_val, sizeof(on_off_1_val), &on_off_1_addr, sizeof(on_off_1_addr)))) { R_ASSERT(ReadI2cRegister(this->i2c_session, &on_off_1_val, sizeof(on_off_1_val), &on_off_1_addr, sizeof(on_off_1_addr)));
std::abort();
}
on_off_1_val |= 0x80; on_off_1_val |= 0x80;
/* Finalize the battery. */ /* Finalize the battery. */
@@ -92,9 +85,7 @@ Result PmicDriver::ShutdownSystem(bool reboot) {
} }
/* Actually write the value to trigger shutdown/reset. */ /* Actually write the value to trigger shutdown/reset. */
if (R_FAILED(Boot::WriteI2cRegister(this->i2c_session, &on_off_1_val, sizeof(on_off_1_val), &on_off_1_addr, sizeof(on_off_1_addr)))) { R_ASSERT(WriteI2cRegister(this->i2c_session, &on_off_1_val, sizeof(on_off_1_val), &on_off_1_addr, sizeof(on_off_1_addr)));
std::abort();
}
/* Allow up to 5 seconds for shutdown/reboot to take place. */ /* Allow up to 5 seconds for shutdown/reboot to take place. */
svcSleepThread(5'000'000'000ul); svcSleepThread(5'000'000'000ul);
@@ -123,3 +114,5 @@ void PmicDriver::FinalizeBattery(BatteryDriver *battery_driver) {
battery_driver->SetShutdownEnabled(desired_shutdown_enabled); battery_driver->SetShutdownEnabled(desired_shutdown_enabled);
} }
} }
}
+11 -6
View File
@@ -18,21 +18,23 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "i2c_driver/i2c_api.hpp"
#include "boot_battery_driver.hpp" #include "boot_battery_driver.hpp"
namespace sts::boot {
/* Driver object. */
class PmicDriver { class PmicDriver {
private: private:
I2cSessionImpl i2c_session; i2c::driver::Session i2c_session;
public: public:
PmicDriver() { PmicDriver() {
I2cDriver::Initialize(); i2c::driver::Initialize();
I2cDriver::OpenSession(&this->i2c_session, I2cDevice_Max77620Pmic); i2c::driver::OpenSession(&this->i2c_session, I2cDevice_Max77620Pmic);
} }
~PmicDriver() { ~PmicDriver() {
I2cDriver::CloseSession(this->i2c_session); i2c::driver::CloseSession(this->i2c_session);
I2cDriver::Finalize(); i2c::driver::Finalize();
} }
private: private:
Result GetPowerStatus(u8 *out); Result GetPowerStatus(u8 *out);
@@ -46,3 +48,6 @@ class PmicDriver {
Result GetNvErc(u8 *out); Result GetNvErc(u8 *out);
Result GetPowerButtonPressed(bool *out); Result GetPowerButtonPressed(bool *out);
}; };
}
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include <strings.h>
#include "boot_power_utils.hpp"
#include "fusee-primary_bin.h"
namespace sts::boot {
namespace {
/* Convenience definitions. */
constexpr uintptr_t IramBase = 0x40000000ull;
constexpr uintptr_t IramPayloadBase = 0x40010000ull;
constexpr size_t IramSize = 0x40000;
constexpr size_t IramPayloadMaxSize = 0x2E000;
/* Globals. */
u8 __attribute__ ((aligned (0x1000))) g_work_page[0x1000];
/* Helpers. */
void ClearIram() {
/* Make page FFs. */
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)) {
CopyToIram(IramBase + ofs, g_work_page, sizeof(g_work_page));
}
}
void DoRebootToPayload(AtmosphereFatalErrorContext *ctx) {
/* Ensure clean IRAM state. */
ClearIram();
/* Copy in payload. */
for (size_t ofs = 0; ofs < fusee_primary_bin_size; ofs += 0x1000) {
std::memcpy(g_work_page, &fusee_primary_bin[ofs], std::min(static_cast<size_t>(fusee_primary_bin_size - ofs), size_t(0x1000)));
CopyToIram(IramPayloadBase + ofs, g_work_page, 0x1000);
}
/* 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));
CopyToIram(IramPayloadBase + IramPayloadMaxSize, g_work_page, sizeof(g_work_page));
}
RebootToIramPayload();
}
}
void RebootSystem() {
DoRebootToPayload(nullptr);
}
void RebootForFatalError(AtmosphereFatalErrorContext *ctx) {
DoRebootToPayload(ctx);
}
}
@@ -18,27 +18,13 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
enum HardwareType { namespace sts::boot {
HardwareType_Icosa = 0,
HardwareType_Copper = 1,
HardwareType_Hoag = 2,
HardwareType_Iowa = 3,
};
struct GpioInitialConfig { /* Power utilities. */
u32 pad_name; void RebootSystem();
GpioDirection direction; void ShutdownSystem();
GpioValue value;
};
struct PinmuxInitialConfig { /* Atmosphere power utilities. */
u32 name; void RebootForFatalError(AtmosphereFatalErrorContext *ctx);
u32 val;
u32 mask;
};
struct WakePinConfig { }
u32 index;
bool enabled;
u32 level;
};
@@ -1,75 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include <strings.h>
#include "boot_functions.hpp"
#include "boot_reboot_manager.hpp"
#include "fusee-primary_bin.h"
static u8 g_work_page[0x1000] __attribute__ ((aligned (0x1000)));
static void ClearIram() {
/* Make page FFs. */
memset(g_work_page, 0xFF, sizeof(g_work_page));
/* Overwrite all of IRAM with FFs. */
for (size_t ofs = 0; ofs < IRAM_SIZE; ofs += sizeof(g_work_page)) {
CopyToIram(IRAM_BASE + ofs, g_work_page, sizeof(g_work_page));
}
}
static void DoRebootToPayload() {
/* Ensure clean IRAM state. */
ClearIram();
/* Copy in payload. */
for (size_t ofs = 0; ofs < fusee_primary_bin_size; ofs += 0x1000) {
std::memcpy(g_work_page, &fusee_primary_bin[ofs], std::min(static_cast<size_t>(fusee_primary_bin_size - ofs), size_t(0x1000)));
CopyToIram(IRAM_PAYLOAD_BASE + ofs, g_work_page, 0x1000);
}
RebootToIramPayload();
}
Result BootRebootManager::PerformReboot() {
DoRebootToPayload();
return ResultSuccess;
}
void BootRebootManager::RebootForFatalError(AtmosphereFatalErrorContext *ctx) {
/* Ensure clean IRAM state. */
ClearIram();
/* Copy in payload. */
for (size_t ofs = 0; ofs < fusee_primary_bin_size; ofs += 0x1000) {
std::memcpy(g_work_page, &fusee_primary_bin[ofs], std::min(static_cast<size_t>(fusee_primary_bin_size - ofs), size_t(0x1000)));
CopyToIram(IRAM_PAYLOAD_BASE + ofs, g_work_page, 0x1000);
}
std::memset(g_work_page, 0xCC, sizeof(g_work_page));
std::memcpy(g_work_page, ctx, sizeof(*ctx));
CopyToIram(IRAM_PAYLOAD_BASE + IRAM_PAYLOAD_MAX_SIZE, g_work_page, sizeof(g_work_page));
RebootToIramPayload();
}
void Boot::RebootSystem() {
if (R_FAILED(BootRebootManager::PerformReboot())) {
std::abort();
}
}
@@ -17,8 +17,6 @@
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include "boot_types.hpp"
static constexpr size_t CLK_RST_CONTROLLER_RST_SOURCE = 0x0; static constexpr size_t CLK_RST_CONTROLLER_RST_SOURCE = 0x0;
static constexpr size_t CLK_RST_CONTROLLER_RST_DEVICES_L = 0x4; static constexpr size_t CLK_RST_CONTROLLER_RST_DEVICES_L = 0x4;
static constexpr size_t CLK_RST_CONTROLLER_RST_DEVICES_H = 0x8; static constexpr size_t CLK_RST_CONTROLLER_RST_DEVICES_H = 0x8;
@@ -19,8 +19,6 @@
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include "boot_types.hpp"
#define DC_CMD_GENERAL_INCR_SYNCPT 0x00 #define DC_CMD_GENERAL_INCR_SYNCPT 0x00
#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01 #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x01
@@ -17,8 +17,6 @@
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include "boot_types.hpp"
static constexpr size_t GPIO_PORT3_CNF_0 = 0x200; static constexpr size_t GPIO_PORT3_CNF_0 = 0x200;
static constexpr size_t GPIO_PORT3_OE_0 = 0x210; static constexpr size_t GPIO_PORT3_OE_0 = 0x210;
static constexpr size_t GPIO_PORT3_OUT_0 = 0x220; static constexpr size_t GPIO_PORT3_OUT_0 = 0x220;
@@ -17,8 +17,6 @@
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include "boot_types.hpp"
static constexpr size_t APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL = 0x8D4; static constexpr size_t APB_MISC_GP_SDMMC1_CLK_LPBK_CONTROL = 0x8D4;
static constexpr size_t APB_MISC_GP_SDMMC3_CLK_LPBK_CONTROL = 0x8D8; static constexpr size_t APB_MISC_GP_SDMMC3_CLK_LPBK_CONTROL = 0x8D8;
static constexpr size_t APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL = 0xA98; static constexpr size_t APB_MISC_GP_SDMMC1_PAD_CFGPADCTRL = 0xA98;
@@ -17,8 +17,6 @@
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include "boot_types.hpp"
static constexpr uintptr_t PmcBase = 0x7000E400ul; static constexpr uintptr_t PmcBase = 0x7000E400ul;
static constexpr size_t APBDEV_PMC_CNTRL = 0x0; static constexpr size_t APBDEV_PMC_CNTRL = 0x0;
@@ -14,17 +14,29 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp" #include <stratosphere/spl.hpp>
#include "updater/updater_api.hpp" #include <stratosphere/updater.hpp>
static u8 __attribute__((__aligned__(0x1000))) g_boot_image_work_buffer[0x10000]; #include "boot_power_utils.hpp"
#include "boot_repair_boot_images.hpp"
void Boot::CheckAndRepairBootImages() { namespace sts::boot {
const BootImageUpdateType boot_image_update_type = Updater::GetBootImageUpdateType(Boot::GetHardwareType());
namespace {
/* Globals. */
u8 __attribute__((aligned(0x1000))) g_boot_image_work_buffer[0x10000];
}
void CheckAndRepairBootImages() {
const auto boot_image_update_type = updater::GetBootImageUpdateType(spl::GetHardwareType());
bool repaired_normal, repaired_safe; 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) { 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. */ /* Nintendo only performs a reboot on successful normal repair. */
Boot::RebootSystem(); RebootSystem();
} }
} }
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::boot {
void CheckAndRepairBootImages();
}
+8 -4
View File
@@ -16,23 +16,27 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "boot_functions.hpp"
#include "boot_rtc_driver.hpp" #include "boot_rtc_driver.hpp"
namespace sts::boot {
Result RtcDriver::ReadRtcRegister(u8 *out, u8 address) { Result RtcDriver::ReadRtcRegister(u8 *out, u8 address) {
const u8 update_addr = 0x04; const u8 update_addr = 0x04;
const u8 update_val = 0x10; const u8 update_val = 0x10;
R_TRY(Boot::WriteI2cRegister(this->i2c_session, &update_val, sizeof(update_val), &update_addr, sizeof(update_addr))); R_TRY(WriteI2cRegister(this->i2c_session, &update_val, sizeof(update_val), &update_addr, sizeof(update_addr)));
svcSleepThread(16'000'000ul); svcSleepThread(16'000'000ul);
return Boot::ReadI2cRegister(this->i2c_session, out, sizeof(*out), &address, sizeof(address)); return ReadI2cRegister(this->i2c_session, out, sizeof(*out), &address, sizeof(address));
} }
Result RtcDriver::GetRtcIntr(u8 *out) { Result RtcDriver::GetRtcIntr(u8 *out) {
const u8 addr = 0x00; const u8 addr = 0x00;
return Boot::ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr)); return ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr));
} }
Result RtcDriver::GetRtcIntrM(u8 *out) { Result RtcDriver::GetRtcIntrM(u8 *out) {
const u8 addr = 0x01; const u8 addr = 0x01;
return this->ReadRtcRegister(out, addr); return this->ReadRtcRegister(out, addr);
} }
}
+10 -6
View File
@@ -18,20 +18,22 @@
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "i2c_driver/i2c_api.hpp" #include "boot_i2c_utils.hpp"
namespace sts::boot {
class RtcDriver { class RtcDriver {
private: private:
I2cSessionImpl i2c_session; i2c::driver::Session i2c_session;
public: public:
RtcDriver() { RtcDriver() {
I2cDriver::Initialize(); i2c::driver::Initialize();
I2cDriver::OpenSession(&this->i2c_session, I2cDevice_Max77620Rtc); i2c::driver::OpenSession(&this->i2c_session, I2cDevice_Max77620Rtc);
} }
~RtcDriver() { ~RtcDriver() {
I2cDriver::CloseSession(this->i2c_session); i2c::driver::CloseSession(this->i2c_session);
I2cDriver::Finalize(); i2c::driver::Finalize();
} }
private: private:
Result ReadRtcRegister(u8 *out, u8 address); Result ReadRtcRegister(u8 *out, u8 address);
@@ -39,3 +41,5 @@ class RtcDriver {
Result GetRtcIntr(u8 *out); Result GetRtcIntr(u8 *out);
Result GetRtcIntrM(u8 *out); Result GetRtcIntrM(u8 *out);
}; };
}
@@ -1,47 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "boot_functions.hpp"
HardwareType Boot::GetHardwareType() {
u64 out_val = 0;
if (R_FAILED(splGetConfig(SplConfigItem_HardwareType, &out_val))) {
std::abort();
}
return static_cast<HardwareType>(out_val);
}
bool Boot::IsRecoveryBoot() {
u64 val = 0;
if (R_FAILED(splGetConfig(SplConfigItem_IsRecoveryBoot, &val))) {
std::abort();
}
return val != 0;
}
bool Boot::IsMariko() {
HardwareType hw_type = GetHardwareType();
switch (hw_type) {
case HardwareType_Icosa:
case HardwareType_Copper:
return false;
case HardwareType_Hoag:
case HardwareType_Iowa:
return true;
default:
std::abort();
}
}
@@ -14,21 +14,34 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp" #include "boot_boot_reason.hpp"
#include "boot_splash_screen_notext.hpp" #include "boot_display.hpp"
/* TODO: Compile-time switch for splash_screen_text.hpp? */ #include "boot_splash_screen.hpp"
void Boot::ShowSplashScreen() { namespace sts::boot {
const u32 boot_reason = Boot::GetBootReason();
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 u32 boot_reason = GetBootReason();
if (boot_reason == 1 || boot_reason == 4) { if (boot_reason == 1 || boot_reason == 4) {
return; return;
} }
Boot::InitializeDisplay(); InitializeDisplay();
{ {
/* Splash screen is shown for 2 seconds. */ /* Splash screen is shown for 2 seconds. */
Boot::ShowDisplay(SplashScreenX, SplashScreenY, SplashScreenW, SplashScreenH, SplashScreen); ShowDisplay(SplashScreenX, SplashScreenY, SplashScreenW, SplashScreenH, SplashScreen);
svcSleepThread(2'000'000'000ul); svcSleepThread(2'000'000'000ul);
} }
Boot::FinalizeDisplay(); FinalizeDisplay();
} }
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::boot {
void ShowSplashScreen();
}
@@ -1,28 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include "boot_types.hpp"
static constexpr size_t SplashScreenX = 535;
static constexpr size_t SplashScreenY = 274;
static constexpr size_t SplashScreenW = 210;
static constexpr size_t SplashScreenH = 172;
static constexpr u32 SplashScreen[] = {0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF202020, 0xFF404040, 0xFF666666, 0xFF666666, 0xFF707070, 0xFF666666, 0xFF666666, 0xFF404040, 0xFF333333, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF101010, 0xFF707070, 0xFFAFAFAF, 0xFFEFEFEF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFEFEFEF, 0xFFBFBFBF, 0xFF707070, 0xFF202020, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFLine truncated
static_assert(sizeof(SplashScreen) == sizeof(u32) * SplashScreenW * SplashScreenH, "Incorrect SplashScreen definition!");
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
constexpr size_t SplashScreenX = 535;
constexpr size_t SplashScreenY = 274;
constexpr size_t SplashScreenW = 210;
constexpr size_t SplashScreenH = 172;
constexpr u32 SplashScreen[] = {0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF202020, 0xFF404040, 0xFF666666, 0xFF666666, 0xFF707070, 0xFF666666, 0xFF666666, 0xFF404040, 0xFF333333, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF101010, 0xFF707070, 0xFFAFAFAF, 0xFFEFEFEF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFEFEFEF, 0xFFBFBFBF, 0xFF707070, 0xFF202020, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000,Line truncated
static_assert(sizeof(SplashScreen) == sizeof(u32) * SplashScreenW * SplashScreenH, "Incorrect SplashScreen definition!");
@@ -1,28 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include "boot_types.hpp"
static constexpr size_t SplashScreenX = 464;
static constexpr size_t SplashScreenY = 274;
static constexpr size_t SplashScreenW = 351;
static constexpr size_t SplashScreenH = 172;
static constexpr u32 SplashScreen[] = {0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF202020, 0xFF202020, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFLine truncated
static_assert(sizeof(SplashScreen) == sizeof(u32) * SplashScreenW * SplashScreenH, "Incorrect SplashScreen definition!");
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
constexpr size_t SplashScreenX = 464;
constexpr size_t SplashScreenY = 274;
constexpr size_t SplashScreenW = 351;
constexpr size_t SplashScreenH = 172;
constexpr u32 SplashScreen[] = {0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF202020, 0xFF202020, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000,Line truncated
static_assert(sizeof(SplashScreen) == sizeof(u32) * SplashScreenW * SplashScreenH, "Incorrect SplashScreen definition!");
@@ -14,19 +14,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once
#include <switch.h>
#include "boot_types.hpp"
#include "boot_registers_pmc.hpp"
struct WakeControlConfig { struct WakeControlConfig {
u32 reg_offset; u32 reg_offset;
u32 mask_val; u32 mask_val;
bool flag_val; bool flag_val;
}; };
static constexpr WakeControlConfig WakeControlConfigs[] = { constexpr WakeControlConfig WakeControlConfigs[] = {
{APBDEV_PMC_CNTRL, 0x0800, true}, {APBDEV_PMC_CNTRL, 0x0800, true},
{APBDEV_PMC_CNTRL, 0x0400, false}, {APBDEV_PMC_CNTRL, 0x0400, false},
{APBDEV_PMC_CNTRL, 0x0200, true}, {APBDEV_PMC_CNTRL, 0x0200, true},
@@ -38,4 +32,4 @@ static constexpr WakeControlConfig WakeControlConfigs[] = {
{APBDEV_PMC_CNTRL2, 0x0001, true}, {APBDEV_PMC_CNTRL2, 0x0001, true},
}; };
static constexpr size_t NumWakeControlConfigs = sizeof(WakeControlConfigs) / sizeof(WakeControlConfigs[0]); constexpr size_t NumWakeControlConfigs = sizeof(WakeControlConfigs) / sizeof(WakeControlConfigs[0]);
@@ -14,11 +14,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once
#include <switch.h>
#include "boot_types.hpp"
static constexpr WakePinConfig WakePinConfigs[] = { static constexpr WakePinConfig WakePinConfigs[] = {
{0x00, false, 0x02}, {0x00, false, 0x02},
{0x01, false, 0x02}, {0x01, false, 0x02},
@@ -14,11 +14,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once
#include <switch.h>
#include "boot_types.hpp"
static constexpr WakePinConfig WakePinConfigsCopper[] = { static constexpr WakePinConfig WakePinConfigsCopper[] = {
{0x00, true, 0x02}, {0x00, true, 0x02},
{0x01, false, 0x02}, {0x01, false, 0x02},
+43 -18
View File
@@ -14,25 +14,46 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "boot_functions.hpp" #include <stratosphere/spl.hpp>
#include "boot_pmc_wrapper.hpp"
#include "boot_wake_pins.hpp"
#include "boot_registers_pmc.hpp" #include "boot_registers_pmc.hpp"
#include "boot_wake_control_configs.hpp"
#include "boot_wake_pin_configuration.hpp" namespace sts::boot {
#include "boot_wake_pin_configuration_copper.hpp"
/* Include configuration into anonymous namespace. */
namespace {
struct WakePinConfig {
u32 index;
bool enabled;
u32 level;
};
#include "boot_wake_control_configs.inc"
#include "boot_wake_pin_configuration.inc"
#include "boot_wake_pin_configuration_copper.inc"
static void UpdatePmcControlBit(const u32 reg_offset, const u32 mask_val, const bool flag) {
Boot::WritePmcRegister(PmcBase + reg_offset, flag ? UINT32_MAX : 0, mask_val);
Boot::ReadPmcRegister(PmcBase + reg_offset);
} }
static void InitializePmcWakeConfiguration(const bool is_blink) { namespace {
/* Helpers. */
void UpdatePmcControlBit(const u32 reg_offset, const u32 mask_val, const bool flag) {
WritePmcRegister(PmcBase + reg_offset, flag ? UINT32_MAX : 0, mask_val);
ReadPmcRegister(PmcBase + reg_offset);
}
void InitializePmcWakeConfiguration(const bool is_blink) {
/* Initialize APBDEV_PMC_WAKE_DEBOUNCE_EN, do a dummy read. */ /* Initialize APBDEV_PMC_WAKE_DEBOUNCE_EN, do a dummy read. */
Boot::WritePmcRegister(PmcBase + APBDEV_PMC_WAKE_DEBOUNCE_EN, 0); WritePmcRegister(PmcBase + APBDEV_PMC_WAKE_DEBOUNCE_EN, 0);
Boot::ReadPmcRegister(PmcBase + APBDEV_PMC_WAKE_DEBOUNCE_EN); ReadPmcRegister(PmcBase + APBDEV_PMC_WAKE_DEBOUNCE_EN);
/* Initialize APBDEV_PMC_BLINK_TIMER, do a dummy read. */ /* Initialize APBDEV_PMC_BLINK_TIMER, do a dummy read. */
Boot::WritePmcRegister(PmcBase + APBDEV_PMC_BLINK_TIMER, 0x8008800); WritePmcRegister(PmcBase + APBDEV_PMC_BLINK_TIMER, 0x8008800);
Boot::ReadPmcRegister(PmcBase + APBDEV_PMC_BLINK_TIMER); ReadPmcRegister(PmcBase + APBDEV_PMC_BLINK_TIMER);
/* Set control bits, do dummy reads. */ /* Set control bits, do dummy reads. */
for (size_t i = 0; i < NumWakeControlConfigs; i++) { for (size_t i = 0; i < NumWakeControlConfigs; i++) {
@@ -46,7 +67,7 @@ static void InitializePmcWakeConfiguration(const bool is_blink) {
UpdatePmcControlBit(APBDEV_PMC_DPD_PADS_ORIDE, 0x100000, is_blink); UpdatePmcControlBit(APBDEV_PMC_DPD_PADS_ORIDE, 0x100000, is_blink);
} }
void Boot::SetWakeEventLevel(u32 index, u32 level) { void SetWakeEventLevel(u32 index, u32 level) {
u32 pmc_wake_level_reg_offset = index <= 0x1F ? APBDEV_PMC_WAKE_LVL : APBDEV_PMC_WAKE2_LVL; u32 pmc_wake_level_reg_offset = index <= 0x1F ? APBDEV_PMC_WAKE_LVL : APBDEV_PMC_WAKE2_LVL;
u32 pmc_wake_level_mask_reg_offset = index <= 0x1F ? APBDEV_PMC_AUTO_WAKE_LVL_MASK : APBDEV_PMC_AUTO_WAKE2_LVL_MASK; u32 pmc_wake_level_mask_reg_offset = index <= 0x1F ? APBDEV_PMC_AUTO_WAKE_LVL_MASK : APBDEV_PMC_AUTO_WAKE2_LVL_MASK;
if (level != 2) { if (level != 2) {
@@ -62,18 +83,20 @@ void Boot::SetWakeEventLevel(u32 index, u32 level) {
UpdatePmcControlBit(pmc_wake_level_mask_reg_offset, mask_val, level > 0); UpdatePmcControlBit(pmc_wake_level_mask_reg_offset, mask_val, level > 0);
} }
void Boot::SetWakeEventEnabled(u32 index, bool enabled) { void SetWakeEventEnabled(u32 index, bool enabled) {
/* Set or clear enabled bit. */ /* Set or clear enabled bit. */
UpdatePmcControlBit(index <= 0x1F ? APBDEV_PMC_WAKE_MASK : APBDEV_PMC_WAKE2_MASK, (1 << (index & 0x1F)), enabled); UpdatePmcControlBit(index <= 0x1F ? APBDEV_PMC_WAKE_MASK : APBDEV_PMC_WAKE2_MASK, (1 << (index & 0x1F)), enabled);
} }
void Boot::SetInitialWakePinConfiguration() { }
void SetInitialWakePinConfiguration() {
InitializePmcWakeConfiguration(false); InitializePmcWakeConfiguration(false);
/* Set wake event levels, wake event enables. */ /* Set wake event levels, wake event enables. */
const WakePinConfig *configs; const WakePinConfig *configs;
size_t num_configs; size_t num_configs;
if (Boot::GetHardwareType() == HardwareType_Copper) { if (spl::GetHardwareType() == spl::HardwareType::Copper) {
configs = WakePinConfigsCopper; configs = WakePinConfigsCopper;
num_configs = NumWakePinConfigsCopper; num_configs = NumWakePinConfigsCopper;
} else { } else {
@@ -82,7 +105,9 @@ void Boot::SetInitialWakePinConfiguration() {
} }
for (size_t i = 0; i < num_configs; i++) { for (size_t i = 0; i < num_configs; i++) {
Boot::SetWakeEventLevel(configs[i].index, configs[i].level); SetWakeEventLevel(configs[i].index, configs[i].level);
Boot::SetWakeEventEnabled(configs[i].index, configs[i].enabled); SetWakeEventEnabled(configs[i].index, configs[i].enabled);
} }
} }
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::boot {
void SetInitialWakePinConfiguration();
}
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere/spl.hpp>
#include "gpio_initial_configuration.hpp"
#include "gpio_utils.hpp"
namespace sts::gpio {
namespace {
struct InitialConfig {
u32 pad_name;
GpioDirection direction;
GpioValue value;
};
/* Include all initial configuration definitions. */
#include "gpio_initial_configuration_icosa.inc"
#include "gpio_initial_configuration_copper.inc"
#include "gpio_initial_configuration_hoag.inc"
#include "gpio_initial_configuration_iowa.inc"
}
void SetInitialConfiguration() {
const InitialConfig *configs = nullptr;
size_t num_configs = 0;
const auto hw_type = spl::GetHardwareType();
const FirmwareVersion fw_ver = GetRuntimeFirmwareVersion();
/* Choose GPIO map. */
if (fw_ver >= FirmwareVersion_200) {
switch (hw_type) {
case spl::HardwareType::Icosa:
{
if (fw_ver >= FirmwareVersion_400) {
configs = InitialConfigsIcosa4x;
num_configs = NumInitialConfigsIcosa4x;
} else {
configs = InitialConfigsIcosa;
num_configs = NumInitialConfigsIcosa;
}
}
break;
case spl::HardwareType::Copper:
configs = InitialConfigsCopper;
num_configs = NumInitialConfigsCopper;
break;
case spl::HardwareType::Hoag:
configs = InitialConfigsHoag;
num_configs = NumInitialConfigsHoag;
break;
case spl::HardwareType::Iowa:
configs = InitialConfigsIowa;
num_configs = NumInitialConfigsIowa;
break;
default:
/* Unknown hardware type, we can't proceed. */
std::abort();
}
} else {
/* Until 2.0.0, the GPIO map for Icosa was used for all hardware types. */
configs = InitialConfigsIcosa;
num_configs = NumInitialConfigsIcosa;
}
/* Ensure we found an appropriate config. */
if (configs == nullptr) {
std::abort();
}
for (size_t i = 0; i < num_configs; i++) {
/* Configure the GPIO. */
Configure(configs[i].pad_name);
/* Set the GPIO's direction. */
SetDirection(configs[i].pad_name, configs[i].direction);
if (configs[i].direction == GpioDirection_Output) {
/* Set the GPIO's value. */
SetValue(configs[i].pad_name, configs[i].value);
}
}
}
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::gpio {
void SetInitialConfiguration();
}
@@ -14,12 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once constexpr InitialConfig InitialConfigsCopper[] = {
#include <switch.h>
#include "boot_types.hpp"
static constexpr GpioInitialConfig GpioInitialConfigsCopper[] = {
{0x40, GpioDirection_Output, GpioValue_Low}, {0x40, GpioDirection_Output, GpioValue_Low},
{0x05, GpioDirection_Output, GpioValue_Low}, {0x05, GpioDirection_Output, GpioValue_Low},
{0x41, GpioDirection_Input, GpioValue_High}, {0x41, GpioDirection_Input, GpioValue_High},
@@ -66,4 +61,4 @@ static constexpr GpioInitialConfig GpioInitialConfigsCopper[] = {
{0x4E, GpioDirection_Input, GpioValue_Low}, {0x4E, GpioDirection_Input, GpioValue_Low},
}; };
static constexpr u32 GpioNumInitialConfigsCopper = (sizeof(GpioInitialConfigsCopper) / sizeof(GpioInitialConfigsCopper[0])); constexpr u32 NumInitialConfigsCopper = (sizeof(InitialConfigsCopper) / sizeof(InitialConfigsCopper[0]));
@@ -14,12 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once constexpr InitialConfig InitialConfigsHoag[] = {
#include <switch.h>
#include "boot_types.hpp"
static constexpr GpioInitialConfig GpioInitialConfigsIowa[] = {
{0x04, GpioDirection_Input, GpioValue_High}, {0x04, GpioDirection_Input, GpioValue_High},
{0x05, GpioDirection_Output, GpioValue_Low}, {0x05, GpioDirection_Output, GpioValue_Low},
{0x06, GpioDirection_Input, GpioValue_Low}, {0x06, GpioDirection_Input, GpioValue_Low},
@@ -78,7 +73,6 @@ static constexpr GpioInitialConfig GpioInitialConfigsIowa[] = {
{0x35, GpioDirection_Input, GpioValue_High}, {0x35, GpioDirection_Input, GpioValue_High},
{0x2C, GpioDirection_Output, GpioValue_Low}, {0x2C, GpioDirection_Output, GpioValue_Low},
{0x36, GpioDirection_Output, GpioValue_Low}, {0x36, GpioDirection_Output, GpioValue_Low},
}; };
static constexpr u32 GpioNumInitialConfigsIowa = (sizeof(GpioInitialConfigsIowa) / sizeof(GpioInitialConfigsIowa[0])); constexpr u32 NumInitialConfigsHoag = (sizeof(InitialConfigsHoag) / sizeof(InitialConfigsHoag[0]));
@@ -14,12 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once constexpr InitialConfig InitialConfigsIcosa[] = {
#include <switch.h>
#include "boot_types.hpp"
static constexpr GpioInitialConfig GpioInitialConfigsIcosa[] = {
{0x04, GpioDirection_Input, GpioValue_High}, {0x04, GpioDirection_Input, GpioValue_High},
{0x05, GpioDirection_Output, GpioValue_Low}, {0x05, GpioDirection_Output, GpioValue_Low},
{0x06, GpioDirection_Input, GpioValue_Low}, {0x06, GpioDirection_Input, GpioValue_Low},
@@ -82,9 +77,9 @@ static constexpr GpioInitialConfig GpioInitialConfigsIcosa[] = {
{0x36, GpioDirection_Output, GpioValue_Low}, {0x36, GpioDirection_Output, GpioValue_Low},
}; };
static constexpr u32 GpioNumInitialConfigsIcosa = (sizeof(GpioInitialConfigsIcosa) / sizeof(GpioInitialConfigsIcosa[0])); constexpr u32 NumInitialConfigsIcosa = (sizeof(InitialConfigsIcosa) / sizeof(InitialConfigsIcosa[0]));
static constexpr GpioInitialConfig GpioInitialConfigsIcosa4x[] = { constexpr InitialConfig InitialConfigsIcosa4x[] = {
{0x04, GpioDirection_Input, GpioValue_High}, {0x04, GpioDirection_Input, GpioValue_High},
{0x05, GpioDirection_Output, GpioValue_Low}, {0x05, GpioDirection_Output, GpioValue_Low},
{0x06, GpioDirection_Input, GpioValue_Low}, {0x06, GpioDirection_Input, GpioValue_Low},
@@ -147,4 +142,4 @@ static constexpr GpioInitialConfig GpioInitialConfigsIcosa4x[] = {
{0x36, GpioDirection_Output, GpioValue_Low}, {0x36, GpioDirection_Output, GpioValue_Low},
}; };
static constexpr u32 GpioNumInitialConfigsIcosa4x = (sizeof(GpioInitialConfigsIcosa4x) / sizeof(GpioInitialConfigsIcosa4x[0])); constexpr u32 NumInitialConfigsIcosa4x = (sizeof(InitialConfigsIcosa4x) / sizeof(InitialConfigsIcosa4x[0]));
@@ -14,12 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once constexpr InitialConfig InitialConfigsIowa[] = {
#include <switch.h>
#include "boot_types.hpp"
static constexpr GpioInitialConfig GpioInitialConfigsHoag[] = {
{0x04, GpioDirection_Input, GpioValue_High}, {0x04, GpioDirection_Input, GpioValue_High},
{0x05, GpioDirection_Output, GpioValue_Low}, {0x05, GpioDirection_Output, GpioValue_Low},
{0x06, GpioDirection_Input, GpioValue_Low}, {0x06, GpioDirection_Input, GpioValue_Low},
@@ -78,7 +73,6 @@ static constexpr GpioInitialConfig GpioInitialConfigsHoag[] = {
{0x35, GpioDirection_Input, GpioValue_High}, {0x35, GpioDirection_Input, GpioValue_High},
{0x2C, GpioDirection_Output, GpioValue_Low}, {0x2C, GpioDirection_Output, GpioValue_Low},
{0x36, GpioDirection_Output, GpioValue_Low}, {0x36, GpioDirection_Output, GpioValue_Low},
}; };
static constexpr u32 GpioNumInitialConfigsHoag = (sizeof(GpioInitialConfigsHoag) / sizeof(GpioInitialConfigsHoag[0])); constexpr u32 NumInitialConfigsIowa = (sizeof(InitialConfigsIowa) / sizeof(InitialConfigsIowa[0]));
@@ -14,13 +14,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once constexpr u32 InvalidPadName = UINT32_MAX;
#include <switch.h>
static constexpr u32 GpioInvalid = UINT32_MAX; constexpr u32 Map[] = {
InvalidPadName, /* Invalid */
static constexpr u32 GpioMap[] = {
GpioInvalid, /* Invalid */
0x000000CC, /* Port Z, Pin 4 */ 0x000000CC, /* Port Z, Pin 4 */
0x00000024, /* Port E, Pin 4 */ 0x00000024, /* Port E, Pin 4 */
0x0000003C, /* Port H, Pin 4 */ 0x0000003C, /* Port H, Pin 4 */
@@ -83,7 +80,7 @@ static constexpr u32 GpioMap[] = {
0x00000026, /* Port E, Pin 6 */ 0x00000026, /* Port E, Pin 6 */
/* Copper only */ /* Copper only */
GpioInvalid, /* Invalid */ InvalidPadName, /* Invalid */
0x00000033, /* Port G, Pin 3 */ 0x00000033, /* Port G, Pin 3 */
0x0000001C, /* Port D, Pin 4 */ 0x0000001C, /* Port D, Pin 4 */
0x000000D9, /* Port BB, Pin 1 */ 0x000000D9, /* Port BB, Pin 1 */
@@ -108,4 +105,4 @@ static constexpr u32 GpioMap[] = {
0x00000056, /* Port K, Pin 6 */ 0x00000056, /* Port K, Pin 6 */
}; };
static constexpr u32 GpioPadNameMax = (sizeof(GpioMap) / sizeof(GpioMap[0])); static constexpr u32 PadNameMax = (sizeof(Map) / sizeof(Map[0]));
@@ -0,0 +1,132 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere/reg.hpp>
#include "gpio_utils.hpp"
namespace sts::gpio {
namespace {
/* Pull in GPIO map definitions. */
#include "gpio_map.inc"
constexpr u32 PhysicalBase = 0x6000D000;
/* Globals. */
bool g_initialized_gpio_vaddr = false;
uintptr_t g_gpio_vaddr = 0;
/* Helpers. */
inline u32 GetPadDescriptor(u32 gpio_pad_name) {
if (gpio_pad_name >= PadNameMax) {
std::abort();
}
return Map[gpio_pad_name];
}
uintptr_t GetBaseAddress() {
if (!g_initialized_gpio_vaddr) {
g_gpio_vaddr = GetIoMapping(PhysicalBase, 0x1000);
g_initialized_gpio_vaddr = true;
}
return g_gpio_vaddr;
}
}
u32 Configure(u32 gpio_pad_name) {
uintptr_t gpio_base_vaddr = GetBaseAddress();
/* Fetch this GPIO's pad descriptor */
const u32 gpio_pad_desc = GetPadDescriptor(gpio_pad_name);
/* Discard invalid GPIOs */
if (gpio_pad_desc == InvalidPadName) {
return InvalidPadName;
}
/* Convert the GPIO pad descriptor into its register offset */
u32 gpio_reg_offset = (((gpio_pad_desc << 0x03) & 0xFFFFFF00) | ((gpio_pad_desc >> 0x01) & 0x0C));
/* Extract the bit and lock values from the GPIO pad descriptor */
u32 gpio_cnf_val = ((0x01 << ((gpio_pad_desc & 0x07) | 0x08)) | (0x01 << (gpio_pad_desc & 0x07)));
/* Write to the appropriate GPIO_CNF_x register (upper offset) */
reg::Write(gpio_base_vaddr + gpio_reg_offset + 0x80, gpio_cnf_val);
/* Do a dummy read from GPIO_CNF_x register (lower offset) */
gpio_cnf_val = reg::Read(gpio_base_vaddr + gpio_reg_offset + 0x00);
return gpio_cnf_val;
}
u32 SetDirection(u32 gpio_pad_name, GpioDirection dir) {
uintptr_t gpio_base_vaddr = GetBaseAddress();
/* Fetch this GPIO's pad descriptor */
const u32 gpio_pad_desc = GetPadDescriptor(gpio_pad_name);
/* Discard invalid GPIOs */
if (gpio_pad_desc == InvalidPadName) {
return InvalidPadName;
}
/* Convert the GPIO pad descriptor into its register offset */
u32 gpio_reg_offset = (((gpio_pad_desc << 0x03) & 0xFFFFFF00) | ((gpio_pad_desc >> 0x01) & 0x0C));
/* Set the direction bit and lock values */
u32 gpio_oe_val = ((0x01 << ((gpio_pad_desc & 0x07) | 0x08)) | (static_cast<u32>(dir) << (gpio_pad_desc & 0x07)));
/* Write to the appropriate GPIO_OE_x register (upper offset) */
reg::Write(gpio_base_vaddr + gpio_reg_offset + 0x90, gpio_oe_val);
/* Do a dummy read from GPIO_OE_x register (lower offset) */
gpio_oe_val = reg::Read(gpio_base_vaddr + gpio_reg_offset + 0x10);
return gpio_oe_val;
}
u32 SetValue(u32 gpio_pad_name, GpioValue val) {
uintptr_t gpio_base_vaddr = GetBaseAddress();
/* Fetch this GPIO's pad descriptor */
const u32 gpio_pad_desc = GetPadDescriptor(gpio_pad_name);
/* Discard invalid GPIOs */
if (gpio_pad_desc == InvalidPadName) {
return InvalidPadName;
}
/* Convert the GPIO pad descriptor into its register offset */
u32 gpio_reg_offset = (((gpio_pad_desc << 0x03) & 0xFFFFFF00) | ((gpio_pad_desc >> 0x01) & 0x0C));
/* Set the output bit and lock values */
u32 gpio_out_val = ((0x01 << ((gpio_pad_desc & 0x07) | 0x08)) | (static_cast<u32>(val) << (gpio_pad_desc & 0x07)));
/* Write to the appropriate GPIO_OUT_x register (upper offset) */
reg::Write(gpio_base_vaddr + gpio_reg_offset + 0xA0, gpio_out_val);
/* Do a dummy read from GPIO_OUT_x register (lower offset) */
gpio_out_val = reg::Read(gpio_base_vaddr + gpio_reg_offset + 0x20);
return gpio_out_val;
}
}
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::gpio {
/* GPIO Utilities. */
u32 Configure(u32 gpio_pad_name);
u32 SetDirection(u32 gpio_pad_name, GpioDirection dir);
u32 SetValue(u32 gpio_pad_name, GpioValue val);
}
@@ -0,0 +1,188 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_api.hpp"
#include "impl/i2c_resource_manager.hpp"
namespace sts::i2c::driver {
namespace {
/* For convenience. */
using CommandHandler = Result (*)(const u8 **cur_cmd, u8 **cur_dst, Session& session);
/* Command handlers. */
Result SendHandler(const u8 **cur_cmd, u8 **cur_dst, Session& session) {
I2cTransactionOption option = static_cast<I2cTransactionOption>(
(((**cur_cmd) & (1 << 6)) ? I2cTransactionOption_Start : 0) | (((**cur_cmd) & (1 << 7)) ? I2cTransactionOption_Stop : 0)
);
(*cur_cmd)++;
size_t num_bytes = (**cur_cmd);
(*cur_cmd)++;
R_TRY(Send(session, *cur_cmd, num_bytes, option));
(*cur_cmd) += num_bytes;
return ResultSuccess;
}
Result ReceiveHandler(const u8 **cur_cmd, u8 **cur_dst, Session& session) {
I2cTransactionOption option = static_cast<I2cTransactionOption>(
(((**cur_cmd) & (1 << 6)) ? I2cTransactionOption_Start : 0) | (((**cur_cmd) & (1 << 7)) ? I2cTransactionOption_Stop : 0)
);
(*cur_cmd)++;
size_t num_bytes = (**cur_cmd);
(*cur_cmd)++;
R_TRY(Receive(session, *cur_dst, num_bytes, option));
(*cur_dst) += num_bytes;
return ResultSuccess;
}
Result SubCommandHandler(const u8 **cur_cmd, u8 **cur_dst, Session& session) {
const SubCommand sub_cmd = static_cast<SubCommand>((**cur_cmd) >> 2);
(*cur_cmd)++;
switch (sub_cmd) {
case SubCommand::Sleep:
{
const size_t us = (**cur_cmd);
(*cur_cmd)++;
svcSleepThread(us * 1'000ul);
}
break;
default:
std::abort();
}
return ResultSuccess;
}
/* Command handler list. */
constexpr CommandHandler g_cmd_handlers[static_cast<size_t>(Command::Count)] = {
SendHandler,
ReceiveHandler,
SubCommandHandler,
};
inline impl::ResourceManager &GetResourceManager() {
return impl::ResourceManager::GetInstance();
}
inline void CheckInitialized() {
if (!GetResourceManager().IsInitialized()) {
std::abort();
}
}
}
/* Initialization. */
void Initialize() {
GetResourceManager().Initialize();
}
void Finalize() {
GetResourceManager().Finalize();
}
/* Session management. */
void OpenSession(Session *out_session, I2cDevice device) {
CheckInitialized();
if (!impl::IsDeviceSupported(device)) {
std::abort();
}
const auto bus = impl::GetDeviceBus(device);
const auto slave_address = impl::GetDeviceSlaveAddress(device);
const auto addressing_mode = impl::GetDeviceAddressingMode(device);
const auto speed_mode = impl::GetDeviceSpeedMode(device);
const auto max_retries = impl::GetDeviceMaxRetries(device);
const auto retry_wait_time = impl::GetDeviceRetryWaitTime(device);
GetResourceManager().OpenSession(out_session, bus, slave_address, addressing_mode, speed_mode, max_retries, retry_wait_time);
}
void CloseSession(Session &session) {
CheckInitialized();
GetResourceManager().CloseSession(session);
}
/* Communication. */
Result Send(Session &session, const void *src, size_t size, I2cTransactionOption option) {
CheckInitialized();
if (src == nullptr || size == 0) {
std::abort();
}
std::scoped_lock<HosMutex &> lk(GetResourceManager().GetTransactionMutex(impl::ConvertFromIndex(session.bus_idx)));
return GetResourceManager().GetSession(session.session_id).DoTransactionWithRetry(nullptr, src, size, option, impl::Command::Send);
}
Result Receive(Session &session, void *dst, size_t size, I2cTransactionOption option) {
CheckInitialized();
if (dst == nullptr || size == 0) {
std::abort();
}
std::scoped_lock<HosMutex &> lk(GetResourceManager().GetTransactionMutex(impl::ConvertFromIndex(session.bus_idx)));
return GetResourceManager().GetSession(session.session_id).DoTransactionWithRetry(dst, nullptr, size, option, impl::Command::Receive);
}
Result ExecuteCommandList(Session &session, void *dst, size_t size, const void *cmd_list, size_t cmd_list_size) {
CheckInitialized();
if (dst == nullptr || size == 0 || cmd_list == nullptr || cmd_list_size == 0) {
std::abort();
}
u8 *cur_dst = static_cast<u8 *>(dst);
const u8 *cur_cmd = static_cast<const u8 *>(cmd_list);
const u8 *cmd_list_end = cur_cmd + cmd_list_size;
while (cur_cmd < cmd_list_end) {
Command cmd = static_cast<Command>((*cur_cmd) & 3);
if (cmd >= Command::Count) {
std::abort();
}
R_TRY(g_cmd_handlers[static_cast<size_t>(cmd)](&cur_cmd, &cur_dst, session));
}
return ResultSuccess;
}
/* Power management. */
void SuspendBuses() {
GetResourceManager().SuspendBuses();
}
void ResumeBuses() {
GetResourceManager().ResumeBuses();
}
void SuspendPowerBus() {
GetResourceManager().SuspendPowerBus();
}
void ResumePowerBus() {
GetResourceManager().ResumePowerBus();
}
}
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "../i2c_types.hpp"
#include "../i2c_command_list.hpp"
namespace sts::i2c::driver {
struct Session {
size_t bus_idx;
size_t session_id;
};
/* Initialization. */
void Initialize();
void Finalize();
/* Session management. */
void OpenSession(Session *out_session, I2cDevice device);
void CloseSession(Session &session);
/* Communication. */
Result Send(Session &session, const void *src, size_t size, I2cTransactionOption option);
Result Receive(Session &session, void *dst, size_t size, I2cTransactionOption option);
Result ExecuteCommandList(Session &session, void *dst, size_t size, const void *cmd_list, size_t cmd_list_size);
/* Power management. */
void SuspendBuses();
void ResumeBuses();
void SuspendPowerBus();
void ResumePowerBus();
}
@@ -0,0 +1,478 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_pcv.hpp"
#include "i2c_bus_accessor.hpp"
namespace sts::i2c::driver::impl {
void BusAccessor::Open(Bus bus, SpeedMode speed_mode) {
std::scoped_lock<HosMutex> lk(this->open_mutex);
/* Open new session. */
this->open_sessions++;
/* Ensure we're good if this isn't our first session. */
if (this->open_sessions > 1) {
if (this->speed_mode != speed_mode) {
std::abort();
}
return;
}
/* Set all members for chosen bus. */
{
std::scoped_lock<HosMutex> lk(this->register_mutex);
/* Set bus/registers. */
this->SetBus(bus);
/* Set pcv module. */
this->pcv_module = ConvertToPcvModule(bus);
/* Set speed mode. */
this->speed_mode = speed_mode;
/* Setup interrupt event. */
this->CreateInterruptEvent(bus);
}
}
void BusAccessor::Close() {
std::scoped_lock<HosMutex> lk(this->open_mutex);
/* Close current session. */
this->open_sessions--;
if (this->open_sessions > 0) {
return;
}
/* Close interrupt event. */
eventClose(&this->interrupt_event);
/* Close PCV. */
pcv::Finalize();
this->suspended = false;
}
void BusAccessor::Suspend() {
std::scoped_lock<HosMutex> lk(this->open_mutex);
std::scoped_lock<HosMutex> lk_reg(this->register_mutex);
if (!this->suspended) {
this->suspended = true;
if (this->pcv_module != PcvModule_I2C5) {
this->DisableClock();
}
}
}
void BusAccessor::Resume() {
if (this->suspended) {
this->DoInitialConfig();
this->suspended = false;
}
}
void BusAccessor::DoInitialConfig() {
std::scoped_lock<HosMutex> lk(this->register_mutex);
if (this->pcv_module != PcvModule_I2C5) {
pcv::Initialize();
}
this->ResetController();
this->SetClock(this->speed_mode);
this->SetPacketMode();
this->FlushFifos();
}
size_t BusAccessor::GetOpenSessions() const {
return this->open_sessions;
}
bool BusAccessor::GetBusy() const {
/* Nintendo has a loop here that calls a member function to check if busy, retrying a few times. */
/* This member function does "return false". */
/* We will not bother with the loop. */
return false;
}
void BusAccessor::OnStartTransaction() const {
/* Nothing actually happens here. */
}
void BusAccessor::OnStopTransaction() const {
/* Nothing actually happens here. */
}
Result BusAccessor::StartTransaction(Command command, AddressingMode addressing_mode, u32 slave_address) {
/* Nothing actually happens here... */
return ResultSuccess;
}
Result BusAccessor::Send(const u8 *data, size_t num_bytes, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address) {
std::scoped_lock<HosMutex> lk(this->register_mutex);
const u8 *cur_src = data;
size_t remaining = num_bytes;
/* Set interrupt enable, clear interrupt status. */
reg::Write(&this->i2c_registers->I2C_INTERRUPT_MASK_REGISTER_0, 0x8E);
reg::Write(&this->i2c_registers->I2C_INTERRUPT_STATUS_REGISTER_0, 0xFC);
ON_SCOPE_EXIT { this->ClearInterruptMask(); };
/* Send header. */
this->WriteTransferHeader(TransferMode::Send, option, addressing_mode, slave_address, num_bytes);
/* Send bytes. */
while (true) {
const u32 fifo_status = reg::Read(&this->i2c_registers->I2C_FIFO_STATUS_0);
const size_t fifo_cnt = (fifo_status >> 4);
for (size_t fifo_idx = 0; remaining > 0 && fifo_idx < fifo_cnt; fifo_idx++) {
const size_t cur_bytes = std::min(remaining, sizeof(u32));
u32 val = 0;
for (size_t i = 0; i < cur_bytes; i++) {
val |= cur_src[i] << (8 * i);
}
reg::Write(&this->i2c_registers->I2C_I2C_TX_PACKET_FIFO_0, val);
cur_src += cur_bytes;
remaining -= cur_bytes;
}
if (remaining == 0) {
break;
}
eventClear(&this->interrupt_event);
if (R_FAILED(eventWait(&this->interrupt_event, InterruptTimeout))) {
this->HandleTransactionResult(ResultI2cBusBusy);
eventClear(&this->interrupt_event);
return ResultI2cTimedOut;
}
R_TRY(this->GetAndHandleTransactionResult());
}
reg::Write(&this->i2c_registers->I2C_INTERRUPT_MASK_REGISTER_0, 0x8C);
/* Wait for successful completion. */
while (true) {
R_TRY(this->GetAndHandleTransactionResult());
/* Check PACKET_XFER_COMPLETE */
const u32 interrupt_status = reg::Read(&this->i2c_registers->I2C_INTERRUPT_STATUS_REGISTER_0);
if (interrupt_status & 0x80) {
R_TRY(this->GetAndHandleTransactionResult());
break;
}
eventClear(&this->interrupt_event);
if (R_FAILED(eventWait(&this->interrupt_event, InterruptTimeout))) {
this->HandleTransactionResult(ResultI2cBusBusy);
eventClear(&this->interrupt_event);
return ResultI2cTimedOut;
}
}
return ResultSuccess;
}
Result BusAccessor::Receive(u8 *out_data, size_t num_bytes, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address) {
std::scoped_lock<HosMutex> lk(this->register_mutex);
u8 *cur_dst = out_data;
size_t remaining = num_bytes;
/* Set interrupt enable, clear interrupt status. */
reg::Write(&this->i2c_registers->I2C_INTERRUPT_MASK_REGISTER_0, 0x8D);
reg::Write(&this->i2c_registers->I2C_INTERRUPT_STATUS_REGISTER_0, 0xFC);
/* Send header. */
this->WriteTransferHeader(TransferMode::Receive, option, addressing_mode, slave_address, num_bytes);
/* Receive bytes. */
while (remaining > 0) {
eventClear(&this->interrupt_event);
if (R_FAILED(eventWait(&this->interrupt_event, InterruptTimeout))) {
this->HandleTransactionResult(ResultI2cBusBusy);
this->ClearInterruptMask();
eventClear(&this->interrupt_event);
return ResultI2cTimedOut;
}
R_TRY(this->GetAndHandleTransactionResult());
const u32 fifo_status = reg::Read(&this->i2c_registers->I2C_FIFO_STATUS_0);
const size_t fifo_cnt = std::min((remaining + 3) >> 2, static_cast<size_t>(fifo_status & 0xF));
for (size_t fifo_idx = 0; remaining > 0 && fifo_idx < fifo_cnt; fifo_idx++) {
const u32 val = reg::Read(&this->i2c_registers->I2C_I2C_RX_FIFO_0);
const size_t cur_bytes = std::min(remaining, sizeof(u32));
for (size_t i = 0; i < cur_bytes; i++) {
cur_dst[i] = static_cast<u8>((val >> (8 * i)) & 0xFF);
}
cur_dst += cur_bytes;
remaining -= cur_bytes;
}
}
/* N doesn't do ClearInterruptMask. */
return ResultSuccess;
}
void BusAccessor::SetBus(Bus bus) {
this->bus = bus;
this->i2c_registers = GetRegisters(bus);
this->clkrst_registers.SetBus(bus);
}
void BusAccessor::CreateInterruptEvent(Bus bus) {
static constexpr u64 s_interrupts[] = {
0x46, 0x74, 0x7C, 0x98, 0x55, 0x5F
};
if (ConvertToIndex(bus) >= sizeof(s_interrupts) / sizeof(s_interrupts[0])) {
std::abort();
}
Handle evt_h;
if (R_FAILED(svcCreateInterruptEvent(&evt_h, s_interrupts[ConvertToIndex(bus)], 1))) {
std::abort();
}
eventLoadRemote(&this->interrupt_event, evt_h, false);
}
void BusAccessor::SetClock(SpeedMode speed_mode) {
u32 t_high, t_low;
u32 clk_div, src_div;
u32 debounce;
switch (speed_mode) {
case SpeedMode::Normal:
t_high = 2;
t_low = 4;
clk_div = 0x19;
src_div = 0x13;
debounce = 2;
break;
case SpeedMode::Fast:
t_high = 2;
t_low = 4;
clk_div = 0x19;
src_div = 0x04;
debounce = 2;
break;
case SpeedMode::FastPlus:
t_high = 2;
t_low = 4;
clk_div = 0x10;
src_div = 0x02;
debounce = 0;
break;
case SpeedMode::HighSpeed:
t_high = 3;
t_low = 8;
clk_div = 0x02;
src_div = 0x02;
debounce = 0;
break;
default:
std::abort();
}
if (speed_mode == SpeedMode::HighSpeed) {
reg::Write(&this->i2c_registers->I2C_I2C_HS_INTERFACE_TIMING_0_0, (t_high << 8) | (t_low));
reg::Write(&this->i2c_registers->I2C_I2C_CLK_DIVISOR_REGISTER_0, clk_div);
} else {
reg::Write(&this->i2c_registers->I2C_I2C_INTERFACE_TIMING_0_0, (t_high << 8) | (t_low));
reg::Write(&this->i2c_registers->I2C_I2C_CLK_DIVISOR_REGISTER_0, (clk_div << 16));
}
reg::Write(&this->i2c_registers->I2C_I2C_CNFG_0, debounce);
reg::Read(&this->i2c_registers->I2C_I2C_CNFG_0);
if (this->pcv_module != PcvModule_I2C5) {
if (R_FAILED(pcv::SetReset(this->pcv_module, true))) {
std::abort();
}
if (R_FAILED(pcv::SetClockRate(this->pcv_module, (408'000'000) / (src_div + 1)))) {
std::abort();
}
if (R_FAILED(pcv::SetReset(this->pcv_module, false))) {
std::abort();
}
}
}
void BusAccessor::ResetController() const {
if (this->pcv_module != PcvModule_I2C5) {
if (R_FAILED(pcv::SetReset(this->pcv_module, true))) {
std::abort();
}
if (R_FAILED(pcv::SetClockRate(this->pcv_module, 81'600'000))) {
std::abort();
}
if (R_FAILED(pcv::SetReset(this->pcv_module, false))) {
std::abort();
}
}
}
void BusAccessor::ClearBus() const {
bool success = false;
for (size_t i = 0; i < 3 && !success; i++) {
success = true;
this->ResetController();
reg::Write(&this->i2c_registers->I2C_I2C_BUS_CLEAR_CONFIG_0, 0x90000);
reg::SetBits(&this->i2c_registers->I2C_I2C_BUS_CLEAR_CONFIG_0, 0x4);
reg::SetBits(&this->i2c_registers->I2C_I2C_BUS_CLEAR_CONFIG_0, 0x2);
reg::SetBits(&this->i2c_registers->I2C_I2C_CONFIG_LOAD_0, 0x1);
{
u64 start_tick = armGetSystemTick();
while (reg::Read(&this->i2c_registers->I2C_I2C_CONFIG_LOAD_0) & 1) {
if (armTicksToNs(armGetSystemTick() - start_tick) > 1'000'000) {
success = false;
break;
}
}
}
if (!success) {
continue;
}
reg::SetBits(&this->i2c_registers->I2C_I2C_BUS_CLEAR_CONFIG_0, 0x1);
{
u64 start_tick = armGetSystemTick();
while (reg::Read(&this->i2c_registers->I2C_I2C_BUS_CLEAR_CONFIG_0) & 1) {
if (armTicksToNs(armGetSystemTick() - start_tick) > 1'000'000) {
success = false;
break;
}
}
}
if (!success) {
continue;
}
{
u64 start_tick = armGetSystemTick();
while (reg::Read(&this->i2c_registers->I2C_I2C_BUS_CLEAR_STATUS_0) & 1) {
if (armTicksToNs(armGetSystemTick() - start_tick) > 1'000'000) {
success = false;
break;
}
}
}
if (!success) {
continue;
}
}
}
void BusAccessor::DisableClock() {
if (R_FAILED(pcv::SetClockEnabled(this->pcv_module, false))) {
std::abort();
}
}
void BusAccessor::SetPacketMode() {
/* Set PACKET_MODE_EN, MSTR_CONFIG_LOAD */
reg::SetBits(&this->i2c_registers->I2C_I2C_CNFG_0, 0x400);
reg::SetBits(&this->i2c_registers->I2C_I2C_CONFIG_LOAD_0, 0x1);
/* Set TX_FIFO_TRIGGER, RX_FIFO_TRIGGER */
reg::Write(&this->i2c_registers->I2C_FIFO_CONTROL_0, 0xFC);
}
Result BusAccessor::FlushFifos() {
reg::Write(&this->i2c_registers->I2C_FIFO_CONTROL_0, 0xFF);
/* Wait for flush to finish, check every ms for 5 ms. */
for (size_t i = 0; i < 5; i++) {
if (!(reg::Read(&this->i2c_registers->I2C_FIFO_CONTROL_0) & 3)) {
return ResultSuccess;
}
svcSleepThread(1'000'000ul);
}
return ResultI2cBusBusy;
}
Result BusAccessor::GetTransactionResult() const {
const u32 packet_status = reg::Read(&this->i2c_registers->I2C_PACKET_TRANSFER_STATUS_0);
const u32 interrupt_status = reg::Read(&this->i2c_registers->I2C_INTERRUPT_STATUS_REGISTER_0);
/* Check for no ack. */
if ((packet_status & 0xC) || (interrupt_status & 0x8)) {
return ResultI2cNoAck;
}
/* Check for arb lost. */
if ((packet_status & 0x2) || (interrupt_status & 0x4)) {
this->ClearBus();
return ResultI2cBusBusy;
}
return ResultSuccess;
}
void BusAccessor::HandleTransactionResult(Result result) {
if (R_FAILED(result)) {
if (result == ResultI2cNoAck || result == ResultI2cBusBusy) {
this->ResetController();
this->SetClock(this->speed_mode);
this->SetPacketMode();
this->FlushFifos();
} else {
std::abort();
}
}
}
Result BusAccessor::GetAndHandleTransactionResult() {
const Result transaction_res = this->GetTransactionResult();
R_TRY_CLEANUP(transaction_res, {
this->HandleTransactionResult(transaction_res);
this->ClearInterruptMask();
eventClear(&this->interrupt_event);
});
return ResultSuccess;
}
void BusAccessor::WriteTransferHeader(TransferMode transfer_mode, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address, size_t num_bytes) {
this->FlushFifos();
reg::Write(&this->i2c_registers->I2C_I2C_TX_PACKET_FIFO_0, 0x10);
reg::Write(&this->i2c_registers->I2C_I2C_TX_PACKET_FIFO_0, static_cast<u32>(num_bytes - 1) & 0xFFF);
const u32 slave_addr_val = ((transfer_mode == TransferMode::Receive) & 1) | ((slave_address & 0x7F) << 1);
u32 hdr_val = 0;
hdr_val |= ((this->speed_mode == SpeedMode::HighSpeed) & 1) << 22;
hdr_val |= ((transfer_mode == TransferMode::Receive) & 1) << 19;
hdr_val |= ((addressing_mode != AddressingMode::SevenBit) & 1) << 18;
hdr_val |= (1 << 17);
hdr_val |= (((option & I2cTransactionOption_Stop) == 0) & 1) << 16;
hdr_val |= slave_addr_val;
reg::Write(&this->i2c_registers->I2C_I2C_TX_PACKET_FIFO_0, hdr_val);
}
}
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_driver_types.hpp"
#include "i2c_registers.hpp"
namespace sts::i2c::driver::impl {
class BusAccessor {
private:
enum class TransferMode {
Send = 0,
Receive = 1,
};
static constexpr u64 InterruptTimeout = 100'000'000ul;
private:
Event interrupt_event;
HosMutex open_mutex;
HosMutex register_mutex;
Registers *i2c_registers = nullptr;
ClkRstRegisters clkrst_registers;
SpeedMode speed_mode = SpeedMode::Fast;
size_t open_sessions = 0;
Bus bus = Bus::I2C1;
PcvModule pcv_module = PcvModule_I2C1;
bool suspended = false;
public:
BusAccessor() { /* ... */ }
private:
inline void ClearInterruptMask() const {
reg::Write(&i2c_registers->I2C_INTERRUPT_MASK_REGISTER_0, 0);
reg::Read(&i2c_registers->I2C_INTERRUPT_MASK_REGISTER_0);
}
void SetBus(Bus bus);
void CreateInterruptEvent(Bus bus);
void SetClock(SpeedMode speed_mode);
void ResetController() const;
void ClearBus() const;
void DisableClock();
void SetPacketMode();
Result FlushFifos();
Result GetTransactionResult() const;
void HandleTransactionResult(Result result);
Result GetAndHandleTransactionResult();
void WriteTransferHeader(TransferMode transfer_mode, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address, size_t num_bytes);
public:
void Open(Bus bus, SpeedMode speed_mode);
void Close();
void Suspend();
void Resume();
void DoInitialConfig();
size_t GetOpenSessions() const;
bool GetBusy() const;
void OnStartTransaction() const;
Result StartTransaction(Command command, AddressingMode addressing_mode, u32 slave_address);
Result Send(const u8 *data, size_t num_bytes, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address);
Result Receive(u8 *out_data, size_t num_bytes, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address);
void OnStopTransaction() const;
};
}
@@ -0,0 +1,125 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_driver_types.hpp"
namespace sts::i2c::driver::impl {
namespace {
struct DeviceConfig {
I2cDevice device;
Bus bus;
u32 slave_address;
AddressingMode addressing_mode;
SpeedMode speed_mode;
u32 max_retries;
u64 retry_wait_time;
};
constexpr DeviceConfig g_device_configs[I2cDevice_Count] = {
{I2cDevice_DebugPad, Bus::I2C1, 0x52, AddressingMode::SevenBit, SpeedMode::Normal, 0, 0},
{I2cDevice_TouchPanel, Bus::I2C3, 0x49, AddressingMode::SevenBit, SpeedMode::Fast, 0, 0},
{I2cDevice_Tmp451, Bus::I2C1, 0x4c, AddressingMode::SevenBit, SpeedMode::Normal, 0, 0},
{I2cDevice_Nct72, Bus::I2C1, 0x4c, AddressingMode::SevenBit, SpeedMode::Normal, 0, 0},
{I2cDevice_Alc5639, Bus::I2C1, 0x1c, AddressingMode::SevenBit, SpeedMode::Normal, 0, 0},
{I2cDevice_Max77620Rtc, Bus::I2C5, 0x68, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Max77620Pmic, Bus::I2C5, 0x3c, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Max77621Cpu, Bus::I2C5, 0x1b, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Max77621Gpu, Bus::I2C5, 0x1c, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Bq24193, Bus::I2C1, 0x6b, AddressingMode::SevenBit, SpeedMode::Normal, 3, 5'000'000},
{I2cDevice_Max17050, Bus::I2C1, 0x36, AddressingMode::SevenBit, SpeedMode::Normal, 3, 5'000'000},
{I2cDevice_Bm92t30mwv, Bus::I2C1, 0x18, AddressingMode::SevenBit, SpeedMode::Normal, 3, 5'000'000},
{I2cDevice_Ina226Vdd15v0Hb, Bus::I2C2, 0x40, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Ina226VsysCpuDs, Bus::I2C2, 0x41, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Ina226VsysGpuDs, Bus::I2C2, 0x44, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Ina226VsysDdrDs, Bus::I2C2, 0x45, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Ina226VsysAp, Bus::I2C2, 0x46, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Ina226VsysBlDs, Bus::I2C2, 0x47, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Bh1730, Bus::I2C2, 0x29, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Ina226VsysCore, Bus::I2C2, 0x48, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Ina226Soc1V8, Bus::I2C2, 0x49, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Ina226Lpddr1V8, Bus::I2C2, 0x4a, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Ina226Reg1V32, Bus::I2C2, 0x4b, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_Ina226Vdd3V3Sys, Bus::I2C2, 0x4d, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
{I2cDevice_HdmiDdc, Bus::I2C4, 0x50, AddressingMode::SevenBit, SpeedMode::Normal, 0, 0},
{I2cDevice_HdmiScdc, Bus::I2C4, 0x54, AddressingMode::SevenBit, SpeedMode::Normal, 0, 0},
{I2cDevice_HdmiHdcp, Bus::I2C4, 0x3a, AddressingMode::SevenBit, SpeedMode::Normal, 0, 0},
{I2cDevice_Fan53528, Bus::I2C5, 0xa4, AddressingMode::SevenBit, SpeedMode::Fast, 0, 0},
{I2cDevice_Max77812_3, Bus::I2C5, 0x31, AddressingMode::SevenBit, SpeedMode::Fast, 0, 0},
{I2cDevice_Max77812_2, Bus::I2C5, 0x33, AddressingMode::SevenBit, SpeedMode::Fast, 0, 0},
{I2cDevice_Ina226VddDdr0V6, Bus::I2C2, 0x4e, AddressingMode::SevenBit, SpeedMode::Fast, 3, 5'000'000},
};
constexpr size_t NumDeviceConfigs = sizeof(g_device_configs) / sizeof(g_device_configs[0]);
constexpr size_t DeviceInvalidIndex = static_cast<size_t>(-1);
size_t GetDeviceIndex(I2cDevice dev) {
for (size_t i = 0; i < NumDeviceConfigs; i++) {
if (g_device_configs[i].device == dev) {
return i;
}
}
return DeviceInvalidIndex;
}
}
bool IsDeviceSupported(I2cDevice dev) {
return GetDeviceIndex(dev) != DeviceInvalidIndex;
}
Bus GetDeviceBus(I2cDevice dev) {
const size_t dev_idx = GetDeviceIndex(dev);
if (dev_idx == DeviceInvalidIndex) { std::abort(); }
return g_device_configs[dev_idx].bus;
}
u32 GetDeviceSlaveAddress(I2cDevice dev) {
const size_t dev_idx = GetDeviceIndex(dev);
if (dev_idx == DeviceInvalidIndex) { std::abort(); }
return g_device_configs[dev_idx].slave_address;
}
AddressingMode GetDeviceAddressingMode(I2cDevice dev) {
const size_t dev_idx = GetDeviceIndex(dev);
if (dev_idx == DeviceInvalidIndex) { std::abort(); }
return g_device_configs[dev_idx].addressing_mode;
}
SpeedMode GetDeviceSpeedMode(I2cDevice dev) {
const size_t dev_idx = GetDeviceIndex(dev);
if (dev_idx == DeviceInvalidIndex) { std::abort(); }
return g_device_configs[dev_idx].speed_mode;
}
u32 GetDeviceMaxRetries(I2cDevice dev) {
const size_t dev_idx = GetDeviceIndex(dev);
if (dev_idx == DeviceInvalidIndex) { std::abort(); }
return g_device_configs[dev_idx].max_retries;
}
u64 GetDeviceRetryWaitTime(I2cDevice dev) {
const size_t dev_idx = GetDeviceIndex(dev);
if (dev_idx == DeviceInvalidIndex) { std::abort(); }
return g_device_configs[dev_idx].retry_wait_time;
}
}
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "../../i2c_types.hpp"
namespace sts::i2c::driver::impl {
enum class Command {
Send = 0,
Receive = 1,
};
enum class Bus {
I2C1 = 0,
I2C2 = 1,
I2C3 = 2,
I2C4 = 3,
I2C5 = 4,
I2C6 = 5,
Count,
};
/* Bus helpers. */
constexpr inline size_t ConvertToIndex(Bus bus) {
return static_cast<size_t>(bus);
}
constexpr inline Bus ConvertFromIndex(size_t idx) {
if (idx >= static_cast<size_t>(Bus::Count)) {
std::abort();
}
return static_cast<Bus>(idx);
}
constexpr inline PcvModule ConvertToPcvModule(Bus bus) {
switch (bus) {
case Bus::I2C1:
return PcvModule_I2C1;
case Bus::I2C2:
return PcvModule_I2C2;
case Bus::I2C3:
return PcvModule_I2C3;
case Bus::I2C4:
return PcvModule_I2C4;
case Bus::I2C5:
return PcvModule_I2C5;
case Bus::I2C6:
return PcvModule_I2C6;
default:
std::abort();
}
}
constexpr inline Bus ConvertFromPcvModule(PcvModule module) {
switch (module) {
case PcvModule_I2C1:
return Bus::I2C1;
case PcvModule_I2C2:
return Bus::I2C2;
case PcvModule_I2C3:
return Bus::I2C3;
case PcvModule_I2C4:
return Bus::I2C4;
case PcvModule_I2C5:
return Bus::I2C5;
case PcvModule_I2C6:
return Bus::I2C6;
default:
std::abort();
}
}
/* Global type functions. */
bool IsDeviceSupported(I2cDevice dev);
Bus GetDeviceBus(I2cDevice dev);
u32 GetDeviceSlaveAddress(I2cDevice dev);
AddressingMode GetDeviceAddressingMode(I2cDevice dev);
SpeedMode GetDeviceSpeedMode(I2cDevice dev);
u32 GetDeviceMaxRetries(I2cDevice dev);
u64 GetDeviceRetryWaitTime(I2cDevice dev);
}
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
/* This forward declares the functionality from pcv that i2c::driver uses. */
/* This allows for overriding at compile-time (e.g., for boot sysmodule). */
namespace sts::pcv {
void Initialize();
void Finalize();
Result SetClockRate(PcvModule module, u32 hz);
Result SetClockEnabled(PcvModule module, bool enabled);
Result SetVoltageEnabled(u32 domain, bool enabled);
Result SetVoltageValue(u32 domain, u32 voltage);
Result SetReset(PcvModule module, bool reset);
}
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include <stratosphere/reg.hpp>
#include "i2c_driver_types.hpp"
namespace sts::i2c::driver::impl {
struct Registers {
volatile u32 I2C_I2C_CNFG_0;
volatile u32 I2C_I2C_CMD_ADDR0_0;
volatile u32 I2C_I2C_CMD_ADDR1_0;
volatile u32 I2C_I2C_CMD_DATA1_0;
volatile u32 I2C_I2C_CMD_DATA2_0;
volatile u32 _0x14;
volatile u32 _0x18;
volatile u32 I2C_I2C_STATUS_0;
volatile u32 I2C_I2C_SL_CNFG_0;
volatile u32 I2C_I2C_SL_RCVD_0;
volatile u32 I2C_I2C_SL_STATUS_0;
volatile u32 I2C_I2C_SL_ADDR1_0;
volatile u32 I2C_I2C_SL_ADDR2_0;
volatile u32 I2C_I2C_TLOW_SEXT_0;
volatile u32 _0x38;
volatile u32 I2C_I2C_SL_DELAY_COUNT_0;
volatile u32 I2C_I2C_SL_INT_MASK_0;
volatile u32 I2C_I2C_SL_INT_SOURCE_0;
volatile u32 I2C_I2C_SL_INT_SET_0;
volatile u32 _0x4C;
volatile u32 I2C_I2C_TX_PACKET_FIFO_0;
volatile u32 I2C_I2C_RX_FIFO_0;
volatile u32 I2C_PACKET_TRANSFER_STATUS_0;
volatile u32 I2C_FIFO_CONTROL_0;
volatile u32 I2C_FIFO_STATUS_0;
volatile u32 I2C_INTERRUPT_MASK_REGISTER_0;
volatile u32 I2C_INTERRUPT_STATUS_REGISTER_0;
volatile u32 I2C_I2C_CLK_DIVISOR_REGISTER_0;
volatile u32 I2C_I2C_INTERRUPT_SOURCE_REGISTER_0;
volatile u32 I2C_I2C_INTERRUPT_SET_REGISTER_0;
volatile u32 I2C_I2C_SLV_TX_PACKET_FIFO_0;
volatile u32 I2C_I2C_SLV_RX_FIFO_0;
volatile u32 I2C_I2C_SLV_PACKET_STATUS_0;
volatile u32 I2C_I2C_BUS_CLEAR_CONFIG_0;
volatile u32 I2C_I2C_BUS_CLEAR_STATUS_0;
volatile u32 I2C_I2C_CONFIG_LOAD_0;
volatile u32 _0x90;
volatile u32 I2C_I2C_INTERFACE_TIMING_0_0;
volatile u32 I2C_I2C_INTERFACE_TIMING_1_0;
volatile u32 I2C_I2C_HS_INTERFACE_TIMING_0_0;
volatile u32 I2C_I2C_HS_INTERFACE_TIMING_1_0;
};
struct ClkRstRegisters {
public:
uintptr_t clk_src_reg;
uintptr_t clk_en_reg;
uintptr_t rst_reg;
u32 mask;
public:
void SetBus(Bus bus) {
static constexpr uintptr_t s_clk_src_offsets[ConvertToIndex(Bus::Count)] = {
0x124, 0x198, 0x1b8, 0x3c4, 0x128, 0x65c
};
static constexpr uintptr_t s_clk_en_offsets[ConvertToIndex(Bus::Count)] = {
0x010, 0x014, 0x018, 0x360, 0x014, 0x280
};
static constexpr uintptr_t s_rst_offsets[ConvertToIndex(Bus::Count)] = {
0x004, 0x008, 0x00c, 0x358, 0x008, 0x28c
};
static constexpr size_t s_bit_shifts[ConvertToIndex(Bus::Count)] = {
12, 22, 3, 7, 15, 6
};
const uintptr_t registers = GetIoMapping(0x60006000ul, 0x1000);
const size_t idx = ConvertToIndex(bus);
this->clk_src_reg = registers + s_clk_src_offsets[idx];
this->clk_en_reg = registers + s_clk_en_offsets[idx];
this->rst_reg = registers + s_rst_offsets[idx];
this->mask = (1u << s_bit_shifts[idx]);
}
};
inline Registers *GetRegisters(Bus bus) {
static constexpr uintptr_t s_offsets[ConvertToIndex(Bus::Count)] = {
0x0000, 0x0400, 0x0500, 0x0700, 0x1000, 0x1100
};
const uintptr_t registers = GetIoMapping(0x7000c000ul, 0x2000) + s_offsets[ConvertToIndex(bus)];
return reinterpret_cast<Registers *>(registers);
}
}
@@ -0,0 +1,205 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_pcv.hpp"
#include "i2c_resource_manager.hpp"
namespace sts::i2c::driver::impl {
void ResourceManager::Initialize() {
std::scoped_lock<HosMutex> lk(this->initialize_mutex);
this->ref_cnt++;
}
void ResourceManager::Finalize() {
std::scoped_lock<HosMutex> lk(this->initialize_mutex);
if (this->ref_cnt == 0) {
std::abort();
}
this->ref_cnt--;
if (this->ref_cnt > 0) {
return;
}
{
std::scoped_lock<HosMutex> sess_lk(this->session_open_mutex);
for (size_t i = 0; i < MaxDriverSessions; i++) {
this->sessions[i].Close();
}
}
}
size_t ResourceManager::GetFreeSessionId() const {
for (size_t i = 0; i < MaxDriverSessions; i++) {
if (!this->sessions[i].IsOpen()) {
return i;
}
}
return InvalidSessionId;
}
void ResourceManager::OpenSession(driver::Session *out_session, Bus bus, u32 slave_address, AddressingMode addressing_mode, SpeedMode speed_mode, u32 max_retries, u64 retry_wait_time) {
bool need_enable_ldo6 = false;
size_t session_id = InvalidSessionId;
/* Get, open session. */
{
std::scoped_lock<HosMutex> lk(this->session_open_mutex);
if (out_session == nullptr || bus >= Bus::Count) {
std::abort();
}
session_id = GetFreeSessionId();
if (session_id == InvalidSessionId) {
std::abort();
}
if ((bus == Bus::I2C2 || bus == Bus::I2C3) && (this->bus_accessors[ConvertToIndex(Bus::I2C2)].GetOpenSessions() == 0 && this->bus_accessors[ConvertToIndex(Bus::I2C3)].GetOpenSessions() == 0)) {
need_enable_ldo6 = true;
}
out_session->session_id = session_id;
out_session->bus_idx = ConvertToIndex(bus);
this->sessions[session_id].Open(bus, slave_address, addressing_mode, speed_mode, &this->bus_accessors[ConvertToIndex(bus)], max_retries, retry_wait_time);
}
this->sessions[session_id].Start();
if (need_enable_ldo6) {
pcv::Initialize();
if (R_FAILED(pcv::SetVoltageValue(10, 2'900'000))) {
std::abort();
}
if (R_FAILED(pcv::SetVoltageEnabled(10, true))) {
std::abort();
}
pcv::Finalize();
svcSleepThread(560'000ul);
}
}
void ResourceManager::CloseSession(const driver::Session &session) {
bool need_disable_ldo6 = false;
/* Get, open session. */
{
std::scoped_lock<HosMutex> lk(this->session_open_mutex);
if (!this->sessions[session.session_id].IsOpen()) {
std::abort();
}
this->sessions[session.session_id].Close();
if ((ConvertFromIndex(session.bus_idx) == Bus::I2C2 || ConvertFromIndex(session.bus_idx) == Bus::I2C3) &&
(this->bus_accessors[ConvertToIndex(Bus::I2C2)].GetOpenSessions() == 0 && this->bus_accessors[ConvertToIndex(Bus::I2C3)].GetOpenSessions() == 0)) {
need_disable_ldo6 = true;
}
}
if (need_disable_ldo6) {
pcv::Initialize();
if (R_FAILED(pcv::SetVoltageEnabled(10, false))) {
std::abort();
}
pcv::Finalize();
}
}
void ResourceManager::SuspendBuses() {
if (this->ref_cnt == 0) {
std::abort();
}
if (!this->suspended) {
{
std::scoped_lock<HosMutex> lk(this->session_open_mutex);
this->suspended = true;
for (size_t i = 0; i < ConvertToIndex(Bus::Count); i++) {
if (i != PowerBusId && this->bus_accessors[i].GetOpenSessions() > 0) {
this->bus_accessors[i].Suspend();
}
}
}
pcv::Initialize();
if (R_FAILED(pcv::SetVoltageEnabled(10, false))) {
std::abort();
}
pcv::Finalize();
}
}
void ResourceManager::ResumeBuses() {
if (this->ref_cnt == 0) {
std::abort();
}
if (this->suspended) {
if (this->bus_accessors[ConvertToIndex(Bus::I2C2)].GetOpenSessions() > 0 || this->bus_accessors[ConvertToIndex(Bus::I2C3)].GetOpenSessions() > 0) {
pcv::Initialize();
if (R_FAILED(pcv::SetVoltageValue(10, 2'900'000))) {
std::abort();
}
if (R_FAILED(pcv::SetVoltageEnabled(10, true))) {
std::abort();
}
pcv::Finalize();
svcSleepThread(1'560'000ul);
}
{
std::scoped_lock<HosMutex> lk(this->session_open_mutex);
for (size_t i = 0; i < ConvertToIndex(Bus::Count); i++) {
if (i != PowerBusId && this->bus_accessors[i].GetOpenSessions() > 0) {
this->bus_accessors[i].Resume();
}
}
}
this->suspended = false;
}
}
void ResourceManager::SuspendPowerBus() {
if (this->ref_cnt == 0) {
std::abort();
}
std::scoped_lock<HosMutex> lk(this->session_open_mutex);
if (!this->power_bus_suspended) {
this->power_bus_suspended = true;
if (this->bus_accessors[PowerBusId].GetOpenSessions() > 0) {
this->bus_accessors[PowerBusId].Suspend();
}
}
}
void ResourceManager::ResumePowerBus() {
if (this->ref_cnt == 0) {
std::abort();
}
std::scoped_lock<HosMutex> lk(this->session_open_mutex);
if (this->power_bus_suspended) {
if (this->bus_accessors[PowerBusId].GetOpenSessions() > 0) {
this->bus_accessors[PowerBusId].Resume();
}
this->power_bus_suspended = false;
}
}
}
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "../i2c_api.hpp"
#include "i2c_driver_types.hpp"
#include "i2c_bus_accessor.hpp"
#include "i2c_session.hpp"
namespace sts::i2c::driver::impl {
class ResourceManager {
public:
static constexpr size_t MaxDriverSessions = 40;
static constexpr size_t PowerBusId = ConvertToIndex(Bus::I2C5);
static constexpr size_t InvalidSessionId = static_cast<size_t>(-1);
private:
HosMutex initialize_mutex;
HosMutex session_open_mutex;
size_t ref_cnt = 0;
bool suspended = false;
bool power_bus_suspended = false;
Session sessions[MaxDriverSessions];
BusAccessor bus_accessors[ConvertToIndex(Bus::Count)];
HosMutex transaction_mutexes[ConvertToIndex(Bus::Count)];
public:
ResourceManager() {
/* ... */
}
private:
size_t GetFreeSessionId() const;
public:
/* N uses a singleton here, we'll oblige. */
static ResourceManager &GetInstance() {
static ResourceManager s_instance;
return s_instance;
}
bool IsInitialized() const {
return this->ref_cnt > 0;
}
Session& GetSession(size_t id) {
return this->sessions[id];
}
HosMutex& GetTransactionMutex(Bus bus) {
return this->transaction_mutexes[ConvertToIndex(bus)];
}
void Initialize();
void Finalize();
void OpenSession(driver::Session *out_session, Bus bus, u32 slave_address, AddressingMode addressing_mode, SpeedMode speed_mode, u32 max_retries, u64 retry_wait_time);
void CloseSession(const driver::Session &session);
void SuspendBuses();
void ResumeBuses();
void SuspendPowerBus();
void ResumePowerBus();
};
}
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_session.hpp"
namespace sts::i2c::driver::impl {
void Session::Open(Bus bus, u32 slave_address, AddressingMode addr_mode, SpeedMode speed_mode, BusAccessor *bus_accessor, u32 max_retries, u64 retry_wait_time) {
std::scoped_lock<HosMutex> lk(this->bus_accessor_mutex);
if (!this->open) {
this->bus_accessor = bus_accessor;
this->bus = bus;
this->slave_address = slave_address;
this->addressing_mode = addr_mode;
this->max_retries = max_retries;
this->retry_wait_time = retry_wait_time;
this->bus_accessor->Open(this->bus, speed_mode);
this->open = true;
}
}
void Session::Start() {
std::scoped_lock<HosMutex> lk(this->bus_accessor_mutex);
if (this->open) {
if (this->bus_accessor->GetOpenSessions() == 1) {
this->bus_accessor->DoInitialConfig();
}
}
}
void Session::Close() {
std::scoped_lock<HosMutex> lk(this->bus_accessor_mutex);
if (this->open) {
this->bus_accessor->Close();
this->bus_accessor = nullptr;
this->open = false;
}
}
bool Session::IsOpen() const {
return this->open;
}
Result Session::DoTransaction(void *dst, const void *src, size_t num_bytes, I2cTransactionOption option, Command command) {
std::scoped_lock<HosMutex> lk(this->bus_accessor_mutex);
if (this->bus_accessor->GetBusy()) {
return ResultI2cBusBusy;
}
this->bus_accessor->OnStartTransaction();
ON_SCOPE_EXIT { this->bus_accessor->OnStopTransaction(); };
R_TRY(this->bus_accessor->StartTransaction(command, this->addressing_mode, this->slave_address));
switch (command) {
case Command::Send:
R_TRY(this->bus_accessor->Send(reinterpret_cast<const u8 *>(src), num_bytes, option, this->addressing_mode, this->slave_address));
break;
case Command::Receive:
R_TRY(this->bus_accessor->Receive(reinterpret_cast<u8 *>(dst), num_bytes, option, this->addressing_mode, this->slave_address));
break;
default:
std::abort();
}
return ResultSuccess;
}
Result Session::DoTransactionWithRetry(void *dst, const void *src, size_t num_bytes, I2cTransactionOption option, Command command) {
size_t i = 0;
while (true) {
R_TRY_CATCH(this->DoTransaction(dst, src, num_bytes, option, command)) {
R_CATCH(ResultI2cTimedOut) {
i++;
if (i <= this->max_retries) {
svcSleepThread(this->retry_wait_time);
continue;
}
return ResultI2cBusBusy;
}
} R_END_TRY_CATCH;
return ResultSuccess;
}
}
}
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_driver_types.hpp"
#include "i2c_bus_accessor.hpp"
namespace sts::i2c::driver::impl {
class Session {
private:
HosMutex bus_accessor_mutex;
BusAccessor *bus_accessor = nullptr;
Bus bus = Bus::I2C1;
u32 slave_address = 0;
AddressingMode addressing_mode = AddressingMode::SevenBit;
u32 max_retries = 0;
u64 retry_wait_time = 0;
bool open = false;
public:
Session() { /* ... */ }
public:
void Open(Bus bus, u32 slave_address, AddressingMode addr_mode, SpeedMode speed_mode, BusAccessor *bus_accessor, u32 max_retries, u64 retry_wait_time);
void Start();
void Close();
bool IsOpen() const;
Result DoTransaction(void *dst, const void *src, size_t num_bytes, I2cTransactionOption option, Command command);
Result DoTransactionWithRetry(void *dst, const void *src, size_t num_bytes, I2cTransactionOption option, Command command);
};
}
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_types.hpp"
#include "i2c_command_list.hpp"
namespace sts::i2c {
namespace {
/* Useful definitions. */
constexpr size_t SendCommandSize = 2;
constexpr size_t ReceiveCommandSize = 2;
constexpr size_t SleepCommandSize = 2;
}
Result CommandListFormatter::CanEnqueue(size_t size) const {
if (this->cmd_list_size - this->cur_index < size) {
return ResultI2cFullCommandList;
}
return ResultSuccess;
}
Result CommandListFormatter::EnqueueSendCommand(I2cTransactionOption option, const void *src, size_t size) {
R_TRY(this->CanEnqueue(SendCommandSize + size));
this->cmd_list[this->cur_index] = static_cast<u8>(Command::Send);
this->cmd_list[this->cur_index] |= ((option & I2cTransactionOption_Start) != 0) << 6;
this->cmd_list[this->cur_index] |= ((option & I2cTransactionOption_Stop) != 0) << 7;
this->cur_index++;
this->cmd_list[this->cur_index++] = size;
const u8 *src_u8 = reinterpret_cast<const u8 *>(src);
for (size_t i = 0; i < size; i++) {
this->cmd_list[this->cur_index++] = src_u8[i];
}
return ResultSuccess;
}
Result CommandListFormatter::EnqueueReceiveCommand(I2cTransactionOption option, size_t size) {
R_TRY(this->CanEnqueue(ReceiveCommandSize));
this->cmd_list[this->cur_index] = static_cast<u8>(Command::Receive);
this->cmd_list[this->cur_index] |= ((option & I2cTransactionOption_Start) != 0) << 6;
this->cmd_list[this->cur_index] |= ((option & I2cTransactionOption_Stop) != 0) << 7;
this->cur_index++;
this->cmd_list[this->cur_index++] = size;
return ResultSuccess;
}
Result CommandListFormatter::EnqueueSleepCommand(size_t us) {
R_TRY(this->CanEnqueue(SleepCommandSize));
this->cmd_list[this->cur_index] = static_cast<u8>(Command::SubCommand);
this->cmd_list[this->cur_index] |= static_cast<u8>(SubCommand::Sleep) << 2;
this->cur_index++;
this->cmd_list[this->cur_index++] = us;
return ResultSuccess;
}
}
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_types.hpp"
namespace sts::i2c {
enum class Command {
Send = 0,
Receive = 1,
SubCommand = 2,
Count,
};
enum class SubCommand {
Sleep = 0,
Count,
};
class CommandListFormatter {
public:
static constexpr size_t MaxCommandListSize = 0x100;
private:
u8 *cmd_list = nullptr;
size_t cmd_list_size = 0;
size_t cur_index = 0;
public:
CommandListFormatter(void *cmd_list, size_t cmd_list_size) : cmd_list(static_cast<u8 *>(cmd_list)), cmd_list_size(cmd_list_size) {
if (cmd_list_size > MaxCommandListSize) {
std::abort();
}
}
~CommandListFormatter() {
this->cmd_list = nullptr;
}
private:
Result CanEnqueue(size_t size) const;
public:
size_t GetCurrentSize() const {
return this->cur_index;
}
Result EnqueueSendCommand(I2cTransactionOption option, const void *src, size_t size);
Result EnqueueReceiveCommand(I2cTransactionOption option, size_t size);
Result EnqueueSleepCommand(size_t us);
};
}
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
namespace sts::i2c {
enum class AddressingMode {
SevenBit = 0,
};
enum class SpeedMode {
Normal = 100000,
Fast = 400000,
FastPlus = 1000000,
HighSpeed = 3400000,
};
}
@@ -1,90 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_types.hpp"
#include "i2c_registers.hpp"
#include "boot_pcv.hpp"
static I2cBus GetI2cBus(PcvModule module) {
switch (module) {
case PcvModule_I2C1:
return I2cBus_I2c1;
case PcvModule_I2C2:
return I2cBus_I2c2;
case PcvModule_I2C3:
return I2cBus_I2c3;
case PcvModule_I2C4:
return I2cBus_I2c4;
case PcvModule_I2C5:
return I2cBus_I2c5;
case PcvModule_I2C6:
return I2cBus_I2c6;
default:
std::abort();
}
}
void Pcv::Initialize() {
/* Don't do anything. */
}
void Pcv::Finalize() {
/* Don't do anything. */
}
Result Pcv::SetClockRate(PcvModule module, u32 hz) {
/* Get clock/reset registers. */
ClkRstRegisters regs;
regs.SetBus(GetI2cBus(module));
/* Set clock enabled/source. */
SetRegisterBits(regs.clk_en_reg, regs.mask);
ReadWriteRegisterBits(regs.clk_src_reg, 0x4, 0xFF);
svcSleepThread(1000ul);
ReadWriteRegisterBits(regs.clk_src_reg, 0, 0xE0000000);
svcSleepThread(2000ul);
return ResultSuccess;
}
Result Pcv::SetClockEnabled(PcvModule module, bool enabled) {
return ResultSuccess;
}
Result Pcv::SetVoltageEnabled(u32 domain, bool enabled) {
return ResultSuccess;
}
Result Pcv::SetVoltageValue(u32 domain, u32 voltage) {
return ResultSuccess;
}
Result Pcv::SetReset(PcvModule module, bool reset) {
/* Get clock/reset registers. */
ClkRstRegisters regs;
regs.SetBus(GetI2cBus(module));
/* Set/clear reset. */
if (reset) {
SetRegisterBits(regs.rst_reg, regs.mask);
} else {
ClearRegisterBits(regs.rst_reg, ~regs.mask);
}
return ResultSuccess;
}
@@ -1,173 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_api.hpp"
#include "i2c_resource_manager.hpp"
typedef Result (*CommandHandler)(const u8 **cur_cmd, u8 **cur_dst, I2cSessionImpl& session);
static Result I2cSendHandler(const u8 **cur_cmd, u8 **cur_dst, I2cSessionImpl& session) {
I2cTransactionOption option = static_cast<I2cTransactionOption>(
(((**cur_cmd) & (1 << 6)) ? I2cTransactionOption_Start : 0) | (((**cur_cmd) & (1 << 7)) ? I2cTransactionOption_Stop : 0)
);
(*cur_cmd)++;
size_t num_bytes = (**cur_cmd);
(*cur_cmd)++;
R_TRY(I2cDriver::Send(session, *cur_cmd, num_bytes, option));
(*cur_cmd) += num_bytes;
return ResultSuccess;
}
static Result I2cReceiveHandler(const u8 **cur_cmd, u8 **cur_dst, I2cSessionImpl& session) {
I2cTransactionOption option = static_cast<I2cTransactionOption>(
(((**cur_cmd) & (1 << 6)) ? I2cTransactionOption_Start : 0) | (((**cur_cmd) & (1 << 7)) ? I2cTransactionOption_Stop : 0)
);
(*cur_cmd)++;
size_t num_bytes = (**cur_cmd);
(*cur_cmd)++;
R_TRY(I2cDriver::Receive(session, *cur_dst, num_bytes, option));
(*cur_dst) += num_bytes;
return ResultSuccess;
}
static Result I2cSubCommandHandler(const u8 **cur_cmd, u8 **cur_dst, I2cSessionImpl& session) {
const I2cSubCommand sub_cmd = static_cast<I2cSubCommand>((**cur_cmd) >> 2);
(*cur_cmd)++;
switch (sub_cmd) {
case I2cSubCommand_Sleep:
{
const size_t us = (**cur_cmd);
(*cur_cmd)++;
svcSleepThread(us * 1'000ul);
}
break;
default:
std::abort();
}
return ResultSuccess;
}
static constexpr CommandHandler g_cmd_handlers[I2cCommand_Count] = {
I2cSendHandler,
I2cReceiveHandler,
I2cSubCommandHandler,
};
static inline I2cResourceManager &GetResourceManager() {
return I2cResourceManager::GetInstance();
}
static inline void CheckInitialized() {
if (!GetResourceManager().IsInitialized()) {
std::abort();
}
}
void I2cDriver::Initialize() {
GetResourceManager().Initialize();
}
void I2cDriver::Finalize() {
GetResourceManager().Finalize();
}
void I2cDriver::OpenSession(I2cSessionImpl *out_session, I2cDevice device) {
CheckInitialized();
if (!IsI2cDeviceSupported(device)) {
std::abort();
}
const I2cBus bus = GetI2cDeviceBus(device);
const u32 slave_address = GetI2cDeviceSlaveAddress(device);
const AddressingMode addressing_mode = GetI2cDeviceAddressingMode(device);
const SpeedMode speed_mode = GetI2cDeviceSpeedMode(device);
const u32 max_retries = GetI2cDeviceMaxRetries(device);
const u64 retry_wait_time = GetI2cDeviceRetryWaitTime(device);
GetResourceManager().OpenSession(out_session, bus, slave_address, addressing_mode, speed_mode, max_retries, retry_wait_time);
}
void I2cDriver::CloseSession(I2cSessionImpl &session) {
CheckInitialized();
GetResourceManager().CloseSession(session);
}
Result I2cDriver::Send(I2cSessionImpl &session, const void *src, size_t size, I2cTransactionOption option) {
CheckInitialized();
if (src == nullptr || size == 0) {
std::abort();
}
std::scoped_lock<HosMutex &> lk(GetResourceManager().GetTransactionMutex(session.bus));
return GetResourceManager().GetSession(session.session_id).DoTransactionWithRetry(nullptr, src, size, option, DriverCommand_Send);
}
Result I2cDriver::Receive(I2cSessionImpl &session, void *dst, size_t size, I2cTransactionOption option) {
CheckInitialized();
if (dst == nullptr || size == 0) {
std::abort();
}
std::scoped_lock<HosMutex &> lk(GetResourceManager().GetTransactionMutex(session.bus));
return GetResourceManager().GetSession(session.session_id).DoTransactionWithRetry(dst, nullptr, size, option, DriverCommand_Receive);
}
Result I2cDriver::ExecuteCommandList(I2cSessionImpl &session, void *dst, size_t size, const void *cmd_list, size_t cmd_list_size) {
CheckInitialized();
if (dst == nullptr || size == 0 || cmd_list == nullptr || cmd_list_size == 0) {
std::abort();
}
u8 *cur_dst = static_cast<u8 *>(dst);
const u8 *cur_cmd = static_cast<const u8 *>(cmd_list);
const u8 *cmd_list_end = cur_cmd + cmd_list_size;
while (cur_cmd < cmd_list_end) {
I2cCommand cmd = static_cast<I2cCommand>((*cur_cmd) & 3);
if (cmd >= I2cCommand_Count) {
std::abort();
}
R_TRY(g_cmd_handlers[cmd](&cur_cmd, &cur_dst, session));
}
return ResultSuccess;
}
void I2cDriver::SuspendBuses() {
GetResourceManager().SuspendBuses();
}
void I2cDriver::ResumeBuses() {
GetResourceManager().ResumeBuses();
}
void I2cDriver::SuspendPowerBus() {
GetResourceManager().SuspendPowerBus();
}
void I2cDriver::ResumePowerBus() {
GetResourceManager().ResumePowerBus();
}
@@ -1,38 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_types.hpp"
#include "i2c_command_list.hpp"
class I2cDriver {
public:
static void Initialize();
static void Finalize();
static void OpenSession(I2cSessionImpl *out_session, I2cDevice device);
static void CloseSession(I2cSessionImpl &session);
static Result Send(I2cSessionImpl &session, const void *src, size_t size, I2cTransactionOption option);
static Result Receive(I2cSessionImpl &session, void *dst, size_t size, I2cTransactionOption option);
static Result ExecuteCommandList(I2cSessionImpl &session, void *dst, size_t size, const void *cmd_list, size_t cmd_list_size);
static void SuspendBuses();
static void ResumeBuses();
static void SuspendPowerBus();
static void ResumePowerBus();
};
@@ -1,495 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_bus_accessor.hpp"
#include "boot_pcv.hpp"
void I2cBusAccessor::Open(I2cBus bus, SpeedMode speed_mode) {
std::scoped_lock<HosMutex> lk(this->open_mutex);
/* Open new session. */
this->open_sessions++;
/* Ensure we're good if this isn't our first session. */
if (this->open_sessions > 1) {
if (this->speed_mode != speed_mode) {
std::abort();
}
return;
}
/* Set all members for chosen bus. */
{
std::scoped_lock<HosMutex> lk(this->register_mutex);
/* Set bus/registers. */
this->SetBus(bus);
/* Set pcv module. */
switch (bus) {
case I2cBus_I2c1:
this->pcv_module = PcvModule_I2C1;
break;
case I2cBus_I2c2:
this->pcv_module = PcvModule_I2C2;
break;
case I2cBus_I2c3:
this->pcv_module = PcvModule_I2C3;
break;
case I2cBus_I2c4:
this->pcv_module = PcvModule_I2C4;
break;
case I2cBus_I2c5:
this->pcv_module = PcvModule_I2C5;
break;
case I2cBus_I2c6:
this->pcv_module = PcvModule_I2C6;
break;
default:
std::abort();
}
/* Set speed mode. */
this->speed_mode = speed_mode;
/* Setup interrupt event. */
this->CreateInterruptEvent(bus);
}
}
void I2cBusAccessor::Close() {
std::scoped_lock<HosMutex> lk(this->open_mutex);
/* Close current session. */
this->open_sessions--;
if (this->open_sessions > 0) {
return;
}
/* Close interrupt event. */
eventClose(&this->interrupt_event);
/* Close PCV. */
Pcv::Finalize();
this->suspended = false;
}
void I2cBusAccessor::Suspend() {
std::scoped_lock<HosMutex> lk(this->open_mutex);
std::scoped_lock<HosMutex> lk_reg(this->register_mutex);
if (!this->suspended) {
this->suspended = true;
if (this->pcv_module != PcvModule_I2C5) {
this->DisableClock();
}
}
}
void I2cBusAccessor::Resume() {
if (this->suspended) {
this->DoInitialConfig();
this->suspended = false;
}
}
void I2cBusAccessor::DoInitialConfig() {
std::scoped_lock<HosMutex> lk(this->register_mutex);
if (this->pcv_module != PcvModule_I2C5) {
Pcv::Initialize();
}
this->ResetController();
this->SetClock(this->speed_mode);
this->SetPacketMode();
this->FlushFifos();
}
size_t I2cBusAccessor::GetOpenSessions() const {
return this->open_sessions;
}
bool I2cBusAccessor::GetBusy() const {
/* Nintendo has a loop here that calls a member function to check if busy, retrying a few times. */
/* This member function does "return false". */
/* We will not bother with the loop. */
return false;
}
void I2cBusAccessor::OnStartTransaction() const {
/* Nothing actually happens here. */
}
void I2cBusAccessor::OnStopTransaction() const {
/* Nothing actually happens here. */
}
Result I2cBusAccessor::StartTransaction(DriverCommand command, AddressingMode addressing_mode, u32 slave_address) {
/* Nothing actually happens here... */
return ResultSuccess;
}
Result I2cBusAccessor::Send(const u8 *data, size_t num_bytes, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address) {
std::scoped_lock<HosMutex> lk(this->register_mutex);
const u8 *cur_src = data;
size_t remaining = num_bytes;
/* Set interrupt enable, clear interrupt status. */
WriteRegister(&this->i2c_registers->I2C_INTERRUPT_MASK_REGISTER_0, 0x8E);
WriteRegister(&this->i2c_registers->I2C_INTERRUPT_STATUS_REGISTER_0, 0xFC);
ON_SCOPE_EXIT { this->ClearInterruptMask(); };
/* Send header. */
this->WriteTransferHeader(TransferMode_Send, option, addressing_mode, slave_address, num_bytes);
/* Send bytes. */
while (true) {
const u32 fifo_status = ReadRegister(&this->i2c_registers->I2C_FIFO_STATUS_0);
const size_t fifo_cnt = (fifo_status >> 4);
for (size_t fifo_idx = 0; remaining > 0 && fifo_idx < fifo_cnt; fifo_idx++) {
const size_t cur_bytes = std::min(remaining, sizeof(u32));
u32 val = 0;
for (size_t i = 0; i < cur_bytes; i++) {
val |= cur_src[i] << (8 * i);
}
WriteRegister(&this->i2c_registers->I2C_I2C_TX_PACKET_FIFO_0, val);
cur_src += cur_bytes;
remaining -= cur_bytes;
}
if (remaining == 0) {
break;
}
eventClear(&this->interrupt_event);
if (R_FAILED(eventWait(&this->interrupt_event, InterruptTimeout))) {
this->HandleTransactionResult(ResultI2cBusBusy);
eventClear(&this->interrupt_event);
return ResultI2cTimedOut;
}
R_TRY(this->GetAndHandleTransactionResult());
}
WriteRegister(&this->i2c_registers->I2C_INTERRUPT_MASK_REGISTER_0, 0x8C);
/* Wait for successful completion. */
while (true) {
R_TRY(this->GetAndHandleTransactionResult());
/* Check PACKET_XFER_COMPLETE */
const u32 interrupt_status = ReadRegister(&this->i2c_registers->I2C_INTERRUPT_STATUS_REGISTER_0);
if (interrupt_status & 0x80) {
R_TRY(this->GetAndHandleTransactionResult());
break;
}
eventClear(&this->interrupt_event);
if (R_FAILED(eventWait(&this->interrupt_event, InterruptTimeout))) {
this->HandleTransactionResult(ResultI2cBusBusy);
eventClear(&this->interrupt_event);
return ResultI2cTimedOut;
}
}
return ResultSuccess;
}
Result I2cBusAccessor::Receive(u8 *out_data, size_t num_bytes, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address) {
std::scoped_lock<HosMutex> lk(this->register_mutex);
u8 *cur_dst = out_data;
size_t remaining = num_bytes;
/* Set interrupt enable, clear interrupt status. */
WriteRegister(&this->i2c_registers->I2C_INTERRUPT_MASK_REGISTER_0, 0x8D);
WriteRegister(&this->i2c_registers->I2C_INTERRUPT_STATUS_REGISTER_0, 0xFC);
/* Send header. */
this->WriteTransferHeader(TransferMode_Receive, option, addressing_mode, slave_address, num_bytes);
/* Receive bytes. */
while (remaining > 0) {
eventClear(&this->interrupt_event);
if (R_FAILED(eventWait(&this->interrupt_event, InterruptTimeout))) {
this->HandleTransactionResult(ResultI2cBusBusy);
this->ClearInterruptMask();
eventClear(&this->interrupt_event);
return ResultI2cTimedOut;
}
R_TRY(this->GetAndHandleTransactionResult());
const u32 fifo_status = ReadRegister(&this->i2c_registers->I2C_FIFO_STATUS_0);
const size_t fifo_cnt = std::min((remaining + 3) >> 2, static_cast<size_t>(fifo_status & 0xF));
for (size_t fifo_idx = 0; remaining > 0 && fifo_idx < fifo_cnt; fifo_idx++) {
const u32 val = ReadRegister(&this->i2c_registers->I2C_I2C_RX_FIFO_0);
const size_t cur_bytes = std::min(remaining, sizeof(u32));
for (size_t i = 0; i < cur_bytes; i++) {
cur_dst[i] = static_cast<u8>((val >> (8 * i)) & 0xFF);
}
cur_dst += cur_bytes;
remaining -= cur_bytes;
}
}
/* N doesn't do ClearInterruptMask. */
return ResultSuccess;
}
void I2cBusAccessor::SetBus(I2cBus bus) {
this->bus = bus;
this->i2c_registers = GetI2cRegisters(bus);
this->clkrst_registers.SetBus(bus);
}
void I2cBusAccessor::CreateInterruptEvent(I2cBus bus) {
static constexpr u64 s_interrupts[] = {
0x46, 0x74, 0x7C, 0x98, 0x55, 0x5F
};
if (static_cast<size_t>(bus) >= sizeof(s_interrupts) / sizeof(s_interrupts[0])) {
std::abort();
}
Handle evt_h;
if (R_FAILED(svcCreateInterruptEvent(&evt_h, s_interrupts[static_cast<size_t>(bus)], 1))) {
std::abort();
}
eventLoadRemote(&this->interrupt_event, evt_h, false);
}
void I2cBusAccessor::SetClock(SpeedMode speed_mode) {
u32 t_high, t_low;
u32 clk_div, src_div;
u32 debounce;
switch (speed_mode) {
case SpeedMode_Normal:
t_high = 2;
t_low = 4;
clk_div = 0x19;
src_div = 0x13;
debounce = 2;
break;
case SpeedMode_Fast:
t_high = 2;
t_low = 4;
clk_div = 0x19;
src_div = 0x04;
debounce = 2;
break;
case SpeedMode_FastPlus:
t_high = 2;
t_low = 4;
clk_div = 0x10;
src_div = 0x02;
debounce = 0;
break;
case SpeedMode_HighSpeed:
t_high = 3;
t_low = 8;
clk_div = 0x02;
src_div = 0x02;
debounce = 0;
break;
default:
std::abort();
}
if (speed_mode == SpeedMode_HighSpeed) {
WriteRegister(&this->i2c_registers->I2C_I2C_HS_INTERFACE_TIMING_0_0, (t_high << 8) | (t_low));
WriteRegister(&this->i2c_registers->I2C_I2C_CLK_DIVISOR_REGISTER_0, clk_div);
} else {
WriteRegister(&this->i2c_registers->I2C_I2C_INTERFACE_TIMING_0_0, (t_high << 8) | (t_low));
WriteRegister(&this->i2c_registers->I2C_I2C_CLK_DIVISOR_REGISTER_0, (clk_div << 16));
}
WriteRegister(&this->i2c_registers->I2C_I2C_CNFG_0, debounce);
ReadRegister(&this->i2c_registers->I2C_I2C_CNFG_0);
if (this->pcv_module != PcvModule_I2C5) {
if (R_FAILED(Pcv::SetReset(this->pcv_module, true))) {
std::abort();
}
if (R_FAILED(Pcv::SetClockRate(this->pcv_module, (408'000'000) / (src_div + 1)))) {
std::abort();
}
if (R_FAILED(Pcv::SetReset(this->pcv_module, false))) {
std::abort();
}
}
}
void I2cBusAccessor::ResetController() const {
if (this->pcv_module != PcvModule_I2C5) {
if (R_FAILED(Pcv::SetReset(this->pcv_module, true))) {
std::abort();
}
if (R_FAILED(Pcv::SetClockRate(this->pcv_module, 81'600'000))) {
std::abort();
}
if (R_FAILED(Pcv::SetReset(this->pcv_module, false))) {
std::abort();
}
}
}
void I2cBusAccessor::ClearBus() const {
bool success = false;
for (size_t i = 0; i < 3 && !success; i++) {
success = true;
this->ResetController();
WriteRegister(&this->i2c_registers->I2C_I2C_BUS_CLEAR_CONFIG_0, 0x90000);
SetRegisterBits(&this->i2c_registers->I2C_I2C_BUS_CLEAR_CONFIG_0, 0x4);
SetRegisterBits(&this->i2c_registers->I2C_I2C_BUS_CLEAR_CONFIG_0, 0x2);
SetRegisterBits(&this->i2c_registers->I2C_I2C_CONFIG_LOAD_0, 0x1);
{
u64 start_tick = armGetSystemTick();
while (ReadRegister(&this->i2c_registers->I2C_I2C_CONFIG_LOAD_0) & 1) {
if (armTicksToNs(armGetSystemTick() - start_tick) > 1'000'000) {
success = false;
break;
}
}
}
if (!success) {
continue;
}
SetRegisterBits(&this->i2c_registers->I2C_I2C_BUS_CLEAR_CONFIG_0, 0x1);
{
u64 start_tick = armGetSystemTick();
while (ReadRegister(&this->i2c_registers->I2C_I2C_BUS_CLEAR_CONFIG_0) & 1) {
if (armTicksToNs(armGetSystemTick() - start_tick) > 1'000'000) {
success = false;
break;
}
}
}
if (!success) {
continue;
}
{
u64 start_tick = armGetSystemTick();
while (ReadRegister(&this->i2c_registers->I2C_I2C_BUS_CLEAR_STATUS_0) & 1) {
if (armTicksToNs(armGetSystemTick() - start_tick) > 1'000'000) {
success = false;
break;
}
}
}
if (!success) {
continue;
}
}
}
void I2cBusAccessor::DisableClock() {
if (R_FAILED(Pcv::SetClockEnabled(this->pcv_module, false))) {
std::abort();
}
}
void I2cBusAccessor::SetPacketMode() {
/* Set PACKET_MODE_EN, MSTR_CONFIG_LOAD */
SetRegisterBits(&this->i2c_registers->I2C_I2C_CNFG_0, 0x400);
SetRegisterBits(&this->i2c_registers->I2C_I2C_CONFIG_LOAD_0, 0x1);
/* Set TX_FIFO_TRIGGER, RX_FIFO_TRIGGER */
WriteRegister(&this->i2c_registers->I2C_FIFO_CONTROL_0, 0xFC);
}
Result I2cBusAccessor::FlushFifos() {
WriteRegister(&this->i2c_registers->I2C_FIFO_CONTROL_0, 0xFF);
/* Wait for flush to finish, check every ms for 5 ms. */
for (size_t i = 0; i < 5; i++) {
if (!(ReadRegister(&this->i2c_registers->I2C_FIFO_CONTROL_0) & 3)) {
return ResultSuccess;
}
svcSleepThread(1'000'000ul);
}
return ResultI2cBusBusy;
}
Result I2cBusAccessor::GetTransactionResult() const {
const u32 packet_status = ReadRegister(&this->i2c_registers->I2C_PACKET_TRANSFER_STATUS_0);
const u32 interrupt_status = ReadRegister(&this->i2c_registers->I2C_INTERRUPT_STATUS_REGISTER_0);
/* Check for no ack. */
if ((packet_status & 0xC) || (interrupt_status & 0x8)) {
return ResultI2cNoAck;
}
/* Check for arb lost. */
if ((packet_status & 0x2) || (interrupt_status & 0x4)) {
this->ClearBus();
return ResultI2cBusBusy;
}
return ResultSuccess;
}
void I2cBusAccessor::HandleTransactionResult(Result result) {
if (R_FAILED(result)) {
if (result == ResultI2cNoAck || result == ResultI2cBusBusy) {
this->ResetController();
this->SetClock(this->speed_mode);
this->SetPacketMode();
this->FlushFifos();
} else {
std::abort();
}
}
}
Result I2cBusAccessor::GetAndHandleTransactionResult() {
const Result transaction_res = this->GetTransactionResult();
R_TRY_CLEANUP(transaction_res, {
this->HandleTransactionResult(transaction_res);
this->ClearInterruptMask();
eventClear(&this->interrupt_event);
});
return ResultSuccess;
}
void I2cBusAccessor::WriteTransferHeader(TransferMode transfer_mode, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address, size_t num_bytes) {
this->FlushFifos();
WriteRegister(&this->i2c_registers->I2C_I2C_TX_PACKET_FIFO_0, 0x10);
WriteRegister(&this->i2c_registers->I2C_I2C_TX_PACKET_FIFO_0, static_cast<u32>(num_bytes - 1) & 0xFFF);
const u32 slave_addr_val = ((transfer_mode == TransferMode_Receive) & 1) | ((slave_address & 0x7F) << 1);
u32 hdr_val = 0;
hdr_val |= ((this->speed_mode == SpeedMode_HighSpeed) & 1) << 22;
hdr_val |= ((transfer_mode == TransferMode_Receive) & 1) << 19;
hdr_val |= ((addressing_mode != AddressingMode_7Bit) & 1) << 18;
hdr_val |= (1 << 17);
hdr_val |= (((option & I2cTransactionOption_Stop) == 0) & 1) << 16;
hdr_val |= slave_addr_val;
WriteRegister(&this->i2c_registers->I2C_I2C_TX_PACKET_FIFO_0, hdr_val);
}
@@ -1,82 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_types.hpp"
#include "i2c_registers.hpp"
class I2cBusAccessor {
private:
enum TransferMode {
TransferMode_Send = 0,
TransferMode_Receive = 1,
};
static constexpr u64 InterruptTimeout = 100'000'000ul;
private:
Event interrupt_event;
HosMutex open_mutex;
HosMutex register_mutex;
I2cRegisters *i2c_registers = nullptr;
ClkRstRegisters clkrst_registers;
SpeedMode speed_mode = SpeedMode_Fast;
size_t open_sessions = 0;
I2cBus bus = I2cBus_I2c1;
PcvModule pcv_module = PcvModule_I2C1;
bool suspended = false;
public:
I2cBusAccessor() {
/* ... */
}
private:
inline void ClearInterruptMask() const {
WriteRegister(&i2c_registers->I2C_INTERRUPT_MASK_REGISTER_0, 0);
ReadRegister(&i2c_registers->I2C_INTERRUPT_MASK_REGISTER_0);
}
void SetBus(I2cBus bus);
void CreateInterruptEvent(I2cBus bus);
void SetClock(SpeedMode speed_mode);
void ResetController() const;
void ClearBus() const;
void DisableClock();
void SetPacketMode();
Result FlushFifos();
Result GetTransactionResult() const;
void HandleTransactionResult(Result result);
Result GetAndHandleTransactionResult();
void WriteTransferHeader(TransferMode transfer_mode, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address, size_t num_bytes);
public:
void Open(I2cBus bus, SpeedMode speed_mode);
void Close();
void Suspend();
void Resume();
void DoInitialConfig();
size_t GetOpenSessions() const;
bool GetBusy() const;
void OnStartTransaction() const;
Result StartTransaction(DriverCommand command, AddressingMode addressing_mode, u32 slave_address);
Result Send(const u8 *data, size_t num_bytes, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address);
Result Receive(u8 *out_data, size_t num_bytes, I2cTransactionOption option, AddressingMode addressing_mode, u32 slave_address);
void OnStopTransaction() const;
};
@@ -1,67 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_command_list.hpp"
Result I2cCommandListFormatter::CanEnqueue(size_t size) const {
if (this->cmd_list_size - this->cur_index < size) {
return ResultI2cFullCommandList;
}
return ResultSuccess;
}
Result I2cCommandListFormatter::EnqueueSendCommand(I2cTransactionOption option, const void *src, size_t size) {
R_TRY(this->CanEnqueue(SendCommandSize + size));
this->cmd_list[this->cur_index] = I2cCommand_Send;
this->cmd_list[this->cur_index] |= ((option & I2cTransactionOption_Start) != 0) << 6;
this->cmd_list[this->cur_index] |= ((option & I2cTransactionOption_Stop) != 0) << 7;
this->cur_index++;
this->cmd_list[this->cur_index++] = size;
const u8 *src_u8 = reinterpret_cast<const u8 *>(src);
for (size_t i = 0; i < size; i++) {
this->cmd_list[this->cur_index++] = src_u8[i];
}
return ResultSuccess;
}
Result I2cCommandListFormatter::EnqueueReceiveCommand(I2cTransactionOption option, size_t size) {
R_TRY(this->CanEnqueue(ReceiveCommandSize));
this->cmd_list[this->cur_index] = I2cCommand_Receive;
this->cmd_list[this->cur_index] |= ((option & I2cTransactionOption_Start) != 0) << 6;
this->cmd_list[this->cur_index] |= ((option & I2cTransactionOption_Stop) != 0) << 7;
this->cur_index++;
this->cmd_list[this->cur_index++] = size;
return ResultSuccess;
}
Result I2cCommandListFormatter::EnqueueSleepCommand(size_t us) {
R_TRY(this->CanEnqueue(SleepCommandSize));
this->cmd_list[this->cur_index] = I2cCommand_SubCommand;
this->cmd_list[this->cur_index] |= I2cSubCommand_Sleep << 2;
this->cur_index++;
this->cmd_list[this->cur_index++] = us;
return ResultSuccess;
}
@@ -1,53 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_types.hpp"
class I2cCommandListFormatter {
public:
static constexpr size_t MaxCommandListSize = 0x100;
static constexpr size_t SendCommandSize = 2;
static constexpr size_t ReceiveCommandSize = 2;
static constexpr size_t SleepCommandSize = 2;
private:
u8 *cmd_list = nullptr;
size_t cmd_list_size = 0;
size_t cur_index = 0;
public:
I2cCommandListFormatter(void *cmd_list, size_t cmd_list_size) : cmd_list(static_cast<u8 *>(cmd_list)), cmd_list_size(cmd_list_size) {
if (cmd_list_size > MaxCommandListSize) {
std::abort();
}
}
~I2cCommandListFormatter() {
this->cmd_list = nullptr;
}
private:
Result CanEnqueue(size_t size) const;
public:
size_t GetCurrentSize() const {
return this->cur_index;
}
Result EnqueueSendCommand(I2cTransactionOption option, const void *src, size_t size);
Result EnqueueReceiveCommand(I2cTransactionOption option, size_t size);
Result EnqueueSleepCommand(size_t us);
};
@@ -1,117 +0,0 @@
/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <switch.h>
#include <stratosphere.hpp>
#include "i2c_types.hpp"
struct DeviceConfig {
I2cDevice device;
I2cBus bus;
u32 slave_address;
AddressingMode addressing_mode;
SpeedMode speed_mode;
u32 max_retries;
u64 retry_wait_time;
};
static constexpr DeviceConfig g_device_configs[I2cDevice_Count] = {
{I2cDevice_DebugPad, I2cBus_I2c1, 0x52, AddressingMode_7Bit, SpeedMode_Normal, 0, 0},
{I2cDevice_TouchPanel, I2cBus_I2c3, 0x49, AddressingMode_7Bit, SpeedMode_Fast, 0, 0},
{I2cDevice_Tmp451, I2cBus_I2c1, 0x4c, AddressingMode_7Bit, SpeedMode_Normal, 0, 0},
{I2cDevice_Nct72, I2cBus_I2c1, 0x4c, AddressingMode_7Bit, SpeedMode_Normal, 0, 0},
{I2cDevice_Alc5639, I2cBus_I2c1, 0x1c, AddressingMode_7Bit, SpeedMode_Normal, 0, 0},
{I2cDevice_Max77620Rtc, I2cBus_I2c5, 0x68, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Max77620Pmic, I2cBus_I2c5, 0x3c, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Max77621Cpu, I2cBus_I2c5, 0x1b, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Max77621Gpu, I2cBus_I2c5, 0x1c, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Bq24193, I2cBus_I2c1, 0x6b, AddressingMode_7Bit, SpeedMode_Normal, 3, 5'000'000},
{I2cDevice_Max17050, I2cBus_I2c1, 0x36, AddressingMode_7Bit, SpeedMode_Normal, 3, 5'000'000},
{I2cDevice_Bm92t30mwv, I2cBus_I2c1, 0x18, AddressingMode_7Bit, SpeedMode_Normal, 3, 5'000'000},
{I2cDevice_Ina226Vdd15v0Hb, I2cBus_I2c2, 0x40, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Ina226VsysCpuDs, I2cBus_I2c2, 0x41, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Ina226VsysGpuDs, I2cBus_I2c2, 0x44, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Ina226VsysDdrDs, I2cBus_I2c2, 0x45, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Ina226VsysAp, I2cBus_I2c2, 0x46, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Ina226VsysBlDs, I2cBus_I2c2, 0x47, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Bh1730, I2cBus_I2c2, 0x29, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Ina226VsysCore, I2cBus_I2c2, 0x48, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Ina226Soc1V8, I2cBus_I2c2, 0x49, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Ina226Lpddr1V8, I2cBus_I2c2, 0x4a, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Ina226Reg1V32, I2cBus_I2c2, 0x4b, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_Ina226Vdd3V3Sys, I2cBus_I2c2, 0x4d, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
{I2cDevice_HdmiDdc, I2cBus_I2c4, 0x50, AddressingMode_7Bit, SpeedMode_Normal, 0, 0},
{I2cDevice_HdmiScdc, I2cBus_I2c4, 0x54, AddressingMode_7Bit, SpeedMode_Normal, 0, 0},
{I2cDevice_HdmiHdcp, I2cBus_I2c4, 0x3a, AddressingMode_7Bit, SpeedMode_Normal, 0, 0},
{I2cDevice_Fan53528, I2cBus_I2c5, 0xa4, AddressingMode_7Bit, SpeedMode_Fast, 0, 0},
{I2cDevice_Max77812_3, I2cBus_I2c5, 0x31, AddressingMode_7Bit, SpeedMode_Fast, 0, 0},
{I2cDevice_Max77812_2, I2cBus_I2c5, 0x33, AddressingMode_7Bit, SpeedMode_Fast, 0, 0},
{I2cDevice_Ina226VddDdr0V6, I2cBus_I2c2, 0x4e, AddressingMode_7Bit, SpeedMode_Fast, 3, 5'000'000},
};
static constexpr size_t NumDeviceConfigs = sizeof(g_device_configs) / sizeof(g_device_configs[0]);
static constexpr size_t I2cDeviceInvalidIndex = static_cast<size_t>(-1);
static size_t GetI2cDeviceIndex(I2cDevice dev) {
for (size_t i = 0; i < NumDeviceConfigs; i++) {
if (g_device_configs[i].device == dev) {
return i;
}
}
return I2cDeviceInvalidIndex;
}
bool IsI2cDeviceSupported(I2cDevice dev) {
return GetI2cDeviceIndex(dev) != I2cDeviceInvalidIndex;
}
I2cBus GetI2cDeviceBus(I2cDevice dev) {
const size_t dev_idx = GetI2cDeviceIndex(dev);
if (dev_idx == I2cDeviceInvalidIndex) { std::abort(); }
return g_device_configs[dev_idx].bus;
}
u32 GetI2cDeviceSlaveAddress(I2cDevice dev) {
const size_t dev_idx = GetI2cDeviceIndex(dev);
if (dev_idx == I2cDeviceInvalidIndex) { std::abort(); }
return g_device_configs[dev_idx].slave_address;
}
AddressingMode GetI2cDeviceAddressingMode(I2cDevice dev) {
const size_t dev_idx = GetI2cDeviceIndex(dev);
if (dev_idx == I2cDeviceInvalidIndex) { std::abort(); }
return g_device_configs[dev_idx].addressing_mode;
}
SpeedMode GetI2cDeviceSpeedMode(I2cDevice dev) {
const size_t dev_idx = GetI2cDeviceIndex(dev);
if (dev_idx == I2cDeviceInvalidIndex) { std::abort(); }
return g_device_configs[dev_idx].speed_mode;
}
u32 GetI2cDeviceMaxRetries(I2cDevice dev) {
const size_t dev_idx = GetI2cDeviceIndex(dev);
if (dev_idx == I2cDeviceInvalidIndex) { std::abort(); }
return g_device_configs[dev_idx].max_retries;
}
u64 GetI2cDeviceRetryWaitTime(I2cDevice dev) {
const size_t dev_idx = GetI2cDeviceIndex(dev);
if (dev_idx == I2cDeviceInvalidIndex) { std::abort(); }
return g_device_configs[dev_idx].retry_wait_time;
}
Loaded 100 of 151 files, more files were not shown because too many files have changed in this diff. Show more