xref: /openbmc/qemu/hw/intc/omap_intc.c (revision 41074f3d)
17702e47cSPaolo Bonzini /*
27702e47cSPaolo Bonzini  * TI OMAP interrupt controller emulation.
37702e47cSPaolo Bonzini  *
47702e47cSPaolo Bonzini  * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
57702e47cSPaolo Bonzini  * Copyright (C) 2007-2008 Nokia Corporation
67702e47cSPaolo Bonzini  *
77702e47cSPaolo Bonzini  * This program is free software; you can redistribute it and/or
87702e47cSPaolo Bonzini  * modify it under the terms of the GNU General Public License as
97702e47cSPaolo Bonzini  * published by the Free Software Foundation; either version 2 or
107702e47cSPaolo Bonzini  * (at your option) version 3 of the License.
117702e47cSPaolo Bonzini  *
127702e47cSPaolo Bonzini  * This program is distributed in the hope that it will be useful,
137702e47cSPaolo Bonzini  * but WITHOUT ANY WARRANTY; without even the implied warranty of
147702e47cSPaolo Bonzini  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
157702e47cSPaolo Bonzini  * GNU General Public License for more details.
167702e47cSPaolo Bonzini  *
177702e47cSPaolo Bonzini  * You should have received a copy of the GNU General Public License along
187702e47cSPaolo Bonzini  * with this program; if not, see <http://www.gnu.org/licenses/>.
197702e47cSPaolo Bonzini  */
207702e47cSPaolo Bonzini #include "hw/hw.h"
217702e47cSPaolo Bonzini #include "hw/arm/omap.h"
227702e47cSPaolo Bonzini #include "hw/sysbus.h"
237702e47cSPaolo Bonzini 
247702e47cSPaolo Bonzini /* Interrupt Handlers */
257702e47cSPaolo Bonzini struct omap_intr_handler_bank_s {
267702e47cSPaolo Bonzini     uint32_t irqs;
277702e47cSPaolo Bonzini     uint32_t inputs;
287702e47cSPaolo Bonzini     uint32_t mask;
297702e47cSPaolo Bonzini     uint32_t fiq;
307702e47cSPaolo Bonzini     uint32_t sens_edge;
317702e47cSPaolo Bonzini     uint32_t swi;
327702e47cSPaolo Bonzini     unsigned char priority[32];
337702e47cSPaolo Bonzini };
347702e47cSPaolo Bonzini 
3547edc5a4SAndreas Färber #define TYPE_OMAP_INTC "common-omap-intc"
3647edc5a4SAndreas Färber #define OMAP_INTC(obj) \
3747edc5a4SAndreas Färber     OBJECT_CHECK(struct omap_intr_handler_s, (obj), TYPE_OMAP_INTC)
3847edc5a4SAndreas Färber 
397702e47cSPaolo Bonzini struct omap_intr_handler_s {
4047edc5a4SAndreas Färber     SysBusDevice parent_obj;
4147edc5a4SAndreas Färber 
427702e47cSPaolo Bonzini     qemu_irq *pins;
437702e47cSPaolo Bonzini     qemu_irq parent_intr[2];
447702e47cSPaolo Bonzini     MemoryRegion mmio;
457702e47cSPaolo Bonzini     void *iclk;
467702e47cSPaolo Bonzini     void *fclk;
477702e47cSPaolo Bonzini     unsigned char nbanks;
487702e47cSPaolo Bonzini     int level_only;
497702e47cSPaolo Bonzini     uint32_t size;
507702e47cSPaolo Bonzini 
517702e47cSPaolo Bonzini     uint8_t revision;
527702e47cSPaolo Bonzini 
537702e47cSPaolo Bonzini     /* state */
547702e47cSPaolo Bonzini     uint32_t new_agr[2];
557702e47cSPaolo Bonzini     int sir_intr[2];
567702e47cSPaolo Bonzini     int autoidle;
577702e47cSPaolo Bonzini     uint32_t mask;
587702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s bank[3];
597702e47cSPaolo Bonzini };
607702e47cSPaolo Bonzini 
617702e47cSPaolo Bonzini static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
627702e47cSPaolo Bonzini {
63*41074f3dSPaolo Bonzini     int i, j, sir_intr, p_intr, p;
647702e47cSPaolo Bonzini     uint32_t level;
657702e47cSPaolo Bonzini     sir_intr = 0;
667702e47cSPaolo Bonzini     p_intr = 255;
677702e47cSPaolo Bonzini 
687702e47cSPaolo Bonzini     /* Find the interrupt line with the highest dynamic priority.
697702e47cSPaolo Bonzini      * Note: 0 denotes the hightest priority.
707702e47cSPaolo Bonzini      * If all interrupts have the same priority, the default order is IRQ_N,
717702e47cSPaolo Bonzini      * IRQ_N-1,...,IRQ_0. */
727702e47cSPaolo Bonzini     for (j = 0; j < s->nbanks; ++j) {
737702e47cSPaolo Bonzini         level = s->bank[j].irqs & ~s->bank[j].mask &
747702e47cSPaolo Bonzini                 (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);
75*41074f3dSPaolo Bonzini 
76*41074f3dSPaolo Bonzini         while (level != 0) {
77*41074f3dSPaolo Bonzini             i = ctz32(level);
787702e47cSPaolo Bonzini             p = s->bank[j].priority[i];
797702e47cSPaolo Bonzini             if (p <= p_intr) {
807702e47cSPaolo Bonzini                 p_intr = p;
817702e47cSPaolo Bonzini                 sir_intr = 32 * j + i;
827702e47cSPaolo Bonzini             }
83*41074f3dSPaolo Bonzini             level &= level - 1;
847702e47cSPaolo Bonzini         }
857702e47cSPaolo Bonzini     }
867702e47cSPaolo Bonzini     s->sir_intr[is_fiq] = sir_intr;
877702e47cSPaolo Bonzini }
887702e47cSPaolo Bonzini 
897702e47cSPaolo Bonzini static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq)
907702e47cSPaolo Bonzini {
917702e47cSPaolo Bonzini     int i;
927702e47cSPaolo Bonzini     uint32_t has_intr = 0;
937702e47cSPaolo Bonzini 
947702e47cSPaolo Bonzini     for (i = 0; i < s->nbanks; ++i)
957702e47cSPaolo Bonzini         has_intr |= s->bank[i].irqs & ~s->bank[i].mask &
967702e47cSPaolo Bonzini                 (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq);
977702e47cSPaolo Bonzini 
987702e47cSPaolo Bonzini     if (s->new_agr[is_fiq] & has_intr & s->mask) {
997702e47cSPaolo Bonzini         s->new_agr[is_fiq] = 0;
1007702e47cSPaolo Bonzini         omap_inth_sir_update(s, is_fiq);
1017702e47cSPaolo Bonzini         qemu_set_irq(s->parent_intr[is_fiq], 1);
1027702e47cSPaolo Bonzini     }
1037702e47cSPaolo Bonzini }
1047702e47cSPaolo Bonzini 
1057702e47cSPaolo Bonzini #define INT_FALLING_EDGE	0
1067702e47cSPaolo Bonzini #define INT_LOW_LEVEL		1
1077702e47cSPaolo Bonzini 
1087702e47cSPaolo Bonzini static void omap_set_intr(void *opaque, int irq, int req)
1097702e47cSPaolo Bonzini {
1107702e47cSPaolo Bonzini     struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
1117702e47cSPaolo Bonzini     uint32_t rise;
1127702e47cSPaolo Bonzini 
1137702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
1147702e47cSPaolo Bonzini     int n = irq & 31;
1157702e47cSPaolo Bonzini 
1167702e47cSPaolo Bonzini     if (req) {
1177702e47cSPaolo Bonzini         rise = ~bank->irqs & (1 << n);
1187702e47cSPaolo Bonzini         if (~bank->sens_edge & (1 << n))
1197702e47cSPaolo Bonzini             rise &= ~bank->inputs;
1207702e47cSPaolo Bonzini 
1217702e47cSPaolo Bonzini         bank->inputs |= (1 << n);
1227702e47cSPaolo Bonzini         if (rise) {
1237702e47cSPaolo Bonzini             bank->irqs |= rise;
1247702e47cSPaolo Bonzini             omap_inth_update(ih, 0);
1257702e47cSPaolo Bonzini             omap_inth_update(ih, 1);
1267702e47cSPaolo Bonzini         }
1277702e47cSPaolo Bonzini     } else {
1287702e47cSPaolo Bonzini         rise = bank->sens_edge & bank->irqs & (1 << n);
1297702e47cSPaolo Bonzini         bank->irqs &= ~rise;
1307702e47cSPaolo Bonzini         bank->inputs &= ~(1 << n);
1317702e47cSPaolo Bonzini     }
1327702e47cSPaolo Bonzini }
1337702e47cSPaolo Bonzini 
1347702e47cSPaolo Bonzini /* Simplified version with no edge detection */
1357702e47cSPaolo Bonzini static void omap_set_intr_noedge(void *opaque, int irq, int req)
1367702e47cSPaolo Bonzini {
1377702e47cSPaolo Bonzini     struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
1387702e47cSPaolo Bonzini     uint32_t rise;
1397702e47cSPaolo Bonzini 
1407702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
1417702e47cSPaolo Bonzini     int n = irq & 31;
1427702e47cSPaolo Bonzini 
1437702e47cSPaolo Bonzini     if (req) {
1447702e47cSPaolo Bonzini         rise = ~bank->inputs & (1 << n);
1457702e47cSPaolo Bonzini         if (rise) {
1467702e47cSPaolo Bonzini             bank->irqs |= bank->inputs |= rise;
1477702e47cSPaolo Bonzini             omap_inth_update(ih, 0);
1487702e47cSPaolo Bonzini             omap_inth_update(ih, 1);
1497702e47cSPaolo Bonzini         }
1507702e47cSPaolo Bonzini     } else
1517702e47cSPaolo Bonzini         bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
1527702e47cSPaolo Bonzini }
1537702e47cSPaolo Bonzini 
1547702e47cSPaolo Bonzini static uint64_t omap_inth_read(void *opaque, hwaddr addr,
1557702e47cSPaolo Bonzini                                unsigned size)
1567702e47cSPaolo Bonzini {
1577702e47cSPaolo Bonzini     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
1587702e47cSPaolo Bonzini     int i, offset = addr;
1597702e47cSPaolo Bonzini     int bank_no = offset >> 8;
1607702e47cSPaolo Bonzini     int line_no;
1617702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
1627702e47cSPaolo Bonzini     offset &= 0xff;
1637702e47cSPaolo Bonzini 
1647702e47cSPaolo Bonzini     switch (offset) {
1657702e47cSPaolo Bonzini     case 0x00:	/* ITR */
1667702e47cSPaolo Bonzini         return bank->irqs;
1677702e47cSPaolo Bonzini 
1687702e47cSPaolo Bonzini     case 0x04:	/* MIR */
1697702e47cSPaolo Bonzini         return bank->mask;
1707702e47cSPaolo Bonzini 
1717702e47cSPaolo Bonzini     case 0x10:	/* SIR_IRQ_CODE */
1727702e47cSPaolo Bonzini     case 0x14:  /* SIR_FIQ_CODE */
1737702e47cSPaolo Bonzini         if (bank_no != 0)
1747702e47cSPaolo Bonzini             break;
1757702e47cSPaolo Bonzini         line_no = s->sir_intr[(offset - 0x10) >> 2];
1767702e47cSPaolo Bonzini         bank = &s->bank[line_no >> 5];
1777702e47cSPaolo Bonzini         i = line_no & 31;
1787702e47cSPaolo Bonzini         if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE)
1797702e47cSPaolo Bonzini             bank->irqs &= ~(1 << i);
1807702e47cSPaolo Bonzini         return line_no;
1817702e47cSPaolo Bonzini 
1827702e47cSPaolo Bonzini     case 0x18:	/* CONTROL_REG */
1837702e47cSPaolo Bonzini         if (bank_no != 0)
1847702e47cSPaolo Bonzini             break;
1857702e47cSPaolo Bonzini         return 0;
1867702e47cSPaolo Bonzini 
1877702e47cSPaolo Bonzini     case 0x1c:	/* ILR0 */
1887702e47cSPaolo Bonzini     case 0x20:	/* ILR1 */
1897702e47cSPaolo Bonzini     case 0x24:	/* ILR2 */
1907702e47cSPaolo Bonzini     case 0x28:	/* ILR3 */
1917702e47cSPaolo Bonzini     case 0x2c:	/* ILR4 */
1927702e47cSPaolo Bonzini     case 0x30:	/* ILR5 */
1937702e47cSPaolo Bonzini     case 0x34:	/* ILR6 */
1947702e47cSPaolo Bonzini     case 0x38:	/* ILR7 */
1957702e47cSPaolo Bonzini     case 0x3c:	/* ILR8 */
1967702e47cSPaolo Bonzini     case 0x40:	/* ILR9 */
1977702e47cSPaolo Bonzini     case 0x44:	/* ILR10 */
1987702e47cSPaolo Bonzini     case 0x48:	/* ILR11 */
1997702e47cSPaolo Bonzini     case 0x4c:	/* ILR12 */
2007702e47cSPaolo Bonzini     case 0x50:	/* ILR13 */
2017702e47cSPaolo Bonzini     case 0x54:	/* ILR14 */
2027702e47cSPaolo Bonzini     case 0x58:	/* ILR15 */
2037702e47cSPaolo Bonzini     case 0x5c:	/* ILR16 */
2047702e47cSPaolo Bonzini     case 0x60:	/* ILR17 */
2057702e47cSPaolo Bonzini     case 0x64:	/* ILR18 */
2067702e47cSPaolo Bonzini     case 0x68:	/* ILR19 */
2077702e47cSPaolo Bonzini     case 0x6c:	/* ILR20 */
2087702e47cSPaolo Bonzini     case 0x70:	/* ILR21 */
2097702e47cSPaolo Bonzini     case 0x74:	/* ILR22 */
2107702e47cSPaolo Bonzini     case 0x78:	/* ILR23 */
2117702e47cSPaolo Bonzini     case 0x7c:	/* ILR24 */
2127702e47cSPaolo Bonzini     case 0x80:	/* ILR25 */
2137702e47cSPaolo Bonzini     case 0x84:	/* ILR26 */
2147702e47cSPaolo Bonzini     case 0x88:	/* ILR27 */
2157702e47cSPaolo Bonzini     case 0x8c:	/* ILR28 */
2167702e47cSPaolo Bonzini     case 0x90:	/* ILR29 */
2177702e47cSPaolo Bonzini     case 0x94:	/* ILR30 */
2187702e47cSPaolo Bonzini     case 0x98:	/* ILR31 */
2197702e47cSPaolo Bonzini         i = (offset - 0x1c) >> 2;
2207702e47cSPaolo Bonzini         return (bank->priority[i] << 2) |
2217702e47cSPaolo Bonzini                 (((bank->sens_edge >> i) & 1) << 1) |
2227702e47cSPaolo Bonzini                 ((bank->fiq >> i) & 1);
2237702e47cSPaolo Bonzini 
2247702e47cSPaolo Bonzini     case 0x9c:	/* ISR */
2257702e47cSPaolo Bonzini         return 0x00000000;
2267702e47cSPaolo Bonzini 
2277702e47cSPaolo Bonzini     }
2287702e47cSPaolo Bonzini     OMAP_BAD_REG(addr);
2297702e47cSPaolo Bonzini     return 0;
2307702e47cSPaolo Bonzini }
2317702e47cSPaolo Bonzini 
2327702e47cSPaolo Bonzini static void omap_inth_write(void *opaque, hwaddr addr,
2337702e47cSPaolo Bonzini                             uint64_t value, unsigned size)
2347702e47cSPaolo Bonzini {
2357702e47cSPaolo Bonzini     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
2367702e47cSPaolo Bonzini     int i, offset = addr;
2377702e47cSPaolo Bonzini     int bank_no = offset >> 8;
2387702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
2397702e47cSPaolo Bonzini     offset &= 0xff;
2407702e47cSPaolo Bonzini 
2417702e47cSPaolo Bonzini     switch (offset) {
2427702e47cSPaolo Bonzini     case 0x00:	/* ITR */
2437702e47cSPaolo Bonzini         /* Important: ignore the clearing if the IRQ is level-triggered and
2447702e47cSPaolo Bonzini            the input bit is 1 */
2457702e47cSPaolo Bonzini         bank->irqs &= value | (bank->inputs & bank->sens_edge);
2467702e47cSPaolo Bonzini         return;
2477702e47cSPaolo Bonzini 
2487702e47cSPaolo Bonzini     case 0x04:	/* MIR */
2497702e47cSPaolo Bonzini         bank->mask = value;
2507702e47cSPaolo Bonzini         omap_inth_update(s, 0);
2517702e47cSPaolo Bonzini         omap_inth_update(s, 1);
2527702e47cSPaolo Bonzini         return;
2537702e47cSPaolo Bonzini 
2547702e47cSPaolo Bonzini     case 0x10:	/* SIR_IRQ_CODE */
2557702e47cSPaolo Bonzini     case 0x14:	/* SIR_FIQ_CODE */
2567702e47cSPaolo Bonzini         OMAP_RO_REG(addr);
2577702e47cSPaolo Bonzini         break;
2587702e47cSPaolo Bonzini 
2597702e47cSPaolo Bonzini     case 0x18:	/* CONTROL_REG */
2607702e47cSPaolo Bonzini         if (bank_no != 0)
2617702e47cSPaolo Bonzini             break;
2627702e47cSPaolo Bonzini         if (value & 2) {
2637702e47cSPaolo Bonzini             qemu_set_irq(s->parent_intr[1], 0);
2647702e47cSPaolo Bonzini             s->new_agr[1] = ~0;
2657702e47cSPaolo Bonzini             omap_inth_update(s, 1);
2667702e47cSPaolo Bonzini         }
2677702e47cSPaolo Bonzini         if (value & 1) {
2687702e47cSPaolo Bonzini             qemu_set_irq(s->parent_intr[0], 0);
2697702e47cSPaolo Bonzini             s->new_agr[0] = ~0;
2707702e47cSPaolo Bonzini             omap_inth_update(s, 0);
2717702e47cSPaolo Bonzini         }
2727702e47cSPaolo Bonzini         return;
2737702e47cSPaolo Bonzini 
2747702e47cSPaolo Bonzini     case 0x1c:	/* ILR0 */
2757702e47cSPaolo Bonzini     case 0x20:	/* ILR1 */
2767702e47cSPaolo Bonzini     case 0x24:	/* ILR2 */
2777702e47cSPaolo Bonzini     case 0x28:	/* ILR3 */
2787702e47cSPaolo Bonzini     case 0x2c:	/* ILR4 */
2797702e47cSPaolo Bonzini     case 0x30:	/* ILR5 */
2807702e47cSPaolo Bonzini     case 0x34:	/* ILR6 */
2817702e47cSPaolo Bonzini     case 0x38:	/* ILR7 */
2827702e47cSPaolo Bonzini     case 0x3c:	/* ILR8 */
2837702e47cSPaolo Bonzini     case 0x40:	/* ILR9 */
2847702e47cSPaolo Bonzini     case 0x44:	/* ILR10 */
2857702e47cSPaolo Bonzini     case 0x48:	/* ILR11 */
2867702e47cSPaolo Bonzini     case 0x4c:	/* ILR12 */
2877702e47cSPaolo Bonzini     case 0x50:	/* ILR13 */
2887702e47cSPaolo Bonzini     case 0x54:	/* ILR14 */
2897702e47cSPaolo Bonzini     case 0x58:	/* ILR15 */
2907702e47cSPaolo Bonzini     case 0x5c:	/* ILR16 */
2917702e47cSPaolo Bonzini     case 0x60:	/* ILR17 */
2927702e47cSPaolo Bonzini     case 0x64:	/* ILR18 */
2937702e47cSPaolo Bonzini     case 0x68:	/* ILR19 */
2947702e47cSPaolo Bonzini     case 0x6c:	/* ILR20 */
2957702e47cSPaolo Bonzini     case 0x70:	/* ILR21 */
2967702e47cSPaolo Bonzini     case 0x74:	/* ILR22 */
2977702e47cSPaolo Bonzini     case 0x78:	/* ILR23 */
2987702e47cSPaolo Bonzini     case 0x7c:	/* ILR24 */
2997702e47cSPaolo Bonzini     case 0x80:	/* ILR25 */
3007702e47cSPaolo Bonzini     case 0x84:	/* ILR26 */
3017702e47cSPaolo Bonzini     case 0x88:	/* ILR27 */
3027702e47cSPaolo Bonzini     case 0x8c:	/* ILR28 */
3037702e47cSPaolo Bonzini     case 0x90:	/* ILR29 */
3047702e47cSPaolo Bonzini     case 0x94:	/* ILR30 */
3057702e47cSPaolo Bonzini     case 0x98:	/* ILR31 */
3067702e47cSPaolo Bonzini         i = (offset - 0x1c) >> 2;
3077702e47cSPaolo Bonzini         bank->priority[i] = (value >> 2) & 0x1f;
3087702e47cSPaolo Bonzini         bank->sens_edge &= ~(1 << i);
3097702e47cSPaolo Bonzini         bank->sens_edge |= ((value >> 1) & 1) << i;
3107702e47cSPaolo Bonzini         bank->fiq &= ~(1 << i);
3117702e47cSPaolo Bonzini         bank->fiq |= (value & 1) << i;
3127702e47cSPaolo Bonzini         return;
3137702e47cSPaolo Bonzini 
3147702e47cSPaolo Bonzini     case 0x9c:	/* ISR */
3157702e47cSPaolo Bonzini         for (i = 0; i < 32; i ++)
3167702e47cSPaolo Bonzini             if (value & (1 << i)) {
3177702e47cSPaolo Bonzini                 omap_set_intr(s, 32 * bank_no + i, 1);
3187702e47cSPaolo Bonzini                 return;
3197702e47cSPaolo Bonzini             }
3207702e47cSPaolo Bonzini         return;
3217702e47cSPaolo Bonzini     }
3227702e47cSPaolo Bonzini     OMAP_BAD_REG(addr);
3237702e47cSPaolo Bonzini }
3247702e47cSPaolo Bonzini 
3257702e47cSPaolo Bonzini static const MemoryRegionOps omap_inth_mem_ops = {
3267702e47cSPaolo Bonzini     .read = omap_inth_read,
3277702e47cSPaolo Bonzini     .write = omap_inth_write,
3287702e47cSPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
3297702e47cSPaolo Bonzini     .valid = {
3307702e47cSPaolo Bonzini         .min_access_size = 4,
3317702e47cSPaolo Bonzini         .max_access_size = 4,
3327702e47cSPaolo Bonzini     },
3337702e47cSPaolo Bonzini };
3347702e47cSPaolo Bonzini 
3357702e47cSPaolo Bonzini static void omap_inth_reset(DeviceState *dev)
3367702e47cSPaolo Bonzini {
33747edc5a4SAndreas Färber     struct omap_intr_handler_s *s = OMAP_INTC(dev);
3387702e47cSPaolo Bonzini     int i;
3397702e47cSPaolo Bonzini 
3407702e47cSPaolo Bonzini     for (i = 0; i < s->nbanks; ++i){
3417702e47cSPaolo Bonzini         s->bank[i].irqs = 0x00000000;
3427702e47cSPaolo Bonzini         s->bank[i].mask = 0xffffffff;
3437702e47cSPaolo Bonzini         s->bank[i].sens_edge = 0x00000000;
3447702e47cSPaolo Bonzini         s->bank[i].fiq = 0x00000000;
3457702e47cSPaolo Bonzini         s->bank[i].inputs = 0x00000000;
3467702e47cSPaolo Bonzini         s->bank[i].swi = 0x00000000;
3477702e47cSPaolo Bonzini         memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority));
3487702e47cSPaolo Bonzini 
3497702e47cSPaolo Bonzini         if (s->level_only)
3507702e47cSPaolo Bonzini             s->bank[i].sens_edge = 0xffffffff;
3517702e47cSPaolo Bonzini     }
3527702e47cSPaolo Bonzini 
3537702e47cSPaolo Bonzini     s->new_agr[0] = ~0;
3547702e47cSPaolo Bonzini     s->new_agr[1] = ~0;
3557702e47cSPaolo Bonzini     s->sir_intr[0] = 0;
3567702e47cSPaolo Bonzini     s->sir_intr[1] = 0;
3577702e47cSPaolo Bonzini     s->autoidle = 0;
3587702e47cSPaolo Bonzini     s->mask = ~0;
3597702e47cSPaolo Bonzini 
3607702e47cSPaolo Bonzini     qemu_set_irq(s->parent_intr[0], 0);
3617702e47cSPaolo Bonzini     qemu_set_irq(s->parent_intr[1], 0);
3627702e47cSPaolo Bonzini }
3637702e47cSPaolo Bonzini 
36447edc5a4SAndreas Färber static int omap_intc_init(SysBusDevice *sbd)
3657702e47cSPaolo Bonzini {
36647edc5a4SAndreas Färber     DeviceState *dev = DEVICE(sbd);
36747edc5a4SAndreas Färber     struct omap_intr_handler_s *s = OMAP_INTC(dev);
36847edc5a4SAndreas Färber 
3697702e47cSPaolo Bonzini     if (!s->iclk) {
3707702e47cSPaolo Bonzini         hw_error("omap-intc: clk not connected\n");
3717702e47cSPaolo Bonzini     }
3727702e47cSPaolo Bonzini     s->nbanks = 1;
37347edc5a4SAndreas Färber     sysbus_init_irq(sbd, &s->parent_intr[0]);
37447edc5a4SAndreas Färber     sysbus_init_irq(sbd, &s->parent_intr[1]);
37547edc5a4SAndreas Färber     qdev_init_gpio_in(dev, omap_set_intr, s->nbanks * 32);
3761437c94bSPaolo Bonzini     memory_region_init_io(&s->mmio, OBJECT(s), &omap_inth_mem_ops, s,
3777702e47cSPaolo Bonzini                           "omap-intc", s->size);
37847edc5a4SAndreas Färber     sysbus_init_mmio(sbd, &s->mmio);
3797702e47cSPaolo Bonzini     return 0;
3807702e47cSPaolo Bonzini }
3817702e47cSPaolo Bonzini 
3827702e47cSPaolo Bonzini static Property omap_intc_properties[] = {
3837702e47cSPaolo Bonzini     DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
3847702e47cSPaolo Bonzini     DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
3857702e47cSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
3867702e47cSPaolo Bonzini };
3877702e47cSPaolo Bonzini 
3887702e47cSPaolo Bonzini static void omap_intc_class_init(ObjectClass *klass, void *data)
3897702e47cSPaolo Bonzini {
3907702e47cSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
3917702e47cSPaolo Bonzini     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
3927702e47cSPaolo Bonzini 
3937702e47cSPaolo Bonzini     k->init = omap_intc_init;
3947702e47cSPaolo Bonzini     dc->reset = omap_inth_reset;
3957702e47cSPaolo Bonzini     dc->props = omap_intc_properties;
3961b111dc1SMarkus Armbruster     /* Reason: pointer property "clk" */
3971b111dc1SMarkus Armbruster     dc->cannot_instantiate_with_device_add_yet = true;
3987702e47cSPaolo Bonzini }
3997702e47cSPaolo Bonzini 
4007702e47cSPaolo Bonzini static const TypeInfo omap_intc_info = {
4017702e47cSPaolo Bonzini     .name          = "omap-intc",
40247edc5a4SAndreas Färber     .parent        = TYPE_OMAP_INTC,
4037702e47cSPaolo Bonzini     .class_init    = omap_intc_class_init,
4047702e47cSPaolo Bonzini };
4057702e47cSPaolo Bonzini 
4067702e47cSPaolo Bonzini static uint64_t omap2_inth_read(void *opaque, hwaddr addr,
4077702e47cSPaolo Bonzini                                 unsigned size)
4087702e47cSPaolo Bonzini {
4097702e47cSPaolo Bonzini     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
4107702e47cSPaolo Bonzini     int offset = addr;
4117702e47cSPaolo Bonzini     int bank_no, line_no;
4127702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s *bank = NULL;
4137702e47cSPaolo Bonzini 
4147702e47cSPaolo Bonzini     if ((offset & 0xf80) == 0x80) {
4157702e47cSPaolo Bonzini         bank_no = (offset & 0x60) >> 5;
4167702e47cSPaolo Bonzini         if (bank_no < s->nbanks) {
4177702e47cSPaolo Bonzini             offset &= ~0x60;
4187702e47cSPaolo Bonzini             bank = &s->bank[bank_no];
4197702e47cSPaolo Bonzini         } else {
4207702e47cSPaolo Bonzini             OMAP_BAD_REG(addr);
4217702e47cSPaolo Bonzini             return 0;
4227702e47cSPaolo Bonzini         }
4237702e47cSPaolo Bonzini     }
4247702e47cSPaolo Bonzini 
4257702e47cSPaolo Bonzini     switch (offset) {
4267702e47cSPaolo Bonzini     case 0x00:	/* INTC_REVISION */
4277702e47cSPaolo Bonzini         return s->revision;
4287702e47cSPaolo Bonzini 
4297702e47cSPaolo Bonzini     case 0x10:	/* INTC_SYSCONFIG */
4307702e47cSPaolo Bonzini         return (s->autoidle >> 2) & 1;
4317702e47cSPaolo Bonzini 
4327702e47cSPaolo Bonzini     case 0x14:	/* INTC_SYSSTATUS */
4337702e47cSPaolo Bonzini         return 1;						/* RESETDONE */
4347702e47cSPaolo Bonzini 
4357702e47cSPaolo Bonzini     case 0x40:	/* INTC_SIR_IRQ */
4367702e47cSPaolo Bonzini         return s->sir_intr[0];
4377702e47cSPaolo Bonzini 
4387702e47cSPaolo Bonzini     case 0x44:	/* INTC_SIR_FIQ */
4397702e47cSPaolo Bonzini         return s->sir_intr[1];
4407702e47cSPaolo Bonzini 
4417702e47cSPaolo Bonzini     case 0x48:	/* INTC_CONTROL */
4427702e47cSPaolo Bonzini         return (!s->mask) << 2;					/* GLOBALMASK */
4437702e47cSPaolo Bonzini 
4447702e47cSPaolo Bonzini     case 0x4c:	/* INTC_PROTECTION */
4457702e47cSPaolo Bonzini         return 0;
4467702e47cSPaolo Bonzini 
4477702e47cSPaolo Bonzini     case 0x50:	/* INTC_IDLE */
4487702e47cSPaolo Bonzini         return s->autoidle & 3;
4497702e47cSPaolo Bonzini 
4507702e47cSPaolo Bonzini     /* Per-bank registers */
4517702e47cSPaolo Bonzini     case 0x80:	/* INTC_ITR */
4527702e47cSPaolo Bonzini         return bank->inputs;
4537702e47cSPaolo Bonzini 
4547702e47cSPaolo Bonzini     case 0x84:	/* INTC_MIR */
4557702e47cSPaolo Bonzini         return bank->mask;
4567702e47cSPaolo Bonzini 
4577702e47cSPaolo Bonzini     case 0x88:	/* INTC_MIR_CLEAR */
4587702e47cSPaolo Bonzini     case 0x8c:	/* INTC_MIR_SET */
4597702e47cSPaolo Bonzini         return 0;
4607702e47cSPaolo Bonzini 
4617702e47cSPaolo Bonzini     case 0x90:	/* INTC_ISR_SET */
4627702e47cSPaolo Bonzini         return bank->swi;
4637702e47cSPaolo Bonzini 
4647702e47cSPaolo Bonzini     case 0x94:	/* INTC_ISR_CLEAR */
4657702e47cSPaolo Bonzini         return 0;
4667702e47cSPaolo Bonzini 
4677702e47cSPaolo Bonzini     case 0x98:	/* INTC_PENDING_IRQ */
4687702e47cSPaolo Bonzini         return bank->irqs & ~bank->mask & ~bank->fiq;
4697702e47cSPaolo Bonzini 
4707702e47cSPaolo Bonzini     case 0x9c:	/* INTC_PENDING_FIQ */
4717702e47cSPaolo Bonzini         return bank->irqs & ~bank->mask & bank->fiq;
4727702e47cSPaolo Bonzini 
4737702e47cSPaolo Bonzini     /* Per-line registers */
4747702e47cSPaolo Bonzini     case 0x100 ... 0x300:	/* INTC_ILR */
4757702e47cSPaolo Bonzini         bank_no = (offset - 0x100) >> 7;
4767702e47cSPaolo Bonzini         if (bank_no > s->nbanks)
4777702e47cSPaolo Bonzini             break;
4787702e47cSPaolo Bonzini         bank = &s->bank[bank_no];
4797702e47cSPaolo Bonzini         line_no = (offset & 0x7f) >> 2;
4807702e47cSPaolo Bonzini         return (bank->priority[line_no] << 2) |
4817702e47cSPaolo Bonzini                 ((bank->fiq >> line_no) & 1);
4827702e47cSPaolo Bonzini     }
4837702e47cSPaolo Bonzini     OMAP_BAD_REG(addr);
4847702e47cSPaolo Bonzini     return 0;
4857702e47cSPaolo Bonzini }
4867702e47cSPaolo Bonzini 
4877702e47cSPaolo Bonzini static void omap2_inth_write(void *opaque, hwaddr addr,
4887702e47cSPaolo Bonzini                              uint64_t value, unsigned size)
4897702e47cSPaolo Bonzini {
4907702e47cSPaolo Bonzini     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
4917702e47cSPaolo Bonzini     int offset = addr;
4927702e47cSPaolo Bonzini     int bank_no, line_no;
4937702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s *bank = NULL;
4947702e47cSPaolo Bonzini 
4957702e47cSPaolo Bonzini     if ((offset & 0xf80) == 0x80) {
4967702e47cSPaolo Bonzini         bank_no = (offset & 0x60) >> 5;
4977702e47cSPaolo Bonzini         if (bank_no < s->nbanks) {
4987702e47cSPaolo Bonzini             offset &= ~0x60;
4997702e47cSPaolo Bonzini             bank = &s->bank[bank_no];
5007702e47cSPaolo Bonzini         } else {
5017702e47cSPaolo Bonzini             OMAP_BAD_REG(addr);
5027702e47cSPaolo Bonzini             return;
5037702e47cSPaolo Bonzini         }
5047702e47cSPaolo Bonzini     }
5057702e47cSPaolo Bonzini 
5067702e47cSPaolo Bonzini     switch (offset) {
5077702e47cSPaolo Bonzini     case 0x10:	/* INTC_SYSCONFIG */
5087702e47cSPaolo Bonzini         s->autoidle &= 4;
5097702e47cSPaolo Bonzini         s->autoidle |= (value & 1) << 2;
51047edc5a4SAndreas Färber         if (value & 2) {                                        /* SOFTRESET */
51147edc5a4SAndreas Färber             omap_inth_reset(DEVICE(s));
51247edc5a4SAndreas Färber         }
5137702e47cSPaolo Bonzini         return;
5147702e47cSPaolo Bonzini 
5157702e47cSPaolo Bonzini     case 0x48:	/* INTC_CONTROL */
5167702e47cSPaolo Bonzini         s->mask = (value & 4) ? 0 : ~0;				/* GLOBALMASK */
5177702e47cSPaolo Bonzini         if (value & 2) {					/* NEWFIQAGR */
5187702e47cSPaolo Bonzini             qemu_set_irq(s->parent_intr[1], 0);
5197702e47cSPaolo Bonzini             s->new_agr[1] = ~0;
5207702e47cSPaolo Bonzini             omap_inth_update(s, 1);
5217702e47cSPaolo Bonzini         }
5227702e47cSPaolo Bonzini         if (value & 1) {					/* NEWIRQAGR */
5237702e47cSPaolo Bonzini             qemu_set_irq(s->parent_intr[0], 0);
5247702e47cSPaolo Bonzini             s->new_agr[0] = ~0;
5257702e47cSPaolo Bonzini             omap_inth_update(s, 0);
5267702e47cSPaolo Bonzini         }
5277702e47cSPaolo Bonzini         return;
5287702e47cSPaolo Bonzini 
5297702e47cSPaolo Bonzini     case 0x4c:	/* INTC_PROTECTION */
5307702e47cSPaolo Bonzini         /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
5317702e47cSPaolo Bonzini          * for every register, see Chapter 3 and 4 for privileged mode.  */
5327702e47cSPaolo Bonzini         if (value & 1)
5337702e47cSPaolo Bonzini             fprintf(stderr, "%s: protection mode enable attempt\n",
5347702e47cSPaolo Bonzini                             __FUNCTION__);
5357702e47cSPaolo Bonzini         return;
5367702e47cSPaolo Bonzini 
5377702e47cSPaolo Bonzini     case 0x50:	/* INTC_IDLE */
5387702e47cSPaolo Bonzini         s->autoidle &= ~3;
5397702e47cSPaolo Bonzini         s->autoidle |= value & 3;
5407702e47cSPaolo Bonzini         return;
5417702e47cSPaolo Bonzini 
5427702e47cSPaolo Bonzini     /* Per-bank registers */
5437702e47cSPaolo Bonzini     case 0x84:	/* INTC_MIR */
5447702e47cSPaolo Bonzini         bank->mask = value;
5457702e47cSPaolo Bonzini         omap_inth_update(s, 0);
5467702e47cSPaolo Bonzini         omap_inth_update(s, 1);
5477702e47cSPaolo Bonzini         return;
5487702e47cSPaolo Bonzini 
5497702e47cSPaolo Bonzini     case 0x88:	/* INTC_MIR_CLEAR */
5507702e47cSPaolo Bonzini         bank->mask &= ~value;
5517702e47cSPaolo Bonzini         omap_inth_update(s, 0);
5527702e47cSPaolo Bonzini         omap_inth_update(s, 1);
5537702e47cSPaolo Bonzini         return;
5547702e47cSPaolo Bonzini 
5557702e47cSPaolo Bonzini     case 0x8c:	/* INTC_MIR_SET */
5567702e47cSPaolo Bonzini         bank->mask |= value;
5577702e47cSPaolo Bonzini         return;
5587702e47cSPaolo Bonzini 
5597702e47cSPaolo Bonzini     case 0x90:	/* INTC_ISR_SET */
5607702e47cSPaolo Bonzini         bank->irqs |= bank->swi |= value;
5617702e47cSPaolo Bonzini         omap_inth_update(s, 0);
5627702e47cSPaolo Bonzini         omap_inth_update(s, 1);
5637702e47cSPaolo Bonzini         return;
5647702e47cSPaolo Bonzini 
5657702e47cSPaolo Bonzini     case 0x94:	/* INTC_ISR_CLEAR */
5667702e47cSPaolo Bonzini         bank->swi &= ~value;
5677702e47cSPaolo Bonzini         bank->irqs = bank->swi & bank->inputs;
5687702e47cSPaolo Bonzini         return;
5697702e47cSPaolo Bonzini 
5707702e47cSPaolo Bonzini     /* Per-line registers */
5717702e47cSPaolo Bonzini     case 0x100 ... 0x300:	/* INTC_ILR */
5727702e47cSPaolo Bonzini         bank_no = (offset - 0x100) >> 7;
5737702e47cSPaolo Bonzini         if (bank_no > s->nbanks)
5747702e47cSPaolo Bonzini             break;
5757702e47cSPaolo Bonzini         bank = &s->bank[bank_no];
5767702e47cSPaolo Bonzini         line_no = (offset & 0x7f) >> 2;
5777702e47cSPaolo Bonzini         bank->priority[line_no] = (value >> 2) & 0x3f;
5787702e47cSPaolo Bonzini         bank->fiq &= ~(1 << line_no);
5797702e47cSPaolo Bonzini         bank->fiq |= (value & 1) << line_no;
5807702e47cSPaolo Bonzini         return;
5817702e47cSPaolo Bonzini 
5827702e47cSPaolo Bonzini     case 0x00:	/* INTC_REVISION */
5837702e47cSPaolo Bonzini     case 0x14:	/* INTC_SYSSTATUS */
5847702e47cSPaolo Bonzini     case 0x40:	/* INTC_SIR_IRQ */
5857702e47cSPaolo Bonzini     case 0x44:	/* INTC_SIR_FIQ */
5867702e47cSPaolo Bonzini     case 0x80:	/* INTC_ITR */
5877702e47cSPaolo Bonzini     case 0x98:	/* INTC_PENDING_IRQ */
5887702e47cSPaolo Bonzini     case 0x9c:	/* INTC_PENDING_FIQ */
5897702e47cSPaolo Bonzini         OMAP_RO_REG(addr);
5907702e47cSPaolo Bonzini         return;
5917702e47cSPaolo Bonzini     }
5927702e47cSPaolo Bonzini     OMAP_BAD_REG(addr);
5937702e47cSPaolo Bonzini }
5947702e47cSPaolo Bonzini 
5957702e47cSPaolo Bonzini static const MemoryRegionOps omap2_inth_mem_ops = {
5967702e47cSPaolo Bonzini     .read = omap2_inth_read,
5977702e47cSPaolo Bonzini     .write = omap2_inth_write,
5987702e47cSPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
5997702e47cSPaolo Bonzini     .valid = {
6007702e47cSPaolo Bonzini         .min_access_size = 4,
6017702e47cSPaolo Bonzini         .max_access_size = 4,
6027702e47cSPaolo Bonzini     },
6037702e47cSPaolo Bonzini };
6047702e47cSPaolo Bonzini 
60547edc5a4SAndreas Färber static int omap2_intc_init(SysBusDevice *sbd)
6067702e47cSPaolo Bonzini {
60747edc5a4SAndreas Färber     DeviceState *dev = DEVICE(sbd);
60847edc5a4SAndreas Färber     struct omap_intr_handler_s *s = OMAP_INTC(dev);
60947edc5a4SAndreas Färber 
6107702e47cSPaolo Bonzini     if (!s->iclk) {
6117702e47cSPaolo Bonzini         hw_error("omap2-intc: iclk not connected\n");
6127702e47cSPaolo Bonzini     }
6137702e47cSPaolo Bonzini     if (!s->fclk) {
6147702e47cSPaolo Bonzini         hw_error("omap2-intc: fclk not connected\n");
6157702e47cSPaolo Bonzini     }
6167702e47cSPaolo Bonzini     s->level_only = 1;
6177702e47cSPaolo Bonzini     s->nbanks = 3;
61847edc5a4SAndreas Färber     sysbus_init_irq(sbd, &s->parent_intr[0]);
61947edc5a4SAndreas Färber     sysbus_init_irq(sbd, &s->parent_intr[1]);
62047edc5a4SAndreas Färber     qdev_init_gpio_in(dev, omap_set_intr_noedge, s->nbanks * 32);
6211437c94bSPaolo Bonzini     memory_region_init_io(&s->mmio, OBJECT(s), &omap2_inth_mem_ops, s,
6227702e47cSPaolo Bonzini                           "omap2-intc", 0x1000);
62347edc5a4SAndreas Färber     sysbus_init_mmio(sbd, &s->mmio);
6247702e47cSPaolo Bonzini     return 0;
6257702e47cSPaolo Bonzini }
6267702e47cSPaolo Bonzini 
6277702e47cSPaolo Bonzini static Property omap2_intc_properties[] = {
6287702e47cSPaolo Bonzini     DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
6297702e47cSPaolo Bonzini     revision, 0x21),
6307702e47cSPaolo Bonzini     DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
6317702e47cSPaolo Bonzini     DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
6327702e47cSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
6337702e47cSPaolo Bonzini };
6347702e47cSPaolo Bonzini 
6357702e47cSPaolo Bonzini static void omap2_intc_class_init(ObjectClass *klass, void *data)
6367702e47cSPaolo Bonzini {
6377702e47cSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
6387702e47cSPaolo Bonzini     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
6397702e47cSPaolo Bonzini 
6407702e47cSPaolo Bonzini     k->init = omap2_intc_init;
6417702e47cSPaolo Bonzini     dc->reset = omap_inth_reset;
6427702e47cSPaolo Bonzini     dc->props = omap2_intc_properties;
6431b111dc1SMarkus Armbruster     /* Reason: pointer property "iclk", "fclk" */
6441b111dc1SMarkus Armbruster     dc->cannot_instantiate_with_device_add_yet = true;
6457702e47cSPaolo Bonzini }
6467702e47cSPaolo Bonzini 
6477702e47cSPaolo Bonzini static const TypeInfo omap2_intc_info = {
6487702e47cSPaolo Bonzini     .name          = "omap2-intc",
64947edc5a4SAndreas Färber     .parent        = TYPE_OMAP_INTC,
65047edc5a4SAndreas Färber     .class_init    = omap2_intc_class_init,
65147edc5a4SAndreas Färber };
65247edc5a4SAndreas Färber 
65347edc5a4SAndreas Färber static const TypeInfo omap_intc_type_info = {
65447edc5a4SAndreas Färber     .name          = TYPE_OMAP_INTC,
6557702e47cSPaolo Bonzini     .parent        = TYPE_SYS_BUS_DEVICE,
6567702e47cSPaolo Bonzini     .instance_size = sizeof(struct omap_intr_handler_s),
65747edc5a4SAndreas Färber     .abstract      = true,
6587702e47cSPaolo Bonzini };
6597702e47cSPaolo Bonzini 
6607702e47cSPaolo Bonzini static void omap_intc_register_types(void)
6617702e47cSPaolo Bonzini {
66247edc5a4SAndreas Färber     type_register_static(&omap_intc_type_info);
6637702e47cSPaolo Bonzini     type_register_static(&omap_intc_info);
6647702e47cSPaolo Bonzini     type_register_static(&omap2_intc_info);
6657702e47cSPaolo Bonzini }
6667702e47cSPaolo Bonzini 
6677702e47cSPaolo Bonzini type_init(omap_intc_register_types)
668