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