uboot/arch/powerpc/cpu/mpc8260/interrupts.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2000-2002
   3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   4 *
   5 * See file CREDITS for list of people who contributed to this
   6 * project.
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License as
  10 * published by the Free Software Foundation; either version 2 of
  11 * the License, or (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21 * MA 02111-1307 USA
  22 *
  23 * Hacked for MPC8260 by Murray.Jensen@cmst.csiro.au, 22-Oct-00
  24 */
  25
  26#include <common.h>
  27#include <command.h>
  28#include <mpc8260.h>
  29#include <mpc8260_irq.h>
  30#include <asm/processor.h>
  31
  32DECLARE_GLOBAL_DATA_PTR;
  33
  34/****************************************************************************/
  35
  36struct irq_action {
  37        interrupt_handler_t *handler;
  38        void *arg;
  39        ulong count;
  40};
  41
  42static struct irq_action irq_handlers[NR_IRQS];
  43
  44static ulong ppc_cached_irq_mask[NR_MASK_WORDS];
  45
  46/****************************************************************************/
  47/* this section was ripped out of arch/powerpc/kernel/ppc8260_pic.c in the          */
  48/* Linux/PPC 2.4.x source. There was no copyright notice in that file.      */
  49
  50/* The 8260 internal interrupt controller.  It is usually
  51 * the only interrupt controller.
  52 * There are two 32-bit registers (high/low) for up to 64
  53 * possible interrupts.
  54 *
  55 * Now, the fun starts.....Interrupt Numbers DO NOT MAP
  56 * in a simple arithmetic fashion to mask or pending registers.
  57 * That is, interrupt 4 does not map to bit position 4.
  58 * We create two tables, indexed by vector number, to indicate
  59 * which register to use and which bit in the register to use.
  60 */
  61static u_char irq_to_siureg[] = {
  62        1, 1, 1, 1, 1, 1, 1, 1,
  63        1, 1, 1, 1, 1, 1, 1, 1,
  64        0, 0, 0, 0, 0, 0, 0, 0,
  65        0, 0, 0, 0, 0, 0, 0, 0,
  66        1, 1, 1, 1, 1, 1, 1, 1,
  67        1, 1, 1, 1, 1, 1, 1, 1,
  68        0, 0, 0, 0, 0, 0, 0, 0,
  69        0, 0, 0, 0, 0, 0, 0, 0
  70};
  71
  72static u_char irq_to_siubit[] = {
  73        31, 16, 17, 18, 19, 20, 21, 22,
  74        23, 24, 25, 26, 27, 28, 29, 30,
  75        29, 30, 16, 17, 18, 19, 20, 21,
  76        22, 23, 24, 25, 26, 27, 28, 31,
  77        0, 1, 2, 3, 4, 5, 6, 7,
  78        8, 9, 10, 11, 12, 13, 14, 15,
  79        15, 14, 13, 12, 11, 10, 9, 8,
  80        7, 6, 5, 4, 3, 2, 1, 0
  81};
  82
  83static void m8260_mask_irq (unsigned int irq_nr)
  84{
  85        volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
  86        int bit, word;
  87        volatile uint *simr;
  88
  89        bit = irq_to_siubit[irq_nr];
  90        word = irq_to_siureg[irq_nr];
  91
  92        simr = &(immr->im_intctl.ic_simrh);
  93        ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
  94        simr[word] = ppc_cached_irq_mask[word];
  95}
  96
  97static void m8260_unmask_irq (unsigned int irq_nr)
  98{
  99        volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
 100        int bit, word;
 101        volatile uint *simr;
 102
 103        bit = irq_to_siubit[irq_nr];
 104        word = irq_to_siureg[irq_nr];
 105
 106        simr = &(immr->im_intctl.ic_simrh);
 107        ppc_cached_irq_mask[word] |= (1 << (31 - bit));
 108        simr[word] = ppc_cached_irq_mask[word];
 109}
 110
 111static void m8260_mask_and_ack (unsigned int irq_nr)
 112{
 113        volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
 114        int bit, word;
 115        volatile uint *simr, *sipnr;
 116
 117        bit = irq_to_siubit[irq_nr];
 118        word = irq_to_siureg[irq_nr];
 119
 120        simr = &(immr->im_intctl.ic_simrh);
 121        sipnr = &(immr->im_intctl.ic_sipnrh);
 122        ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
 123        simr[word] = ppc_cached_irq_mask[word];
 124        sipnr[word] = 1 << (31 - bit);
 125}
 126
 127static int m8260_get_irq (struct pt_regs *regs)
 128{
 129        volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
 130        int irq;
 131        unsigned long bits;
 132
 133        /* For MPC8260, read the SIVEC register and shift the bits down
 134         * to get the irq number.         */
 135        bits = immr->im_intctl.ic_sivec;
 136        irq = bits >> 26;
 137        return irq;
 138}
 139
 140/* end of code ripped out of arch/powerpc/kernel/ppc8260_pic.c              */
 141/****************************************************************************/
 142
 143int interrupt_init_cpu (unsigned *decrementer_count)
 144{
 145        volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
 146
 147        *decrementer_count = (gd->bus_clk / 4) / CONFIG_SYS_HZ;
 148
 149        /* Initialize the default interrupt mapping priorities */
 150        immr->im_intctl.ic_sicr = 0;
 151        immr->im_intctl.ic_siprr = 0x05309770;
 152        immr->im_intctl.ic_scprrh = 0x05309770;
 153        immr->im_intctl.ic_scprrl = 0x05309770;
 154
 155        /* disable all interrupts and clear all pending bits */
 156        immr->im_intctl.ic_simrh = ppc_cached_irq_mask[0] = 0;
 157        immr->im_intctl.ic_simrl = ppc_cached_irq_mask[1] = 0;
 158        immr->im_intctl.ic_sipnrh = 0xffffffff;
 159        immr->im_intctl.ic_sipnrl = 0xffffffff;
 160
 161#ifdef CONFIG_HYMOD
 162        /*
 163         * ensure all external interrupt sources default to trigger on
 164         * high-to-low transition (i.e. edge triggered active low)
 165         */
 166        immr->im_intctl.ic_siexr = -1;
 167#endif
 168
 169        return (0);
 170}
 171
 172/****************************************************************************/
 173
 174/*
 175 * Handle external interrupts
 176 */
 177void external_interrupt (struct pt_regs *regs)
 178{
 179        int irq, unmask = 1;
 180
 181        irq = m8260_get_irq (regs);
 182
 183        m8260_mask_and_ack (irq);
 184
 185        enable_interrupts ();
 186
 187        if (irq_handlers[irq].handler != NULL)
 188                (*irq_handlers[irq].handler) (irq_handlers[irq].arg);
 189        else {
 190                printf ("\nBogus External Interrupt IRQ %d\n", irq);
 191                /*
 192                 * turn off the bogus interrupt, otherwise it
 193                 * might repeat forever
 194                 */
 195                unmask = 0;
 196        }
 197
 198        if (unmask)
 199                m8260_unmask_irq (irq);
 200}
 201
 202/****************************************************************************/
 203
 204/*
 205 * Install and free an interrupt handler.
 206 */
 207
 208void
 209irq_install_handler (int irq, interrupt_handler_t * handler, void *arg)
 210{
 211        if (irq < 0 || irq >= NR_IRQS) {
 212                printf ("irq_install_handler: bad irq number %d\n", irq);
 213                return;
 214        }
 215
 216        if (irq_handlers[irq].handler != NULL)
 217                printf ("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
 218                                (ulong) handler, (ulong) irq_handlers[irq].handler);
 219
 220        irq_handlers[irq].handler = handler;
 221        irq_handlers[irq].arg = arg;
 222
 223        m8260_unmask_irq (irq);
 224}
 225
 226void irq_free_handler (int irq)
 227{
 228        if (irq < 0 || irq >= NR_IRQS) {
 229                printf ("irq_free_handler: bad irq number %d\n", irq);
 230                return;
 231        }
 232
 233        m8260_mask_irq (irq);
 234
 235        irq_handlers[irq].handler = NULL;
 236        irq_handlers[irq].arg = NULL;
 237}
 238
 239/****************************************************************************/
 240
 241void timer_interrupt_cpu (struct pt_regs *regs)
 242{
 243        /* nothing to do here */
 244        return;
 245}
 246
 247/****************************************************************************/
 248
 249#if defined(CONFIG_CMD_IRQ)
 250
 251/* ripped this out of ppc4xx/interrupts.c */
 252
 253/*******************************************************************************
 254*
 255* irqinfo - print information about PCI devices
 256*
 257*/
 258void
 259do_irqinfo (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char * const argv[])
 260{
 261        int irq, re_enable;
 262
 263        re_enable = disable_interrupts ();
 264
 265        puts ("\nInterrupt-Information:\n"
 266                "Nr  Routine   Arg       Count\n");
 267
 268        for (irq = 0; irq < 32; irq++)
 269                if (irq_handlers[irq].handler != NULL)
 270                        printf ("%02d  %08lx  %08lx  %ld\n", irq,
 271                                        (ulong) irq_handlers[irq].handler,
 272                                        (ulong) irq_handlers[irq].arg,
 273                                        irq_handlers[irq].count);
 274
 275        if (re_enable)
 276                enable_interrupts ();
 277}
 278
 279#endif
 280