From 38159bdf9a8388cc2b70e571308afdbfe5632686 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 29 Apr 2019 09:43:48 -0700 Subject: [PATCH] boot: Implement initial gpio configuration --- stratosphere/boot/source/boot_functions.hpp | 13 ++ .../boot_gpio_initial_configuration.cpp | 80 ++++++++++ ...boot_gpio_initial_configuration_copper.hpp | 69 ++++++++ .../boot_gpio_initial_configuration_hoag.hpp | 84 ++++++++++ .../boot_gpio_initial_configuration_icosa.hpp | 150 ++++++++++++++++++ .../boot_gpio_initial_configuration_iowa.hpp | 84 ++++++++++ stratosphere/boot/source/boot_gpio_map.hpp | 111 +++++++++++++ stratosphere/boot/source/boot_gpio_utils.cpp | 119 ++++++++++++++ stratosphere/boot/source/boot_main.cpp | 3 +- stratosphere/boot/source/boot_spl_utils.cpp | 25 +++ stratosphere/boot/source/boot_types.hpp | 32 ++++ 11 files changed, 769 insertions(+), 1 deletion(-) create mode 100644 stratosphere/boot/source/boot_gpio_initial_configuration.cpp create mode 100644 stratosphere/boot/source/boot_gpio_initial_configuration_copper.hpp create mode 100644 stratosphere/boot/source/boot_gpio_initial_configuration_hoag.hpp create mode 100644 stratosphere/boot/source/boot_gpio_initial_configuration_icosa.hpp create mode 100644 stratosphere/boot/source/boot_gpio_initial_configuration_iowa.hpp create mode 100644 stratosphere/boot/source/boot_gpio_map.hpp create mode 100644 stratosphere/boot/source/boot_gpio_utils.cpp create mode 100644 stratosphere/boot/source/boot_spl_utils.cpp create mode 100644 stratosphere/boot/source/boot_types.hpp diff --git a/stratosphere/boot/source/boot_functions.hpp b/stratosphere/boot/source/boot_functions.hpp index 8b2e09758..faafba936 100644 --- a/stratosphere/boot/source/boot_functions.hpp +++ b/stratosphere/boot/source/boot_functions.hpp @@ -18,12 +18,25 @@ #include #include +#include "boot_types.hpp" + class Boot { + public: + static constexpr u32 GpioPhysicalBase = 0x6000D000; public: /* Functions for actually booting. */ static void ChangeGpioVoltageTo1_8v(); + static void SetInitialGpioConfiguration(); /* 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); + + /* SPL Utilities. */ + static HardwareType GetHardwareType(); }; diff --git a/stratosphere/boot/source/boot_gpio_initial_configuration.cpp b/stratosphere/boot/source/boot_gpio_initial_configuration.cpp new file mode 100644 index 000000000..367bd28dd --- /dev/null +++ b/stratosphere/boot/source/boot_gpio_initial_configuration.cpp @@ -0,0 +1,80 @@ +/* + * 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" +#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); + + /* Set the GPIO's value. */ + Boot::GpioSetValue(configs[i].pad_name, configs[i].value); + } +} \ No newline at end of file diff --git a/stratosphere/boot/source/boot_gpio_initial_configuration_copper.hpp b/stratosphere/boot/source/boot_gpio_initial_configuration_copper.hpp new file mode 100644 index 000000000..7a4abc90a --- /dev/null +++ b/stratosphere/boot/source/boot_gpio_initial_configuration_copper.hpp @@ -0,0 +1,69 @@ +/* + * 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 "boot_types.hpp" + +static constexpr GpioInitialConfig GpioInitialConfigsCopper[] = { + {0x40, GpioDirection_Output, GpioValue_Low}, + {0x05, GpioDirection_Output, GpioValue_Low}, + {0x41, GpioDirection_Input, GpioValue_High}, + {0x42, GpioDirection_Input, GpioValue_Low}, + {0x43, GpioDirection_Output, GpioValue_Low}, + {0x02, GpioDirection_Output, GpioValue_Low}, + {0x07, GpioDirection_Output, GpioValue_Low}, + {0x44, GpioDirection_Input, GpioValue_High}, + {0x45, GpioDirection_Input, GpioValue_High}, + {0x0F, GpioDirection_Input, GpioValue_High}, + {0x46, GpioDirection_Output, GpioValue_Low}, + {0x47, GpioDirection_Output, GpioValue_Low}, + {0x10, GpioDirection_Input, GpioValue_Low}, + {0x11, GpioDirection_Input, GpioValue_Low}, + {0x12, GpioDirection_Input, GpioValue_Low}, + {0x13, GpioDirection_Input, GpioValue_Low}, + {0x14, GpioDirection_Input, GpioValue_High}, + {0x18, GpioDirection_Input, GpioValue_Low}, + {0x19, GpioDirection_Input, GpioValue_High}, + {0x1A, GpioDirection_Input, GpioValue_High}, + {0x1C, GpioDirection_Input, GpioValue_High}, + {0x4D, GpioDirection_Output, GpioValue_Low}, + {0x20, GpioDirection_Output, GpioValue_Low}, + {0x38, GpioDirection_Input, GpioValue_High}, + {0x23, GpioDirection_Input, GpioValue_High}, + {0x25, GpioDirection_Input, GpioValue_Low}, + {0x26, GpioDirection_Input, GpioValue_Low}, + {0x27, GpioDirection_Input, GpioValue_Low}, + {0x28, GpioDirection_Input, GpioValue_High}, + {0x29, GpioDirection_Input, GpioValue_High}, + {0x2A, GpioDirection_Input, GpioValue_High}, + {0x48, GpioDirection_Output, GpioValue_Low}, + {0x49, GpioDirection_Output, GpioValue_Low}, + {0x4A, GpioDirection_Output, GpioValue_Low}, + {0x2D, GpioDirection_Output, GpioValue_Low}, + {0x2E, GpioDirection_Output, GpioValue_Low}, + {0x37, GpioDirection_Input, GpioValue_Low}, + {0x2F, GpioDirection_Output, GpioValue_Low}, + {0x03, GpioDirection_Output, GpioValue_Low}, + {0x30, GpioDirection_Input, GpioValue_Low}, + {0x31, GpioDirection_Output, GpioValue_Low}, + {0x4B, GpioDirection_Output, GpioValue_Low}, + {0x4C, GpioDirection_Input, GpioValue_High}, + {0x4E, GpioDirection_Input, GpioValue_Low}, +}; + +static constexpr u32 GpioNumInitialConfigsCopper = (sizeof(GpioInitialConfigsCopper) / sizeof(GpioInitialConfigsCopper[0])); diff --git a/stratosphere/boot/source/boot_gpio_initial_configuration_hoag.hpp b/stratosphere/boot/source/boot_gpio_initial_configuration_hoag.hpp new file mode 100644 index 000000000..adecfec2d --- /dev/null +++ b/stratosphere/boot/source/boot_gpio_initial_configuration_hoag.hpp @@ -0,0 +1,84 @@ +/* + * 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 "boot_types.hpp" + +static constexpr GpioInitialConfig GpioInitialConfigsHoag[] = { + {0x04, GpioDirection_Input, GpioValue_High}, + {0x05, GpioDirection_Output, GpioValue_Low}, + {0x06, GpioDirection_Input, GpioValue_Low}, + {0x02, GpioDirection_Output, GpioValue_Low}, + {0x3C, GpioDirection_Input, GpioValue_Low}, + {0x0F, GpioDirection_Input, GpioValue_High}, + {0x08, GpioDirection_Input, GpioValue_Low}, + {0x09, GpioDirection_Input, GpioValue_Low}, + {0x0A, GpioDirection_Output, GpioValue_Low}, + {0x0B, GpioDirection_Input, GpioValue_Low}, + {0x0D, GpioDirection_Output, GpioValue_Low}, + {0x0E, GpioDirection_Input, GpioValue_Low}, + {0x10, GpioDirection_Input, GpioValue_Low}, + {0x11, GpioDirection_Input, GpioValue_Low}, + {0x12, GpioDirection_Input, GpioValue_Low}, + {0x13, GpioDirection_Input, GpioValue_Low}, + {0x14, GpioDirection_Input, GpioValue_High}, + {0x16, GpioDirection_Input, GpioValue_Low}, + {0x15, GpioDirection_Input, GpioValue_Low}, + {0x17, GpioDirection_Input, GpioValue_High}, + {0x18, GpioDirection_Input, GpioValue_Low}, + {0x19, GpioDirection_Input, GpioValue_High}, + {0x1A, GpioDirection_Input, GpioValue_High}, + {0x1B, GpioDirection_Input, GpioValue_Low}, + {0x1C, GpioDirection_Input, GpioValue_Low}, + {0x1D, GpioDirection_Output, GpioValue_Low}, + {0x1E, GpioDirection_Output, GpioValue_Low}, + {0x20, GpioDirection_Output, GpioValue_Low}, + {0x21, GpioDirection_Input, GpioValue_Low}, + {0x38, GpioDirection_Input, GpioValue_High}, + {0x22, GpioDirection_Input, GpioValue_Low}, + {0x23, GpioDirection_Input, GpioValue_High}, + {0x01, GpioDirection_Output, GpioValue_Low}, + {0x39, GpioDirection_Output, GpioValue_Low}, + {0x24, GpioDirection_Output, GpioValue_Low}, + {0x34, GpioDirection_Input, GpioValue_Low}, + {0x25, GpioDirection_Input, GpioValue_Low}, + {0x26, GpioDirection_Input, GpioValue_Low}, + {0x27, GpioDirection_Input, GpioValue_Low}, + {0x2B, GpioDirection_Output, GpioValue_Low}, + {0x28, GpioDirection_Input, GpioValue_High}, + {0x1F, GpioDirection_Output, GpioValue_Low}, + {0x29, GpioDirection_Input, GpioValue_High}, + {0x3A, GpioDirection_Output, GpioValue_Low}, + {0x0C, GpioDirection_Input, GpioValue_Low}, + {0x2D, GpioDirection_Output, GpioValue_Low}, + {0x2E, GpioDirection_Output, GpioValue_Low}, + {0x37, GpioDirection_Input, GpioValue_Low}, + {0x2F, GpioDirection_Output, GpioValue_Low}, + {0x03, GpioDirection_Output, GpioValue_Low}, + {0x30, GpioDirection_Input, GpioValue_Low}, + {0x3B, GpioDirection_Input, GpioValue_Low}, + {0x31, GpioDirection_Output, GpioValue_Low}, + {0x32, GpioDirection_Output, GpioValue_Low}, + {0x33, GpioDirection_Output, GpioValue_Low}, + {0x35, GpioDirection_Input, GpioValue_High}, + {0x2C, GpioDirection_Output, GpioValue_Low}, + {0x36, GpioDirection_Output, GpioValue_Low}, + +}; + +static constexpr u32 GpioNumInitialConfigsHoag = (sizeof(GpioInitialConfigsHoag) / sizeof(GpioInitialConfigsHoag[0])); diff --git a/stratosphere/boot/source/boot_gpio_initial_configuration_icosa.hpp b/stratosphere/boot/source/boot_gpio_initial_configuration_icosa.hpp new file mode 100644 index 000000000..351f990d2 --- /dev/null +++ b/stratosphere/boot/source/boot_gpio_initial_configuration_icosa.hpp @@ -0,0 +1,150 @@ +/* + * 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 "boot_types.hpp" + +static constexpr GpioInitialConfig GpioInitialConfigsIcosa[] = { + {0x04, GpioDirection_Input, GpioValue_High}, + {0x05, GpioDirection_Output, GpioValue_Low}, + {0x06, GpioDirection_Input, GpioValue_Low}, + {0x02, GpioDirection_Output, GpioValue_Low}, + {0x07, GpioDirection_Output, GpioValue_Low}, + {0x3C, GpioDirection_Input, GpioValue_Low}, + {0x0F, GpioDirection_Input, GpioValue_High}, + {0x08, GpioDirection_Input, GpioValue_Low}, + {0x09, GpioDirection_Input, GpioValue_Low}, + {0x0A, GpioDirection_Output, GpioValue_Low}, + {0x0B, GpioDirection_Input, GpioValue_High}, + {0x0D, GpioDirection_Output, GpioValue_Low}, + {0x0E, GpioDirection_Input, GpioValue_Low}, + {0x10, GpioDirection_Input, GpioValue_Low}, + {0x11, GpioDirection_Input, GpioValue_Low}, + {0x12, GpioDirection_Input, GpioValue_Low}, + {0x13, GpioDirection_Input, GpioValue_Low}, + {0x14, GpioDirection_Input, GpioValue_High}, + {0x16, GpioDirection_Input, GpioValue_Low}, + {0x15, GpioDirection_Input, GpioValue_Low}, + {0x17, GpioDirection_Input, GpioValue_High}, + {0x18, GpioDirection_Input, GpioValue_Low}, + {0x19, GpioDirection_Input, GpioValue_High}, + {0x1A, GpioDirection_Input, GpioValue_High}, + {0x1B, GpioDirection_Input, GpioValue_High}, + {0x1C, GpioDirection_Input, GpioValue_Low}, + {0x1D, GpioDirection_Output, GpioValue_Low}, + {0x1E, GpioDirection_Output, GpioValue_Low}, + {0x20, GpioDirection_Output, GpioValue_Low}, + {0x21, GpioDirection_Input, GpioValue_High}, + {0x38, GpioDirection_Input, GpioValue_High}, + {0x22, GpioDirection_Input, GpioValue_Low}, + {0x23, GpioDirection_Input, GpioValue_High}, + {0x01, GpioDirection_Output, GpioValue_Low}, + {0x39, GpioDirection_Output, GpioValue_Low}, + {0x24, GpioDirection_Output, GpioValue_Low}, + {0x34, GpioDirection_Input, GpioValue_Low}, + {0x25, GpioDirection_Input, GpioValue_Low}, + {0x26, GpioDirection_Input, GpioValue_Low}, + {0x27, GpioDirection_Input, GpioValue_Low}, + {0x2B, GpioDirection_Output, GpioValue_Low}, + {0x28, GpioDirection_Input, GpioValue_High}, + {0x1F, GpioDirection_Output, GpioValue_Low}, + {0x29, GpioDirection_Input, GpioValue_High}, + {0x2A, GpioDirection_Input, GpioValue_High}, + {0x3A, GpioDirection_Output, GpioValue_Low}, + {0x0C, GpioDirection_Input, GpioValue_Low}, + {0x2D, GpioDirection_Output, GpioValue_Low}, + {0x2E, GpioDirection_Output, GpioValue_Low}, + {0x37, GpioDirection_Input, GpioValue_Low}, + {0x2F, GpioDirection_Output, GpioValue_Low}, + {0x03, GpioDirection_Output, GpioValue_Low}, + {0x30, GpioDirection_Input, GpioValue_Low}, + {0x3B, GpioDirection_Input, GpioValue_Low}, + {0x31, GpioDirection_Output, GpioValue_Low}, + {0x32, GpioDirection_Output, GpioValue_Low}, + {0x33, GpioDirection_Output, GpioValue_Low}, + {0x35, GpioDirection_Input, GpioValue_High}, + {0x2C, GpioDirection_Output, GpioValue_Low}, + {0x36, GpioDirection_Output, GpioValue_Low}, +}; + +static constexpr u32 GpioNumInitialConfigsIcosa = (sizeof(GpioInitialConfigsIcosa) / sizeof(GpioInitialConfigsIcosa[0])); + +static constexpr GpioInitialConfig GpioInitialConfigsIcosa4x[] = { + {0x04, GpioDirection_Input, GpioValue_High}, + {0x05, GpioDirection_Output, GpioValue_Low}, + {0x06, GpioDirection_Input, GpioValue_Low}, + {0x02, GpioDirection_Output, GpioValue_Low}, + {0x07, GpioDirection_Output, GpioValue_Low}, + {0x3C, GpioDirection_Input, GpioValue_Low}, + {0x0F, GpioDirection_Input, GpioValue_High}, + {0x08, GpioDirection_Input, GpioValue_Low}, + {0x09, GpioDirection_Input, GpioValue_Low}, + {0x0A, GpioDirection_Output, GpioValue_Low}, + {0x0B, GpioDirection_Input, GpioValue_High}, + {0x0D, GpioDirection_Output, GpioValue_Low}, + {0x0E, GpioDirection_Input, GpioValue_Low}, + {0x10, GpioDirection_Input, GpioValue_Low}, + {0x11, GpioDirection_Input, GpioValue_Low}, + {0x12, GpioDirection_Input, GpioValue_Low}, + {0x13, GpioDirection_Input, GpioValue_Low}, + {0x14, GpioDirection_Input, GpioValue_High}, + {0x16, GpioDirection_Input, GpioValue_Low}, + {0x15, GpioDirection_Input, GpioValue_Low}, + {0x17, GpioDirection_Input, GpioValue_High}, + {0x18, GpioDirection_Input, GpioValue_High}, + {0x19, GpioDirection_Input, GpioValue_High}, + {0x1A, GpioDirection_Input, GpioValue_High}, + {0x1B, GpioDirection_Input, GpioValue_High}, + {0x1C, GpioDirection_Input, GpioValue_Low}, + {0x1D, GpioDirection_Output, GpioValue_Low}, + {0x1E, GpioDirection_Output, GpioValue_Low}, + {0x20, GpioDirection_Output, GpioValue_Low}, + {0x21, GpioDirection_Input, GpioValue_High}, + {0x38, GpioDirection_Input, GpioValue_High}, + {0x22, GpioDirection_Input, GpioValue_Low}, + {0x23, GpioDirection_Input, GpioValue_High}, + {0x01, GpioDirection_Output, GpioValue_Low}, + {0x39, GpioDirection_Output, GpioValue_Low}, + {0x24, GpioDirection_Output, GpioValue_Low}, + {0x34, GpioDirection_Input, GpioValue_Low}, + {0x25, GpioDirection_Input, GpioValue_Low}, + {0x26, GpioDirection_Input, GpioValue_Low}, + {0x27, GpioDirection_Input, GpioValue_Low}, + {0x2B, GpioDirection_Output, GpioValue_Low}, + {0x28, GpioDirection_Input, GpioValue_High}, + {0x1F, GpioDirection_Output, GpioValue_Low}, + {0x29, GpioDirection_Input, GpioValue_High}, + {0x2A, GpioDirection_Input, GpioValue_High}, + {0x3A, GpioDirection_Output, GpioValue_Low}, + {0x0C, GpioDirection_Input, GpioValue_Low}, + {0x2D, GpioDirection_Output, GpioValue_Low}, + {0x2E, GpioDirection_Output, GpioValue_Low}, + {0x37, GpioDirection_Input, GpioValue_Low}, + {0x2F, GpioDirection_Output, GpioValue_Low}, + {0x03, GpioDirection_Output, GpioValue_Low}, + {0x30, GpioDirection_Input, GpioValue_Low}, + {0x3B, GpioDirection_Input, GpioValue_Low}, + {0x31, GpioDirection_Output, GpioValue_Low}, + {0x32, GpioDirection_Output, GpioValue_Low}, + {0x33, GpioDirection_Output, GpioValue_Low}, + {0x35, GpioDirection_Input, GpioValue_High}, + {0x2C, GpioDirection_Output, GpioValue_Low}, + {0x36, GpioDirection_Output, GpioValue_Low}, +}; + +static constexpr u32 GpioNumInitialConfigsIcosa4x = (sizeof(GpioInitialConfigsIcosa4x) / sizeof(GpioInitialConfigsIcosa4x[0])); diff --git a/stratosphere/boot/source/boot_gpio_initial_configuration_iowa.hpp b/stratosphere/boot/source/boot_gpio_initial_configuration_iowa.hpp new file mode 100644 index 000000000..4b91f99ce --- /dev/null +++ b/stratosphere/boot/source/boot_gpio_initial_configuration_iowa.hpp @@ -0,0 +1,84 @@ +/* + * 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 "boot_types.hpp" + +static constexpr GpioInitialConfig GpioInitialConfigsIowa[] = { + {0x04, GpioDirection_Input, GpioValue_High}, + {0x05, GpioDirection_Output, GpioValue_Low}, + {0x06, GpioDirection_Input, GpioValue_Low}, + {0x02, GpioDirection_Output, GpioValue_Low}, + {0x3C, GpioDirection_Input, GpioValue_Low}, + {0x0F, GpioDirection_Input, GpioValue_High}, + {0x08, GpioDirection_Input, GpioValue_Low}, + {0x09, GpioDirection_Input, GpioValue_Low}, + {0x0A, GpioDirection_Output, GpioValue_Low}, + {0x0B, GpioDirection_Input, GpioValue_Low}, + {0x0D, GpioDirection_Output, GpioValue_Low}, + {0x0E, GpioDirection_Input, GpioValue_Low}, + {0x10, GpioDirection_Input, GpioValue_Low}, + {0x11, GpioDirection_Input, GpioValue_Low}, + {0x12, GpioDirection_Input, GpioValue_Low}, + {0x13, GpioDirection_Input, GpioValue_Low}, + {0x14, GpioDirection_Input, GpioValue_High}, + {0x16, GpioDirection_Input, GpioValue_Low}, + {0x15, GpioDirection_Input, GpioValue_Low}, + {0x17, GpioDirection_Input, GpioValue_High}, + {0x18, GpioDirection_Input, GpioValue_Low}, + {0x19, GpioDirection_Input, GpioValue_High}, + {0x1A, GpioDirection_Input, GpioValue_High}, + {0x1B, GpioDirection_Input, GpioValue_Low}, + {0x1C, GpioDirection_Input, GpioValue_Low}, + {0x1D, GpioDirection_Output, GpioValue_Low}, + {0x1E, GpioDirection_Output, GpioValue_Low}, + {0x20, GpioDirection_Output, GpioValue_Low}, + {0x21, GpioDirection_Input, GpioValue_Low}, + {0x38, GpioDirection_Input, GpioValue_High}, + {0x22, GpioDirection_Input, GpioValue_Low}, + {0x23, GpioDirection_Input, GpioValue_High}, + {0x01, GpioDirection_Output, GpioValue_Low}, + {0x39, GpioDirection_Output, GpioValue_Low}, + {0x24, GpioDirection_Output, GpioValue_Low}, + {0x34, GpioDirection_Input, GpioValue_Low}, + {0x25, GpioDirection_Input, GpioValue_Low}, + {0x26, GpioDirection_Input, GpioValue_Low}, + {0x27, GpioDirection_Input, GpioValue_Low}, + {0x2B, GpioDirection_Output, GpioValue_Low}, + {0x28, GpioDirection_Input, GpioValue_High}, + {0x1F, GpioDirection_Output, GpioValue_Low}, + {0x29, GpioDirection_Input, GpioValue_High}, + {0x3A, GpioDirection_Output, GpioValue_Low}, + {0x0C, GpioDirection_Input, GpioValue_Low}, + {0x2D, GpioDirection_Output, GpioValue_Low}, + {0x2E, GpioDirection_Output, GpioValue_Low}, + {0x37, GpioDirection_Input, GpioValue_Low}, + {0x2F, GpioDirection_Output, GpioValue_Low}, + {0x03, GpioDirection_Output, GpioValue_Low}, + {0x30, GpioDirection_Input, GpioValue_Low}, + {0x3B, GpioDirection_Input, GpioValue_Low}, + {0x31, GpioDirection_Output, GpioValue_Low}, + {0x32, GpioDirection_Output, GpioValue_Low}, + {0x33, GpioDirection_Output, GpioValue_Low}, + {0x35, GpioDirection_Input, GpioValue_High}, + {0x2C, GpioDirection_Output, GpioValue_Low}, + {0x36, GpioDirection_Output, GpioValue_Low}, + +}; + +static constexpr u32 GpioNumInitialConfigsIowa = (sizeof(GpioInitialConfigsIowa) / sizeof(GpioInitialConfigsIowa[0])); diff --git a/stratosphere/boot/source/boot_gpio_map.hpp b/stratosphere/boot/source/boot_gpio_map.hpp new file mode 100644 index 000000000..e89e2de53 --- /dev/null +++ b/stratosphere/boot/source/boot_gpio_map.hpp @@ -0,0 +1,111 @@ +/* + * 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 + +static constexpr u32 GpioInvalid = UINT32_MAX; + +static constexpr u32 GpioMap[] = { + GpioInvalid, /* Invalid */ + 0x000000CC, /* Port Z, Pin 4 */ + 0x00000024, /* Port E, Pin 4 */ + 0x0000003C, /* Port H, Pin 4 */ + 0x000000DA, /* Port BB, Pin 2 */ + 0x000000DB, /* Port BB, Pin 3 */ + 0x000000DC, /* Port BB, Pin 4 */ + 0x00000025, /* Port E, Pin 5 */ + 0x00000090, /* Port S, Pin 0 */ + 0x00000091, /* Port S, Pin 1 */ + 0x00000096, /* Port S, Pin 6 */ + 0x00000097, /* Port S, Pin 7 */ + 0x00000026, /* Port E, Pin 6 */ + 0x00000005, /* Port A, Pin 5 */ + 0x00000078, /* Port P, Pin 0 */ + 0x00000093, /* Port S, Pin 3 */ + 0x0000007D, /* Port P, Pin 5 */ + 0x0000007C, /* Port P, Pin 4 */ + 0x0000007B, /* Port P, Pin 3 */ + 0x0000007A, /* Port P, Pin 2 */ + 0x000000BC, /* Port X, Pin 4 */ + 0x000000AE, /* Port V, Pin 6 */ + 0x000000BA, /* Port X, Pin 2 */ + 0x000000B9, /* Port X, Pin 1 */ + 0x000000BD, /* Port X, Pin 5 */ + 0x000000BE, /* Port X, Pin 6 */ + 0x000000BF, /* Port X, Pin 7 */ + 0x000000C0, /* Port Y, Pin 0 */ + 0x000000C1, /* Port Y, Pin 1 */ + 0x000000A9, /* Port V, Pin 1 */ + 0x000000AA, /* Port V, Pin 2 */ + 0x00000055, /* Port K, Pin 5 */ + 0x000000AD, /* Port V, Pin 5 */ + 0x000000C8, /* Port Z, Pin 0 */ + 0x000000CA, /* Port Z, Pin 2 */ + 0x000000CB, /* Port Z, Pin 3 */ + 0x0000004F, /* Port J, Pin 7 */ + 0x00000050, /* Port K, Pin 0 */ + 0x00000051, /* Port K, Pin 1 */ + 0x00000052, /* Port K, Pin 2 */ + 0x00000054, /* Port K, Pin 4 */ + 0x00000056, /* Port K, Pin 6 */ + 0x00000057, /* Port K, Pin 7 */ + 0x00000053, /* Port K, Pin 3 */ + 0x000000E3, /* Port CC, Pin 3 */ + 0x00000038, /* Port H, Pin 0 */ + 0x00000039, /* Port H, Pin 1 */ + 0x0000003B, /* Port H, Pin 3 */ + 0x0000003D, /* Port H, Pin 5 */ + 0x0000003F, /* Port H, Pin 7 */ + 0x00000040, /* Port I, Pin 0 */ + 0x00000041, /* Port I, Pin 1 */ + 0x0000003E, /* Port H, Pin 6 */ + 0x000000E2, /* Port CC, Pin 2 */ + 0x000000E4, /* Port CC, Pin 4 */ + 0x0000003A, /* Port H, Pin 2 */ + 0x000000C9, /* Port Z, Pin 1 */ + 0x0000004D, /* Port J, Pin 5 */ + 0x00000058, /* Port L, Pin 0 */ + 0x0000003E, /* Port H, Pin 6 */ + 0x00000026, /* Port E, Pin 6 */ + + /* Copper only */ + GpioInvalid, /* Invalid */ + 0x00000033, /* Port G, Pin 3 */ + 0x0000001C, /* Port D, Pin 4 */ + 0x000000D9, /* Port BB, Pin 1 */ + 0x0000000C, /* Port B, Pin 4 */ + 0x0000000D, /* Port B, Pin 5 */ + 0x00000021, /* Port E, Pin 1 */ + 0x00000027, /* Port E, Pin 7 */ + 0x00000092, /* Port S, Pin 2 */ + 0x00000095, /* Port S, Pin 5 */ + 0x00000098, /* Port T, Pin 0 */ + 0x00000010, /* Port C, Pin 0 */ + 0x00000011, /* Port C, Pin 1 */ + 0x00000012, /* Port C, Pin 2 */ + 0x00000042, /* Port I, Pin 2 */ + 0x000000E6, /* Port CC, Pin 6 */ + + /* 2.0.0+ Copper only */ + 0x000000AC, /* Port V, Pin 4 */ + 0x000000E1, /* Port CC, Pin 1 */ + + /* 5.0.0+ Copper only (unused) */ + 0x00000056, /* Port K, Pin 6 */ +}; + +static constexpr u32 GpioPadNameMax = (sizeof(GpioMap) / sizeof(GpioMap[0])); diff --git a/stratosphere/boot/source/boot_gpio_utils.cpp b/stratosphere/boot/source/boot_gpio_utils.cpp new file mode 100644 index 000000000..0ce420275 --- /dev/null +++ b/stratosphere/boot/source/boot_gpio_utils.cpp @@ -0,0 +1,119 @@ +/* + * 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" +#include "boot_gpio_map.hpp" + +static bool g_initialized_gpio_vaddr = false; +static void *g_gpio_vaddr = nullptr; + +static inline u32 GetGpioPadDescriptor(u32 gpio_pad_name) { + if (gpio_pad_name >= GpioPadNameMax) { + std::abort(); + } + + return GpioMap[gpio_pad_name]; +} + +static void *GetGpioBaseAddress() { + if (!g_initialized_gpio_vaddr) { + u64 vaddr; + if (R_FAILED(svcQueryIoMapping(&vaddr, Boot::GpioPhysicalBase, 0x1000))) { + std::abort(); + } + g_gpio_vaddr = reinterpret_cast(g_gpio_vaddr); + g_initialized_gpio_vaddr = true; + } + return g_gpio_vaddr; +} + +u32 Boot::GpioConfigure(u32 gpio_pad_name) { + void *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(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(gpio_base_vaddr) + gpio_reg_offset); + + return gpio_cnf_val; +} + +u32 Boot::GpioSetDirection(u32 gpio_pad_name, GpioDirection dir) { + void *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(dir) << (gpio_pad_desc & 0x07))); + + /* Write to the appropriate GPIO_OE_x register (upper offset) */ + *(reinterpret_cast(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(gpio_base_vaddr) + gpio_reg_offset); + + return gpio_oe_val; +} + +u32 Boot::GpioSetValue(u32 gpio_pad_name, GpioValue val) { + void *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(val) << (gpio_pad_desc & 0x07))); + + /* Write to the appropriate GPIO_OUT_x register (upper offset) */ + *(reinterpret_cast(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(gpio_base_vaddr) + gpio_reg_offset); + + return gpio_out_val; +} diff --git a/stratosphere/boot/source/boot_main.cpp b/stratosphere/boot/source/boot_main.cpp index 42eeda584..f5dad1a7f 100644 --- a/stratosphere/boot/source/boot_main.cpp +++ b/stratosphere/boot/source/boot_main.cpp @@ -107,7 +107,8 @@ int main(int argc, char **argv) /* Change voltage from 3.3v to 1.8v for select devices. */ Boot::ChangeGpioVoltageTo1_8v(); - /* TODO: SetInitialGpioConfiguration(); */ + /* Setup GPIO. */ + Boot::SetInitialGpioConfiguration(); /* TODO: CheckClock(); */ diff --git a/stratosphere/boot/source/boot_spl_utils.cpp b/stratosphere/boot/source/boot_spl_utils.cpp new file mode 100644 index 000000000..2602deb3c --- /dev/null +++ b/stratosphere/boot/source/boot_spl_utils.cpp @@ -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 . + */ + +#include "boot_functions.hpp" + +HardwareType Boot::GetHardwareType() { + u64 out_val = 0; + if (R_FAILED(splGetConfig(SplConfigItem_HardwareType, &out_val))) { + std::abort(); + } + return static_cast(out_val); +} diff --git a/stratosphere/boot/source/boot_types.hpp b/stratosphere/boot/source/boot_types.hpp new file mode 100644 index 000000000..2e5608055 --- /dev/null +++ b/stratosphere/boot/source/boot_types.hpp @@ -0,0 +1,32 @@ +/* + * 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 + +enum HardwareType { + HardwareType_Icosa = 0, + HardwareType_Copper = 1, + HardwareType_Hoag = 2, + HardwareType_Iowa = 3, +}; + +struct GpioInitialConfig { + u32 pad_name; + GpioDirection direction; + GpioValue value; +};