/*
 * Copyright (c) 2006 Jon Sevy <jsevy@cs.drexel.edu>
 * All rights reserved.
 * 
 * Based on code by Jason R. Thorpe
 *
 * Copyright (c) 2002 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *This product includes software developed for the NetBSD Project by
 *Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _VX115_INTR_H_
#define _VX115_INTR_H_


#define ARM_IRQ_HANDLER _C_LABEL(vx115_irq_dispatcher)


#ifndef _LOCORE

#include <arm/cpu.h>
#include <arm/armreg.h>
#include <arm/cpufunc.h>
#include <arm/softintr.h>

#include <machine/atomic.h>
#include <machine/bus.h>
#include <machine/intr.h>

#include <arm/vx115/vx115_reg.h>

typedef int (* vx115_irq_handler_t)(void *);


#define NR_IRQS     32
#define VALID_IRQ(i)    ((i!=24) && (i!=27) && (i<NR_IRQS))

#define IRQ_EXT2        1
#define IRQ_EXT3        2
#define IRQ_EXT4        3
#define IRQ_EXT5        4
#define IRQ_EXT6        5
#define IRQ_EXT7        6
#define IRQ_DMA1_ERROR  7
#define IRQ_DMA1        8   
#define IRQ_TIMER1      9
#define IRQ_AGPIOA      10
#define IRQ_AGPIOB      11
#define IRQ_SDMCC0      12
#define IRQ_SDMCC1      13
#define IRQ_SSP3        14
#define IRQ_I2C         15
#define IRQ_SSP1        16
#define IRQ_GPIOA       17
#define IRQ_GPIOB       18
#define IRQ_UART0       19
#define IRQ_KEYPAD      20
#define IRQ_DISPLAY     21
#define IRQ_DISP_SYNC   22
#define IRQ_CAMERA      23
#define IRQ_RESERVED24  24
#define IRQ_DSP_PCU     25
#define IRQ_ARM7_PCU    26
#define IRQ_RESERVED27  27
#define IRQ_UART0_WAKE  28
#define IRQ_USB_OTG     29
#define IRQ_USB_EXTINT  30
#define IRQ_SWI         31


/* priorities assigned to each interrupt source */
#define IRQ_TIMER1_PRIORITY         1
#define IRQ_DMA1_ERROR_PRIORITY     2
#define IRQ_DMA1_PRIORITY           3
#define IRQ_DISPLAY_PRIORITY        4
#define IRQ_DISP_SYNC_PRIORITY      5
#define IRQ_SSP1_PRIORITY           6
#define IRQ_SSP3_PRIORITY           7
#define IRQ_UART0_WAKE_PRIORITY     8
#define IRQ_UART0_PRIORITY          9
#define IRQ_SDMCC0_PRIORITY         10
#define IRQ_SDMCC1_PRIORITY         11
#define IRQ_I2C_PRIORITY            12
#define IRQ_KEYPAD_PRIORITY         13
#define IRQ_GPIOA_PRIORITY          14
#define IRQ_GPIOB_PRIORITY          15
#define IRQ_USB_EXTINT_PRIORITY     16
#define IRQ_USB_OTG_PRIORITY        17
#define IRQ_DSP_PCU_PRIORITY        18
#define IRQ_ARM7_PCU_PRIORITY       19
#define IRQ_SWI_PRIORITY            20
#define IRQ_CAMERA_PRIORITY         21
#define IRQ_EXT2_PRIORITY           22
#define IRQ_EXT3_PRIORITY           23
#define IRQ_AGPIOA_PRIORITY         24
#define IRQ_AGPIOB_PRIORITY         25
#define IRQ_EXT4_PRIORITY           26
#define IRQ_EXT5_PRIORITY           27
#define IRQ_EXT6_PRIORITY           28
#define IRQ_EXT7_PRIORITY           29
#define IRQ_RESERVED24_PRIORITY     30
#define IRQ_RESERVED27_PRIORITY     31
    


extern __volatile int current_spl_level;
extern __volatile int softint_pending;
extern int vx115_pic_spl_soft_mask[];
void vx115_do_pending(void);

/*
 * We use all of the bits in the hardware interrupt controller,
 * so we use a separate mask for the soft interrupts, and just
 * map them to corresponding bits
 */
#define SI_TO_IRQBIT(si)  (1U<<(si))

#define VX115_IRQ_MIN   0
#define VX115_IRQ_MAX   32


struct vx115_pic_softc
{
    struct device       dev;
    bus_space_tag_t     sc_iot;
    bus_space_handle_t  sc_ioh;
};

extern struct vx115_pic_softc *vx115_pic_sc;
extern int vx115_pic_spl_mask[NIPL];
extern int vx115_pic_spl_soft_mask[NIPL];

/* macros to simplify writing to the interrupt controller */
#define vx115_read_pic(offset)           bus_space_read_4(vx115_pic_sc->sc_iot, vx115_pic_sc->sc_ioh, offset)
#define vx115_write_pic(offset, value)   bus_space_write_4(vx115_pic_sc->sc_iot, vx115_pic_sc->sc_ioh, offset, value)


/*
 * Utility function for interrupt handler.
 */
static __inline int
find_first_bit( uint32_t bits )
{
    int count;

    /* CLZ is available only on ARMv5 */
    asm( "clz %0, %1" : "=r" (count) : "r" (bits) );
    return 31-count;
}


static __inline void
vx115_setipl(int new)
{
    current_spl_level = new;
    
    /* enable hardware interrupts appropriate to current spl level */
    vx115_write_pic(PIC_ENABLE_SET, vx115_pic_spl_mask[current_spl_level]);
    
    /* clear hardware interrupts not appropriate to current spl level */
    vx115_write_pic(PIC_ENABLE_CLEAR, ~vx115_pic_spl_mask[current_spl_level]);

}


static __inline void
vx115_splx(int new)
{
    int psw;

    psw = disable_interrupts(I32_bit);
    vx115_setipl(new);
    restore_interrupts(psw);

    /* if there are software interrupts pending, process */
    if (softint_pending & vx115_pic_spl_soft_mask[current_spl_level])
        vx115_do_pending();
}


static __inline int
vx115_splraise(int ipl)
{
    int old, psw;

    psw = disable_interrupts(I32_bit);
    
    old = current_spl_level;
    if( ipl > old )
        vx115_setipl(ipl);
    
    restore_interrupts(psw);

    return (old);
}

static __inline int
vx115_spllower(int ipl)
{
    int old, psw;

    psw = disable_interrupts(I32_bit);
    
    old = current_spl_level;
    if( ipl < old )
        vx115_setipl(ipl);
    
    restore_interrupts(psw);
    
    /* if there are software interrupts pending, process */
    if (softint_pending & vx115_pic_spl_soft_mask[current_spl_level])
        vx115_do_pending();
        
    return(old);
}

static __inline void
vx115_setsoftintr(int si)
{
    atomic_set_bit( (u_int *)&softint_pending, SI_TO_IRQBIT(si) );

    /* Process unmasked pending soft interrupts. */
    if ( softint_pending & vx115_pic_spl_soft_mask[current_spl_level] )
        vx115_do_pending();
}




int     _splraise(int);
int     _spllower(int);
void    splx(int);
void    _setsoftintr(int);

#if !defined(EVBARM_SPL_NOINLINE)

#define splx(new)           vx115_splx(new)
#define _spllower(ipl)      vx115_spllower(ipl)
#define _splraise(ipl)      vx115_splraise(ipl)
#define _setsoftintr(si)    vx115_setsoftintr(si)

#endif  /* !EVBARM_SPL_NOINTR */

/*
 * This function *MUST* be called very early on in a port's
 * initarm() function, before ANY spl*() functions are called.
 *
 * The parameters are the virtual address of the Vx115's Interrupt
 * Controller registers and the size of the reg region.
 */
void vx115_intr_bootstrap(bus_addr_t addr, bus_size_t size);

void vx115_irq_dispatcher(void *);
void *vx115_intr_establish(int irqno, int level, int (*func)(void *), void *cookie);
void vx115_update_intr_masks(int irqno, int level);




#define VX115_INT_DISABLED             (unsigned int)0x00000000
#define VX115_INT_ENABLED              (unsigned int)0x00000001

#define VX115_INT_SENSE_LEVEL          (unsigned int)0x00000000
#define VX115_INT_SENSE_EDGE           (unsigned int)0x00000002

#define VX115_INT_POLARITY_LOW         (unsigned int)0x00000000
#define VX115_INT_POLARITY_HIGH        (unsigned int)0x00000004
#define VX115_INT_POLARITY_HIGH_LOW    (unsigned int)0x00000000
#define VX115_INT_POLARITY_LOW_HIGH    (unsigned int)0x00000004


int vx115_configure_irq(unsigned int irq, unsigned int sense, unsigned int polarity);
void vx115_enable_irq(unsigned int irq);
void vx115_disable_irq(unsigned int irq);


#endif /* ! _LOCORE */

#endif /* _VX115_INTR_H_ */
