forked from Miroirs/x49gp
679 lines
17 KiB
C
679 lines
17 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 )
|
|
{
|
|
#ifdef DEBUG_X49GP_ENABLE_IRQ
|
|
uint32_t change;
|
|
int i;
|
|
|
|
change = intc->intmsk ^ data;
|
|
#endif
|
|
|
|
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;
|
|
|
|
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 [%08lx] data %08x\n", "s3c2410-intc", S3C2410_INTC_BASE, reg->name, ( unsigned long )offset, data );
|
|
#endif
|
|
|
|
return data;
|
|
}
|
|
|
|
static void s3c2410_intc_write( void* opaque, target_phys_addr_t offset, uint32_t data )
|
|
{
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
s3c2410_offset_t* reg;
|
|
#endif
|
|
s3c2410_intc_t* intc = opaque;
|
|
|
|
if ( !S3C2410_OFFSET_OK( intc, offset ) ) {
|
|
return;
|
|
}
|
|
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
reg = S3C2410_OFFSET_ENTRY( intc, offset );
|
|
|
|
printf( "write %s [%08x] %s [%08lx] data %08x\n", "s3c2410-intc", S3C2410_INTC_BASE, reg->name, ( unsigned long )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;
|
|
|
|
iotype = cpu_register_io_memory( s3c2410_intc_readfn, s3c2410_intc_writefn, intc );
|
|
#ifdef DEBUG_S3C2410_INTC
|
|
printf( "%s: iotype %08x\n", __FUNCTION__, iotype );
|
|
#endif
|
|
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 );
|
|
}
|