linux/arch/powerpc/sysdev/mpc8xx_pic.c
<<
>>
Prefs
   1#include <linux/kernel.h>
   2#include <linux/module.h>
   3#include <linux/stddef.h>
   4#include <linux/init.h>
   5#include <linux/sched.h>
   6#include <linux/signal.h>
   7#include <linux/irq.h>
   8#include <linux/dma-mapping.h>
   9#include <asm/prom.h>
  10#include <asm/irq.h>
  11#include <asm/io.h>
  12#include <asm/8xx_immap.h>
  13
  14#include "mpc8xx_pic.h"
  15
  16
  17#define PIC_VEC_SPURRIOUS      15
  18
  19extern int cpm_get_irq(struct pt_regs *regs);
  20
  21static struct irq_host *mpc8xx_pic_host;
  22#define NR_MASK_WORDS   ((NR_IRQS + 31) / 32)
  23static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
  24static sysconf8xx_t __iomem *siu_reg;
  25
  26int cpm_get_irq(struct pt_regs *regs);
  27
  28static void mpc8xx_unmask_irq(unsigned int virq)
  29{
  30        int     bit, word;
  31        unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
  32
  33        bit = irq_nr & 0x1f;
  34        word = irq_nr >> 5;
  35
  36        ppc_cached_irq_mask[word] |= (1 << (31-bit));
  37        out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
  38}
  39
  40static void mpc8xx_mask_irq(unsigned int virq)
  41{
  42        int     bit, word;
  43        unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
  44
  45        bit = irq_nr & 0x1f;
  46        word = irq_nr >> 5;
  47
  48        ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
  49        out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
  50}
  51
  52static void mpc8xx_ack(unsigned int virq)
  53{
  54        int     bit;
  55        unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
  56
  57        bit = irq_nr & 0x1f;
  58        out_be32(&siu_reg->sc_sipend, 1 << (31-bit));
  59}
  60
  61static void mpc8xx_end_irq(unsigned int virq)
  62{
  63        int bit, word;
  64        unsigned int irq_nr = (unsigned int)irq_map[virq].hwirq;
  65
  66        bit = irq_nr & 0x1f;
  67        word = irq_nr >> 5;
  68
  69        ppc_cached_irq_mask[word] |= (1 << (31-bit));
  70        out_be32(&siu_reg->sc_simask, ppc_cached_irq_mask[word]);
  71}
  72
  73static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type)
  74{
  75        struct irq_desc *desc = get_irq_desc(virq);
  76
  77        desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
  78        desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
  79        if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
  80                desc->status |= IRQ_LEVEL;
  81
  82        if (flow_type & IRQ_TYPE_EDGE_FALLING) {
  83                irq_hw_number_t hw = (unsigned int)irq_map[virq].hwirq;
  84                unsigned int siel = in_be32(&siu_reg->sc_siel);
  85
  86                /* only external IRQ senses are programmable */
  87                if ((hw & 1) == 0) {
  88                        siel |= (0x80000000 >> hw);
  89                        out_be32(&siu_reg->sc_siel, siel);
  90                        desc->handle_irq = handle_edge_irq;
  91                }
  92        }
  93        return 0;
  94}
  95
  96static struct irq_chip mpc8xx_pic = {
  97        .typename = " MPC8XX SIU ",
  98        .unmask = mpc8xx_unmask_irq,
  99        .mask = mpc8xx_mask_irq,
 100        .ack = mpc8xx_ack,
 101        .eoi = mpc8xx_end_irq,
 102        .set_type = mpc8xx_set_irq_type,
 103};
 104
 105unsigned int mpc8xx_get_irq(void)
 106{
 107        int irq;
 108
 109        /* For MPC8xx, read the SIVEC register and shift the bits down
 110         * to get the irq number.
 111         */
 112        irq = in_be32(&siu_reg->sc_sivec) >> 26;
 113
 114        if (irq == PIC_VEC_SPURRIOUS)
 115                irq = NO_IRQ;
 116
 117        return irq_linear_revmap(mpc8xx_pic_host, irq);
 118
 119}
 120
 121static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq,
 122                          irq_hw_number_t hw)
 123{
 124        pr_debug("mpc8xx_pic_host_map(%d, 0x%lx)\n", virq, hw);
 125
 126        /* Set default irq handle */
 127        set_irq_chip_and_handler(virq, &mpc8xx_pic, handle_level_irq);
 128        return 0;
 129}
 130
 131
 132static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct,
 133                            u32 *intspec, unsigned int intsize,
 134                            irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 135{
 136        static unsigned char map_pic_senses[4] = {
 137                IRQ_TYPE_EDGE_RISING,
 138                IRQ_TYPE_LEVEL_LOW,
 139                IRQ_TYPE_LEVEL_HIGH,
 140                IRQ_TYPE_EDGE_FALLING,
 141        };
 142
 143        *out_hwirq = intspec[0];
 144        if (intsize > 1 && intspec[1] < 4)
 145                *out_flags = map_pic_senses[intspec[1]];
 146        else
 147                *out_flags = IRQ_TYPE_NONE;
 148
 149        return 0;
 150}
 151
 152
 153static struct irq_host_ops mpc8xx_pic_host_ops = {
 154        .map = mpc8xx_pic_host_map,
 155        .xlate = mpc8xx_pic_host_xlate,
 156};
 157
 158int mpc8xx_pic_init(void)
 159{
 160        struct resource res;
 161        struct device_node *np;
 162        int ret;
 163
 164        np = of_find_compatible_node(NULL, NULL, "fsl,pq1-pic");
 165        if (np == NULL)
 166                np = of_find_node_by_type(NULL, "mpc8xx-pic");
 167        if (np == NULL) {
 168                printk(KERN_ERR "Could not find fsl,pq1-pic node\n");
 169                return -ENOMEM;
 170        }
 171
 172        ret = of_address_to_resource(np, 0, &res);
 173        if (ret)
 174                goto out;
 175
 176        siu_reg = ioremap(res.start, res.end - res.start + 1);
 177        if (siu_reg == NULL) {
 178                ret = -EINVAL;
 179                goto out;
 180        }
 181
 182        mpc8xx_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
 183                                         64, &mpc8xx_pic_host_ops, 64);
 184        if (mpc8xx_pic_host == NULL) {
 185                printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
 186                ret = -ENOMEM;
 187                goto out;
 188        }
 189        return 0;
 190
 191out:
 192        of_node_put(np);
 193        return ret;
 194}
 195
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.