mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-15 17:39:28 +00:00
99 lines
7 KiB
C++
99 lines
7 KiB
C++
/*
|
|
* Copyright (c) Atmosphère-NX
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include <exosphere.hpp>
|
|
#include "warmboot_clkrst.hpp"
|
|
|
|
namespace ams::warmboot {
|
|
|
|
namespace {
|
|
|
|
constexpr inline const uintptr_t CLKRST = secmon::MemoryRegionPhysicalDeviceClkRst.GetAddress();
|
|
constexpr inline const uintptr_t EMC = EMC_ADDRESS(0);
|
|
|
|
}
|
|
|
|
void ApplyMbistWorkaround() {
|
|
/* Clear all LVL2 clock gate overrides to zero. */
|
|
reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA, 0);
|
|
reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB, 0);
|
|
reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC, 0);
|
|
reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD, 0);
|
|
reg::Write(CLKRST + CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRE, 0);
|
|
|
|
/* Clear clock enable for all but a select few devices. */
|
|
auto devices_to_clear_l = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_L);
|
|
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_l), CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_RTC ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_TMR ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_GPIO ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_L_CLK_ENB_CACHE2));
|
|
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_L_CLR, devices_to_clear_l);
|
|
|
|
auto devices_to_clear_h = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_H);
|
|
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_h), CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_MEM ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_PMC ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_FUSE),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_H_CLK_ENB_EMC ));
|
|
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_H_CLR, devices_to_clear_h);
|
|
|
|
auto devices_to_clear_u = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_U);
|
|
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_u), CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_CSITE),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMA),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMB),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMC),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_IRAMD),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_U_CLK_ENB_CRAM2));
|
|
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_U_CLR, devices_to_clear_u);
|
|
|
|
auto devices_to_clear_v = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_V);
|
|
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_v), CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_MSELECT ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_SPDIF_DOUBLER),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_TZRAM ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_V_CLK_ENB_SE ));
|
|
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_V_CLR, devices_to_clear_v);
|
|
|
|
auto devices_to_clear_w = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_W);
|
|
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_w), CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX0),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX1),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX2),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX3),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX4),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_PCIERX5),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_W_CLK_ENB_ENTROPY));
|
|
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_CLR, devices_to_clear_w);
|
|
|
|
auto devices_to_clear_x = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_X);
|
|
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_x), CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_CAPA ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_CBPA ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_CPU ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_MC_BBC ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_EMC_DLL ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_GPU ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_DBGAPB ),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_X_CLK_ENB_PLLG_REF));
|
|
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_X_CLR, devices_to_clear_x);
|
|
|
|
auto devices_to_clear_y = reg::Read(CLKRST + CLK_RST_CONTROLLER_CLK_OUT_ENB_Y);
|
|
reg::ClearBits(static_cast<volatile u32 &>(devices_to_clear_y), CLK_RST_REG_BITS_MASK(CLK_ENB_Y_CLK_ENB_MC_CCPA),
|
|
CLK_RST_REG_BITS_MASK(CLK_ENB_Y_CLK_ENB_MC_CDPA));
|
|
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_Y_CLR, devices_to_clear_y);
|
|
|
|
/* If CH1 is enabled, enable clock to MC1. */
|
|
if (reg::HasValue(EMC + EMC_FBIO_CFG7, EMC_REG_BITS_ENUM(FBIO_CFG7_CH1_ENABLE, ENABLE))) {
|
|
reg::Write(CLKRST + CLK_RST_CONTROLLER_CLK_ENB_W_SET, CLK_RST_REG_BITS_ENUM(CLK_ENB_W_CLK_ENB_MC1, ENABLE));
|
|
}
|
|
}
|
|
|
|
}
|