diff --git a/stratosphere/boot/source/boot_change_voltage.cpp b/stratosphere/boot/source/boot_change_voltage.cpp new file mode 100644 index 000000000..8e6a9c2c5 --- /dev/null +++ b/stratosphere/boot/source/boot_change_voltage.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "boot_functions.hpp" + +static constexpr u32 Sdmmc3VoltageBit = (1 << 13); /* SDMMC3 */ +static constexpr u32 AudioVoltageBit = (1 << 18); /* AUDIO_HV */ +static constexpr u32 GpioVoltageBit = (1 << 21); /* GPIO */ +static constexpr u32 SpiVoltageBit = (1 << 23); /* SPI_HV */ + +static constexpr u32 VoltageChangeMask = SpiVoltageBit | GpioVoltageBit | AudioVoltageBit | Sdmmc3VoltageBit; + +static constexpr u32 PmcPwrDet = 0x7000E448; +static constexpr u32 PmcPwrDetVal = 0x7000E4E4; + +void Boot::ChangeGpioVoltageTo1_8v() { + /* Write mask to APBDEV_PMC_PWR_DET, then clear APBDEV_PMC_PWR_DET_VAL. */ + WritePmcRegister(PmcPwrDet, VoltageChangeMask, VoltageChangeMask); + WritePmcRegister(PmcPwrDetVal, 0, VoltageChangeMask); + + /* Sleep for 100 us. */ + svcSleepThread(100'000ul); +} diff --git a/stratosphere/boot/source/boot_functions.hpp b/stratosphere/boot/source/boot_functions.hpp new file mode 100644 index 000000000..8b2e09758 --- /dev/null +++ b/stratosphere/boot/source/boot_functions.hpp @@ -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 . + */ + +#pragma once +#include +#include + +class Boot { + public: + /* Functions for actually booting. */ + static void ChangeGpioVoltageTo1_8v(); + + /* Register Utilities. */ + static u32 ReadPmcRegister(u32 phys_addr); + static void WritePmcRegister(u32 phys_addr, u32 value, u32 mask = UINT32_MAX); +}; diff --git a/stratosphere/boot/source/boot_main.cpp b/stratosphere/boot/source/boot_main.cpp index 69b5d2a8f..42eeda584 100644 --- a/stratosphere/boot/source/boot_main.cpp +++ b/stratosphere/boot/source/boot_main.cpp @@ -23,6 +23,8 @@ #include #include +#include "boot_functions.hpp" + extern "C" { extern u32 __start__; @@ -102,7 +104,8 @@ int main(int argc, char **argv) /* TODO: Explicitly: */ - /* TODO: ChangeGpioVoltageTo1_8v(); */ + /* Change voltage from 3.3v to 1.8v for select devices. */ + Boot::ChangeGpioVoltageTo1_8v(); /* TODO: SetInitialGpioConfiguration(); */ diff --git a/stratosphere/boot/source/boot_pmc_wrapper.cpp b/stratosphere/boot/source/boot_pmc_wrapper.cpp new file mode 100644 index 000000000..00f6f004d --- /dev/null +++ b/stratosphere/boot/source/boot_pmc_wrapper.cpp @@ -0,0 +1,57 @@ +/* + * 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 . + */ + +#include "boot_functions.hpp" + +static constexpr u32 SmcFunctionId_AtmosphereReadWriteRegister = 0xF0000002; + +static constexpr u32 PmcPhysStart = 0x7000E400; +static constexpr u32 PmcPhysEnd = 0x7000EFFF; + +static inline bool IsValidPmcAddress(u32 phys_addr) { + return (phys_addr & 3) == 0 && PmcPhysStart <= phys_addr && phys_addr <= PmcPhysEnd; +} + +static inline u32 SmcAtmosphereReadWriteRegister(u32 phys_addr, u32 value, u32 mask) { + SecmonArgs args; + + args.X[0] = SmcFunctionId_AtmosphereReadWriteRegister; + args.X[1] = phys_addr; + args.X[2] = mask; + args.X[3] = value; + svcCallSecureMonitor(&args); + if (args.X[0] != 0) { + std::abort(); + } + + return static_cast(args.X[1]); +} + +u32 Boot::ReadPmcRegister(u32 phys_addr) { + if (!IsValidPmcAddress(phys_addr)) { + std::abort(); + } + + return SmcAtmosphereReadWriteRegister(phys_addr, 0, 0); +} + +void Boot::WritePmcRegister(u32 phys_addr, u32 value, u32 mask) { + if (!IsValidPmcAddress(phys_addr)) { + std::abort(); + } + + SmcAtmosphereReadWriteRegister(phys_addr, value, mask); +}