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);
+}