mirror of
				https://github.com/Atmosphere-NX/Atmosphere.git
				synced 2025-10-31 11:15:51 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			100 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			100 lines
		
	
	
		
			7.0 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));
 | |
|         }
 | |
|     }
 | |
| 
 | |
| }
 |