xref: /openbmc/qemu/hw/intc/omap_intc.c (revision 1437c94b)
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 
357702e47cSPaolo Bonzini struct omap_intr_handler_s {
367702e47cSPaolo Bonzini     SysBusDevice busdev;
377702e47cSPaolo Bonzini     qemu_irq *pins;
387702e47cSPaolo Bonzini     qemu_irq parent_intr[2];
397702e47cSPaolo Bonzini     MemoryRegion mmio;
407702e47cSPaolo Bonzini     void *iclk;
417702e47cSPaolo Bonzini     void *fclk;
427702e47cSPaolo Bonzini     unsigned char nbanks;
437702e47cSPaolo Bonzini     int level_only;
447702e47cSPaolo Bonzini     uint32_t size;
457702e47cSPaolo Bonzini 
467702e47cSPaolo Bonzini     uint8_t revision;
477702e47cSPaolo Bonzini 
487702e47cSPaolo Bonzini     /* state */
497702e47cSPaolo Bonzini     uint32_t new_agr[2];
507702e47cSPaolo Bonzini     int sir_intr[2];
517702e47cSPaolo Bonzini     int autoidle;
527702e47cSPaolo Bonzini     uint32_t mask;
537702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s bank[3];
547702e47cSPaolo Bonzini };
557702e47cSPaolo Bonzini 
567702e47cSPaolo Bonzini static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
577702e47cSPaolo Bonzini {
587702e47cSPaolo Bonzini     int i, j, sir_intr, p_intr, p, f;
597702e47cSPaolo Bonzini     uint32_t level;
607702e47cSPaolo Bonzini     sir_intr = 0;
617702e47cSPaolo Bonzini     p_intr = 255;
627702e47cSPaolo Bonzini 
637702e47cSPaolo Bonzini     /* Find the interrupt line with the highest dynamic priority.
647702e47cSPaolo Bonzini      * Note: 0 denotes the hightest priority.
657702e47cSPaolo Bonzini      * If all interrupts have the same priority, the default order is IRQ_N,
667702e47cSPaolo Bonzini      * IRQ_N-1,...,IRQ_0. */
677702e47cSPaolo Bonzini     for (j = 0; j < s->nbanks; ++j) {
687702e47cSPaolo Bonzini         level = s->bank[j].irqs & ~s->bank[j].mask &
697702e47cSPaolo Bonzini                 (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);
707702e47cSPaolo Bonzini         for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f,
717702e47cSPaolo Bonzini                         level >>= f) {
727702e47cSPaolo Bonzini             p = s->bank[j].priority[i];
737702e47cSPaolo Bonzini             if (p <= p_intr) {
747702e47cSPaolo Bonzini                 p_intr = p;
757702e47cSPaolo Bonzini                 sir_intr = 32 * j + i;
767702e47cSPaolo Bonzini             }
777702e47cSPaolo Bonzini             f = ffs(level >> 1);
787702e47cSPaolo Bonzini         }
797702e47cSPaolo Bonzini     }
807702e47cSPaolo Bonzini     s->sir_intr[is_fiq] = sir_intr;
817702e47cSPaolo Bonzini }
827702e47cSPaolo Bonzini 
837702e47cSPaolo Bonzini static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq)
847702e47cSPaolo Bonzini {
857702e47cSPaolo Bonzini     int i;
867702e47cSPaolo Bonzini     uint32_t has_intr = 0;
877702e47cSPaolo Bonzini 
887702e47cSPaolo Bonzini     for (i = 0; i < s->nbanks; ++i)
897702e47cSPaolo Bonzini         has_intr |= s->bank[i].irqs & ~s->bank[i].mask &
907702e47cSPaolo Bonzini                 (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq);
917702e47cSPaolo Bonzini 
927702e47cSPaolo Bonzini     if (s->new_agr[is_fiq] & has_intr & s->mask) {
937702e47cSPaolo Bonzini         s->new_agr[is_fiq] = 0;
947702e47cSPaolo Bonzini         omap_inth_sir_update(s, is_fiq);
957702e47cSPaolo Bonzini         qemu_set_irq(s->parent_intr[is_fiq], 1);
967702e47cSPaolo Bonzini     }
977702e47cSPaolo Bonzini }
987702e47cSPaolo Bonzini 
997702e47cSPaolo Bonzini #define INT_FALLING_EDGE	0
1007702e47cSPaolo Bonzini #define INT_LOW_LEVEL		1
1017702e47cSPaolo Bonzini 
1027702e47cSPaolo Bonzini static void omap_set_intr(void *opaque, int irq, int req)
1037702e47cSPaolo Bonzini {
1047702e47cSPaolo Bonzini     struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
1057702e47cSPaolo Bonzini     uint32_t rise;
1067702e47cSPaolo Bonzini 
1077702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
1087702e47cSPaolo Bonzini     int n = irq & 31;
1097702e47cSPaolo Bonzini 
1107702e47cSPaolo Bonzini     if (req) {
1117702e47cSPaolo Bonzini         rise = ~bank->irqs & (1 << n);
1127702e47cSPaolo Bonzini         if (~bank->sens_edge & (1 << n))
1137702e47cSPaolo Bonzini             rise &= ~bank->inputs;
1147702e47cSPaolo Bonzini 
1157702e47cSPaolo Bonzini         bank->inputs |= (1 << n);
1167702e47cSPaolo Bonzini         if (rise) {
1177702e47cSPaolo Bonzini             bank->irqs |= rise;
1187702e47cSPaolo Bonzini             omap_inth_update(ih, 0);
1197702e47cSPaolo Bonzini             omap_inth_update(ih, 1);
1207702e47cSPaolo Bonzini         }
1217702e47cSPaolo Bonzini     } else {
1227702e47cSPaolo Bonzini         rise = bank->sens_edge & bank->irqs & (1 << n);
1237702e47cSPaolo Bonzini         bank->irqs &= ~rise;
1247702e47cSPaolo Bonzini         bank->inputs &= ~(1 << n);
1257702e47cSPaolo Bonzini     }
1267702e47cSPaolo Bonzini }
1277702e47cSPaolo Bonzini 
1287702e47cSPaolo Bonzini /* Simplified version with no edge detection */
1297702e47cSPaolo Bonzini static void omap_set_intr_noedge(void *opaque, int irq, int req)
1307702e47cSPaolo Bonzini {
1317702e47cSPaolo Bonzini     struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
1327702e47cSPaolo Bonzini     uint32_t rise;
1337702e47cSPaolo Bonzini 
1347702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
1357702e47cSPaolo Bonzini     int n = irq & 31;
1367702e47cSPaolo Bonzini 
1377702e47cSPaolo Bonzini     if (req) {
1387702e47cSPaolo Bonzini         rise = ~bank->inputs & (1 << n);
1397702e47cSPaolo Bonzini         if (rise) {
1407702e47cSPaolo Bonzini             bank->irqs |= bank->inputs |= rise;
1417702e47cSPaolo Bonzini             omap_inth_update(ih, 0);
1427702e47cSPaolo Bonzini             omap_inth_update(ih, 1);
1437702e47cSPaolo Bonzini         }
1447702e47cSPaolo Bonzini     } else
1457702e47cSPaolo Bonzini         bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
1467702e47cSPaolo Bonzini }
1477702e47cSPaolo Bonzini 
1487702e47cSPaolo Bonzini static uint64_t omap_inth_read(void *opaque, hwaddr addr,
1497702e47cSPaolo Bonzini                                unsigned size)
1507702e47cSPaolo Bonzini {
1517702e47cSPaolo Bonzini     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
1527702e47cSPaolo Bonzini     int i, offset = addr;
1537702e47cSPaolo Bonzini     int bank_no = offset >> 8;
1547702e47cSPaolo Bonzini     int line_no;
1557702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
1567702e47cSPaolo Bonzini     offset &= 0xff;
1577702e47cSPaolo Bonzini 
1587702e47cSPaolo Bonzini     switch (offset) {
1597702e47cSPaolo Bonzini     case 0x00:	/* ITR */
1607702e47cSPaolo Bonzini         return bank->irqs;
1617702e47cSPaolo Bonzini 
1627702e47cSPaolo Bonzini     case 0x04:	/* MIR */
1637702e47cSPaolo Bonzini         return bank->mask;
1647702e47cSPaolo Bonzini 
1657702e47cSPaolo Bonzini     case 0x10:	/* SIR_IRQ_CODE */
1667702e47cSPaolo Bonzini     case 0x14:  /* SIR_FIQ_CODE */
1677702e47cSPaolo Bonzini         if (bank_no != 0)
1687702e47cSPaolo Bonzini             break;
1697702e47cSPaolo Bonzini         line_no = s->sir_intr[(offset - 0x10) >> 2];
1707702e47cSPaolo Bonzini         bank = &s->bank[line_no >> 5];
1717702e47cSPaolo Bonzini         i = line_no & 31;
1727702e47cSPaolo Bonzini         if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE)
1737702e47cSPaolo Bonzini             bank->irqs &= ~(1 << i);
1747702e47cSPaolo Bonzini         return line_no;
1757702e47cSPaolo Bonzini 
1767702e47cSPaolo Bonzini     case 0x18:	/* CONTROL_REG */
1777702e47cSPaolo Bonzini         if (bank_no != 0)
1787702e47cSPaolo Bonzini             break;
1797702e47cSPaolo Bonzini         return 0;
1807702e47cSPaolo Bonzini 
1817702e47cSPaolo Bonzini     case 0x1c:	/* ILR0 */
1827702e47cSPaolo Bonzini     case 0x20:	/* ILR1 */
1837702e47cSPaolo Bonzini     case 0x24:	/* ILR2 */
1847702e47cSPaolo Bonzini     case 0x28:	/* ILR3 */
1857702e47cSPaolo Bonzini     case 0x2c:	/* ILR4 */
1867702e47cSPaolo Bonzini     case 0x30:	/* ILR5 */
1877702e47cSPaolo Bonzini     case 0x34:	/* ILR6 */
1887702e47cSPaolo Bonzini     case 0x38:	/* ILR7 */
1897702e47cSPaolo Bonzini     case 0x3c:	/* ILR8 */
1907702e47cSPaolo Bonzini     case 0x40:	/* ILR9 */
1917702e47cSPaolo Bonzini     case 0x44:	/* ILR10 */
1927702e47cSPaolo Bonzini     case 0x48:	/* ILR11 */
1937702e47cSPaolo Bonzini     case 0x4c:	/* ILR12 */
1947702e47cSPaolo Bonzini     case 0x50:	/* ILR13 */
1957702e47cSPaolo Bonzini     case 0x54:	/* ILR14 */
1967702e47cSPaolo Bonzini     case 0x58:	/* ILR15 */
1977702e47cSPaolo Bonzini     case 0x5c:	/* ILR16 */
1987702e47cSPaolo Bonzini     case 0x60:	/* ILR17 */
1997702e47cSPaolo Bonzini     case 0x64:	/* ILR18 */
2007702e47cSPaolo Bonzini     case 0x68:	/* ILR19 */
2017702e47cSPaolo Bonzini     case 0x6c:	/* ILR20 */
2027702e47cSPaolo Bonzini     case 0x70:	/* ILR21 */
2037702e47cSPaolo Bonzini     case 0x74:	/* ILR22 */
2047702e47cSPaolo Bonzini     case 0x78:	/* ILR23 */
2057702e47cSPaolo Bonzini     case 0x7c:	/* ILR24 */
2067702e47cSPaolo Bonzini     case 0x80:	/* ILR25 */
2077702e47cSPaolo Bonzini     case 0x84:	/* ILR26 */
2087702e47cSPaolo Bonzini     case 0x88:	/* ILR27 */
2097702e47cSPaolo Bonzini     case 0x8c:	/* ILR28 */
2107702e47cSPaolo Bonzini     case 0x90:	/* ILR29 */
2117702e47cSPaolo Bonzini     case 0x94:	/* ILR30 */
2127702e47cSPaolo Bonzini     case 0x98:	/* ILR31 */
2137702e47cSPaolo Bonzini         i = (offset - 0x1c) >> 2;
2147702e47cSPaolo Bonzini         return (bank->priority[i] << 2) |
2157702e47cSPaolo Bonzini                 (((bank->sens_edge >> i) & 1) << 1) |
2167702e47cSPaolo Bonzini                 ((bank->fiq >> i) & 1);
2177702e47cSPaolo Bonzini 
2187702e47cSPaolo Bonzini     case 0x9c:	/* ISR */
2197702e47cSPaolo Bonzini         return 0x00000000;
2207702e47cSPaolo Bonzini 
2217702e47cSPaolo Bonzini     }
2227702e47cSPaolo Bonzini     OMAP_BAD_REG(addr);
2237702e47cSPaolo Bonzini     return 0;
2247702e47cSPaolo Bonzini }
2257702e47cSPaolo Bonzini 
2267702e47cSPaolo Bonzini static void omap_inth_write(void *opaque, hwaddr addr,
2277702e47cSPaolo Bonzini                             uint64_t value, unsigned size)
2287702e47cSPaolo Bonzini {
2297702e47cSPaolo Bonzini     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
2307702e47cSPaolo Bonzini     int i, offset = addr;
2317702e47cSPaolo Bonzini     int bank_no = offset >> 8;
2327702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
2337702e47cSPaolo Bonzini     offset &= 0xff;
2347702e47cSPaolo Bonzini 
2357702e47cSPaolo Bonzini     switch (offset) {
2367702e47cSPaolo Bonzini     case 0x00:	/* ITR */
2377702e47cSPaolo Bonzini         /* Important: ignore the clearing if the IRQ is level-triggered and
2387702e47cSPaolo Bonzini            the input bit is 1 */
2397702e47cSPaolo Bonzini         bank->irqs &= value | (bank->inputs & bank->sens_edge);
2407702e47cSPaolo Bonzini         return;
2417702e47cSPaolo Bonzini 
2427702e47cSPaolo Bonzini     case 0x04:	/* MIR */
2437702e47cSPaolo Bonzini         bank->mask = value;
2447702e47cSPaolo Bonzini         omap_inth_update(s, 0);
2457702e47cSPaolo Bonzini         omap_inth_update(s, 1);
2467702e47cSPaolo Bonzini         return;
2477702e47cSPaolo Bonzini 
2487702e47cSPaolo Bonzini     case 0x10:	/* SIR_IRQ_CODE */
2497702e47cSPaolo Bonzini     case 0x14:	/* SIR_FIQ_CODE */
2507702e47cSPaolo Bonzini         OMAP_RO_REG(addr);
2517702e47cSPaolo Bonzini         break;
2527702e47cSPaolo Bonzini 
2537702e47cSPaolo Bonzini     case 0x18:	/* CONTROL_REG */
2547702e47cSPaolo Bonzini         if (bank_no != 0)
2557702e47cSPaolo Bonzini             break;
2567702e47cSPaolo Bonzini         if (value & 2) {
2577702e47cSPaolo Bonzini             qemu_set_irq(s->parent_intr[1], 0);
2587702e47cSPaolo Bonzini             s->new_agr[1] = ~0;
2597702e47cSPaolo Bonzini             omap_inth_update(s, 1);
2607702e47cSPaolo Bonzini         }
2617702e47cSPaolo Bonzini         if (value & 1) {
2627702e47cSPaolo Bonzini             qemu_set_irq(s->parent_intr[0], 0);
2637702e47cSPaolo Bonzini             s->new_agr[0] = ~0;
2647702e47cSPaolo Bonzini             omap_inth_update(s, 0);
2657702e47cSPaolo Bonzini         }
2667702e47cSPaolo Bonzini         return;
2677702e47cSPaolo Bonzini 
2687702e47cSPaolo Bonzini     case 0x1c:	/* ILR0 */
2697702e47cSPaolo Bonzini     case 0x20:	/* ILR1 */
2707702e47cSPaolo Bonzini     case 0x24:	/* ILR2 */
2717702e47cSPaolo Bonzini     case 0x28:	/* ILR3 */
2727702e47cSPaolo Bonzini     case 0x2c:	/* ILR4 */
2737702e47cSPaolo Bonzini     case 0x30:	/* ILR5 */
2747702e47cSPaolo Bonzini     case 0x34:	/* ILR6 */
2757702e47cSPaolo Bonzini     case 0x38:	/* ILR7 */
2767702e47cSPaolo Bonzini     case 0x3c:	/* ILR8 */
2777702e47cSPaolo Bonzini     case 0x40:	/* ILR9 */
2787702e47cSPaolo Bonzini     case 0x44:	/* ILR10 */
2797702e47cSPaolo Bonzini     case 0x48:	/* ILR11 */
2807702e47cSPaolo Bonzini     case 0x4c:	/* ILR12 */
2817702e47cSPaolo Bonzini     case 0x50:	/* ILR13 */
2827702e47cSPaolo Bonzini     case 0x54:	/* ILR14 */
2837702e47cSPaolo Bonzini     case 0x58:	/* ILR15 */
2847702e47cSPaolo Bonzini     case 0x5c:	/* ILR16 */
2857702e47cSPaolo Bonzini     case 0x60:	/* ILR17 */
2867702e47cSPaolo Bonzini     case 0x64:	/* ILR18 */
2877702e47cSPaolo Bonzini     case 0x68:	/* ILR19 */
2887702e47cSPaolo Bonzini     case 0x6c:	/* ILR20 */
2897702e47cSPaolo Bonzini     case 0x70:	/* ILR21 */
2907702e47cSPaolo Bonzini     case 0x74:	/* ILR22 */
2917702e47cSPaolo Bonzini     case 0x78:	/* ILR23 */
2927702e47cSPaolo Bonzini     case 0x7c:	/* ILR24 */
2937702e47cSPaolo Bonzini     case 0x80:	/* ILR25 */
2947702e47cSPaolo Bonzini     case 0x84:	/* ILR26 */
2957702e47cSPaolo Bonzini     case 0x88:	/* ILR27 */
2967702e47cSPaolo Bonzini     case 0x8c:	/* ILR28 */
2977702e47cSPaolo Bonzini     case 0x90:	/* ILR29 */
2987702e47cSPaolo Bonzini     case 0x94:	/* ILR30 */
2997702e47cSPaolo Bonzini     case 0x98:	/* ILR31 */
3007702e47cSPaolo Bonzini         i = (offset - 0x1c) >> 2;
3017702e47cSPaolo Bonzini         bank->priority[i] = (value >> 2) & 0x1f;
3027702e47cSPaolo Bonzini         bank->sens_edge &= ~(1 << i);
3037702e47cSPaolo Bonzini         bank->sens_edge |= ((value >> 1) & 1) << i;
3047702e47cSPaolo Bonzini         bank->fiq &= ~(1 << i);
3057702e47cSPaolo Bonzini         bank->fiq |= (value & 1) << i;
3067702e47cSPaolo Bonzini         return;
3077702e47cSPaolo Bonzini 
3087702e47cSPaolo Bonzini     case 0x9c:	/* ISR */
3097702e47cSPaolo Bonzini         for (i = 0; i < 32; i ++)
3107702e47cSPaolo Bonzini             if (value & (1 << i)) {
3117702e47cSPaolo Bonzini                 omap_set_intr(s, 32 * bank_no + i, 1);
3127702e47cSPaolo Bonzini                 return;
3137702e47cSPaolo Bonzini             }
3147702e47cSPaolo Bonzini         return;
3157702e47cSPaolo Bonzini     }
3167702e47cSPaolo Bonzini     OMAP_BAD_REG(addr);
3177702e47cSPaolo Bonzini }
3187702e47cSPaolo Bonzini 
3197702e47cSPaolo Bonzini static const MemoryRegionOps omap_inth_mem_ops = {
3207702e47cSPaolo Bonzini     .read = omap_inth_read,
3217702e47cSPaolo Bonzini     .write = omap_inth_write,
3227702e47cSPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
3237702e47cSPaolo Bonzini     .valid = {
3247702e47cSPaolo Bonzini         .min_access_size = 4,
3257702e47cSPaolo Bonzini         .max_access_size = 4,
3267702e47cSPaolo Bonzini     },
3277702e47cSPaolo Bonzini };
3287702e47cSPaolo Bonzini 
3297702e47cSPaolo Bonzini static void omap_inth_reset(DeviceState *dev)
3307702e47cSPaolo Bonzini {
3317702e47cSPaolo Bonzini     struct omap_intr_handler_s *s = FROM_SYSBUS(struct omap_intr_handler_s,
3327702e47cSPaolo Bonzini                                                 SYS_BUS_DEVICE(dev));
3337702e47cSPaolo Bonzini     int i;
3347702e47cSPaolo Bonzini 
3357702e47cSPaolo Bonzini     for (i = 0; i < s->nbanks; ++i){
3367702e47cSPaolo Bonzini         s->bank[i].irqs = 0x00000000;
3377702e47cSPaolo Bonzini         s->bank[i].mask = 0xffffffff;
3387702e47cSPaolo Bonzini         s->bank[i].sens_edge = 0x00000000;
3397702e47cSPaolo Bonzini         s->bank[i].fiq = 0x00000000;
3407702e47cSPaolo Bonzini         s->bank[i].inputs = 0x00000000;
3417702e47cSPaolo Bonzini         s->bank[i].swi = 0x00000000;
3427702e47cSPaolo Bonzini         memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority));
3437702e47cSPaolo Bonzini 
3447702e47cSPaolo Bonzini         if (s->level_only)
3457702e47cSPaolo Bonzini             s->bank[i].sens_edge = 0xffffffff;
3467702e47cSPaolo Bonzini     }
3477702e47cSPaolo Bonzini 
3487702e47cSPaolo Bonzini     s->new_agr[0] = ~0;
3497702e47cSPaolo Bonzini     s->new_agr[1] = ~0;
3507702e47cSPaolo Bonzini     s->sir_intr[0] = 0;
3517702e47cSPaolo Bonzini     s->sir_intr[1] = 0;
3527702e47cSPaolo Bonzini     s->autoidle = 0;
3537702e47cSPaolo Bonzini     s->mask = ~0;
3547702e47cSPaolo Bonzini 
3557702e47cSPaolo Bonzini     qemu_set_irq(s->parent_intr[0], 0);
3567702e47cSPaolo Bonzini     qemu_set_irq(s->parent_intr[1], 0);
3577702e47cSPaolo Bonzini }
3587702e47cSPaolo Bonzini 
3597702e47cSPaolo Bonzini static int omap_intc_init(SysBusDevice *dev)
3607702e47cSPaolo Bonzini {
3617702e47cSPaolo Bonzini     struct omap_intr_handler_s *s;
3627702e47cSPaolo Bonzini     s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
3637702e47cSPaolo Bonzini     if (!s->iclk) {
3647702e47cSPaolo Bonzini         hw_error("omap-intc: clk not connected\n");
3657702e47cSPaolo Bonzini     }
3667702e47cSPaolo Bonzini     s->nbanks = 1;
3677702e47cSPaolo Bonzini     sysbus_init_irq(dev, &s->parent_intr[0]);
3687702e47cSPaolo Bonzini     sysbus_init_irq(dev, &s->parent_intr[1]);
3697702e47cSPaolo Bonzini     qdev_init_gpio_in(&dev->qdev, omap_set_intr, s->nbanks * 32);
370*1437c94bSPaolo Bonzini     memory_region_init_io(&s->mmio, OBJECT(s), &omap_inth_mem_ops, s,
3717702e47cSPaolo Bonzini                           "omap-intc", s->size);
3727702e47cSPaolo Bonzini     sysbus_init_mmio(dev, &s->mmio);
3737702e47cSPaolo Bonzini     return 0;
3747702e47cSPaolo Bonzini }
3757702e47cSPaolo Bonzini 
3767702e47cSPaolo Bonzini static Property omap_intc_properties[] = {
3777702e47cSPaolo Bonzini     DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
3787702e47cSPaolo Bonzini     DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
3797702e47cSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
3807702e47cSPaolo Bonzini };
3817702e47cSPaolo Bonzini 
3827702e47cSPaolo Bonzini static void omap_intc_class_init(ObjectClass *klass, void *data)
3837702e47cSPaolo Bonzini {
3847702e47cSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
3857702e47cSPaolo Bonzini     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
3867702e47cSPaolo Bonzini 
3877702e47cSPaolo Bonzini     k->init = omap_intc_init;
3887702e47cSPaolo Bonzini     dc->reset = omap_inth_reset;
3897702e47cSPaolo Bonzini     dc->props = omap_intc_properties;
3907702e47cSPaolo Bonzini }
3917702e47cSPaolo Bonzini 
3927702e47cSPaolo Bonzini static const TypeInfo omap_intc_info = {
3937702e47cSPaolo Bonzini     .name          = "omap-intc",
3947702e47cSPaolo Bonzini     .parent        = TYPE_SYS_BUS_DEVICE,
3957702e47cSPaolo Bonzini     .instance_size = sizeof(struct omap_intr_handler_s),
3967702e47cSPaolo Bonzini     .class_init    = omap_intc_class_init,
3977702e47cSPaolo Bonzini };
3987702e47cSPaolo Bonzini 
3997702e47cSPaolo Bonzini static uint64_t omap2_inth_read(void *opaque, hwaddr addr,
4007702e47cSPaolo Bonzini                                 unsigned size)
4017702e47cSPaolo Bonzini {
4027702e47cSPaolo Bonzini     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
4037702e47cSPaolo Bonzini     int offset = addr;
4047702e47cSPaolo Bonzini     int bank_no, line_no;
4057702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s *bank = NULL;
4067702e47cSPaolo Bonzini 
4077702e47cSPaolo Bonzini     if ((offset & 0xf80) == 0x80) {
4087702e47cSPaolo Bonzini         bank_no = (offset & 0x60) >> 5;
4097702e47cSPaolo Bonzini         if (bank_no < s->nbanks) {
4107702e47cSPaolo Bonzini             offset &= ~0x60;
4117702e47cSPaolo Bonzini             bank = &s->bank[bank_no];
4127702e47cSPaolo Bonzini         } else {
4137702e47cSPaolo Bonzini             OMAP_BAD_REG(addr);
4147702e47cSPaolo Bonzini             return 0;
4157702e47cSPaolo Bonzini         }
4167702e47cSPaolo Bonzini     }
4177702e47cSPaolo Bonzini 
4187702e47cSPaolo Bonzini     switch (offset) {
4197702e47cSPaolo Bonzini     case 0x00:	/* INTC_REVISION */
4207702e47cSPaolo Bonzini         return s->revision;
4217702e47cSPaolo Bonzini 
4227702e47cSPaolo Bonzini     case 0x10:	/* INTC_SYSCONFIG */
4237702e47cSPaolo Bonzini         return (s->autoidle >> 2) & 1;
4247702e47cSPaolo Bonzini 
4257702e47cSPaolo Bonzini     case 0x14:	/* INTC_SYSSTATUS */
4267702e47cSPaolo Bonzini         return 1;						/* RESETDONE */
4277702e47cSPaolo Bonzini 
4287702e47cSPaolo Bonzini     case 0x40:	/* INTC_SIR_IRQ */
4297702e47cSPaolo Bonzini         return s->sir_intr[0];
4307702e47cSPaolo Bonzini 
4317702e47cSPaolo Bonzini     case 0x44:	/* INTC_SIR_FIQ */
4327702e47cSPaolo Bonzini         return s->sir_intr[1];
4337702e47cSPaolo Bonzini 
4347702e47cSPaolo Bonzini     case 0x48:	/* INTC_CONTROL */
4357702e47cSPaolo Bonzini         return (!s->mask) << 2;					/* GLOBALMASK */
4367702e47cSPaolo Bonzini 
4377702e47cSPaolo Bonzini     case 0x4c:	/* INTC_PROTECTION */
4387702e47cSPaolo Bonzini         return 0;
4397702e47cSPaolo Bonzini 
4407702e47cSPaolo Bonzini     case 0x50:	/* INTC_IDLE */
4417702e47cSPaolo Bonzini         return s->autoidle & 3;
4427702e47cSPaolo Bonzini 
4437702e47cSPaolo Bonzini     /* Per-bank registers */
4447702e47cSPaolo Bonzini     case 0x80:	/* INTC_ITR */
4457702e47cSPaolo Bonzini         return bank->inputs;
4467702e47cSPaolo Bonzini 
4477702e47cSPaolo Bonzini     case 0x84:	/* INTC_MIR */
4487702e47cSPaolo Bonzini         return bank->mask;
4497702e47cSPaolo Bonzini 
4507702e47cSPaolo Bonzini     case 0x88:	/* INTC_MIR_CLEAR */
4517702e47cSPaolo Bonzini     case 0x8c:	/* INTC_MIR_SET */
4527702e47cSPaolo Bonzini         return 0;
4537702e47cSPaolo Bonzini 
4547702e47cSPaolo Bonzini     case 0x90:	/* INTC_ISR_SET */
4557702e47cSPaolo Bonzini         return bank->swi;
4567702e47cSPaolo Bonzini 
4577702e47cSPaolo Bonzini     case 0x94:	/* INTC_ISR_CLEAR */
4587702e47cSPaolo Bonzini         return 0;
4597702e47cSPaolo Bonzini 
4607702e47cSPaolo Bonzini     case 0x98:	/* INTC_PENDING_IRQ */
4617702e47cSPaolo Bonzini         return bank->irqs & ~bank->mask & ~bank->fiq;
4627702e47cSPaolo Bonzini 
4637702e47cSPaolo Bonzini     case 0x9c:	/* INTC_PENDING_FIQ */
4647702e47cSPaolo Bonzini         return bank->irqs & ~bank->mask & bank->fiq;
4657702e47cSPaolo Bonzini 
4667702e47cSPaolo Bonzini     /* Per-line registers */
4677702e47cSPaolo Bonzini     case 0x100 ... 0x300:	/* INTC_ILR */
4687702e47cSPaolo Bonzini         bank_no = (offset - 0x100) >> 7;
4697702e47cSPaolo Bonzini         if (bank_no > s->nbanks)
4707702e47cSPaolo Bonzini             break;
4717702e47cSPaolo Bonzini         bank = &s->bank[bank_no];
4727702e47cSPaolo Bonzini         line_no = (offset & 0x7f) >> 2;
4737702e47cSPaolo Bonzini         return (bank->priority[line_no] << 2) |
4747702e47cSPaolo Bonzini                 ((bank->fiq >> line_no) & 1);
4757702e47cSPaolo Bonzini     }
4767702e47cSPaolo Bonzini     OMAP_BAD_REG(addr);
4777702e47cSPaolo Bonzini     return 0;
4787702e47cSPaolo Bonzini }
4797702e47cSPaolo Bonzini 
4807702e47cSPaolo Bonzini static void omap2_inth_write(void *opaque, hwaddr addr,
4817702e47cSPaolo Bonzini                              uint64_t value, unsigned size)
4827702e47cSPaolo Bonzini {
4837702e47cSPaolo Bonzini     struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
4847702e47cSPaolo Bonzini     int offset = addr;
4857702e47cSPaolo Bonzini     int bank_no, line_no;
4867702e47cSPaolo Bonzini     struct omap_intr_handler_bank_s *bank = NULL;
4877702e47cSPaolo Bonzini 
4887702e47cSPaolo Bonzini     if ((offset & 0xf80) == 0x80) {
4897702e47cSPaolo Bonzini         bank_no = (offset & 0x60) >> 5;
4907702e47cSPaolo Bonzini         if (bank_no < s->nbanks) {
4917702e47cSPaolo Bonzini             offset &= ~0x60;
4927702e47cSPaolo Bonzini             bank = &s->bank[bank_no];
4937702e47cSPaolo Bonzini         } else {
4947702e47cSPaolo Bonzini             OMAP_BAD_REG(addr);
4957702e47cSPaolo Bonzini             return;
4967702e47cSPaolo Bonzini         }
4977702e47cSPaolo Bonzini     }
4987702e47cSPaolo Bonzini 
4997702e47cSPaolo Bonzini     switch (offset) {
5007702e47cSPaolo Bonzini     case 0x10:	/* INTC_SYSCONFIG */
5017702e47cSPaolo Bonzini         s->autoidle &= 4;
5027702e47cSPaolo Bonzini         s->autoidle |= (value & 1) << 2;
5037702e47cSPaolo Bonzini         if (value & 2)						/* SOFTRESET */
5047702e47cSPaolo Bonzini             omap_inth_reset(&s->busdev.qdev);
5057702e47cSPaolo Bonzini         return;
5067702e47cSPaolo Bonzini 
5077702e47cSPaolo Bonzini     case 0x48:	/* INTC_CONTROL */
5087702e47cSPaolo Bonzini         s->mask = (value & 4) ? 0 : ~0;				/* GLOBALMASK */
5097702e47cSPaolo Bonzini         if (value & 2) {					/* NEWFIQAGR */
5107702e47cSPaolo Bonzini             qemu_set_irq(s->parent_intr[1], 0);
5117702e47cSPaolo Bonzini             s->new_agr[1] = ~0;
5127702e47cSPaolo Bonzini             omap_inth_update(s, 1);
5137702e47cSPaolo Bonzini         }
5147702e47cSPaolo Bonzini         if (value & 1) {					/* NEWIRQAGR */
5157702e47cSPaolo Bonzini             qemu_set_irq(s->parent_intr[0], 0);
5167702e47cSPaolo Bonzini             s->new_agr[0] = ~0;
5177702e47cSPaolo Bonzini             omap_inth_update(s, 0);
5187702e47cSPaolo Bonzini         }
5197702e47cSPaolo Bonzini         return;
5207702e47cSPaolo Bonzini 
5217702e47cSPaolo Bonzini     case 0x4c:	/* INTC_PROTECTION */
5227702e47cSPaolo Bonzini         /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
5237702e47cSPaolo Bonzini          * for every register, see Chapter 3 and 4 for privileged mode.  */
5247702e47cSPaolo Bonzini         if (value & 1)
5257702e47cSPaolo Bonzini             fprintf(stderr, "%s: protection mode enable attempt\n",
5267702e47cSPaolo Bonzini                             __FUNCTION__);
5277702e47cSPaolo Bonzini         return;
5287702e47cSPaolo Bonzini 
5297702e47cSPaolo Bonzini     case 0x50:	/* INTC_IDLE */
5307702e47cSPaolo Bonzini         s->autoidle &= ~3;
5317702e47cSPaolo Bonzini         s->autoidle |= value & 3;
5327702e47cSPaolo Bonzini         return;
5337702e47cSPaolo Bonzini 
5347702e47cSPaolo Bonzini     /* Per-bank registers */
5357702e47cSPaolo Bonzini     case 0x84:	/* INTC_MIR */
5367702e47cSPaolo Bonzini         bank->mask = value;
5377702e47cSPaolo Bonzini         omap_inth_update(s, 0);
5387702e47cSPaolo Bonzini         omap_inth_update(s, 1);
5397702e47cSPaolo Bonzini         return;
5407702e47cSPaolo Bonzini 
5417702e47cSPaolo Bonzini     case 0x88:	/* INTC_MIR_CLEAR */
5427702e47cSPaolo Bonzini         bank->mask &= ~value;
5437702e47cSPaolo Bonzini         omap_inth_update(s, 0);
5447702e47cSPaolo Bonzini         omap_inth_update(s, 1);
5457702e47cSPaolo Bonzini         return;
5467702e47cSPaolo Bonzini 
5477702e47cSPaolo Bonzini     case 0x8c:	/* INTC_MIR_SET */
5487702e47cSPaolo Bonzini         bank->mask |= value;
5497702e47cSPaolo Bonzini         return;
5507702e47cSPaolo Bonzini 
5517702e47cSPaolo Bonzini     case 0x90:	/* INTC_ISR_SET */
5527702e47cSPaolo Bonzini         bank->irqs |= bank->swi |= value;
5537702e47cSPaolo Bonzini         omap_inth_update(s, 0);
5547702e47cSPaolo Bonzini         omap_inth_update(s, 1);
5557702e47cSPaolo Bonzini         return;
5567702e47cSPaolo Bonzini 
5577702e47cSPaolo Bonzini     case 0x94:	/* INTC_ISR_CLEAR */
5587702e47cSPaolo Bonzini         bank->swi &= ~value;
5597702e47cSPaolo Bonzini         bank->irqs = bank->swi & bank->inputs;
5607702e47cSPaolo Bonzini         return;
5617702e47cSPaolo Bonzini 
5627702e47cSPaolo Bonzini     /* Per-line registers */
5637702e47cSPaolo Bonzini     case 0x100 ... 0x300:	/* INTC_ILR */
5647702e47cSPaolo Bonzini         bank_no = (offset - 0x100) >> 7;
5657702e47cSPaolo Bonzini         if (bank_no > s->nbanks)
5667702e47cSPaolo Bonzini             break;
5677702e47cSPaolo Bonzini         bank = &s->bank[bank_no];
5687702e47cSPaolo Bonzini         line_no = (offset & 0x7f) >> 2;
5697702e47cSPaolo Bonzini         bank->priority[line_no] = (value >> 2) & 0x3f;
5707702e47cSPaolo Bonzini         bank->fiq &= ~(1 << line_no);
5717702e47cSPaolo Bonzini         bank->fiq |= (value & 1) << line_no;
5727702e47cSPaolo Bonzini         return;
5737702e47cSPaolo Bonzini 
5747702e47cSPaolo Bonzini     case 0x00:	/* INTC_REVISION */
5757702e47cSPaolo Bonzini     case 0x14:	/* INTC_SYSSTATUS */
5767702e47cSPaolo Bonzini     case 0x40:	/* INTC_SIR_IRQ */
5777702e47cSPaolo Bonzini     case 0x44:	/* INTC_SIR_FIQ */
5787702e47cSPaolo Bonzini     case 0x80:	/* INTC_ITR */
5797702e47cSPaolo Bonzini     case 0x98:	/* INTC_PENDING_IRQ */
5807702e47cSPaolo Bonzini     case 0x9c:	/* INTC_PENDING_FIQ */
5817702e47cSPaolo Bonzini         OMAP_RO_REG(addr);
5827702e47cSPaolo Bonzini         return;
5837702e47cSPaolo Bonzini     }
5847702e47cSPaolo Bonzini     OMAP_BAD_REG(addr);
5857702e47cSPaolo Bonzini }
5867702e47cSPaolo Bonzini 
5877702e47cSPaolo Bonzini static const MemoryRegionOps omap2_inth_mem_ops = {
5887702e47cSPaolo Bonzini     .read = omap2_inth_read,
5897702e47cSPaolo Bonzini     .write = omap2_inth_write,
5907702e47cSPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
5917702e47cSPaolo Bonzini     .valid = {
5927702e47cSPaolo Bonzini         .min_access_size = 4,
5937702e47cSPaolo Bonzini         .max_access_size = 4,
5947702e47cSPaolo Bonzini     },
5957702e47cSPaolo Bonzini };
5967702e47cSPaolo Bonzini 
5977702e47cSPaolo Bonzini static int omap2_intc_init(SysBusDevice *dev)
5987702e47cSPaolo Bonzini {
5997702e47cSPaolo Bonzini     struct omap_intr_handler_s *s;
6007702e47cSPaolo Bonzini     s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
6017702e47cSPaolo Bonzini     if (!s->iclk) {
6027702e47cSPaolo Bonzini         hw_error("omap2-intc: iclk not connected\n");
6037702e47cSPaolo Bonzini     }
6047702e47cSPaolo Bonzini     if (!s->fclk) {
6057702e47cSPaolo Bonzini         hw_error("omap2-intc: fclk not connected\n");
6067702e47cSPaolo Bonzini     }
6077702e47cSPaolo Bonzini     s->level_only = 1;
6087702e47cSPaolo Bonzini     s->nbanks = 3;
6097702e47cSPaolo Bonzini     sysbus_init_irq(dev, &s->parent_intr[0]);
6107702e47cSPaolo Bonzini     sysbus_init_irq(dev, &s->parent_intr[1]);
6117702e47cSPaolo Bonzini     qdev_init_gpio_in(&dev->qdev, omap_set_intr_noedge, s->nbanks * 32);
612*1437c94bSPaolo Bonzini     memory_region_init_io(&s->mmio, OBJECT(s), &omap2_inth_mem_ops, s,
6137702e47cSPaolo Bonzini                           "omap2-intc", 0x1000);
6147702e47cSPaolo Bonzini     sysbus_init_mmio(dev, &s->mmio);
6157702e47cSPaolo Bonzini     return 0;
6167702e47cSPaolo Bonzini }
6177702e47cSPaolo Bonzini 
6187702e47cSPaolo Bonzini static Property omap2_intc_properties[] = {
6197702e47cSPaolo Bonzini     DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
6207702e47cSPaolo Bonzini     revision, 0x21),
6217702e47cSPaolo Bonzini     DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
6227702e47cSPaolo Bonzini     DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
6237702e47cSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
6247702e47cSPaolo Bonzini };
6257702e47cSPaolo Bonzini 
6267702e47cSPaolo Bonzini static void omap2_intc_class_init(ObjectClass *klass, void *data)
6277702e47cSPaolo Bonzini {
6287702e47cSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
6297702e47cSPaolo Bonzini     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
6307702e47cSPaolo Bonzini 
6317702e47cSPaolo Bonzini     k->init = omap2_intc_init;
6327702e47cSPaolo Bonzini     dc->reset = omap_inth_reset;
6337702e47cSPaolo Bonzini     dc->props = omap2_intc_properties;
6347702e47cSPaolo Bonzini }
6357702e47cSPaolo Bonzini 
6367702e47cSPaolo Bonzini static const TypeInfo omap2_intc_info = {
6377702e47cSPaolo Bonzini     .name          = "omap2-intc",
6387702e47cSPaolo Bonzini     .parent        = TYPE_SYS_BUS_DEVICE,
6397702e47cSPaolo Bonzini     .instance_size = sizeof(struct omap_intr_handler_s),
6407702e47cSPaolo Bonzini     .class_init    = omap2_intc_class_init,
6417702e47cSPaolo Bonzini };
6427702e47cSPaolo Bonzini 
6437702e47cSPaolo Bonzini static void omap_intc_register_types(void)
6447702e47cSPaolo Bonzini {
6457702e47cSPaolo Bonzini     type_register_static(&omap_intc_info);
6467702e47cSPaolo Bonzini     type_register_static(&omap2_intc_info);
6477702e47cSPaolo Bonzini }
6487702e47cSPaolo Bonzini 
6497702e47cSPaolo Bonzini type_init(omap_intc_register_types)
650