mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
Implement driver for the GIC-400.
This commit is contained in:
parent
c94fe287cb
commit
422cd14aac
3 changed files with 148 additions and 1 deletions
98
exosphere/interrupt.c
Normal file
98
exosphere/interrupt.c
Normal file
|
@ -0,0 +1,98 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "interrupt.h"
|
||||
|
||||
/* Global of registered handlers. */
|
||||
struct {
|
||||
unsigned int id;
|
||||
void (*handler)(void);
|
||||
} g_registered_interrupts[MAX_REGISTERED_INTERRUPTS] = { {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL} };
|
||||
|
||||
/* Prototypes for internal (private) functions. */
|
||||
unsigned int get_interrupt_id(void);
|
||||
|
||||
|
||||
/* Initializes the GIC. TODO: This must be called during wakeup. */
|
||||
void intr_initialize_gic(void) {
|
||||
/* Setup interrupts 0-0x1F as nonsecure with highest non-secure priority. */
|
||||
GICD_IGROUPR[0] = 0xFFFFFFFF;
|
||||
for (unsigned int i = 0; i < 0x20; i++) {
|
||||
GICD_IPRIORITYR[i] = GIC_PRI_HIGHEST;
|
||||
}
|
||||
|
||||
/* Setup the GICC. */
|
||||
GICC_CTLR = 0x1D9;
|
||||
GICC_PMR = GIC_PRI_HIGHEST;
|
||||
GICC_BPR = 7;
|
||||
}
|
||||
|
||||
/* Sets an interrupt's group in the GICD. */
|
||||
void intr_set_group(unsigned int id, int group) {
|
||||
GICD_IGROUPR[id >> 5] = (GICD_IGROUPR[id >> 5] & (~(1 << (id & 0x1F)))) | ((group & 1) << (id & 0x1F));
|
||||
}
|
||||
|
||||
/* Sets an interrupt id as pending in the GICD. */
|
||||
void intr_set_pending(unsigned int id) {
|
||||
GICD_ISPENDR[id >> 5] = 1 << (id & 0x1F);
|
||||
}
|
||||
|
||||
/* Sets an interrupt's priority in the GICD. */
|
||||
void intr_set_priority(unsigned int id, uint8_t priority) {
|
||||
GICD_IPRIORITYR[id] = priority;
|
||||
}
|
||||
|
||||
/* Sets an interrupt's target CPU mask in the GICD. */
|
||||
void intr_set_cpu_mask(unsigned int id, uint8_t mask) {
|
||||
GICD_ITARGETSR[id] = mask;
|
||||
}
|
||||
|
||||
/* Sets an interrupt's edge/level bits in the GICD. */
|
||||
void intr_set_edge_level(unsigned int id, int edge_level) {
|
||||
GICD_ICFGR[id >> 4] = (GICD_ICFGR[id >> 4] & (~(3 << ((id & 0xF) << 1))) | (((edge_level & 1) << 1) << ((id & 0xF) << 1));
|
||||
}
|
||||
|
||||
/* Sets an interrupt's enabled status in the GICD. */
|
||||
void intr_set_enabled(unsigned int id, int enabled) {
|
||||
GICD_ISENABLER[id >> 5] = (enabled & 1) << (id & 0x1F);
|
||||
}
|
||||
|
||||
/* To be called by FIQ handler. */
|
||||
void handle_registered_interrupt(void) {
|
||||
unsigned int interrupt_id = get_interrupt_id();
|
||||
if (interrupt_id <= 0xDF) {
|
||||
bool found_handler = false;
|
||||
for (unsigned int i = 0; i < MAX_REGISTERED_INTERRUPTS; i++) {
|
||||
if (g_registered_interrupts[i].id == interrupt_id) {
|
||||
found_handler = true;
|
||||
g_registered_interrupts[i].handler();
|
||||
/* Mark that interrupt is done. */
|
||||
GICC_EOIR = interrupt_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* We must have found a handler, or something went wrong. */
|
||||
if (!found_handler) {
|
||||
panic();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Registers an interrupt into the global. */
|
||||
void intr_register_handler(unsigned int id, void (*handler)(void)) {
|
||||
bool registered_handler = false;
|
||||
for (unsigned int i = 0; i < MAX_REGISTERED_INTERRUPTS; i++) {
|
||||
if (g_registered_interrupts[i].id == 0) {
|
||||
g_registered_interrupts[i].handler = handler;
|
||||
g_registered_interrupts[i].id = id;
|
||||
registered_handler = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Failure to register is an error condition. */
|
||||
if (!registered_handler) {
|
||||
panic();
|
||||
}
|
||||
}
|
||||
|
49
exosphere/interrupt.h
Normal file
49
exosphere/interrupt.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
#ifndef EXOSPHERE_INTERRUPT_H
|
||||
#define EXOSPHERE_INTERRUPT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mmu.h"
|
||||
|
||||
/* Exosphere driver for the Tegra X1 GIC-400 registers. */
|
||||
|
||||
|
||||
#define MAX_REGISTERED_INTERRUPTS 4
|
||||
#define INTERRUPT_ID_SECURITY_ENGINE 0x5A
|
||||
|
||||
#define GICD_BASE (mmio_get_device_address(MMIO_DEVID_GICD))
|
||||
#define GICC_BASE (mmio_get_device_address(MMIO_DEVID_GICC))
|
||||
|
||||
#define GICD_IGROUPR ((volatile uint32_t *)(GICD_BASE + 0x080ULL))
|
||||
#define GICD_ISENABLER ((volatile uint32_t *)(GICD_BASE + 0x100ULL))
|
||||
#define GICD_ISPENDR ((volatile uint32_t *)(GICD_BASE + 0x200ULL))
|
||||
#define GICD_IPRIORITYR ((volatile uint8_t *)(GICD_BASE + 0x400ULL))
|
||||
#define GICD_ITARGETSR ((volatile uint8_t *)(GICD_BASE + 0x800ULL))
|
||||
#define GICD_ICFGR ((volatile uint32_t *)(GICD_BASE + 0xC00ULL))
|
||||
|
||||
#define GICC_CTLR (*((volatile uint32_t *)(GICC_BASE + 0x0000ULL)))
|
||||
#define GICC_PMR (*((volatile uint32_t *)(GICC_BASE + 0x0004ULL)))
|
||||
#define GICC_BPR (*((volatile uint32_t *)(GICC_BASE + 0x0008ULL)))
|
||||
#define GICC_IAR (*((volatile uint32_t *)(GICC_BASE + 0x000CULL)))
|
||||
#define GICC_EOIR (*((volatile uint32_t *)(GICC_BASE + 0x0010ULL)))
|
||||
|
||||
#define GIC_PRI_HIGHEST_SECURE 0x00
|
||||
#define GIC_PRI_HIGHEST_NONSECURE 0x80
|
||||
|
||||
#define GIC_GROUP_SECURE 0
|
||||
#define GIC_GROUP_NONSECURE 1
|
||||
|
||||
/* To be called by FIQ handler. */
|
||||
void handle_registered_interrupt(void);
|
||||
|
||||
/* Initializes the GIC. TODO: This must be called during wakeup. */
|
||||
void intr_initialize_gic(void);
|
||||
|
||||
|
||||
void intr_register_handler(unsigned int id, void (*handler)(void));
|
||||
void intr_set_group(unsigned int id, int group);
|
||||
void intr_set_pending(unsigned int id);
|
||||
void intr_set_priority(unsigned int id, uint8_t priority);
|
||||
void intr_set_cpu_mask(unsigned int id, uint8_t mask);
|
||||
void intr_set_edge_level(unsigned int id, int edge_level);
|
||||
void intr_set_enabled(unsigned int id, int enabled);
|
||||
#endif
|
|
@ -199,7 +199,7 @@ static const struct {
|
|||
};
|
||||
|
||||
#define MMIO_DEVID_GICD 0
|
||||
#define MMIO_DEVID_ICC 1
|
||||
#define MMIO_DEVID_GICC 1
|
||||
#define MMIO_DEVID_UART_A 2
|
||||
#define MMIO_DEVID_CLKRST 3
|
||||
#define MMIO_DEVID_RTC_PMC 4
|
||||
|
|
Loading…
Reference in a new issue