mirror of
				https://github.com/Atmosphere-NX/Atmosphere-libs.git
				synced 2025-10-31 03:25:47 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			114 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			4.4 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 <stratosphere.hpp>
 | |
| 
 | |
| namespace ams::wec {
 | |
| 
 | |
|     /* TODO: How much of this should be namespaced under BOARD_NINTENDO_NX? */
 | |
|     #if defined(ATMOSPHERE_BOARD_NINTENDO_NX)
 | |
|     namespace {
 | |
| 
 | |
|         constexpr inline dd::PhysicalAddress ApbdevPmc = 0x7000E400;
 | |
| 
 | |
|         constinit bool g_initialized = false;
 | |
| 
 | |
|         void UpdateControlBit(dd::PhysicalAddress phys_addr, u32 mask, bool flag) {
 | |
|             dd::ReadModifyWriteIoRegister(phys_addr, flag ? ~0u : 0u, mask);
 | |
|             dd::ReadIoRegister(phys_addr);
 | |
|         }
 | |
| 
 | |
|         void Initialize(bool blink) {
 | |
|             /* Initialize WAKE_DEBOUNCE_EN. */
 | |
|             dd::WriteIoRegister(ApbdevPmc + APBDEV_PMC_WAKE_DEBOUNCE_EN, 0);
 | |
|             dd::ReadIoRegister(ApbdevPmc + APBDEV_PMC_WAKE_DEBOUNCE_EN);
 | |
| 
 | |
|             /* Initialize BLINK_TIMER. */
 | |
|             dd::WriteIoRegister(ApbdevPmc + APBDEV_PMC_BLINK_TIMER, 0x08008800);
 | |
|             dd::ReadIoRegister(ApbdevPmc + APBDEV_PMC_BLINK_TIMER);
 | |
| 
 | |
|             /* Set control configs. */
 | |
|             UpdateControlBit(ApbdevPmc + APBDEV_PMC_CNTRL,  0x0800,  true);
 | |
|             UpdateControlBit(ApbdevPmc + APBDEV_PMC_CNTRL,  0x0400, false);
 | |
|             UpdateControlBit(ApbdevPmc + APBDEV_PMC_CNTRL,  0x0200,  true);
 | |
|             UpdateControlBit(ApbdevPmc + APBDEV_PMC_CNTRL,  0x0100, false);
 | |
|             UpdateControlBit(ApbdevPmc + APBDEV_PMC_CNTRL,  0x0040, false);
 | |
|             UpdateControlBit(ApbdevPmc + APBDEV_PMC_CNTRL,  0x0020, false);
 | |
|             UpdateControlBit(ApbdevPmc + APBDEV_PMC_CNTRL2, 0x4000,  true);
 | |
|             UpdateControlBit(ApbdevPmc + APBDEV_PMC_CNTRL2, 0x0200, false);
 | |
|             UpdateControlBit(ApbdevPmc + APBDEV_PMC_CNTRL2, 0x0001,  true);
 | |
| 
 | |
|             /* Update blink bit in APBDEV_PMC_CNTRL. */
 | |
|             UpdateControlBit(ApbdevPmc + APBDEV_PMC_CNTRL,  0x0080, blink);
 | |
| 
 | |
|             /* Update blink bit in APBDEV_PMC_DPD_PADS_ORIDE. */
 | |
|             UpdateControlBit(ApbdevPmc + APBDEV_PMC_DPD_PADS_ORIDE, 0x100000, blink);
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     void Initialize() {
 | |
|         /* Set initial wake configuration. */
 | |
|         if (!g_initialized) {
 | |
|             Initialize(false);
 | |
|             g_initialized = true;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void ClearWakeEvents() {
 | |
|         /* TODO */
 | |
|         AMS_ABORT();
 | |
|     }
 | |
| 
 | |
|     void WecRestoreForExitSuspend() {
 | |
|         /* TODO */
 | |
|         AMS_ABORT();
 | |
|     }
 | |
| 
 | |
|     void SetWakeEventLevel(wec::WakeEvent event, wec::WakeEventLevel level) {
 | |
|         if (g_initialized && event < wec::WakeEvent_Count) {
 | |
|             /* Determine the event index. */
 | |
|             const bool which = static_cast<u32>(event) < BITSIZEOF(u32);
 | |
|             const u32  index = static_cast<u32>(event) & (BITSIZEOF(u32) - 1);
 | |
| 
 | |
|             /* Get the level and auto_mask offsets. */
 | |
|             u32 level_ofs     = which ? APBDEV_PMC_WAKE_LVL : APBDEV_PMC_WAKE2_LVL;
 | |
|             u32 auto_mask_ofs = which ? APBDEV_PMC_AUTO_WAKE_LVL_MASK : APBDEV_PMC_AUTO_WAKE2_LVL_MASK;
 | |
| 
 | |
|             /* If the level isn't auto, swap the offsets. */
 | |
|             if (level != wec::WakeEventLevel_Auto) {
 | |
|                 std::swap(level_ofs, auto_mask_ofs);
 | |
|             }
 | |
| 
 | |
|             /* Clear the bit in the level register. */
 | |
|             UpdateControlBit(ApbdevPmc + level_ofs, (1u << index), false);
 | |
| 
 | |
|             /* Set or clear the bit in the auto mask register. */
 | |
|             UpdateControlBit(ApbdevPmc + auto_mask_ofs, (1u << index), level != wec::WakeEventLevel_Low);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void SetWakeEventEnabled(wec::WakeEvent event, bool en) {
 | |
|         if (g_initialized && event < wec::WakeEvent_Count) {
 | |
|             /* Set or clear the relevant enabled bit. */
 | |
|             const u32 offset = static_cast<u32>(event) < BITSIZEOF(u32) ? APBDEV_PMC_WAKE_MASK : APBDEV_PMC_WAKE2_MASK;
 | |
|             const u32 index  = static_cast<u32>(event) & (BITSIZEOF(u32) - 1);
 | |
|             UpdateControlBit(ApbdevPmc + offset, (1u << index), en);
 | |
|         }
 | |
|     }
 | |
|     #endif
 | |
| 
 | |
| }
 |