134 строки
4.5 KiB
C
134 строки
4.5 KiB
C
|
/*
|
||
|
* include/asm-v850/v850e_intc.h -- V850E CPU interrupt controller (INTC)
|
||
|
*
|
||
|
* Copyright (C) 2001,02,03 NEC Electronics Corporation
|
||
|
* Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
|
||
|
*
|
||
|
* This file is subject to the terms and conditions of the GNU General
|
||
|
* Public License. See the file COPYING in the main directory of this
|
||
|
* archive for more details.
|
||
|
*
|
||
|
* Written by Miles Bader <miles@gnu.org>
|
||
|
*/
|
||
|
|
||
|
#ifndef __V850_V850E_INTC_H__
|
||
|
#define __V850_V850E_INTC_H__
|
||
|
|
||
|
|
||
|
/* There are 4 16-bit `Interrupt Mask Registers' located contiguously
|
||
|
starting from this base. Each interrupt uses a single bit to
|
||
|
indicated enabled/disabled status. */
|
||
|
#define V850E_INTC_IMR_BASE_ADDR 0xFFFFF100
|
||
|
#define V850E_INTC_IMR_ADDR(irq) (V850E_INTC_IMR_BASE_ADDR + ((irq) >> 3))
|
||
|
#define V850E_INTC_IMR_BIT(irq) ((irq) & 0x7)
|
||
|
|
||
|
/* Each maskable interrupt has a single-byte control register at this
|
||
|
address. */
|
||
|
#define V850E_INTC_IC_BASE_ADDR 0xFFFFF110
|
||
|
#define V850E_INTC_IC_ADDR(irq) (V850E_INTC_IC_BASE_ADDR + ((irq) << 1))
|
||
|
#define V850E_INTC_IC(irq) (*(volatile u8 *)V850E_INTC_IC_ADDR(irq))
|
||
|
/* Encode priority PR for storing in an interrupt control register. */
|
||
|
#define V850E_INTC_IC_PR(pr) (pr)
|
||
|
/* Interrupt disable bit in an interrupt control register. */
|
||
|
#define V850E_INTC_IC_MK_BIT 6
|
||
|
#define V850E_INTC_IC_MK (1 << V850E_INTC_IC_MK_BIT)
|
||
|
/* Interrupt pending flag in an interrupt control register. */
|
||
|
#define V850E_INTC_IC_IF_BIT 7
|
||
|
#define V850E_INTC_IC_IF (1 << V850E_INTC_IC_IF_BIT)
|
||
|
|
||
|
/* The ISPR (In-service priority register) contains one bit for each interrupt
|
||
|
priority level, which is set to one when that level is currently being
|
||
|
serviced (and thus blocking any interrupts of equal or lesser level). */
|
||
|
#define V850E_INTC_ISPR_ADDR 0xFFFFF1FA
|
||
|
#define V850E_INTC_ISPR (*(volatile u8 *)V850E_INTC_ISPR_ADDR)
|
||
|
|
||
|
|
||
|
#ifndef __ASSEMBLY__
|
||
|
|
||
|
/* Enable interrupt handling for interrupt IRQ. */
|
||
|
static inline void v850e_intc_enable_irq (unsigned irq)
|
||
|
{
|
||
|
__asm__ __volatile__ ("clr1 %0, [%1]"
|
||
|
:: "r" (V850E_INTC_IMR_BIT (irq)),
|
||
|
"r" (V850E_INTC_IMR_ADDR (irq))
|
||
|
: "memory");
|
||
|
}
|
||
|
|
||
|
/* Disable interrupt handling for interrupt IRQ. Note that any
|
||
|
interrupts received while disabled will be delivered once the
|
||
|
interrupt is enabled again, unless they are explicitly cleared using
|
||
|
`v850e_intc_clear_pending_irq'. */
|
||
|
static inline void v850e_intc_disable_irq (unsigned irq)
|
||
|
{
|
||
|
__asm__ __volatile__ ("set1 %0, [%1]"
|
||
|
:: "r" (V850E_INTC_IMR_BIT (irq)),
|
||
|
"r" (V850E_INTC_IMR_ADDR (irq))
|
||
|
: "memory");
|
||
|
}
|
||
|
|
||
|
/* Return true if interrupt handling for interrupt IRQ is enabled. */
|
||
|
static inline int v850e_intc_irq_enabled (unsigned irq)
|
||
|
{
|
||
|
int rval;
|
||
|
__asm__ __volatile__ ("tst1 %1, [%2]; setf z, %0"
|
||
|
: "=r" (rval)
|
||
|
: "r" (V850E_INTC_IMR_BIT (irq)),
|
||
|
"r" (V850E_INTC_IMR_ADDR (irq)));
|
||
|
return rval;
|
||
|
}
|
||
|
|
||
|
/* Disable irqs from 0 until LIMIT. LIMIT must be a multiple of 8. */
|
||
|
static inline void _v850e_intc_disable_irqs (unsigned limit)
|
||
|
{
|
||
|
unsigned long addr;
|
||
|
for (addr = V850E_INTC_IMR_BASE_ADDR; limit >= 8; addr++, limit -= 8)
|
||
|
*(char *)addr = 0xFF;
|
||
|
}
|
||
|
|
||
|
/* Disable all irqs. This is purposely a macro, because NUM_MACH_IRQS
|
||
|
will be only be defined later. */
|
||
|
#define v850e_intc_disable_irqs() _v850e_intc_disable_irqs (NUM_MACH_IRQS)
|
||
|
|
||
|
/* Clear any pending interrupts for IRQ. */
|
||
|
static inline void v850e_intc_clear_pending_irq (unsigned irq)
|
||
|
{
|
||
|
__asm__ __volatile__ ("clr1 %0, 0[%1]"
|
||
|
:: "i" (V850E_INTC_IC_IF_BIT),
|
||
|
"r" (V850E_INTC_IC_ADDR (irq))
|
||
|
: "memory");
|
||
|
}
|
||
|
|
||
|
/* Return true if interrupt IRQ is pending (but disabled). */
|
||
|
static inline int v850e_intc_irq_pending (unsigned irq)
|
||
|
{
|
||
|
int rval;
|
||
|
__asm__ __volatile__ ("tst1 %1, 0[%2]; setf nz, %0"
|
||
|
: "=r" (rval)
|
||
|
: "i" (V850E_INTC_IC_IF_BIT),
|
||
|
"r" (V850E_INTC_IC_ADDR (irq)));
|
||
|
return rval;
|
||
|
}
|
||
|
|
||
|
|
||
|
struct v850e_intc_irq_init {
|
||
|
const char *name; /* name of interrupt type */
|
||
|
|
||
|
/* Range of kernel irq numbers for this type:
|
||
|
BASE, BASE+INTERVAL, ..., BASE+INTERVAL*NUM */
|
||
|
unsigned base, num, interval;
|
||
|
|
||
|
unsigned priority; /* interrupt priority to assign */
|
||
|
};
|
||
|
struct hw_interrupt_type; /* fwd decl */
|
||
|
|
||
|
/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
|
||
|
INITS (which is terminated by an entry with the name field == 0). */
|
||
|
extern void v850e_intc_init_irq_types (struct v850e_intc_irq_init *inits,
|
||
|
struct hw_interrupt_type *hw_irq_types);
|
||
|
|
||
|
|
||
|
#endif /* !__ASSEMBLY__ */
|
||
|
|
||
|
|
||
|
#endif /* __V850_V850E_INTC_H__ */
|