123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954 |
- /*
- * arch/powerpc/sysdev/ipic.c
- *
- * IPIC routines implementations.
- *
- * Copyright 2005 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/errno.h>
- #include <linux/reboot.h>
- #include <linux/slab.h>
- #include <linux/stddef.h>
- #include <linux/sched.h>
- #include <linux/signal.h>
- #include <linux/syscore_ops.h>
- #include <linux/device.h>
- #include <linux/spinlock.h>
- #include <linux/fsl_devices.h>
- #include <asm/irq.h>
- #include <asm/io.h>
- #include <asm/prom.h>
- #include <asm/ipic.h>
- #include "ipic.h"
- static struct ipic * primary_ipic;
- static struct irq_chip ipic_level_irq_chip, ipic_edge_irq_chip;
- static DEFINE_RAW_SPINLOCK(ipic_lock);
- static struct ipic_info ipic_info[] = {
- [1] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_C,
- .force = IPIC_SIFCR_H,
- .bit = 16,
- .prio_mask = 0,
- },
- [2] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_C,
- .force = IPIC_SIFCR_H,
- .bit = 17,
- .prio_mask = 1,
- },
- [3] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_C,
- .force = IPIC_SIFCR_H,
- .bit = 18,
- .prio_mask = 2,
- },
- [4] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_C,
- .force = IPIC_SIFCR_H,
- .bit = 19,
- .prio_mask = 3,
- },
- [5] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_C,
- .force = IPIC_SIFCR_H,
- .bit = 20,
- .prio_mask = 4,
- },
- [6] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_C,
- .force = IPIC_SIFCR_H,
- .bit = 21,
- .prio_mask = 5,
- },
- [7] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_C,
- .force = IPIC_SIFCR_H,
- .bit = 22,
- .prio_mask = 6,
- },
- [8] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_C,
- .force = IPIC_SIFCR_H,
- .bit = 23,
- .prio_mask = 7,
- },
- [9] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 24,
- .prio_mask = 0,
- },
- [10] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 25,
- .prio_mask = 1,
- },
- [11] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 26,
- .prio_mask = 2,
- },
- [12] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 27,
- .prio_mask = 3,
- },
- [13] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 28,
- .prio_mask = 4,
- },
- [14] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 29,
- .prio_mask = 5,
- },
- [15] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 30,
- .prio_mask = 6,
- },
- [16] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 31,
- .prio_mask = 7,
- },
- [17] = {
- .ack = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SEFCR,
- .bit = 1,
- .prio_mask = 5,
- },
- [18] = {
- .ack = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SEFCR,
- .bit = 2,
- .prio_mask = 6,
- },
- [19] = {
- .ack = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SEFCR,
- .bit = 3,
- .prio_mask = 7,
- },
- [20] = {
- .ack = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SEFCR,
- .bit = 4,
- .prio_mask = 4,
- },
- [21] = {
- .ack = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SEFCR,
- .bit = 5,
- .prio_mask = 5,
- },
- [22] = {
- .ack = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SEFCR,
- .bit = 6,
- .prio_mask = 6,
- },
- [23] = {
- .ack = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SEFCR,
- .bit = 7,
- .prio_mask = 7,
- },
- [32] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 0,
- .prio_mask = 0,
- },
- [33] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 1,
- .prio_mask = 1,
- },
- [34] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 2,
- .prio_mask = 2,
- },
- [35] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 3,
- .prio_mask = 3,
- },
- [36] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 4,
- .prio_mask = 4,
- },
- [37] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 5,
- .prio_mask = 5,
- },
- [38] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 6,
- .prio_mask = 6,
- },
- [39] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 7,
- .prio_mask = 7,
- },
- [40] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_B,
- .force = IPIC_SIFCR_H,
- .bit = 8,
- .prio_mask = 0,
- },
- [41] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_B,
- .force = IPIC_SIFCR_H,
- .bit = 9,
- .prio_mask = 1,
- },
- [42] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_B,
- .force = IPIC_SIFCR_H,
- .bit = 10,
- .prio_mask = 2,
- },
- [43] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_B,
- .force = IPIC_SIFCR_H,
- .bit = 11,
- .prio_mask = 3,
- },
- [44] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_B,
- .force = IPIC_SIFCR_H,
- .bit = 12,
- .prio_mask = 4,
- },
- [45] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_B,
- .force = IPIC_SIFCR_H,
- .bit = 13,
- .prio_mask = 5,
- },
- [46] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_B,
- .force = IPIC_SIFCR_H,
- .bit = 14,
- .prio_mask = 6,
- },
- [47] = {
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_B,
- .force = IPIC_SIFCR_H,
- .bit = 15,
- .prio_mask = 7,
- },
- [48] = {
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SEFCR,
- .bit = 0,
- .prio_mask = 4,
- },
- [64] = {
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SIFCR_L,
- .bit = 0,
- .prio_mask = 0,
- },
- [65] = {
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SIFCR_L,
- .bit = 1,
- .prio_mask = 1,
- },
- [66] = {
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SIFCR_L,
- .bit = 2,
- .prio_mask = 2,
- },
- [67] = {
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SIFCR_L,
- .bit = 3,
- .prio_mask = 3,
- },
- [68] = {
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SIFCR_L,
- .bit = 4,
- .prio_mask = 0,
- },
- [69] = {
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SIFCR_L,
- .bit = 5,
- .prio_mask = 1,
- },
- [70] = {
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SIFCR_L,
- .bit = 6,
- .prio_mask = 2,
- },
- [71] = {
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SIFCR_L,
- .bit = 7,
- .prio_mask = 3,
- },
- [72] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 8,
- },
- [73] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 9,
- },
- [74] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 10,
- },
- [75] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 11,
- },
- [76] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 12,
- },
- [77] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 13,
- },
- [78] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 14,
- },
- [79] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 15,
- },
- [80] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 16,
- },
- [81] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 17,
- },
- [82] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 18,
- },
- [83] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 19,
- },
- [84] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 20,
- },
- [85] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 21,
- },
- [86] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 22,
- },
- [87] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 23,
- },
- [88] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 24,
- },
- [89] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 25,
- },
- [90] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 26,
- },
- [91] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 27,
- },
- [94] = {
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 30,
- },
- };
- static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg)
- {
- return in_be32(base + (reg >> 2));
- }
- static inline void ipic_write(volatile u32 __iomem *base, unsigned int reg, u32 value)
- {
- out_be32(base + (reg >> 2), value);
- }
- static inline struct ipic * ipic_from_irq(unsigned int virq)
- {
- return primary_ipic;
- }
- static void ipic_unmask_irq(struct irq_data *d)
- {
- struct ipic *ipic = ipic_from_irq(d->irq);
- unsigned int src = irqd_to_hwirq(d);
- unsigned long flags;
- u32 temp;
- raw_spin_lock_irqsave(&ipic_lock, flags);
- temp = ipic_read(ipic->regs, ipic_info[src].mask);
- temp |= (1 << (31 - ipic_info[src].bit));
- ipic_write(ipic->regs, ipic_info[src].mask, temp);
- raw_spin_unlock_irqrestore(&ipic_lock, flags);
- }
- static void ipic_mask_irq(struct irq_data *d)
- {
- struct ipic *ipic = ipic_from_irq(d->irq);
- unsigned int src = irqd_to_hwirq(d);
- unsigned long flags;
- u32 temp;
- raw_spin_lock_irqsave(&ipic_lock, flags);
- temp = ipic_read(ipic->regs, ipic_info[src].mask);
- temp &= ~(1 << (31 - ipic_info[src].bit));
- ipic_write(ipic->regs, ipic_info[src].mask, temp);
- /* mb() can't guarantee that masking is finished. But it does finish
- * for nearly all cases. */
- mb();
- raw_spin_unlock_irqrestore(&ipic_lock, flags);
- }
- static void ipic_ack_irq(struct irq_data *d)
- {
- struct ipic *ipic = ipic_from_irq(d->irq);
- unsigned int src = irqd_to_hwirq(d);
- unsigned long flags;
- u32 temp;
- raw_spin_lock_irqsave(&ipic_lock, flags);
- temp = 1 << (31 - ipic_info[src].bit);
- ipic_write(ipic->regs, ipic_info[src].ack, temp);
- /* mb() can't guarantee that ack is finished. But it does finish
- * for nearly all cases. */
- mb();
- raw_spin_unlock_irqrestore(&ipic_lock, flags);
- }
- static void ipic_mask_irq_and_ack(struct irq_data *d)
- {
- struct ipic *ipic = ipic_from_irq(d->irq);
- unsigned int src = irqd_to_hwirq(d);
- unsigned long flags;
- u32 temp;
- raw_spin_lock_irqsave(&ipic_lock, flags);
- temp = ipic_read(ipic->regs, ipic_info[src].mask);
- temp &= ~(1 << (31 - ipic_info[src].bit));
- ipic_write(ipic->regs, ipic_info[src].mask, temp);
- temp = 1 << (31 - ipic_info[src].bit);
- ipic_write(ipic->regs, ipic_info[src].ack, temp);
- /* mb() can't guarantee that ack is finished. But it does finish
- * for nearly all cases. */
- mb();
- raw_spin_unlock_irqrestore(&ipic_lock, flags);
- }
- static int ipic_set_irq_type(struct irq_data *d, unsigned int flow_type)
- {
- struct ipic *ipic = ipic_from_irq(d->irq);
- unsigned int src = irqd_to_hwirq(d);
- unsigned int vold, vnew, edibit;
- if (flow_type == IRQ_TYPE_NONE)
- flow_type = IRQ_TYPE_LEVEL_LOW;
- /* ipic supports only low assertion and high-to-low change senses
- */
- if (!(flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))) {
- printk(KERN_ERR "ipic: sense type 0x%x not supported\n",
- flow_type);
- return -EINVAL;
- }
- /* ipic supports only edge mode on external interrupts */
- if ((flow_type & IRQ_TYPE_EDGE_FALLING) && !ipic_info[src].ack) {
- printk(KERN_ERR "ipic: edge sense not supported on internal "
- "interrupts\n");
- return -EINVAL;
- }
- irqd_set_trigger_type(d, flow_type);
- if (flow_type & IRQ_TYPE_LEVEL_LOW) {
- irq_set_handler_locked(d, handle_level_irq);
- d->chip = &ipic_level_irq_chip;
- } else {
- irq_set_handler_locked(d, handle_edge_irq);
- d->chip = &ipic_edge_irq_chip;
- }
- /* only EXT IRQ senses are programmable on ipic
- * internal IRQ senses are LEVEL_LOW
- */
- if (src == IPIC_IRQ_EXT0)
- edibit = 15;
- else
- if (src >= IPIC_IRQ_EXT1 && src <= IPIC_IRQ_EXT7)
- edibit = (14 - (src - IPIC_IRQ_EXT1));
- else
- return (flow_type & IRQ_TYPE_LEVEL_LOW) ? 0 : -EINVAL;
- vold = ipic_read(ipic->regs, IPIC_SECNR);
- if ((flow_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_FALLING) {
- vnew = vold | (1 << edibit);
- } else {
- vnew = vold & ~(1 << edibit);
- }
- if (vold != vnew)
- ipic_write(ipic->regs, IPIC_SECNR, vnew);
- return IRQ_SET_MASK_OK_NOCOPY;
- }
- /* level interrupts and edge interrupts have different ack operations */
- static struct irq_chip ipic_level_irq_chip = {
- .name = "IPIC",
- .irq_unmask = ipic_unmask_irq,
- .irq_mask = ipic_mask_irq,
- .irq_mask_ack = ipic_mask_irq,
- .irq_set_type = ipic_set_irq_type,
- };
- static struct irq_chip ipic_edge_irq_chip = {
- .name = "IPIC",
- .irq_unmask = ipic_unmask_irq,
- .irq_mask = ipic_mask_irq,
- .irq_mask_ack = ipic_mask_irq_and_ack,
- .irq_ack = ipic_ack_irq,
- .irq_set_type = ipic_set_irq_type,
- };
- static int ipic_host_match(struct irq_domain *h, struct device_node *node,
- enum irq_domain_bus_token bus_token)
- {
- /* Exact match, unless ipic node is NULL */
- struct device_node *of_node = irq_domain_get_of_node(h);
- return of_node == NULL || of_node == node;
- }
- static int ipic_host_map(struct irq_domain *h, unsigned int virq,
- irq_hw_number_t hw)
- {
- struct ipic *ipic = h->host_data;
- irq_set_chip_data(virq, ipic);
- irq_set_chip_and_handler(virq, &ipic_level_irq_chip, handle_level_irq);
- /* Set default irq type */
- irq_set_irq_type(virq, IRQ_TYPE_NONE);
- return 0;
- }
- static const struct irq_domain_ops ipic_host_ops = {
- .match = ipic_host_match,
- .map = ipic_host_map,
- .xlate = irq_domain_xlate_onetwocell,
- };
- struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
- {
- struct ipic *ipic;
- struct resource res;
- u32 temp = 0, ret;
- ret = of_address_to_resource(node, 0, &res);
- if (ret)
- return NULL;
- ipic = kzalloc(sizeof(*ipic), GFP_KERNEL);
- if (ipic == NULL)
- return NULL;
- ipic->irqhost = irq_domain_add_linear(node, NR_IPIC_INTS,
- &ipic_host_ops, ipic);
- if (ipic->irqhost == NULL) {
- kfree(ipic);
- return NULL;
- }
- ipic->regs = ioremap(res.start, resource_size(&res));
- /* init hw */
- ipic_write(ipic->regs, IPIC_SICNR, 0x0);
- /* default priority scheme is grouped. If spread mode is required
- * configure SICFR accordingly */
- if (flags & IPIC_SPREADMODE_GRP_A)
- temp |= SICFR_IPSA;
- if (flags & IPIC_SPREADMODE_GRP_B)
- temp |= SICFR_IPSB;
- if (flags & IPIC_SPREADMODE_GRP_C)
- temp |= SICFR_IPSC;
- if (flags & IPIC_SPREADMODE_GRP_D)
- temp |= SICFR_IPSD;
- if (flags & IPIC_SPREADMODE_MIX_A)
- temp |= SICFR_MPSA;
- if (flags & IPIC_SPREADMODE_MIX_B)
- temp |= SICFR_MPSB;
- ipic_write(ipic->regs, IPIC_SICFR, temp);
- /* handle MCP route */
- temp = 0;
- if (flags & IPIC_DISABLE_MCP_OUT)
- temp = SERCR_MCPR;
- ipic_write(ipic->regs, IPIC_SERCR, temp);
- /* handle routing of IRQ0 to MCP */
- temp = ipic_read(ipic->regs, IPIC_SEMSR);
- if (flags & IPIC_IRQ0_MCP)
- temp |= SEMSR_SIRQ0;
- else
- temp &= ~SEMSR_SIRQ0;
- ipic_write(ipic->regs, IPIC_SEMSR, temp);
- primary_ipic = ipic;
- irq_set_default_host(primary_ipic->irqhost);
- ipic_write(ipic->regs, IPIC_SIMSR_H, 0);
- ipic_write(ipic->regs, IPIC_SIMSR_L, 0);
- printk ("IPIC (%d IRQ sources) at %p\n", NR_IPIC_INTS,
- primary_ipic->regs);
- return ipic;
- }
- int ipic_set_priority(unsigned int virq, unsigned int priority)
- {
- struct ipic *ipic = ipic_from_irq(virq);
- unsigned int src = virq_to_hw(virq);
- u32 temp;
- if (priority > 7)
- return -EINVAL;
- if (src > 127)
- return -EINVAL;
- if (ipic_info[src].prio == 0)
- return -EINVAL;
- temp = ipic_read(ipic->regs, ipic_info[src].prio);
- if (priority < 4) {
- temp &= ~(0x7 << (20 + (3 - priority) * 3));
- temp |= ipic_info[src].prio_mask << (20 + (3 - priority) * 3);
- } else {
- temp &= ~(0x7 << (4 + (7 - priority) * 3));
- temp |= ipic_info[src].prio_mask << (4 + (7 - priority) * 3);
- }
- ipic_write(ipic->regs, ipic_info[src].prio, temp);
- return 0;
- }
- void ipic_set_highest_priority(unsigned int virq)
- {
- struct ipic *ipic = ipic_from_irq(virq);
- unsigned int src = virq_to_hw(virq);
- u32 temp;
- temp = ipic_read(ipic->regs, IPIC_SICFR);
- /* clear and set HPI */
- temp &= 0x7f000000;
- temp |= (src & 0x7f) << 24;
- ipic_write(ipic->regs, IPIC_SICFR, temp);
- }
- void ipic_set_default_priority(void)
- {
- ipic_write(primary_ipic->regs, IPIC_SIPRR_A, IPIC_PRIORITY_DEFAULT);
- ipic_write(primary_ipic->regs, IPIC_SIPRR_B, IPIC_PRIORITY_DEFAULT);
- ipic_write(primary_ipic->regs, IPIC_SIPRR_C, IPIC_PRIORITY_DEFAULT);
- ipic_write(primary_ipic->regs, IPIC_SIPRR_D, IPIC_PRIORITY_DEFAULT);
- ipic_write(primary_ipic->regs, IPIC_SMPRR_A, IPIC_PRIORITY_DEFAULT);
- ipic_write(primary_ipic->regs, IPIC_SMPRR_B, IPIC_PRIORITY_DEFAULT);
- }
- void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq)
- {
- struct ipic *ipic = primary_ipic;
- u32 temp;
- temp = ipic_read(ipic->regs, IPIC_SERMR);
- temp |= (1 << (31 - mcp_irq));
- ipic_write(ipic->regs, IPIC_SERMR, temp);
- }
- void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq)
- {
- struct ipic *ipic = primary_ipic;
- u32 temp;
- temp = ipic_read(ipic->regs, IPIC_SERMR);
- temp &= (1 << (31 - mcp_irq));
- ipic_write(ipic->regs, IPIC_SERMR, temp);
- }
- u32 ipic_get_mcp_status(void)
- {
- return ipic_read(primary_ipic->regs, IPIC_SERSR);
- }
- void ipic_clear_mcp_status(u32 mask)
- {
- ipic_write(primary_ipic->regs, IPIC_SERSR, mask);
- }
- /* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
- unsigned int ipic_get_irq(void)
- {
- int irq;
- BUG_ON(primary_ipic == NULL);
- #define IPIC_SIVCR_VECTOR_MASK 0x7f
- irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & IPIC_SIVCR_VECTOR_MASK;
- if (irq == 0) /* 0 --> no irq is pending */
- return NO_IRQ;
- return irq_linear_revmap(primary_ipic->irqhost, irq);
- }
- #ifdef CONFIG_SUSPEND
- static struct {
- u32 sicfr;
- u32 siprr[2];
- u32 simsr[2];
- u32 sicnr;
- u32 smprr[2];
- u32 semsr;
- u32 secnr;
- u32 sermr;
- u32 sercr;
- } ipic_saved_state;
- static int ipic_suspend(void)
- {
- struct ipic *ipic = primary_ipic;
- ipic_saved_state.sicfr = ipic_read(ipic->regs, IPIC_SICFR);
- ipic_saved_state.siprr[0] = ipic_read(ipic->regs, IPIC_SIPRR_A);
- ipic_saved_state.siprr[1] = ipic_read(ipic->regs, IPIC_SIPRR_D);
- ipic_saved_state.simsr[0] = ipic_read(ipic->regs, IPIC_SIMSR_H);
- ipic_saved_state.simsr[1] = ipic_read(ipic->regs, IPIC_SIMSR_L);
- ipic_saved_state.sicnr = ipic_read(ipic->regs, IPIC_SICNR);
- ipic_saved_state.smprr[0] = ipic_read(ipic->regs, IPIC_SMPRR_A);
- ipic_saved_state.smprr[1] = ipic_read(ipic->regs, IPIC_SMPRR_B);
- ipic_saved_state.semsr = ipic_read(ipic->regs, IPIC_SEMSR);
- ipic_saved_state.secnr = ipic_read(ipic->regs, IPIC_SECNR);
- ipic_saved_state.sermr = ipic_read(ipic->regs, IPIC_SERMR);
- ipic_saved_state.sercr = ipic_read(ipic->regs, IPIC_SERCR);
- if (fsl_deep_sleep()) {
- /* In deep sleep, make sure there can be no
- * pending interrupts, as this can cause
- * problems on 831x.
- */
- ipic_write(ipic->regs, IPIC_SIMSR_H, 0);
- ipic_write(ipic->regs, IPIC_SIMSR_L, 0);
- ipic_write(ipic->regs, IPIC_SEMSR, 0);
- ipic_write(ipic->regs, IPIC_SERMR, 0);
- }
- return 0;
- }
- static void ipic_resume(void)
- {
- struct ipic *ipic = primary_ipic;
- ipic_write(ipic->regs, IPIC_SICFR, ipic_saved_state.sicfr);
- ipic_write(ipic->regs, IPIC_SIPRR_A, ipic_saved_state.siprr[0]);
- ipic_write(ipic->regs, IPIC_SIPRR_D, ipic_saved_state.siprr[1]);
- ipic_write(ipic->regs, IPIC_SIMSR_H, ipic_saved_state.simsr[0]);
- ipic_write(ipic->regs, IPIC_SIMSR_L, ipic_saved_state.simsr[1]);
- ipic_write(ipic->regs, IPIC_SICNR, ipic_saved_state.sicnr);
- ipic_write(ipic->regs, IPIC_SMPRR_A, ipic_saved_state.smprr[0]);
- ipic_write(ipic->regs, IPIC_SMPRR_B, ipic_saved_state.smprr[1]);
- ipic_write(ipic->regs, IPIC_SEMSR, ipic_saved_state.semsr);
- ipic_write(ipic->regs, IPIC_SECNR, ipic_saved_state.secnr);
- ipic_write(ipic->regs, IPIC_SERMR, ipic_saved_state.sermr);
- ipic_write(ipic->regs, IPIC_SERCR, ipic_saved_state.sercr);
- }
- #else
- #define ipic_suspend NULL
- #define ipic_resume NULL
- #endif
- static struct syscore_ops ipic_syscore_ops = {
- .suspend = ipic_suspend,
- .resume = ipic_resume,
- };
- static int __init init_ipic_syscore(void)
- {
- if (!primary_ipic || !primary_ipic->regs)
- return -ENODEV;
- printk(KERN_DEBUG "Registering ipic system core operations\n");
- register_syscore_ops(&ipic_syscore_ops);
- return 0;
- }
- subsys_initcall(init_ipic_syscore);
|