mirror of
https://github.com/gwenhael-le-moine/x49gp.git
synced 2024-12-26 21:58:41 +01:00
751 lines
15 KiB
C
751 lines
15 KiB
C
/* $Id: s3c2410_intc.c,v 1.8 2008/12/11 12:18:17 ecd Exp $
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include <x49gp.h>
|
|
#include <s3c2410.h>
|
|
#include <s3c2410_intc.h>
|
|
#include <s3c2410_power.h>
|
|
#include <byteorder.h>
|
|
|
|
extern int do_trace;
|
|
|
|
typedef struct {
|
|
int sel_shift;
|
|
uint32_t mode_bit;
|
|
int index;
|
|
int req[6];
|
|
} s3c2410_arb_t;
|
|
|
|
typedef struct {
|
|
uint32_t sel;
|
|
uint32_t mode;
|
|
} s3c2410_arb_data_t;
|
|
|
|
static const int s3c2410_arb_order[4][6] =
|
|
{
|
|
{ 0, 1, 2, 3, 4, 5 },
|
|
{ 0, 2, 3, 4, 1, 5 },
|
|
{ 0, 3, 4, 1, 2, 5 },
|
|
{ 0, 4, 1, 2, 3, 5 }
|
|
};
|
|
|
|
static const s3c2410_arb_t s3c2410_arb_table[] =
|
|
{
|
|
[0] = { ARB0_SEL_SHIFT, ARB0_MODE, 0,
|
|
{ -1, EINT0, EINT1, EINT2, EINT3, -1 } },
|
|
[1] = { ARB1_SEL_SHIFT, ARB1_MODE, 1,
|
|
{ EINT4_7, EINT8_23, -1, nBATT_FLT, INT_TICK, INT_WDT } },
|
|
[2] = { ARB2_SEL_SHIFT, ARB2_MODE, 2,
|
|
{ INT_TIMER0, INT_TIMER1, INT_TIMER2, INT_TIMER3, INT_TIMER4, INT_UART2} },
|
|
[3] = { ARB3_SEL_SHIFT, ARB3_MODE, 3,
|
|
{ INT_LCD, INT_DMA0, INT_DMA1, INT_DMA2, INT_DMA3, INT_SDI } },
|
|
[4] = { ARB4_SEL_SHIFT, ARB4_MODE, 4,
|
|
{ INT_SPI0, INT_UART1, -1, INT_USBD, INT_USBH, INT_IIC } },
|
|
[5] = { ARB5_SEL_SHIFT, ARB5_MODE, 5,
|
|
{ -1, INT_UART0, INT_SPI1, INT_RTC, INT_ADC, -1, } },
|
|
[6] = { ARB6_SEL_SHIFT, ARB6_MODE, 6,
|
|
{ 0, 1, 2, 3, 4, 5 } },
|
|
};
|
|
#define INTC_NR_ARB (sizeof(s3c2410_arb_table) / sizeof(s3c2410_arb_table[0]))
|
|
|
|
|
|
typedef struct {
|
|
uint32_t srcpnd;
|
|
uint32_t intmod;
|
|
uint32_t intmsk;
|
|
uint32_t priority;
|
|
uint32_t intpnd;
|
|
uint32_t intoffset;
|
|
uint32_t subsrcpnd;
|
|
uint32_t intsubmsk;
|
|
|
|
s3c2410_arb_data_t arb_data[INTC_NR_ARB];
|
|
|
|
x49gp_t *x49gp;
|
|
|
|
uint32_t src_pending;
|
|
uint32_t subsrc_pending;
|
|
|
|
unsigned int nr_regs;
|
|
s3c2410_offset_t *regs;
|
|
} s3c2410_intc_t;
|
|
|
|
|
|
static void s3c2410_intc_gen_int(s3c2410_intc_t *intc);
|
|
static void s3c2410_intc_gen_int_from_sub_int(s3c2410_intc_t *intc);
|
|
|
|
static int
|
|
s3c2410_intc_data_init(s3c2410_intc_t *intc)
|
|
{
|
|
int i;
|
|
|
|
s3c2410_offset_t regs[] = {
|
|
S3C2410_OFFSET(INTC, SRCPND, 0x00000000, intc->srcpnd),
|
|
S3C2410_OFFSET(INTC, INTMOD, 0x00000000, intc->intmod),
|
|
S3C2410_OFFSET(INTC, INTMSK, 0xffffffff, intc->intmsk),
|
|
S3C2410_OFFSET(INTC, PRIORITY, 0x0000007f, intc->priority),
|
|
S3C2410_OFFSET(INTC, INTPND, 0x00000000, intc->intpnd),
|
|
S3C2410_OFFSET(INTC, INTOFFSET, 0x00000000, intc->intoffset),
|
|
S3C2410_OFFSET(INTC, SUBSRCPND, 0x00000000, intc->subsrcpnd),
|
|
S3C2410_OFFSET(INTC, INTSUBMSK, 0x000007ff, intc->intsubmsk)
|
|
};
|
|
|
|
memset(intc, 0, sizeof(s3c2410_intc_t));
|
|
|
|
intc->regs = malloc(sizeof(regs));
|
|
if (NULL == intc->regs) {
|
|
fprintf(stderr, "%s:%u: Out of memory\n",
|
|
__FUNCTION__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
memcpy(intc->regs, regs, sizeof(regs));
|
|
intc->nr_regs = sizeof(regs) / sizeof(regs[0]);
|
|
|
|
for (i = 0; i < INTC_NR_ARB; i++) {
|
|
intc->arb_data[i].sel = 0;
|
|
intc->arb_data[i].mode = s3c2410_arb_table[i].mode_bit;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
srcpnd_put_word(s3c2410_intc_t *intc, uint32_t data)
|
|
{
|
|
intc->srcpnd &= ~(data);
|
|
intc->srcpnd |= intc->src_pending;
|
|
|
|
if (intc->src_pending & data) {
|
|
s3c2410_intc_gen_int(intc);
|
|
}
|
|
}
|
|
|
|
static void
|
|
intmod_put_word(s3c2410_intc_t *intc, uint32_t data)
|
|
{
|
|
intc->intmod = data & 0xfeffffbf;
|
|
|
|
s3c2410_intc_gen_int(intc);
|
|
}
|
|
|
|
static void
|
|
intmsk_put_word(s3c2410_intc_t *intc, uint32_t data)
|
|
{
|
|
uint32_t change;
|
|
#ifdef DEBUG_X49GP_ENABLE_IRQ
|
|
int i;
|
|
#endif
|
|
|
|
change = intc->intmsk ^ data;
|
|
|
|
intc->intmsk = data | 0x01000040;
|
|
|
|
#ifdef DEBUG_X49GP_ENABLE_IRQ
|
|
for (i = 0; i < 32; i++) {
|
|
if ((change & (1 << i)) && !(intc->intmsk & (1 << i))) {
|
|
printf("INTC: Enable IRQ %u\n", i);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
s3c2410_intc_gen_int(intc);
|
|
}
|
|
|
|
static uint32_t
|
|
priority_get_word(s3c2410_intc_t *intc)
|
|
{
|
|
const s3c2410_arb_t *arb;
|
|
s3c2410_arb_data_t *arb_data;
|
|
int i;
|
|
|
|
intc->priority = 0;
|
|
|
|
for (i = 0; i < INTC_NR_ARB; i++) {
|
|
arb = &s3c2410_arb_table[i];
|
|
arb_data = &intc->arb_data[i];
|
|
|
|
intc->priority |= (arb_data->sel << arb->sel_shift) |
|
|
arb_data->mode;
|
|
}
|
|
|
|
return intc->priority;
|
|
}
|
|
|
|
static void
|
|
priority_put_word(s3c2410_intc_t *intc, uint32_t data)
|
|
{
|
|
const s3c2410_arb_t *arb;
|
|
s3c2410_arb_data_t *arb_data;
|
|
int i;
|
|
|
|
intc->priority = data & 0x001fffff;
|
|
|
|
for (i = 0; i < INTC_NR_ARB; i++) {
|
|
arb = &s3c2410_arb_table[i];
|
|
arb_data = &intc->arb_data[i];
|
|
|
|
arb_data->sel = (intc->priority >> arb->sel_shift) & ARBx_SEL_MASK;
|
|
arb_data->mode = intc->priority & arb->mode_bit;
|
|
}
|
|
|
|
s3c2410_intc_gen_int(intc);
|
|
}
|
|
|
|
static void
|
|
intpnd_put_word(s3c2410_intc_t *intc, uint32_t data)
|
|
{
|
|
intc->intpnd &= ~(data);
|
|
|
|
s3c2410_intc_gen_int(intc);
|
|
}
|
|
|
|
static void
|
|
subsrcpnd_put_word(s3c2410_intc_t *intc, uint32_t data)
|
|
{
|
|
intc->subsrcpnd &= ~(data);
|
|
intc->subsrcpnd |= intc->subsrc_pending;
|
|
|
|
if (intc->subsrc_pending & data) {
|
|
s3c2410_intc_gen_int_from_sub_int(intc);
|
|
}
|
|
}
|
|
|
|
static void
|
|
intsubmsk_put_word(s3c2410_intc_t *intc, uint32_t data)
|
|
{
|
|
intc->intsubmsk = data & 0x000007ff;
|
|
|
|
s3c2410_intc_gen_int_from_sub_int(intc);
|
|
}
|
|
|
|
static uint32_t
|
|
s3c2410_intc_select_int(s3c2410_intc_t *intc, const s3c2410_arb_t *arb,
|
|
uint32_t service, int *offset)
|
|
{
|
|
s3c2410_arb_data_t *arb_data = &intc->arb_data[arb->index];
|
|
const int *order;
|
|
int i, req;
|
|
|
|
order = s3c2410_arb_order[arb_data->sel];
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
req = order[i];
|
|
|
|
if (-1 == arb->req[req])
|
|
continue;
|
|
|
|
if (service & (1 << arb->req[req])) {
|
|
if (arb_data->mode)
|
|
arb_data->sel = (arb_data->sel + 1) & ARBx_SEL_MASK;
|
|
*offset = arb->req[req];
|
|
return (1 << arb->index);
|
|
}
|
|
}
|
|
|
|
*offset = -1;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
s3c2410_FIQ (CPUState *env)
|
|
{
|
|
cpu_interrupt(env, CPU_INTERRUPT_FIQ);
|
|
}
|
|
|
|
void
|
|
s3c2410_IRQ (CPUState *env)
|
|
{
|
|
cpu_interrupt(env, CPU_INTERRUPT_HARD);
|
|
}
|
|
|
|
|
|
static void
|
|
s3c2410_intc_gen_int(s3c2410_intc_t *intc)
|
|
{
|
|
x49gp_t *x49gp = intc->x49gp;
|
|
uint32_t fiq, service;
|
|
int offset[6], index;
|
|
const s3c2410_arb_t *arb;
|
|
uint32_t request;
|
|
int i;
|
|
|
|
fiq = intc->srcpnd & intc->intmod;
|
|
|
|
#ifdef DEBUG_S3C2410_INTC0
|
|
printf("INTC: FIQ service request: %08x\n", fiq);
|
|
#endif
|
|
|
|
if (fiq) {
|
|
/*
|
|
* Generate FIQ.
|
|
*/
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
printf("INTC: vector to %08x\n", 0x1c);
|
|
#endif
|
|
cpu_interrupt(x49gp->env, CPU_INTERRUPT_FIQ);
|
|
|
|
x49gp_set_idle(x49gp, 0);
|
|
return;
|
|
} else {
|
|
cpu_reset_interrupt(x49gp->env, CPU_INTERRUPT_FIQ);
|
|
}
|
|
|
|
#ifdef DEBUG_S3C2410_INTC0
|
|
printf("INTC: IRQ pending request: %08x\n", intc->intpnd);
|
|
#endif
|
|
|
|
if (intc->intpnd) {
|
|
/*
|
|
* Generate IRQ.
|
|
*/
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
printf("INTC: vector to %08x\n", 0x18);
|
|
#endif
|
|
cpu_interrupt(x49gp->env, CPU_INTERRUPT_HARD);
|
|
|
|
x49gp_set_idle(x49gp, 0);
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG_S3C2410_INTC0
|
|
printf("INTC: srcpnd %08x, intmsk: %08x\n", intc->srcpnd, intc->intmsk);
|
|
#endif
|
|
|
|
service = intc->srcpnd & ~(intc->intmsk);
|
|
|
|
#ifdef DEBUG_S3C2410_INTC0
|
|
printf("INTC: IRQ service request: %08x\n", service);
|
|
#endif
|
|
|
|
if (0 == service) {
|
|
cpu_reset_interrupt(x49gp->env, CPU_INTERRUPT_HARD);
|
|
return;
|
|
}
|
|
|
|
request = 0;
|
|
for (i = 0; i < 6; i++) {
|
|
arb = &s3c2410_arb_table[i];
|
|
|
|
request |= s3c2410_intc_select_int(intc, arb, service, &offset[i]);
|
|
|
|
#ifdef DEBUG_S3C2410_INTC0
|
|
printf("INTC: ARB%u highest %d\n", i, offset[i]);
|
|
#endif
|
|
}
|
|
|
|
arb = &s3c2410_arb_table[6];
|
|
|
|
#ifdef DEBUG_S3C2410_INTC0
|
|
printf("INTC: ARB%u request: %08x\n", 6, request);
|
|
#endif
|
|
|
|
if (s3c2410_intc_select_int(intc, arb, request, &index)) {
|
|
intc->intoffset = offset[index];
|
|
intc->intpnd |= (1 << intc->intoffset);
|
|
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
printf("INTC: irq pending: %u (%08x)\n", intc->intoffset, intc->intpnd);
|
|
#endif
|
|
/*
|
|
* Generate IRQ.
|
|
*/
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
printf("INTC: vector to %08x\n", 0x18);
|
|
#endif
|
|
cpu_interrupt(x49gp->env, CPU_INTERRUPT_HARD);
|
|
|
|
x49gp_set_idle(x49gp, 0);
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG_S3C2410_INTC0
|
|
printf("INTC: No irq pending\n");
|
|
#endif
|
|
|
|
cpu_reset_interrupt(x49gp->env, CPU_INTERRUPT_HARD);
|
|
}
|
|
|
|
void
|
|
s3c2410_intc_assert(x49gp_t *x49gp, int irq, int level)
|
|
{
|
|
s3c2410_intc_t *intc = x49gp->s3c2410_intc;
|
|
|
|
if (irq > 31)
|
|
return;
|
|
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
printf("INTC: assert irq %u (%08x)\n", irq, 1 << irq);
|
|
#endif
|
|
|
|
if (! (intc->src_pending & (1 << irq))) {
|
|
if (level)
|
|
intc->src_pending |= (1 << irq);
|
|
intc->srcpnd |= (1 << irq);
|
|
|
|
s3c2410_intc_gen_int(intc);
|
|
}
|
|
|
|
if (x49gp->arm_idle == 2) {
|
|
if (irq == EINT0 || irq == INT_RTC)
|
|
x49gp_set_idle(x49gp, 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
s3c2410_intc_deassert(x49gp_t *x49gp, int irq)
|
|
{
|
|
s3c2410_intc_t *intc = x49gp->s3c2410_intc;
|
|
|
|
if (irq > 31)
|
|
return;
|
|
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
printf("INTC: deassert irq %u (%08x)\n", irq, 1 << irq);
|
|
#endif
|
|
|
|
intc->src_pending &= ~(1 << irq);
|
|
}
|
|
|
|
static void
|
|
s3c2410_intc_gen_int_from_sub_int(s3c2410_intc_t *intc)
|
|
{
|
|
x49gp_t *x49gp = intc->x49gp;
|
|
uint32_t service;
|
|
|
|
service = intc->subsrcpnd & ~(intc->intsubmsk);
|
|
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
printf("INTC: subirq service request: %08x\n", service);
|
|
#endif
|
|
|
|
if (service & ((1 << SUB_INT_ERR0) | (1 << SUB_INT_TXD0) | (1 << SUB_INT_RXD0))) {
|
|
s3c2410_intc_assert(x49gp, INT_UART0, 1);
|
|
} else {
|
|
s3c2410_intc_deassert(x49gp, INT_UART0);
|
|
}
|
|
|
|
if (service & ((1 << SUB_INT_ERR1) | (1 << SUB_INT_TXD1) | (1 << SUB_INT_RXD1))) {
|
|
s3c2410_intc_assert(x49gp, INT_UART1, 1);
|
|
} else {
|
|
s3c2410_intc_deassert(x49gp, INT_UART1);
|
|
}
|
|
|
|
if (service & ((1 << SUB_INT_ERR2) | (1 << SUB_INT_TXD2) | (1 << SUB_INT_RXD2))) {
|
|
s3c2410_intc_assert(x49gp, INT_UART2, 1);
|
|
} else {
|
|
s3c2410_intc_deassert(x49gp, INT_UART2);
|
|
}
|
|
|
|
if (service & ((1 << SUB_INT_ADC) | (1 << SUB_INT_TC))) {
|
|
s3c2410_intc_assert(x49gp, INT_ADC, 1);
|
|
} else {
|
|
s3c2410_intc_deassert(x49gp, INT_ADC);
|
|
}
|
|
|
|
intc->subsrcpnd = intc->subsrc_pending;
|
|
}
|
|
|
|
void
|
|
s3c2410_intc_sub_assert(x49gp_t *x49gp, int sub_irq, int level)
|
|
{
|
|
s3c2410_intc_t *intc = x49gp->s3c2410_intc;
|
|
|
|
if (sub_irq > 31)
|
|
return;
|
|
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
printf("INTC: assert subirq %u (%08x)\n", sub_irq, 1 << sub_irq);
|
|
#endif
|
|
|
|
if (! (intc->subsrc_pending & (1 << sub_irq))) {
|
|
if (level)
|
|
intc->subsrc_pending |= (1 << sub_irq);
|
|
intc->subsrcpnd |= (1 << sub_irq);
|
|
|
|
s3c2410_intc_gen_int_from_sub_int(intc);
|
|
}
|
|
}
|
|
|
|
void
|
|
s3c2410_intc_sub_deassert(x49gp_t *x49gp, int sub_irq)
|
|
{
|
|
s3c2410_intc_t *intc = x49gp->s3c2410_intc;
|
|
|
|
if (sub_irq > 31)
|
|
return;
|
|
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
printf("INTC: deassert subirq %u (%08x)\n", sub_irq, 1 << sub_irq);
|
|
#endif
|
|
|
|
intc->subsrc_pending &= ~(1 << sub_irq);
|
|
}
|
|
|
|
static uint32_t
|
|
s3c2410_intc_read(void *opaque, target_phys_addr_t offset)
|
|
{
|
|
s3c2410_intc_t *intc = opaque;
|
|
s3c2410_offset_t *reg;
|
|
uint32_t data;
|
|
|
|
#ifdef QEMU_OLD
|
|
offset -= S3C2410_INTC_BASE;
|
|
#endif
|
|
if (! S3C2410_OFFSET_OK(intc, offset)) {
|
|
return ~(0);
|
|
}
|
|
|
|
reg = S3C2410_OFFSET_ENTRY(intc, offset);
|
|
|
|
switch (offset) {
|
|
case S3C2410_INTC_PRIORITY:
|
|
data = priority_get_word(intc);
|
|
break;
|
|
default:
|
|
data = *(reg->datap);
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
printf("read %s [%08x] %s [%08x] data %08x\n",
|
|
"s3c2410-intc", S3C2410_INTC_BASE,
|
|
reg->name, offset, data);
|
|
#endif
|
|
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
s3c2410_intc_write(void *opaque, target_phys_addr_t offset, uint32_t data)
|
|
{
|
|
s3c2410_intc_t *intc = opaque;
|
|
s3c2410_offset_t *reg;
|
|
|
|
#ifdef QEMU_OLD
|
|
offset -= S3C2410_INTC_BASE;
|
|
#endif
|
|
if (! S3C2410_OFFSET_OK(intc, offset)) {
|
|
return;
|
|
}
|
|
|
|
reg = S3C2410_OFFSET_ENTRY(intc, offset);
|
|
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
printf("write %s [%08x] %s [%08x] data %08x\n",
|
|
"s3c2410-intc", S3C2410_INTC_BASE,
|
|
reg->name, offset, data);
|
|
#endif
|
|
|
|
switch (offset) {
|
|
case S3C2410_INTC_SRCPND:
|
|
srcpnd_put_word(intc, data);
|
|
break;
|
|
case S3C2410_INTC_INTMOD:
|
|
intmod_put_word(intc, data);
|
|
break;
|
|
case S3C2410_INTC_INTMSK:
|
|
intmsk_put_word(intc, data);
|
|
break;
|
|
case S3C2410_INTC_PRIORITY:
|
|
priority_put_word(intc, data);
|
|
break;
|
|
case S3C2410_INTC_INTPND:
|
|
intpnd_put_word(intc, data);
|
|
break;
|
|
case S3C2410_INTC_SUBSRCPND:
|
|
subsrcpnd_put_word(intc, data);
|
|
break;
|
|
case S3C2410_INTC_INTSUBMSK:
|
|
intsubmsk_put_word(intc, data);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int
|
|
s3c2410_intc_load(x49gp_module_t *module, GKeyFile *key)
|
|
{
|
|
s3c2410_intc_t *intc = module->user_data;
|
|
s3c2410_offset_t *reg;
|
|
int error = 0;
|
|
int i;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
for (i = 0; i < intc->nr_regs; i++) {
|
|
reg = &intc->regs[i];
|
|
|
|
if (NULL == reg->name)
|
|
continue;
|
|
|
|
if (x49gp_module_get_u32(module, key, reg->name,
|
|
reg->reset, reg->datap))
|
|
error = -EAGAIN;
|
|
}
|
|
|
|
intc->src_pending = intc->srcpnd;
|
|
intc->subsrc_pending = intc->subsrcpnd;
|
|
intc->srcpnd = 0;
|
|
intc->subsrcpnd = 0;
|
|
|
|
priority_put_word(intc, intc->priority);
|
|
intsubmsk_put_word(intc, intc->intsubmsk);
|
|
intmsk_put_word(intc, intc->intmsk);
|
|
|
|
return error;
|
|
}
|
|
|
|
static int
|
|
s3c2410_intc_save(x49gp_module_t *module, GKeyFile *key)
|
|
{
|
|
s3c2410_intc_t *intc = module->user_data;
|
|
s3c2410_offset_t *reg;
|
|
int i;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
intc->srcpnd = intc->src_pending;
|
|
intc->subsrcpnd = intc->subsrc_pending;
|
|
|
|
for (i = 0; i < intc->nr_regs; i++) {
|
|
reg = &intc->regs[i];
|
|
|
|
if (NULL == reg->name)
|
|
continue;
|
|
|
|
x49gp_module_set_u32(module, key, reg->name, *(reg->datap));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
s3c2410_intc_reset(x49gp_module_t *module, x49gp_reset_t reset)
|
|
{
|
|
s3c2410_intc_t *intc = module->user_data;
|
|
s3c2410_offset_t *reg;
|
|
int i;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
if (reset == X49GP_RESET_POWER_OFF) {
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < intc->nr_regs; i++) {
|
|
reg = &intc->regs[i];
|
|
|
|
if (NULL == reg->name)
|
|
continue;
|
|
|
|
*(reg->datap) = reg->reset;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static CPUReadMemoryFunc *s3c2410_intc_readfn[] =
|
|
{
|
|
s3c2410_intc_read,
|
|
s3c2410_intc_read,
|
|
s3c2410_intc_read
|
|
};
|
|
|
|
static CPUWriteMemoryFunc *s3c2410_intc_writefn[] =
|
|
{
|
|
s3c2410_intc_write,
|
|
s3c2410_intc_write,
|
|
s3c2410_intc_write
|
|
};
|
|
|
|
static int
|
|
s3c2410_intc_init(x49gp_module_t *module)
|
|
{
|
|
s3c2410_intc_t *intc;
|
|
int iotype;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
intc = malloc(sizeof(s3c2410_intc_t));
|
|
if (NULL == intc) {
|
|
fprintf(stderr, "%s:%u: Out of memory\n",
|
|
__FUNCTION__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
if (s3c2410_intc_data_init(intc)) {
|
|
free(intc);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
module->user_data = intc;
|
|
|
|
intc->x49gp = module->x49gp;
|
|
intc->x49gp->s3c2410_intc = intc;
|
|
|
|
#ifdef QEMU_OLD
|
|
iotype = cpu_register_io_memory(0, s3c2410_intc_readfn,
|
|
s3c2410_intc_writefn, intc);
|
|
#else
|
|
iotype = cpu_register_io_memory(s3c2410_intc_readfn,
|
|
s3c2410_intc_writefn, intc);
|
|
#endif
|
|
printf("%s: iotype %08x\n", __FUNCTION__, iotype);
|
|
cpu_register_physical_memory(S3C2410_INTC_BASE, S3C2410_MAP_SIZE, iotype);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
s3c2410_intc_exit(x49gp_module_t *module)
|
|
{
|
|
s3c2410_intc_t *intc;
|
|
|
|
#ifdef DEBUG_X49GP_MODULES
|
|
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
|
|
#endif
|
|
|
|
if (module->user_data) {
|
|
intc = module->user_data;
|
|
if (intc->regs)
|
|
free(intc->regs);
|
|
free(intc);
|
|
}
|
|
|
|
x49gp_module_unregister(module);
|
|
free(module);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
x49gp_s3c2410_intc_init(x49gp_t *x49gp)
|
|
{
|
|
x49gp_module_t *module;
|
|
|
|
if (x49gp_module_init(x49gp, "s3c2410-intc",
|
|
s3c2410_intc_init,
|
|
s3c2410_intc_exit,
|
|
s3c2410_intc_reset,
|
|
s3c2410_intc_load,
|
|
s3c2410_intc_save,
|
|
NULL, &module)) {
|
|
return -1;
|
|
}
|
|
|
|
return x49gp_module_register(module);
|
|
}
|