Logo Search packages:      
Sourcecode: linux version File versions  Download package

intc-sh5.c

/*
 * arch/sh/kernel/cpu/irq/intc-sh5.c
 *
 * Interrupt Controller support for SH5 INTC.
 *
 * Copyright (C) 2000, 2001  Paolo Alberelli
 * Copyright (C) 2003  Paul Mundt
 *
 * Per-interrupt selective. IRLM=0 (Fixed priority) is not
 * supported being useless without a cascaded interrupt
 * controller.
 *
 * 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.
 */
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <cpu/irq.h>
#include <asm/page.h>

/*
 * Maybe the generic Peripheral block could move to a more
 * generic include file. INTC Block will be defined here
 * and only here to make INTC self-contained in a single
 * file.
 */
#define     INTC_BLOCK_OFFSET 0x01000000

/* Base */
#define INTC_BASE       PHYS_PERIPHERAL_BLOCK + \
                        INTC_BLOCK_OFFSET

/* Address */
#define INTC_ICR_SET          (intc_virt + 0x0)
#define INTC_ICR_CLEAR        (intc_virt + 0x8)
#define INTC_INTPRI_0         (intc_virt + 0x10)
#define INTC_INTSRC_0         (intc_virt + 0x50)
#define INTC_INTSRC_1         (intc_virt + 0x58)
#define INTC_INTREQ_0         (intc_virt + 0x60)
#define INTC_INTREQ_1         (intc_virt + 0x68)
#define INTC_INTENB_0         (intc_virt + 0x70)
#define INTC_INTENB_1         (intc_virt + 0x78)
#define INTC_INTDSB_0         (intc_virt + 0x80)
#define INTC_INTDSB_1         (intc_virt + 0x88)

#define INTC_ICR_IRLM         0x1
#define     INTC_INTPRI_PREGS 8           /* 8 Priority Registers */
#define     INTC_INTPRI_PPREG 8           /* 8 Priorities per Register */


/*
 * Mapper between the vector ordinal and the IRQ number
 * passed to kernel/device drivers.
 */
int intc_evt_to_irq[(0xE20/0x20)+1] = {
      -1, -1, -1, -1, -1, -1, -1, -1,     /* 0x000 - 0x0E0 */
      -1, -1, -1, -1, -1, -1, -1, -1,     /* 0x100 - 0x1E0 */
       0,  0,  0,  0,  0,  1,  0,  0,     /* 0x200 - 0x2E0 */
       2,  0,  0,  3,  0,  0,  0, -1,     /* 0x300 - 0x3E0 */
      32, 33, 34, 35, 36, 37, 38, -1,     /* 0x400 - 0x4E0 */
      -1, -1, -1, 63, -1, -1, -1, -1,     /* 0x500 - 0x5E0 */
      -1, -1, 18, 19, 20, 21, 22, -1,     /* 0x600 - 0x6E0 */
      39, 40, 41, 42, -1, -1, -1, -1,     /* 0x700 - 0x7E0 */
       4,  5,  6,  7, -1, -1, -1, -1,     /* 0x800 - 0x8E0 */
      -1, -1, -1, -1, -1, -1, -1, -1,     /* 0x900 - 0x9E0 */
      12, 13, 14, 15, 16, 17, -1, -1,     /* 0xA00 - 0xAE0 */
      -1, -1, -1, -1, -1, -1, -1, -1,     /* 0xB00 - 0xBE0 */
      -1, -1, -1, -1, -1, -1, -1, -1,     /* 0xC00 - 0xCE0 */
      -1, -1, -1, -1, -1, -1, -1, -1,     /* 0xD00 - 0xDE0 */
      -1, -1                        /* 0xE00 - 0xE20 */
};

static unsigned long intc_virt;

static unsigned int startup_intc_irq(unsigned int irq);
static void shutdown_intc_irq(unsigned int irq);
static void enable_intc_irq(unsigned int irq);
static void disable_intc_irq(unsigned int irq);
static void mask_and_ack_intc(unsigned int);
static void end_intc_irq(unsigned int irq);

static struct hw_interrupt_type intc_irq_type = {
      .typename = "INTC",
      .startup = startup_intc_irq,
      .shutdown = shutdown_intc_irq,
      .enable = enable_intc_irq,
      .disable = disable_intc_irq,
      .ack = mask_and_ack_intc,
      .end = end_intc_irq
};

static int irlm;        /* IRL mode */

static unsigned int startup_intc_irq(unsigned int irq)
{
      enable_intc_irq(irq);
      return 0; /* never anything pending */
}

static void shutdown_intc_irq(unsigned int irq)
{
      disable_intc_irq(irq);
}

static void enable_intc_irq(unsigned int irq)
{
      unsigned long reg;
      unsigned long bitmask;

      if ((irq <= IRQ_IRL3) && (irlm == NO_PRIORITY))
            printk("Trying to use straight IRL0-3 with an encoding platform.\n");

      if (irq < 32) {
            reg = INTC_INTENB_0;
            bitmask = 1 << irq;
      } else {
            reg = INTC_INTENB_1;
            bitmask = 1 << (irq - 32);
      }

      ctrl_outl(bitmask, reg);
}

static void disable_intc_irq(unsigned int irq)
{
      unsigned long reg;
      unsigned long bitmask;

      if (irq < 32) {
            reg = INTC_INTDSB_0;
            bitmask = 1 << irq;
      } else {
            reg = INTC_INTDSB_1;
            bitmask = 1 << (irq - 32);
      }

      ctrl_outl(bitmask, reg);
}

static void mask_and_ack_intc(unsigned int irq)
{
      disable_intc_irq(irq);
}

static void end_intc_irq(unsigned int irq)
{
      enable_intc_irq(irq);
}

/* For future use, if we ever support IRLM=0) */
void make_intc_irq(unsigned int irq)
{
      disable_irq_nosync(irq);
      irq_desc[irq].chip = &intc_irq_type;
      disable_intc_irq(irq);
}

#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
static int IRQ_to_vectorN[NR_INTC_IRQS] = {
      0x12, 0x15, 0x18, 0x1B, 0x40, 0x41, 0x42, 0x43, /*  0- 7 */
        -1,   -1,   -1,   -1, 0x50, 0x51, 0x52, 0x53, /*  8-15 */
      0x54, 0x55, 0x32, 0x33, 0x34, 0x35, 0x36,   -1, /* 16-23 */
        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, /* 24-31 */
      0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x38, /* 32-39 */
        0x39, 0x3A, 0x3B,   -1,   -1,   -1,   -1,   -1, /* 40-47 */
        -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, /* 48-55 */
        -1,   -1,   -1,   -1,   -1,   -1,   -1, 0x2B, /* 56-63 */

};

int intc_irq_describe(char* p, int irq)
{
      if (irq < NR_INTC_IRQS)
            return sprintf(p, "(0x%3x)", IRQ_to_vectorN[irq]*0x20);
      else
            return 0;
}
#endif

void __init plat_irq_setup(void)
{
      unsigned long long __dummy0, __dummy1=~0x00000000100000f0;
      unsigned long reg;
      int i;

      intc_virt = onchip_remap(INTC_BASE, 1024, "INTC");
      if (!intc_virt) {
            panic("Unable to remap INTC\n");
      }


      /* Set default: per-line enable/disable, priority driven ack/eoi */
      for (i = 0; i < NR_INTC_IRQS; i++)
            irq_desc[i].chip = &intc_irq_type;


      /* Disable all interrupts and set all priorities to 0 to avoid trouble */
      ctrl_outl(-1, INTC_INTDSB_0);
      ctrl_outl(-1, INTC_INTDSB_1);

      for (reg = INTC_INTPRI_0, i = 0; i < INTC_INTPRI_PREGS; i++, reg += 8)
            ctrl_outl( NO_PRIORITY, reg);


#ifdef CONFIG_SH_CAYMAN
      {
            unsigned long data;

            /* Set IRLM */
            /* If all the priorities are set to 'no priority', then
             * assume we are using encoded mode.
             */
            irlm = platform_int_priority[IRQ_IRL0] +
                   platform_int_priority[IRQ_IRL1] +
                   platform_int_priority[IRQ_IRL2] +
                   platform_int_priority[IRQ_IRL3];
            if (irlm == NO_PRIORITY) {
                  /* IRLM = 0 */
                  reg = INTC_ICR_CLEAR;
                  i = IRQ_INTA;
                  printk("Trying to use encoded IRL0-3. IRLs unsupported.\n");
            } else {
                  /* IRLM = 1 */
                  reg = INTC_ICR_SET;
                  i = IRQ_IRL0;
            }
            ctrl_outl(INTC_ICR_IRLM, reg);

            /* Set interrupt priorities according to platform description */
            for (data = 0, reg = INTC_INTPRI_0; i < NR_INTC_IRQS; i++) {
                  data |= platform_int_priority[i] <<
                        ((i % INTC_INTPRI_PPREG) * 4);
                  if ((i % INTC_INTPRI_PPREG) == (INTC_INTPRI_PPREG - 1)) {
                        /* Upon the 7th, set Priority Register */
                        ctrl_outl(data, reg);
                        data = 0;
                        reg += 8;
                  }
            }
      }
#endif

      /*
       * And now let interrupts come in.
       * sti() is not enough, we need to
       * lower priority, too.
       */
        __asm__ __volatile__("getcon    " __SR ", %0\n\t"
                             "and       %0, %1, %0\n\t"
                             "putcon    %0, " __SR "\n\t"
                             : "=&r" (__dummy0)
                             : "r" (__dummy1));
}

Generated by  Doxygen 1.6.0   Back to index