vxKernel/src/drivers/mpu/sh/sh7305/intc/intc.c

164 lines
4.2 KiB
C

#include "vhex/driver.h"
#include "vhex/arch/sh7305/intc.h"
#include <string.h>
/* Construct the Interrupt Controller */
struct sh7305_intc sh7305_INTC = {
.ICR0 = (void *)0xa4140000,
.ICR1 = (void *)0xa414001c,
.INTPRI00 = (void *)0xa4140010,
.INTREQ00 = (void *)0xa4140024,
.INTMSK00 = (void *)0xa4140044,
.INTMSKCLR00 = (void *)0xa4140064,
.NMIFCR = (void *)0xa41400c0,
.IPR = (void *)0xa4080000,
.MSK = (void *)0xa4080080,
.MSKCLR = (void *)0xa40800c0,
.USERIMASK = (void *)0xa4700000,
// PINTCR = (void *)0xa40501dc,
// PINTSR = (void *)0xa40501ea,
};
/* define the private INTerrupt Controller context structure */
struct intc_ctx {
uint16_t ipr[12];
uint8_t imr[13];
sh7305_intc_userimask_t userimask;
sh7305_intc_icr0_t icr0;
sh7305_intc_icr1_t icr1;
sh7305_intc_intpri00_t intpri00;
sh7305_intc_intreq00_t intreq00;
sh7305_intc_intmsk00_t intmsk00;
sh7305_intc_nmifcr_t nmifcr;
};
/* hardware configuration call */
/* __intc_configure() : configure the Interrupt Controller
Note that we don't touch to the NMI configuration because this part is
obscure. I have done some reverse-ingenering in this part, but Casio seems
use this part oddly. So, to avoid any probleme with Non-Maskable Interrupt,
we will use the Casio's configuration.
So, by default, mask all interrupt and enable all interrupt is the user
interrupt mask */
static void __intc_configure(struct intc_ctx *state)
{
memset(state, 0x00, sizeof(struct intc_ctx));
for (int i = 0; i < 12; ++i)
state->ipr[i] = 0x0000;
for (int i = 0; i < 13; ++i)
state->imr[i] = 0x00;
state->userimask._0xa5 = 0xa5;
state->userimask.UIMASK = 0x00;
/* interrupt control register 0 (NMI)
<> enable NMI interruption when a input level is low
<> keep NMI interrupt pending while the SR.BL=1
<> interrupt request is detected on falling edge */
state->icr0.MAI = 0;
state->icr0.NMIB = 0;
state->icr0.NMIE = 0;
state->icr0._HIGH = 0b11;
/* Interrupt control register 1 (IRQ)
<> interrupt request is detected on low-level of IRQx input */
state->icr1.IRQ0S = 0b10;
state->icr1.IRQ1S = 0b10;
state->icr1.IRQ2S = 0b10;
state->icr1.IRQ3S = 0b10;
/* Interrupt priority (IRQ)
<> mask all IRQx interrupt */
state->intpri00.IRQ0 = 0b0000;
state->intpri00.IRQ1 = 0b0000;
state->intpri00.IRQ2 = 0b0000;
state->intpri00.IRQ3 = 0b0000;
/* Interrupt request (IRQ)
<> clear all pending interrupt request */
state->intreq00.IRQ0 = 0;
state->intreq00.IRQ1 = 0;
state->intreq00.IRQ2 = 0;
state->intreq00.IRQ3 = 0;
/* Interurpt mask (IRQ)
<> mask all IRQ interrupt */
state->intmsk00.IRQ0 = 1;
state->intmsk00.IRQ1 = 1;
state->intmsk00.IRQ2 = 1;
state->intmsk00.IRQ3 = 1;
/* NMI Interrupt flagsi (clear) */
state->nmifcr.NMIFL = 0;
}
/* hardware hypervisor call */
/* __intc_hsave() : save hardware information */
static void __intc_hsave(struct intc_ctx *state)
{
for (int i = 0; i < 12; ++i)
state->ipr[i] = sh7305_INTC.IPR[i << 1];
for (int i = 0; i < 13; ++i)
state->imr[i] = sh7305_INTC.MSK[i << 2];
state->userimask = *sh7305_INTC.USERIMASK;
state->icr0 = *sh7305_INTC.ICR0;
state->icr1 = *sh7305_INTC.ICR1;
state->intpri00 = *sh7305_INTC.INTPRI00;
state->intreq00 = *sh7305_INTC.INTREQ00;
state->intmsk00 = *sh7305_INTC.INTMSK00;
}
/* __intc_hrestore() : restore hardware information */
static void __intc_hrestore(struct intc_ctx *state)
{
for (int i = 0; i < 12; ++i)
sh7305_INTC.IPR[i << 1] = state->ipr[i];
for (int i = 0; i < 13; ++i) {
sh7305_INTC.MSKCLR[i << 2] = 0xff;
sh7305_INTC.MSK[i << 2] = state->imr[i];
}
state->userimask._0xa5 = 0xa5;
*sh7305_INTC.USERIMASK = state->userimask;
*sh7305_INTC.ICR0 = state->icr0;
*sh7305_INTC.ICR1 = state->icr1;
*sh7305_INTC.INTPRI00 = state->intpri00;
*sh7305_INTC.INTREQ00 = state->intreq00;
*sh7305_INTC.INTMSKCLR00 = (sh7305_intc_intmskclr00_t){
.IRQ0 = 1,
.IRQ1 = 1,
.IRQ2 = 1,
.IRQ3 = 1,
};
*sh7305_INTC.INTMSK00 = state->intmsk00;
}
/* declare the INTC driver */
struct vhex_driver drv_intc = {
.name = "INTC",
.hsave = (void*)&__intc_hsave,
.hrestore = (void*)&__intc_hrestore,
.configure = (void*)&__intc_configure,
.state_size = sizeof(struct intc_ctx)
};
VHEX_DECLARE_DRIVER(01, drv_intc);