#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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 "types.h"
#include "mem_map.h"
#include "arm.h"
#define CPU_II_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x100)
#define REG_CPU_II_CNT *((vu32*)(CPU_II_REGS_BASE + 0x00))
#define REG_CPU_II_MASK *((vu32*)(CPU_II_REGS_BASE + 0x04))
#define REG_CPU_II_BIN_POI *((vu32*)(CPU_II_REGS_BASE + 0x08))
#define REG_CPU_II_AKN *((vu32*)(CPU_II_REGS_BASE + 0x0C))
#define REG_CPU_II_EOI *((vu32*)(CPU_II_REGS_BASE + 0x10))
#define REG_CPU_II_RUN_PRIO *((vu32*)(CPU_II_REGS_BASE + 0x14))
#define REG_CPU_II_HIGH_PEN *((vu32*)(CPU_II_REGS_BASE + 0x18))
#define GID_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x1000)
#define REG_GID_CNT *((vu32*)(GID_REGS_BASE + 0x000))
#define REG_GID_CONTR_TYPE *((vu32*)(GID_REGS_BASE + 0x004))
#define REGs_GID_ENA_SET ((vu32*)(GID_REGS_BASE + 0x100))
#define REGs_GID_ENA_CLR ((vu32*)(GID_REGS_BASE + 0x180))
#define REGs_GID_PEN_SET ((vu32*)(GID_REGS_BASE + 0x200))
#define REGs_GID_PEN_CLR ((vu32*)(GID_REGS_BASE + 0x280))
#define REGs_GID_ACTIVE_BIT ((vu32*)(GID_REGS_BASE + 0x300))
#define REGs_GID_IPRIO ((vu32*)(GID_REGS_BASE + 0x400))
#define REGs_GID_ITARG ((vu32*)(GID_REGS_BASE + 0x800))
#define REGs_GID_ICONF ((vu32*)(GID_REGS_BASE + 0xC00))
#define REGs_GID_LINE_LEV ((vu32*)(GID_REGS_BASE + 0xD00))
#define REG_GID_SW_INT *((vu32*)(GID_REGS_BASE + 0xF00))
#define REG_GID_PERI_INFO0 *((vu32*)(GID_REGS_BASE + 0xFE0))
#define REG_GID_PERI_INFO1 *((vu32*)(GID_REGS_BASE + 0xFE4))
#define REG_GID_PERI_INFO2 *((vu32*)(GID_REGS_BASE + 0xFE8))
#define REG_GID_PERI_INFO3 *((vu32*)(GID_REGS_BASE + 0xFEC))
#define REG_GID_PRIME_CELL0 *((vu32*)(GID_REGS_BASE + 0xFF0))
#define REG_GID_PRIME_CELL1 *((vu32*)(GID_REGS_BASE + 0xFF4))
#define REG_GID_PRIME_CELL2 *((vu32*)(GID_REGS_BASE + 0xFF8))
#define REG_GID_PRIME_CELL3 *((vu32*)(GID_REGS_BASE + 0xFFC))
typedef enum
{
IRQ_MPCORE_SW0 = 0u,
IRQ_MPCORE_SW1 = 1u,
IRQ_MPCORE_SW2 = 2u,
IRQ_MPCORE_SW3 = 3u,
IRQ_MPCORE_SW4 = 4u,
IRQ_MPCORE_SW5 = 5u,
IRQ_MPCORE_SW6 = 6u,
IRQ_MPCORE_SW7 = 7u,
IRQ_MPCORE_SW8 = 8u,
IRQ_MPCORE_SW9 = 9u,
IRQ_MPCORE_SW10 = 10u,
IRQ_MPCORE_SW11 = 11u,
IRQ_MPCORE_SW12 = 12u,
IRQ_MPCORE_SW13 = 13u,
IRQ_MPCORE_SW14 = 14u,
IRQ_MPCORE_SW15 = 15u,
IRQ_TIMER = 29u, // MPCore timer
IRQ_WATCHDOG = 30u, // MPCore watchdog
IRQ_SPI2 = 36u, // SPI bus 2 interrupt status update
IRQ_PSC0 = 40u,
IRQ_PSC1 = 41u,
IRQ_PDC0 = 42u, // aka VBlank0
IRQ_PDC1 = 43u, // aka VBlank1
IRQ_PPF = 44u,
IRQ_P3D = 45u,
IRQ_CDMA_EVENT0 = 48u, // Old 3DS CDMA
IRQ_CDMA_EVENT1 = 49u, // Old 3DS CDMA
IRQ_CDMA_EVENT2 = 50u, // Old 3DS CDMA
IRQ_CDMA_EVENT3 = 51u, // Old 3DS CDMA
IRQ_CDMA_EVENT4 = 52u, // Old 3DS CDMA
IRQ_CDMA_EVENT5 = 53u, // Old 3DS CDMA
IRQ_CDMA_EVENT6 = 54u, // Old 3DS CDMA
IRQ_CDMA_EVENT7 = 55u, // Old 3DS CDMA
IRQ_CDMA_EVENT8 = 56u, // Old 3DS CDMA
IRQ_CDMA_FAULT = 57u, // Old 3DS CDMA
IRQ_CDMA2_EVENT = 58u, // New 3DS CDMA
IRQ_CDMA2_FAULT = 59u, // New 3DS CDMA
IRQ_SDIO = 64u, // SDIO controller (WiFi)
IRQ_SDIO_IRQ = 65u, // SDIO IRQ pin (WiFi)
IRQ_CAM0 = 72u, // Camera 0 (DSi)
IRQ_CAM1 = 73u, // Camera 1 (left eye)
IRQ_LGYFB_BOT = 76u, // Legacy framebuffer bottom screen
IRQ_LGYFB_TOP = 77u, // Legacy framebuffer top screen
IRQ_PXI_SYNC = 80u,
IRQ_PXI_SYNC2 = 81u,
IRQ_PXI_NOT_FULL = 82u,
IRQ_PXI_NOT_EMPTY = 83u,
IRQ_I2C1 = 84u,
IRQ_I2C2 = 85u,
IRQ_SPI3 = 86u, // SPI bus 3 interrupt status update
IRQ_SPI1 = 87u, // SPI bus 1 interrupt status update
IRQ_PDN = 88u,
IRQ_LGY_SLEEP = 89u, // Triggers if legacy mode enters sleep.
IRQ_HID_PADCNT = 91u,
IRQ_I2C3 = 92u,
IRQ_GPIO_1_2 = 96u,
IRQ_SHELL_CLOSED = 98u, // GPIO_1_0?
IRQ_GPIO_1_1 = 99u,
IRQ_GPIO_2_0 = 100u,
IRQ_GPIO_2_1 = 102u,
IRQ_GPIO_4_0 = 104u,
IRQ_GPIO_4_1 = 105u,
IRQ_GPIO_4_2 = 106u,
IRQ_GPIO_4_3 = 107u,
IRQ_GPIO_4_4 = 108u,
IRQ_GPIO_4_5 = 109u,
IRQ_GPIO_4_6 = 110u,
IRQ_GPIO_4_7 = 111u,
IRQ_GPIO_4_8 = 112u,
IRQ_GPIO_4_9 = 113u,
IRQ_GPIO_4_10 = 114u,
IRQ_GPIO_4_11 = 115u,
IRQ_GAMECARD = 117u, // Gamecard inserted
IRQ_PERF_MONITOR0 = 120u, // Core 0 performance monitor. Triggers on any counter overflow
IRQ_PERF_MONITOR1 = 121u, // Core 1 performance monitor. Triggers on any counter overflow
IRQ_PERF_MONITOR2 = 122u, // Unconfirmed. Core 2 performance monitor. Triggers on any counter overflow
IRQ_PERF_MONITOR3 = 123u, // Unconfirmed. Core 3 performance monitor. Triggers on any counter overflow
// Aliases
IRQ_SHELL_OPENED = IRQ_GPIO_1_2,
IRQ_TOUCHSCREEN = IRQ_GPIO_1_1, // Triggers on touchscreen pen down.
IRQ_HEADPH_JACK = IRQ_GPIO_2_0, // Headphone jack. Triggers on both plugging in and out?
IRQ_CTR_MCU = IRQ_GPIO_4_9 // Various MCU events trigger this. See MCU interrupt mask.
} Interrupt;
// IRQ handler type.
// intSource: bit 10-12 CPU source ID (0 except for interrupt ID 0-15),
// bit 0-9 interrupt ID
typedef void (*IrqHandler)(u32 intSource);
/**
* @brief Initializes the generic interrupt controller.
*/
void IRQ_init(void);
/**
* @brief Registers a interrupt handler and enables the specified interrupt.
*
* @param[in] id The interrupt ID. Must be <128.
* @param[in] prio The priority. 0 = highest, 14 = lowest, 15 = disabled
* @param[in] cpuMask The CPU mask. Each of the 4 bits stands for 1 core. 0 means current CPU.
* @param[in] edgeTriggered Set to true to make the interrupt edge triggered. false is level triggered.
* @param[in] handler The interrupt handler to call.
*/
void IRQ_registerHandler(Interrupt id, u8 prio, u8 cpuMask, bool edgeTriggered, IrqHandler handler);
/**
* @brief Unregisters the interrupt handler and disables the specified interrupt.
*
* @param[in] id The interrupt ID. Must be <128.
*/
void IRQ_unregisterHandler(Interrupt id);
/**
* @brief Reenables a previously disabled but registered interrupt.
*
* @param[in] id The interrupt ID. Must be <128.
*/
void IRQ_enable(Interrupt id);
/**
* @brief Disables a previously registered interrupt temporarily.
*
* @param[in] id The interrupt ID. Must be <128.
*/
void IRQ_disable(Interrupt id);
/**
* @brief Sets the priority of an interrupt.
*
* @param[in] id The interrupt ID. Must be <128.
* @param[in] prio The priority. 0 = highest, 14 = lowest, 15 = disabled
*/
void IRQ_setPriority(Interrupt id, u8 prio);
/**
* @brief Triggers a software interrupt for the specified CPUs.
*
* @param[in] id The interrupt ID. Must be <16.
* @param[in] cpuMask The CPU mask. Each of the 4 bits stands for 1 core.
*/
void IRQ_softwareInterrupt(Interrupt id, u8 cpuMask);
static inline u32 enterCriticalSection(void)
{
const u32 tmp = __getCpsr();
__cpsid(i);
return tmp & PSR_I;
}
static inline void leaveCriticalSection(u32 oldState)
{
__setCpsr_c((__getCpsr() & ~PSR_I) | oldState);
}