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 */
200b8fa32fSMarkus Armbruster
2190191d07SPeter Maydell #include "qemu/osdep.h"
2264552b6bSMarkus Armbruster #include "hw/irq.h"
23a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
247702e47cSPaolo Bonzini #include "hw/arm/omap.h"
257702e47cSPaolo Bonzini #include "hw/sysbus.h"
2684a3a53cSMarkus Armbruster #include "qemu/error-report.h"
270b8fa32fSMarkus Armbruster #include "qemu/module.h"
280a750e2aSxiaoqiang zhao #include "qapi/error.h"
297702e47cSPaolo Bonzini
307702e47cSPaolo Bonzini /* Interrupt Handlers */
317702e47cSPaolo Bonzini struct omap_intr_handler_bank_s {
327702e47cSPaolo Bonzini uint32_t irqs;
337702e47cSPaolo Bonzini uint32_t inputs;
347702e47cSPaolo Bonzini uint32_t mask;
357702e47cSPaolo Bonzini uint32_t fiq;
367702e47cSPaolo Bonzini uint32_t sens_edge;
377702e47cSPaolo Bonzini uint32_t swi;
387702e47cSPaolo Bonzini unsigned char priority[32];
397702e47cSPaolo Bonzini };
407702e47cSPaolo Bonzini
41bded15c9SPhilippe Mathieu-Daudé struct OMAPIntcState {
4247edc5a4SAndreas Färber SysBusDevice parent_obj;
4347edc5a4SAndreas Färber
447702e47cSPaolo Bonzini qemu_irq *pins;
457702e47cSPaolo Bonzini qemu_irq parent_intr[2];
467702e47cSPaolo Bonzini MemoryRegion mmio;
477702e47cSPaolo Bonzini void *iclk;
487702e47cSPaolo Bonzini void *fclk;
497702e47cSPaolo Bonzini unsigned char nbanks;
507702e47cSPaolo Bonzini int level_only;
517702e47cSPaolo Bonzini uint32_t size;
527702e47cSPaolo Bonzini
537702e47cSPaolo Bonzini uint8_t revision;
547702e47cSPaolo Bonzini
557702e47cSPaolo Bonzini /* state */
567702e47cSPaolo Bonzini uint32_t new_agr[2];
577702e47cSPaolo Bonzini int sir_intr[2];
587702e47cSPaolo Bonzini int autoidle;
597702e47cSPaolo Bonzini uint32_t mask;
607702e47cSPaolo Bonzini struct omap_intr_handler_bank_s bank[3];
617702e47cSPaolo Bonzini };
627702e47cSPaolo Bonzini
omap_inth_sir_update(OMAPIntcState * s,int is_fiq)63bded15c9SPhilippe Mathieu-Daudé static void omap_inth_sir_update(OMAPIntcState *s, int is_fiq)
647702e47cSPaolo Bonzini {
6541074f3dSPaolo Bonzini int i, j, sir_intr, p_intr, p;
667702e47cSPaolo Bonzini uint32_t level;
677702e47cSPaolo Bonzini sir_intr = 0;
687702e47cSPaolo Bonzini p_intr = 255;
697702e47cSPaolo Bonzini
707702e47cSPaolo Bonzini /* Find the interrupt line with the highest dynamic priority.
71*9b4b4e51SMichael Tokarev * Note: 0 denotes the highest priority.
727702e47cSPaolo Bonzini * If all interrupts have the same priority, the default order is IRQ_N,
737702e47cSPaolo Bonzini * IRQ_N-1,...,IRQ_0. */
747702e47cSPaolo Bonzini for (j = 0; j < s->nbanks; ++j) {
757702e47cSPaolo Bonzini level = s->bank[j].irqs & ~s->bank[j].mask &
767702e47cSPaolo Bonzini (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);
7741074f3dSPaolo Bonzini
7841074f3dSPaolo Bonzini while (level != 0) {
7941074f3dSPaolo Bonzini i = ctz32(level);
807702e47cSPaolo Bonzini p = s->bank[j].priority[i];
817702e47cSPaolo Bonzini if (p <= p_intr) {
827702e47cSPaolo Bonzini p_intr = p;
837702e47cSPaolo Bonzini sir_intr = 32 * j + i;
847702e47cSPaolo Bonzini }
8541074f3dSPaolo Bonzini level &= level - 1;
867702e47cSPaolo Bonzini }
877702e47cSPaolo Bonzini }
887702e47cSPaolo Bonzini s->sir_intr[is_fiq] = sir_intr;
897702e47cSPaolo Bonzini }
907702e47cSPaolo Bonzini
omap_inth_update(OMAPIntcState * s,int is_fiq)91bded15c9SPhilippe Mathieu-Daudé static inline void omap_inth_update(OMAPIntcState *s, int is_fiq)
927702e47cSPaolo Bonzini {
937702e47cSPaolo Bonzini int i;
947702e47cSPaolo Bonzini uint32_t has_intr = 0;
957702e47cSPaolo Bonzini
967702e47cSPaolo Bonzini for (i = 0; i < s->nbanks; ++i)
977702e47cSPaolo Bonzini has_intr |= s->bank[i].irqs & ~s->bank[i].mask &
987702e47cSPaolo Bonzini (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq);
997702e47cSPaolo Bonzini
1007702e47cSPaolo Bonzini if (s->new_agr[is_fiq] & has_intr & s->mask) {
1017702e47cSPaolo Bonzini s->new_agr[is_fiq] = 0;
1027702e47cSPaolo Bonzini omap_inth_sir_update(s, is_fiq);
1037702e47cSPaolo Bonzini qemu_set_irq(s->parent_intr[is_fiq], 1);
1047702e47cSPaolo Bonzini }
1057702e47cSPaolo Bonzini }
1067702e47cSPaolo Bonzini
1077702e47cSPaolo Bonzini #define INT_FALLING_EDGE 0
1087702e47cSPaolo Bonzini #define INT_LOW_LEVEL 1
1097702e47cSPaolo Bonzini
omap_set_intr(void * opaque,int irq,int req)1107702e47cSPaolo Bonzini static void omap_set_intr(void *opaque, int irq, int req)
1117702e47cSPaolo Bonzini {
112bded15c9SPhilippe Mathieu-Daudé OMAPIntcState *ih = opaque;
1137702e47cSPaolo Bonzini uint32_t rise;
1147702e47cSPaolo Bonzini
1157702e47cSPaolo Bonzini struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
1167702e47cSPaolo Bonzini int n = irq & 31;
1177702e47cSPaolo Bonzini
1187702e47cSPaolo Bonzini if (req) {
1197702e47cSPaolo Bonzini rise = ~bank->irqs & (1 << n);
1207702e47cSPaolo Bonzini if (~bank->sens_edge & (1 << n))
1217702e47cSPaolo Bonzini rise &= ~bank->inputs;
1227702e47cSPaolo Bonzini
1237702e47cSPaolo Bonzini bank->inputs |= (1 << n);
1247702e47cSPaolo Bonzini if (rise) {
1257702e47cSPaolo Bonzini bank->irqs |= rise;
1267702e47cSPaolo Bonzini omap_inth_update(ih, 0);
1277702e47cSPaolo Bonzini omap_inth_update(ih, 1);
1287702e47cSPaolo Bonzini }
1297702e47cSPaolo Bonzini } else {
1307702e47cSPaolo Bonzini rise = bank->sens_edge & bank->irqs & (1 << n);
1317702e47cSPaolo Bonzini bank->irqs &= ~rise;
1327702e47cSPaolo Bonzini bank->inputs &= ~(1 << n);
1337702e47cSPaolo Bonzini }
1347702e47cSPaolo Bonzini }
1357702e47cSPaolo Bonzini
1367702e47cSPaolo Bonzini /* Simplified version with no edge detection */
omap_set_intr_noedge(void * opaque,int irq,int req)1377702e47cSPaolo Bonzini static void omap_set_intr_noedge(void *opaque, int irq, int req)
1387702e47cSPaolo Bonzini {
139bded15c9SPhilippe Mathieu-Daudé OMAPIntcState *ih = opaque;
1407702e47cSPaolo Bonzini uint32_t rise;
1417702e47cSPaolo Bonzini
1427702e47cSPaolo Bonzini struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
1437702e47cSPaolo Bonzini int n = irq & 31;
1447702e47cSPaolo Bonzini
1457702e47cSPaolo Bonzini if (req) {
1467702e47cSPaolo Bonzini rise = ~bank->inputs & (1 << n);
1477702e47cSPaolo Bonzini if (rise) {
1487702e47cSPaolo Bonzini bank->irqs |= bank->inputs |= rise;
1497702e47cSPaolo Bonzini omap_inth_update(ih, 0);
1507702e47cSPaolo Bonzini omap_inth_update(ih, 1);
1517702e47cSPaolo Bonzini }
1527702e47cSPaolo Bonzini } else
1537702e47cSPaolo Bonzini bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
1547702e47cSPaolo Bonzini }
1557702e47cSPaolo Bonzini
omap_inth_read(void * opaque,hwaddr addr,unsigned size)1567702e47cSPaolo Bonzini static uint64_t omap_inth_read(void *opaque, hwaddr addr,
1577702e47cSPaolo Bonzini unsigned size)
1587702e47cSPaolo Bonzini {
159bded15c9SPhilippe Mathieu-Daudé OMAPIntcState *s = opaque;
1607702e47cSPaolo Bonzini int i, offset = addr;
1617702e47cSPaolo Bonzini int bank_no = offset >> 8;
1627702e47cSPaolo Bonzini int line_no;
1637702e47cSPaolo Bonzini struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
1647702e47cSPaolo Bonzini offset &= 0xff;
1657702e47cSPaolo Bonzini
1667702e47cSPaolo Bonzini switch (offset) {
1677702e47cSPaolo Bonzini case 0x00: /* ITR */
1687702e47cSPaolo Bonzini return bank->irqs;
1697702e47cSPaolo Bonzini
1707702e47cSPaolo Bonzini case 0x04: /* MIR */
1717702e47cSPaolo Bonzini return bank->mask;
1727702e47cSPaolo Bonzini
1737702e47cSPaolo Bonzini case 0x10: /* SIR_IRQ_CODE */
1747702e47cSPaolo Bonzini case 0x14: /* SIR_FIQ_CODE */
1757702e47cSPaolo Bonzini if (bank_no != 0)
1767702e47cSPaolo Bonzini break;
1777702e47cSPaolo Bonzini line_no = s->sir_intr[(offset - 0x10) >> 2];
1787702e47cSPaolo Bonzini bank = &s->bank[line_no >> 5];
1797702e47cSPaolo Bonzini i = line_no & 31;
1807702e47cSPaolo Bonzini if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE)
1817702e47cSPaolo Bonzini bank->irqs &= ~(1 << i);
1827702e47cSPaolo Bonzini return line_no;
1837702e47cSPaolo Bonzini
1847702e47cSPaolo Bonzini case 0x18: /* CONTROL_REG */
1857702e47cSPaolo Bonzini if (bank_no != 0)
1867702e47cSPaolo Bonzini break;
1877702e47cSPaolo Bonzini return 0;
1887702e47cSPaolo Bonzini
1897702e47cSPaolo Bonzini case 0x1c: /* ILR0 */
1907702e47cSPaolo Bonzini case 0x20: /* ILR1 */
1917702e47cSPaolo Bonzini case 0x24: /* ILR2 */
1927702e47cSPaolo Bonzini case 0x28: /* ILR3 */
1937702e47cSPaolo Bonzini case 0x2c: /* ILR4 */
1947702e47cSPaolo Bonzini case 0x30: /* ILR5 */
1957702e47cSPaolo Bonzini case 0x34: /* ILR6 */
1967702e47cSPaolo Bonzini case 0x38: /* ILR7 */
1977702e47cSPaolo Bonzini case 0x3c: /* ILR8 */
1987702e47cSPaolo Bonzini case 0x40: /* ILR9 */
1997702e47cSPaolo Bonzini case 0x44: /* ILR10 */
2007702e47cSPaolo Bonzini case 0x48: /* ILR11 */
2017702e47cSPaolo Bonzini case 0x4c: /* ILR12 */
2027702e47cSPaolo Bonzini case 0x50: /* ILR13 */
2037702e47cSPaolo Bonzini case 0x54: /* ILR14 */
2047702e47cSPaolo Bonzini case 0x58: /* ILR15 */
2057702e47cSPaolo Bonzini case 0x5c: /* ILR16 */
2067702e47cSPaolo Bonzini case 0x60: /* ILR17 */
2077702e47cSPaolo Bonzini case 0x64: /* ILR18 */
2087702e47cSPaolo Bonzini case 0x68: /* ILR19 */
2097702e47cSPaolo Bonzini case 0x6c: /* ILR20 */
2107702e47cSPaolo Bonzini case 0x70: /* ILR21 */
2117702e47cSPaolo Bonzini case 0x74: /* ILR22 */
2127702e47cSPaolo Bonzini case 0x78: /* ILR23 */
2137702e47cSPaolo Bonzini case 0x7c: /* ILR24 */
2147702e47cSPaolo Bonzini case 0x80: /* ILR25 */
2157702e47cSPaolo Bonzini case 0x84: /* ILR26 */
2167702e47cSPaolo Bonzini case 0x88: /* ILR27 */
2177702e47cSPaolo Bonzini case 0x8c: /* ILR28 */
2187702e47cSPaolo Bonzini case 0x90: /* ILR29 */
2197702e47cSPaolo Bonzini case 0x94: /* ILR30 */
2207702e47cSPaolo Bonzini case 0x98: /* ILR31 */
2217702e47cSPaolo Bonzini i = (offset - 0x1c) >> 2;
2227702e47cSPaolo Bonzini return (bank->priority[i] << 2) |
2237702e47cSPaolo Bonzini (((bank->sens_edge >> i) & 1) << 1) |
2247702e47cSPaolo Bonzini ((bank->fiq >> i) & 1);
2257702e47cSPaolo Bonzini
2267702e47cSPaolo Bonzini case 0x9c: /* ISR */
2277702e47cSPaolo Bonzini return 0x00000000;
2287702e47cSPaolo Bonzini
2297702e47cSPaolo Bonzini }
2307702e47cSPaolo Bonzini OMAP_BAD_REG(addr);
2317702e47cSPaolo Bonzini return 0;
2327702e47cSPaolo Bonzini }
2337702e47cSPaolo Bonzini
omap_inth_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)2347702e47cSPaolo Bonzini static void omap_inth_write(void *opaque, hwaddr addr,
2357702e47cSPaolo Bonzini uint64_t value, unsigned size)
2367702e47cSPaolo Bonzini {
237bded15c9SPhilippe Mathieu-Daudé OMAPIntcState *s = opaque;
2387702e47cSPaolo Bonzini int i, offset = addr;
2397702e47cSPaolo Bonzini int bank_no = offset >> 8;
2407702e47cSPaolo Bonzini struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
2417702e47cSPaolo Bonzini offset &= 0xff;
2427702e47cSPaolo Bonzini
2437702e47cSPaolo Bonzini switch (offset) {
2447702e47cSPaolo Bonzini case 0x00: /* ITR */
2457702e47cSPaolo Bonzini /* Important: ignore the clearing if the IRQ is level-triggered and
2467702e47cSPaolo Bonzini the input bit is 1 */
2477702e47cSPaolo Bonzini bank->irqs &= value | (bank->inputs & bank->sens_edge);
2487702e47cSPaolo Bonzini return;
2497702e47cSPaolo Bonzini
2507702e47cSPaolo Bonzini case 0x04: /* MIR */
2517702e47cSPaolo Bonzini bank->mask = value;
2527702e47cSPaolo Bonzini omap_inth_update(s, 0);
2537702e47cSPaolo Bonzini omap_inth_update(s, 1);
2547702e47cSPaolo Bonzini return;
2557702e47cSPaolo Bonzini
2567702e47cSPaolo Bonzini case 0x10: /* SIR_IRQ_CODE */
2577702e47cSPaolo Bonzini case 0x14: /* SIR_FIQ_CODE */
2587702e47cSPaolo Bonzini OMAP_RO_REG(addr);
2597702e47cSPaolo Bonzini break;
2607702e47cSPaolo Bonzini
2617702e47cSPaolo Bonzini case 0x18: /* CONTROL_REG */
2627702e47cSPaolo Bonzini if (bank_no != 0)
2637702e47cSPaolo Bonzini break;
2647702e47cSPaolo Bonzini if (value & 2) {
2657702e47cSPaolo Bonzini qemu_set_irq(s->parent_intr[1], 0);
2667702e47cSPaolo Bonzini s->new_agr[1] = ~0;
2677702e47cSPaolo Bonzini omap_inth_update(s, 1);
2687702e47cSPaolo Bonzini }
2697702e47cSPaolo Bonzini if (value & 1) {
2707702e47cSPaolo Bonzini qemu_set_irq(s->parent_intr[0], 0);
2717702e47cSPaolo Bonzini s->new_agr[0] = ~0;
2727702e47cSPaolo Bonzini omap_inth_update(s, 0);
2737702e47cSPaolo Bonzini }
2747702e47cSPaolo Bonzini return;
2757702e47cSPaolo Bonzini
2767702e47cSPaolo Bonzini case 0x1c: /* ILR0 */
2777702e47cSPaolo Bonzini case 0x20: /* ILR1 */
2787702e47cSPaolo Bonzini case 0x24: /* ILR2 */
2797702e47cSPaolo Bonzini case 0x28: /* ILR3 */
2807702e47cSPaolo Bonzini case 0x2c: /* ILR4 */
2817702e47cSPaolo Bonzini case 0x30: /* ILR5 */
2827702e47cSPaolo Bonzini case 0x34: /* ILR6 */
2837702e47cSPaolo Bonzini case 0x38: /* ILR7 */
2847702e47cSPaolo Bonzini case 0x3c: /* ILR8 */
2857702e47cSPaolo Bonzini case 0x40: /* ILR9 */
2867702e47cSPaolo Bonzini case 0x44: /* ILR10 */
2877702e47cSPaolo Bonzini case 0x48: /* ILR11 */
2887702e47cSPaolo Bonzini case 0x4c: /* ILR12 */
2897702e47cSPaolo Bonzini case 0x50: /* ILR13 */
2907702e47cSPaolo Bonzini case 0x54: /* ILR14 */
2917702e47cSPaolo Bonzini case 0x58: /* ILR15 */
2927702e47cSPaolo Bonzini case 0x5c: /* ILR16 */
2937702e47cSPaolo Bonzini case 0x60: /* ILR17 */
2947702e47cSPaolo Bonzini case 0x64: /* ILR18 */
2957702e47cSPaolo Bonzini case 0x68: /* ILR19 */
2967702e47cSPaolo Bonzini case 0x6c: /* ILR20 */
2977702e47cSPaolo Bonzini case 0x70: /* ILR21 */
2987702e47cSPaolo Bonzini case 0x74: /* ILR22 */
2997702e47cSPaolo Bonzini case 0x78: /* ILR23 */
3007702e47cSPaolo Bonzini case 0x7c: /* ILR24 */
3017702e47cSPaolo Bonzini case 0x80: /* ILR25 */
3027702e47cSPaolo Bonzini case 0x84: /* ILR26 */
3037702e47cSPaolo Bonzini case 0x88: /* ILR27 */
3047702e47cSPaolo Bonzini case 0x8c: /* ILR28 */
3057702e47cSPaolo Bonzini case 0x90: /* ILR29 */
3067702e47cSPaolo Bonzini case 0x94: /* ILR30 */
3077702e47cSPaolo Bonzini case 0x98: /* ILR31 */
3087702e47cSPaolo Bonzini i = (offset - 0x1c) >> 2;
3097702e47cSPaolo Bonzini bank->priority[i] = (value >> 2) & 0x1f;
3107702e47cSPaolo Bonzini bank->sens_edge &= ~(1 << i);
3117702e47cSPaolo Bonzini bank->sens_edge |= ((value >> 1) & 1) << i;
3127702e47cSPaolo Bonzini bank->fiq &= ~(1 << i);
3137702e47cSPaolo Bonzini bank->fiq |= (value & 1) << i;
3147702e47cSPaolo Bonzini return;
3157702e47cSPaolo Bonzini
3167702e47cSPaolo Bonzini case 0x9c: /* ISR */
3177702e47cSPaolo Bonzini for (i = 0; i < 32; i ++)
3187702e47cSPaolo Bonzini if (value & (1 << i)) {
3197702e47cSPaolo Bonzini omap_set_intr(s, 32 * bank_no + i, 1);
3207702e47cSPaolo Bonzini return;
3217702e47cSPaolo Bonzini }
3227702e47cSPaolo Bonzini return;
3237702e47cSPaolo Bonzini }
3247702e47cSPaolo Bonzini OMAP_BAD_REG(addr);
3257702e47cSPaolo Bonzini }
3267702e47cSPaolo Bonzini
3277702e47cSPaolo Bonzini static const MemoryRegionOps omap_inth_mem_ops = {
3287702e47cSPaolo Bonzini .read = omap_inth_read,
3297702e47cSPaolo Bonzini .write = omap_inth_write,
3307702e47cSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
3317702e47cSPaolo Bonzini .valid = {
3327702e47cSPaolo Bonzini .min_access_size = 4,
3337702e47cSPaolo Bonzini .max_access_size = 4,
3347702e47cSPaolo Bonzini },
3357702e47cSPaolo Bonzini };
3367702e47cSPaolo Bonzini
omap_inth_reset(DeviceState * dev)3377702e47cSPaolo Bonzini static void omap_inth_reset(DeviceState *dev)
3387702e47cSPaolo Bonzini {
339bded15c9SPhilippe Mathieu-Daudé OMAPIntcState *s = OMAP_INTC(dev);
3407702e47cSPaolo Bonzini int i;
3417702e47cSPaolo Bonzini
3427702e47cSPaolo Bonzini for (i = 0; i < s->nbanks; ++i){
3437702e47cSPaolo Bonzini s->bank[i].irqs = 0x00000000;
3447702e47cSPaolo Bonzini s->bank[i].mask = 0xffffffff;
3457702e47cSPaolo Bonzini s->bank[i].sens_edge = 0x00000000;
3467702e47cSPaolo Bonzini s->bank[i].fiq = 0x00000000;
3477702e47cSPaolo Bonzini s->bank[i].inputs = 0x00000000;
3487702e47cSPaolo Bonzini s->bank[i].swi = 0x00000000;
3497702e47cSPaolo Bonzini memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority));
3507702e47cSPaolo Bonzini
3517702e47cSPaolo Bonzini if (s->level_only)
3527702e47cSPaolo Bonzini s->bank[i].sens_edge = 0xffffffff;
3537702e47cSPaolo Bonzini }
3547702e47cSPaolo Bonzini
3557702e47cSPaolo Bonzini s->new_agr[0] = ~0;
3567702e47cSPaolo Bonzini s->new_agr[1] = ~0;
3577702e47cSPaolo Bonzini s->sir_intr[0] = 0;
3587702e47cSPaolo Bonzini s->sir_intr[1] = 0;
3597702e47cSPaolo Bonzini s->autoidle = 0;
3607702e47cSPaolo Bonzini s->mask = ~0;
3617702e47cSPaolo Bonzini
3627702e47cSPaolo Bonzini qemu_set_irq(s->parent_intr[0], 0);
3637702e47cSPaolo Bonzini qemu_set_irq(s->parent_intr[1], 0);
3647702e47cSPaolo Bonzini }
3657702e47cSPaolo Bonzini
omap_intc_init(Object * obj)3660a750e2aSxiaoqiang zhao static void omap_intc_init(Object *obj)
3677702e47cSPaolo Bonzini {
3680a750e2aSxiaoqiang zhao DeviceState *dev = DEVICE(obj);
369bded15c9SPhilippe Mathieu-Daudé OMAPIntcState *s = OMAP_INTC(obj);
3700a750e2aSxiaoqiang zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
37147edc5a4SAndreas Färber
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);
3760a750e2aSxiaoqiang zhao memory_region_init_io(&s->mmio, obj, &omap_inth_mem_ops, s,
3777702e47cSPaolo Bonzini "omap-intc", s->size);
37847edc5a4SAndreas Färber sysbus_init_mmio(sbd, &s->mmio);
3790a750e2aSxiaoqiang zhao }
3800a750e2aSxiaoqiang zhao
omap_intc_realize(DeviceState * dev,Error ** errp)3810a750e2aSxiaoqiang zhao static void omap_intc_realize(DeviceState *dev, Error **errp)
3820a750e2aSxiaoqiang zhao {
383bded15c9SPhilippe Mathieu-Daudé OMAPIntcState *s = OMAP_INTC(dev);
3840a750e2aSxiaoqiang zhao
3850a750e2aSxiaoqiang zhao if (!s->iclk) {
3860a750e2aSxiaoqiang zhao error_setg(errp, "omap-intc: clk not connected");
3870a750e2aSxiaoqiang zhao }
3887702e47cSPaolo Bonzini }
3897702e47cSPaolo Bonzini
omap_intc_set_iclk(OMAPIntcState * intc,omap_clk clk)390bded15c9SPhilippe Mathieu-Daudé void omap_intc_set_iclk(OMAPIntcState *intc, omap_clk clk)
391bab592a2SMarc-André Lureau {
392bab592a2SMarc-André Lureau intc->iclk = clk;
393bab592a2SMarc-André Lureau }
394bab592a2SMarc-André Lureau
omap_intc_set_fclk(OMAPIntcState * intc,omap_clk clk)395bded15c9SPhilippe Mathieu-Daudé void omap_intc_set_fclk(OMAPIntcState *intc, omap_clk clk)
396bab592a2SMarc-André Lureau {
397bab592a2SMarc-André Lureau intc->fclk = clk;
398bab592a2SMarc-André Lureau }
399bab592a2SMarc-André Lureau
4007702e47cSPaolo Bonzini static Property omap_intc_properties[] = {
401bded15c9SPhilippe Mathieu-Daudé DEFINE_PROP_UINT32("size", OMAPIntcState, size, 0x100),
4027702e47cSPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
4037702e47cSPaolo Bonzini };
4047702e47cSPaolo Bonzini
omap_intc_class_init(ObjectClass * klass,void * data)4057702e47cSPaolo Bonzini static void omap_intc_class_init(ObjectClass *klass, void *data)
4067702e47cSPaolo Bonzini {
4077702e47cSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
4087702e47cSPaolo Bonzini
4097702e47cSPaolo Bonzini dc->reset = omap_inth_reset;
4104f67d30bSMarc-André Lureau device_class_set_props(dc, omap_intc_properties);
4111b111dc1SMarkus Armbruster /* Reason: pointer property "clk" */
412e90f2a8cSEduardo Habkost dc->user_creatable = false;
4130a750e2aSxiaoqiang zhao dc->realize = omap_intc_realize;
4147702e47cSPaolo Bonzini }
4157702e47cSPaolo Bonzini
4167702e47cSPaolo Bonzini static const TypeInfo omap_intc_info = {
4177702e47cSPaolo Bonzini .name = "omap-intc",
41847edc5a4SAndreas Färber .parent = TYPE_OMAP_INTC,
4190a750e2aSxiaoqiang zhao .instance_init = omap_intc_init,
4207702e47cSPaolo Bonzini .class_init = omap_intc_class_init,
4217702e47cSPaolo Bonzini };
4227702e47cSPaolo Bonzini
omap2_inth_read(void * opaque,hwaddr addr,unsigned size)4237702e47cSPaolo Bonzini static uint64_t omap2_inth_read(void *opaque, hwaddr addr,
4247702e47cSPaolo Bonzini unsigned size)
4257702e47cSPaolo Bonzini {
426bded15c9SPhilippe Mathieu-Daudé OMAPIntcState *s = opaque;
4277702e47cSPaolo Bonzini int offset = addr;
4287702e47cSPaolo Bonzini int bank_no, line_no;
4297702e47cSPaolo Bonzini struct omap_intr_handler_bank_s *bank = NULL;
4307702e47cSPaolo Bonzini
4317702e47cSPaolo Bonzini if ((offset & 0xf80) == 0x80) {
4327702e47cSPaolo Bonzini bank_no = (offset & 0x60) >> 5;
4337702e47cSPaolo Bonzini if (bank_no < s->nbanks) {
4347702e47cSPaolo Bonzini offset &= ~0x60;
4357702e47cSPaolo Bonzini bank = &s->bank[bank_no];
4367702e47cSPaolo Bonzini } else {
4377702e47cSPaolo Bonzini OMAP_BAD_REG(addr);
4387702e47cSPaolo Bonzini return 0;
4397702e47cSPaolo Bonzini }
4407702e47cSPaolo Bonzini }
4417702e47cSPaolo Bonzini
4427702e47cSPaolo Bonzini switch (offset) {
4437702e47cSPaolo Bonzini case 0x00: /* INTC_REVISION */
4447702e47cSPaolo Bonzini return s->revision;
4457702e47cSPaolo Bonzini
4467702e47cSPaolo Bonzini case 0x10: /* INTC_SYSCONFIG */
4477702e47cSPaolo Bonzini return (s->autoidle >> 2) & 1;
4487702e47cSPaolo Bonzini
4497702e47cSPaolo Bonzini case 0x14: /* INTC_SYSSTATUS */
4507702e47cSPaolo Bonzini return 1; /* RESETDONE */
4517702e47cSPaolo Bonzini
4527702e47cSPaolo Bonzini case 0x40: /* INTC_SIR_IRQ */
4537702e47cSPaolo Bonzini return s->sir_intr[0];
4547702e47cSPaolo Bonzini
4557702e47cSPaolo Bonzini case 0x44: /* INTC_SIR_FIQ */
4567702e47cSPaolo Bonzini return s->sir_intr[1];
4577702e47cSPaolo Bonzini
4587702e47cSPaolo Bonzini case 0x48: /* INTC_CONTROL */
4597702e47cSPaolo Bonzini return (!s->mask) << 2; /* GLOBALMASK */
4607702e47cSPaolo Bonzini
4617702e47cSPaolo Bonzini case 0x4c: /* INTC_PROTECTION */
4627702e47cSPaolo Bonzini return 0;
4637702e47cSPaolo Bonzini
4647702e47cSPaolo Bonzini case 0x50: /* INTC_IDLE */
4657702e47cSPaolo Bonzini return s->autoidle & 3;
4667702e47cSPaolo Bonzini
4677702e47cSPaolo Bonzini /* Per-bank registers */
4687702e47cSPaolo Bonzini case 0x80: /* INTC_ITR */
4697702e47cSPaolo Bonzini return bank->inputs;
4707702e47cSPaolo Bonzini
4717702e47cSPaolo Bonzini case 0x84: /* INTC_MIR */
4727702e47cSPaolo Bonzini return bank->mask;
4737702e47cSPaolo Bonzini
4747702e47cSPaolo Bonzini case 0x88: /* INTC_MIR_CLEAR */
4757702e47cSPaolo Bonzini case 0x8c: /* INTC_MIR_SET */
4767702e47cSPaolo Bonzini return 0;
4777702e47cSPaolo Bonzini
4787702e47cSPaolo Bonzini case 0x90: /* INTC_ISR_SET */
4797702e47cSPaolo Bonzini return bank->swi;
4807702e47cSPaolo Bonzini
4817702e47cSPaolo Bonzini case 0x94: /* INTC_ISR_CLEAR */
4827702e47cSPaolo Bonzini return 0;
4837702e47cSPaolo Bonzini
4847702e47cSPaolo Bonzini case 0x98: /* INTC_PENDING_IRQ */
4857702e47cSPaolo Bonzini return bank->irqs & ~bank->mask & ~bank->fiq;
4867702e47cSPaolo Bonzini
4877702e47cSPaolo Bonzini case 0x9c: /* INTC_PENDING_FIQ */
4887702e47cSPaolo Bonzini return bank->irqs & ~bank->mask & bank->fiq;
4897702e47cSPaolo Bonzini
4907702e47cSPaolo Bonzini /* Per-line registers */
4917702e47cSPaolo Bonzini case 0x100 ... 0x300: /* INTC_ILR */
4927702e47cSPaolo Bonzini bank_no = (offset - 0x100) >> 7;
4937702e47cSPaolo Bonzini if (bank_no > s->nbanks)
4947702e47cSPaolo Bonzini break;
4957702e47cSPaolo Bonzini bank = &s->bank[bank_no];
4967702e47cSPaolo Bonzini line_no = (offset & 0x7f) >> 2;
4977702e47cSPaolo Bonzini return (bank->priority[line_no] << 2) |
4987702e47cSPaolo Bonzini ((bank->fiq >> line_no) & 1);
4997702e47cSPaolo Bonzini }
5007702e47cSPaolo Bonzini OMAP_BAD_REG(addr);
5017702e47cSPaolo Bonzini return 0;
5027702e47cSPaolo Bonzini }
5037702e47cSPaolo Bonzini
omap2_inth_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)5047702e47cSPaolo Bonzini static void omap2_inth_write(void *opaque, hwaddr addr,
5057702e47cSPaolo Bonzini uint64_t value, unsigned size)
5067702e47cSPaolo Bonzini {
507bded15c9SPhilippe Mathieu-Daudé OMAPIntcState *s = opaque;
5087702e47cSPaolo Bonzini int offset = addr;
5097702e47cSPaolo Bonzini int bank_no, line_no;
5107702e47cSPaolo Bonzini struct omap_intr_handler_bank_s *bank = NULL;
5117702e47cSPaolo Bonzini
5127702e47cSPaolo Bonzini if ((offset & 0xf80) == 0x80) {
5137702e47cSPaolo Bonzini bank_no = (offset & 0x60) >> 5;
5147702e47cSPaolo Bonzini if (bank_no < s->nbanks) {
5157702e47cSPaolo Bonzini offset &= ~0x60;
5167702e47cSPaolo Bonzini bank = &s->bank[bank_no];
5177702e47cSPaolo Bonzini } else {
5187702e47cSPaolo Bonzini OMAP_BAD_REG(addr);
5197702e47cSPaolo Bonzini return;
5207702e47cSPaolo Bonzini }
5217702e47cSPaolo Bonzini }
5227702e47cSPaolo Bonzini
5237702e47cSPaolo Bonzini switch (offset) {
5247702e47cSPaolo Bonzini case 0x10: /* INTC_SYSCONFIG */
5257702e47cSPaolo Bonzini s->autoidle &= 4;
5267702e47cSPaolo Bonzini s->autoidle |= (value & 1) << 2;
52747edc5a4SAndreas Färber if (value & 2) { /* SOFTRESET */
52847edc5a4SAndreas Färber omap_inth_reset(DEVICE(s));
52947edc5a4SAndreas Färber }
5307702e47cSPaolo Bonzini return;
5317702e47cSPaolo Bonzini
5327702e47cSPaolo Bonzini case 0x48: /* INTC_CONTROL */
5337702e47cSPaolo Bonzini s->mask = (value & 4) ? 0 : ~0; /* GLOBALMASK */
5347702e47cSPaolo Bonzini if (value & 2) { /* NEWFIQAGR */
5357702e47cSPaolo Bonzini qemu_set_irq(s->parent_intr[1], 0);
5367702e47cSPaolo Bonzini s->new_agr[1] = ~0;
5377702e47cSPaolo Bonzini omap_inth_update(s, 1);
5387702e47cSPaolo Bonzini }
5397702e47cSPaolo Bonzini if (value & 1) { /* NEWIRQAGR */
5407702e47cSPaolo Bonzini qemu_set_irq(s->parent_intr[0], 0);
5417702e47cSPaolo Bonzini s->new_agr[0] = ~0;
5427702e47cSPaolo Bonzini omap_inth_update(s, 0);
5437702e47cSPaolo Bonzini }
5447702e47cSPaolo Bonzini return;
5457702e47cSPaolo Bonzini
5467702e47cSPaolo Bonzini case 0x4c: /* INTC_PROTECTION */
5477702e47cSPaolo Bonzini /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
5487702e47cSPaolo Bonzini * for every register, see Chapter 3 and 4 for privileged mode. */
5497702e47cSPaolo Bonzini if (value & 1)
5507702e47cSPaolo Bonzini fprintf(stderr, "%s: protection mode enable attempt\n",
551a89f364aSAlistair Francis __func__);
5527702e47cSPaolo Bonzini return;
5537702e47cSPaolo Bonzini
5547702e47cSPaolo Bonzini case 0x50: /* INTC_IDLE */
5557702e47cSPaolo Bonzini s->autoidle &= ~3;
5567702e47cSPaolo Bonzini s->autoidle |= value & 3;
5577702e47cSPaolo Bonzini return;
5587702e47cSPaolo Bonzini
5597702e47cSPaolo Bonzini /* Per-bank registers */
5607702e47cSPaolo Bonzini case 0x84: /* INTC_MIR */
5617702e47cSPaolo Bonzini bank->mask = value;
5627702e47cSPaolo Bonzini omap_inth_update(s, 0);
5637702e47cSPaolo Bonzini omap_inth_update(s, 1);
5647702e47cSPaolo Bonzini return;
5657702e47cSPaolo Bonzini
5667702e47cSPaolo Bonzini case 0x88: /* INTC_MIR_CLEAR */
5677702e47cSPaolo Bonzini bank->mask &= ~value;
5687702e47cSPaolo Bonzini omap_inth_update(s, 0);
5697702e47cSPaolo Bonzini omap_inth_update(s, 1);
5707702e47cSPaolo Bonzini return;
5717702e47cSPaolo Bonzini
5727702e47cSPaolo Bonzini case 0x8c: /* INTC_MIR_SET */
5737702e47cSPaolo Bonzini bank->mask |= value;
5747702e47cSPaolo Bonzini return;
5757702e47cSPaolo Bonzini
5767702e47cSPaolo Bonzini case 0x90: /* INTC_ISR_SET */
5777702e47cSPaolo Bonzini bank->irqs |= bank->swi |= value;
5787702e47cSPaolo Bonzini omap_inth_update(s, 0);
5797702e47cSPaolo Bonzini omap_inth_update(s, 1);
5807702e47cSPaolo Bonzini return;
5817702e47cSPaolo Bonzini
5827702e47cSPaolo Bonzini case 0x94: /* INTC_ISR_CLEAR */
5837702e47cSPaolo Bonzini bank->swi &= ~value;
5847702e47cSPaolo Bonzini bank->irqs = bank->swi & bank->inputs;
5857702e47cSPaolo Bonzini return;
5867702e47cSPaolo Bonzini
5877702e47cSPaolo Bonzini /* Per-line registers */
5887702e47cSPaolo Bonzini case 0x100 ... 0x300: /* INTC_ILR */
5897702e47cSPaolo Bonzini bank_no = (offset - 0x100) >> 7;
5907702e47cSPaolo Bonzini if (bank_no > s->nbanks)
5917702e47cSPaolo Bonzini break;
5927702e47cSPaolo Bonzini bank = &s->bank[bank_no];
5937702e47cSPaolo Bonzini line_no = (offset & 0x7f) >> 2;
5947702e47cSPaolo Bonzini bank->priority[line_no] = (value >> 2) & 0x3f;
5957702e47cSPaolo Bonzini bank->fiq &= ~(1 << line_no);
5967702e47cSPaolo Bonzini bank->fiq |= (value & 1) << line_no;
5977702e47cSPaolo Bonzini return;
5987702e47cSPaolo Bonzini
5997702e47cSPaolo Bonzini case 0x00: /* INTC_REVISION */
6007702e47cSPaolo Bonzini case 0x14: /* INTC_SYSSTATUS */
6017702e47cSPaolo Bonzini case 0x40: /* INTC_SIR_IRQ */
6027702e47cSPaolo Bonzini case 0x44: /* INTC_SIR_FIQ */
6037702e47cSPaolo Bonzini case 0x80: /* INTC_ITR */
6047702e47cSPaolo Bonzini case 0x98: /* INTC_PENDING_IRQ */
6057702e47cSPaolo Bonzini case 0x9c: /* INTC_PENDING_FIQ */
6067702e47cSPaolo Bonzini OMAP_RO_REG(addr);
6077702e47cSPaolo Bonzini return;
6087702e47cSPaolo Bonzini }
6097702e47cSPaolo Bonzini OMAP_BAD_REG(addr);
6107702e47cSPaolo Bonzini }
6117702e47cSPaolo Bonzini
6127702e47cSPaolo Bonzini static const MemoryRegionOps omap2_inth_mem_ops = {
6137702e47cSPaolo Bonzini .read = omap2_inth_read,
6147702e47cSPaolo Bonzini .write = omap2_inth_write,
6157702e47cSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
6167702e47cSPaolo Bonzini .valid = {
6177702e47cSPaolo Bonzini .min_access_size = 4,
6187702e47cSPaolo Bonzini .max_access_size = 4,
6197702e47cSPaolo Bonzini },
6207702e47cSPaolo Bonzini };
6217702e47cSPaolo Bonzini
omap2_intc_init(Object * obj)6220a750e2aSxiaoqiang zhao static void omap2_intc_init(Object *obj)
6237702e47cSPaolo Bonzini {
6240a750e2aSxiaoqiang zhao DeviceState *dev = DEVICE(obj);
625bded15c9SPhilippe Mathieu-Daudé OMAPIntcState *s = OMAP_INTC(obj);
6260a750e2aSxiaoqiang zhao SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
62747edc5a4SAndreas Färber
6287702e47cSPaolo Bonzini s->level_only = 1;
6297702e47cSPaolo Bonzini s->nbanks = 3;
63047edc5a4SAndreas Färber sysbus_init_irq(sbd, &s->parent_intr[0]);
63147edc5a4SAndreas Färber sysbus_init_irq(sbd, &s->parent_intr[1]);
63247edc5a4SAndreas Färber qdev_init_gpio_in(dev, omap_set_intr_noedge, s->nbanks * 32);
6330a750e2aSxiaoqiang zhao memory_region_init_io(&s->mmio, obj, &omap2_inth_mem_ops, s,
6347702e47cSPaolo Bonzini "omap2-intc", 0x1000);
63547edc5a4SAndreas Färber sysbus_init_mmio(sbd, &s->mmio);
6360a750e2aSxiaoqiang zhao }
6370a750e2aSxiaoqiang zhao
omap2_intc_realize(DeviceState * dev,Error ** errp)6380a750e2aSxiaoqiang zhao static void omap2_intc_realize(DeviceState *dev, Error **errp)
6390a750e2aSxiaoqiang zhao {
640bded15c9SPhilippe Mathieu-Daudé OMAPIntcState *s = OMAP_INTC(dev);
6410a750e2aSxiaoqiang zhao
6420a750e2aSxiaoqiang zhao if (!s->iclk) {
6430a750e2aSxiaoqiang zhao error_setg(errp, "omap2-intc: iclk not connected");
6440a750e2aSxiaoqiang zhao return;
6450a750e2aSxiaoqiang zhao }
6460a750e2aSxiaoqiang zhao if (!s->fclk) {
6470a750e2aSxiaoqiang zhao error_setg(errp, "omap2-intc: fclk not connected");
6480a750e2aSxiaoqiang zhao return;
6490a750e2aSxiaoqiang zhao }
6507702e47cSPaolo Bonzini }
6517702e47cSPaolo Bonzini
6527702e47cSPaolo Bonzini static Property omap2_intc_properties[] = {
653bded15c9SPhilippe Mathieu-Daudé DEFINE_PROP_UINT8("revision", OMAPIntcState,
6547702e47cSPaolo Bonzini revision, 0x21),
6557702e47cSPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
6567702e47cSPaolo Bonzini };
6577702e47cSPaolo Bonzini
omap2_intc_class_init(ObjectClass * klass,void * data)6587702e47cSPaolo Bonzini static void omap2_intc_class_init(ObjectClass *klass, void *data)
6597702e47cSPaolo Bonzini {
6607702e47cSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
6617702e47cSPaolo Bonzini
6627702e47cSPaolo Bonzini dc->reset = omap_inth_reset;
6634f67d30bSMarc-André Lureau device_class_set_props(dc, omap2_intc_properties);
6641b111dc1SMarkus Armbruster /* Reason: pointer property "iclk", "fclk" */
665e90f2a8cSEduardo Habkost dc->user_creatable = false;
6660a750e2aSxiaoqiang zhao dc->realize = omap2_intc_realize;
6677702e47cSPaolo Bonzini }
6687702e47cSPaolo Bonzini
6697702e47cSPaolo Bonzini static const TypeInfo omap2_intc_info = {
6707702e47cSPaolo Bonzini .name = "omap2-intc",
67147edc5a4SAndreas Färber .parent = TYPE_OMAP_INTC,
6720a750e2aSxiaoqiang zhao .instance_init = omap2_intc_init,
67347edc5a4SAndreas Färber .class_init = omap2_intc_class_init,
67447edc5a4SAndreas Färber };
67547edc5a4SAndreas Färber
67647edc5a4SAndreas Färber static const TypeInfo omap_intc_type_info = {
67747edc5a4SAndreas Färber .name = TYPE_OMAP_INTC,
6787702e47cSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE,
679bded15c9SPhilippe Mathieu-Daudé .instance_size = sizeof(OMAPIntcState),
68047edc5a4SAndreas Färber .abstract = true,
6817702e47cSPaolo Bonzini };
6827702e47cSPaolo Bonzini
omap_intc_register_types(void)6837702e47cSPaolo Bonzini static void omap_intc_register_types(void)
6847702e47cSPaolo Bonzini {
68547edc5a4SAndreas Färber type_register_static(&omap_intc_type_info);
6867702e47cSPaolo Bonzini type_register_static(&omap_intc_info);
6877702e47cSPaolo Bonzini type_register_static(&omap2_intc_info);
6887702e47cSPaolo Bonzini }
6897702e47cSPaolo Bonzini
6907702e47cSPaolo Bonzini type_init(omap_intc_register_types)
691