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

cpc700_pic.c

/*
 * Interrupt controller support for IBM Spruce
 *
 * Authors: Mark Greer, Matt Porter, and Johnnie Peters
 *        mgreer@mvista.com
 *          mporter@mvista.com
 *          jpeters@mvista.com
 *
 * 2001-2002 (c) MontaVista, Software, Inc.  This file is licensed under
 * the terms of the GNU General Public License version 2.  This program
 * is licensed "as is" without any warranty of any kind, whether express
 * or implied.
 */

#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/irq.h>

#include <asm/io.h>
#include <asm/system.h>
#include <asm/irq.h>

#include "cpc700.h"

static void
cpc700_unmask_irq(unsigned int irq)
{
      unsigned int tr_bits;

      /*
       * IRQ 31 is largest IRQ supported.
       * IRQs 17-19 are reserved.
       */
      if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
            tr_bits = CPC700_IN_32(CPC700_UIC_UICTR);

            if ((tr_bits & (1 << (31 - irq))) == 0) {
                  /* level trigger interrupt, clear bit in status
                   * register */
                  CPC700_OUT_32(CPC700_UIC_UICSR, 1 << (31 - irq));
            }

            /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
            ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq);
      
            CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
      }
      return;
}

static void
cpc700_mask_irq(unsigned int irq)
{
      /*
       * IRQ 31 is largest IRQ supported.
       * IRQs 17-19 are reserved.
       */
      if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
            /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
            ppc_cached_irq_mask[0] &=
                  ~CPC700_UIC_IRQ_BIT(irq);

            CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
      }
      return;
}

static void
cpc700_mask_and_ack_irq(unsigned int irq)
{
      u_int bit;

      /*
       * IRQ 31 is largest IRQ supported.
       * IRQs 17-19 are reserved.
       */
      if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
            /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
            bit = CPC700_UIC_IRQ_BIT(irq);

            ppc_cached_irq_mask[0] &= ~bit;
            CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
            CPC700_OUT_32(CPC700_UIC_UICSR, bit); /* Write 1 clears IRQ */
      }
      return;
}

static struct hw_interrupt_type cpc700_pic = {
      .typename = "CPC700 PIC",
      .enable = cpc700_unmask_irq,
      .disable = cpc700_mask_irq,
      .ack = cpc700_mask_and_ack_irq,
};

__init static void
cpc700_pic_init_irq(unsigned int irq)
{
      unsigned int tmp;

      /* Set interrupt sense */
      tmp = CPC700_IN_32(CPC700_UIC_UICTR);
      if (cpc700_irq_assigns[irq][0] == 0) {
            tmp &= ~CPC700_UIC_IRQ_BIT(irq);
      } else {
            tmp |= CPC700_UIC_IRQ_BIT(irq);
      }
      CPC700_OUT_32(CPC700_UIC_UICTR, tmp);

      /* Set interrupt polarity */
      tmp = CPC700_IN_32(CPC700_UIC_UICPR);
      if (cpc700_irq_assigns[irq][1]) {
            tmp |= CPC700_UIC_IRQ_BIT(irq);
      } else {
            tmp &= ~CPC700_UIC_IRQ_BIT(irq);
      }
      CPC700_OUT_32(CPC700_UIC_UICPR, tmp);

      /* Set interrupt critical */
      tmp = CPC700_IN_32(CPC700_UIC_UICCR);
      tmp |= CPC700_UIC_IRQ_BIT(irq);
      CPC700_OUT_32(CPC700_UIC_UICCR, tmp);
            
      return;
}

__init void
cpc700_init_IRQ(void)
{
      int i;

      ppc_cached_irq_mask[0] = 0;
      CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000);    /* Disable all irq's */
      CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff);    /* Clear cur intrs */
      CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff);    /* Gen INT not MCP */
      CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000);    /* Active low */
      CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000);    /* Level Sensitive */
      CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI);
                                            /* IRQ 0 is highest */

      for (i = 0; i < 17; i++) {
            irq_desc[i].chip = &cpc700_pic;
            cpc700_pic_init_irq(i);
      }

      for (i = 20; i < 32; i++) {
            irq_desc[i].chip = &cpc700_pic;
            cpc700_pic_init_irq(i);
      }

      return;
}



/*
 * Find the highest IRQ that generating an interrupt, if any.
 */
int
cpc700_get_irq(void)
{
      int irq = 0;
      u_int irq_status, irq_test = 1;

      irq_status = CPC700_IN_32(CPC700_UIC_UICMSR);

      do
      {
            if (irq_status & irq_test)
                  break;
            irq++;
            irq_test <<= 1;
      } while (irq < NR_IRQS);
      

      if (irq == NR_IRQS)
          irq = 33;

      return (31 - irq);
}

Generated by  Doxygen 1.6.0   Back to index