17702e47cSPaolo Bonzini /*
27702e47cSPaolo Bonzini * SuperH interrupt controller module
37702e47cSPaolo Bonzini *
47702e47cSPaolo Bonzini * Copyright (c) 2007 Magnus Damm
57702e47cSPaolo Bonzini * Based on sh_timer.c and arm_timer.c by Paul Brook
67702e47cSPaolo Bonzini * Copyright (c) 2005-2006 CodeSourcery.
77702e47cSPaolo Bonzini *
87702e47cSPaolo Bonzini * This code is licensed under the GPL.
97702e47cSPaolo Bonzini */
107702e47cSPaolo Bonzini
1190191d07SPeter Maydell #include "qemu/osdep.h"
12ad52cfc1SBALATON Zoltan #include "qemu/log.h"
134771d756SPaolo Bonzini #include "cpu.h"
147702e47cSPaolo Bonzini #include "hw/sh4/sh_intc.h"
1564552b6bSMarkus Armbruster #include "hw/irq.h"
167702e47cSPaolo Bonzini #include "hw/sh4/sh.h"
17ad52cfc1SBALATON Zoltan #include "trace.h"
187702e47cSPaolo Bonzini
sh_intc_toggle_source(struct intc_source * source,int enable_adj,int assert_adj)197702e47cSPaolo Bonzini void sh_intc_toggle_source(struct intc_source *source,
207702e47cSPaolo Bonzini int enable_adj, int assert_adj)
217702e47cSPaolo Bonzini {
227702e47cSPaolo Bonzini int enable_changed = 0;
237702e47cSPaolo Bonzini int pending_changed = 0;
247702e47cSPaolo Bonzini int old_pending;
257702e47cSPaolo Bonzini
2646ea1f82SBALATON Zoltan if (source->enable_count == source->enable_max && enable_adj == -1) {
277702e47cSPaolo Bonzini enable_changed = -1;
28ac3c9e74SBALATON Zoltan }
297702e47cSPaolo Bonzini source->enable_count += enable_adj;
307702e47cSPaolo Bonzini
31ac3c9e74SBALATON Zoltan if (source->enable_count == source->enable_max) {
327702e47cSPaolo Bonzini enable_changed = 1;
33ac3c9e74SBALATON Zoltan }
347702e47cSPaolo Bonzini source->asserted += assert_adj;
357702e47cSPaolo Bonzini
367702e47cSPaolo Bonzini old_pending = source->pending;
377702e47cSPaolo Bonzini source->pending = source->asserted &&
387702e47cSPaolo Bonzini (source->enable_count == source->enable_max);
397702e47cSPaolo Bonzini
40ac3c9e74SBALATON Zoltan if (old_pending != source->pending) {
417702e47cSPaolo Bonzini pending_changed = 1;
42ac3c9e74SBALATON Zoltan }
437702e47cSPaolo Bonzini if (pending_changed) {
447702e47cSPaolo Bonzini if (source->pending) {
457702e47cSPaolo Bonzini source->parent->pending++;
467702e47cSPaolo Bonzini if (source->parent->pending == 1) {
47182735efSAndreas Färber cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD);
487702e47cSPaolo Bonzini }
497702e47cSPaolo Bonzini } else {
507702e47cSPaolo Bonzini source->parent->pending--;
517702e47cSPaolo Bonzini if (source->parent->pending == 0) {
52182735efSAndreas Färber cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD);
537702e47cSPaolo Bonzini }
547702e47cSPaolo Bonzini }
557702e47cSPaolo Bonzini }
567702e47cSPaolo Bonzini
577702e47cSPaolo Bonzini if (enable_changed || assert_adj || pending_changed) {
58ad52cfc1SBALATON Zoltan trace_sh_intc_sources(source->parent->pending, source->asserted,
59ad52cfc1SBALATON Zoltan source->enable_count, source->enable_max,
60ad52cfc1SBALATON Zoltan source->vect, source->asserted ? "asserted " :
617702e47cSPaolo Bonzini assert_adj ? "deasserted" : "",
627702e47cSPaolo Bonzini enable_changed == 1 ? "enabled " :
637702e47cSPaolo Bonzini enable_changed == -1 ? "disabled " : "",
647702e47cSPaolo Bonzini source->pending ? "pending" : "");
657702e47cSPaolo Bonzini }
667702e47cSPaolo Bonzini }
677702e47cSPaolo Bonzini
sh_intc_set_irq(void * opaque,int n,int level)687702e47cSPaolo Bonzini static void sh_intc_set_irq(void *opaque, int n, int level)
697702e47cSPaolo Bonzini {
707702e47cSPaolo Bonzini struct intc_desc *desc = opaque;
7146ea1f82SBALATON Zoltan struct intc_source *source = &desc->sources[n];
727702e47cSPaolo Bonzini
73ac3c9e74SBALATON Zoltan if (level && !source->asserted) {
747702e47cSPaolo Bonzini sh_intc_toggle_source(source, 0, 1);
75ac3c9e74SBALATON Zoltan } else if (!level && source->asserted) {
767702e47cSPaolo Bonzini sh_intc_toggle_source(source, 0, -1);
777702e47cSPaolo Bonzini }
78ac3c9e74SBALATON Zoltan }
797702e47cSPaolo Bonzini
sh_intc_get_pending_vector(struct intc_desc * desc,int imask)807702e47cSPaolo Bonzini int sh_intc_get_pending_vector(struct intc_desc *desc, int imask)
817702e47cSPaolo Bonzini {
827702e47cSPaolo Bonzini unsigned int i;
837702e47cSPaolo Bonzini
847702e47cSPaolo Bonzini /* slow: use a linked lists of pending sources instead */
857702e47cSPaolo Bonzini /* wrong: take interrupt priority into account (one list per priority) */
867702e47cSPaolo Bonzini
877702e47cSPaolo Bonzini if (imask == 0x0f) {
887702e47cSPaolo Bonzini return -1; /* FIXME, update code to include priority per source */
897702e47cSPaolo Bonzini }
907702e47cSPaolo Bonzini
917702e47cSPaolo Bonzini for (i = 0; i < desc->nr_sources; i++) {
9212201fe3SBALATON Zoltan struct intc_source *source = &desc->sources[i];
937702e47cSPaolo Bonzini
947702e47cSPaolo Bonzini if (source->pending) {
95ad52cfc1SBALATON Zoltan trace_sh_intc_pending(desc->pending, source->vect);
967702e47cSPaolo Bonzini return source->vect;
977702e47cSPaolo Bonzini }
987702e47cSPaolo Bonzini }
9985208f7aSBALATON Zoltan g_assert_not_reached();
1007702e47cSPaolo Bonzini }
1017702e47cSPaolo Bonzini
102dc6f1734SBALATON Zoltan typedef enum {
103dc6f1734SBALATON Zoltan INTC_MODE_NONE,
104dc6f1734SBALATON Zoltan INTC_MODE_DUAL_SET,
105dc6f1734SBALATON Zoltan INTC_MODE_DUAL_CLR,
106dc6f1734SBALATON Zoltan INTC_MODE_ENABLE_REG,
107dc6f1734SBALATON Zoltan INTC_MODE_MASK_REG,
108dc6f1734SBALATON Zoltan } SHIntCMode;
109dc6f1734SBALATON Zoltan #define INTC_MODE_IS_PRIO 0x80
1107702e47cSPaolo Bonzini
sh_intc_mode(unsigned long address,unsigned long set_reg,unsigned long clr_reg)111dc6f1734SBALATON Zoltan static SHIntCMode sh_intc_mode(unsigned long address, unsigned long set_reg,
112dc6f1734SBALATON Zoltan unsigned long clr_reg)
1137702e47cSPaolo Bonzini {
114dc6f1734SBALATON Zoltan if (address != A7ADDR(set_reg) && address != A7ADDR(clr_reg)) {
1157702e47cSPaolo Bonzini return INTC_MODE_NONE;
116dc6f1734SBALATON Zoltan }
1177702e47cSPaolo Bonzini if (set_reg && clr_reg) {
118dc6f1734SBALATON Zoltan return address == A7ADDR(set_reg) ?
119dc6f1734SBALATON Zoltan INTC_MODE_DUAL_SET : INTC_MODE_DUAL_CLR;
1207702e47cSPaolo Bonzini }
121dc6f1734SBALATON Zoltan return set_reg ? INTC_MODE_ENABLE_REG : INTC_MODE_MASK_REG;
122ac3c9e74SBALATON Zoltan }
1237702e47cSPaolo Bonzini
sh_intc_locate(struct intc_desc * desc,unsigned long address,unsigned long ** datap,intc_enum ** enums,unsigned int * first,unsigned int * width,unsigned int * modep)1247702e47cSPaolo Bonzini static void sh_intc_locate(struct intc_desc *desc,
1257702e47cSPaolo Bonzini unsigned long address,
1267702e47cSPaolo Bonzini unsigned long **datap,
1277702e47cSPaolo Bonzini intc_enum **enums,
1287702e47cSPaolo Bonzini unsigned int *first,
1297702e47cSPaolo Bonzini unsigned int *width,
1307702e47cSPaolo Bonzini unsigned int *modep)
1317702e47cSPaolo Bonzini {
132dc6f1734SBALATON Zoltan SHIntCMode mode;
133dc6f1734SBALATON Zoltan unsigned int i;
1347702e47cSPaolo Bonzini
1357702e47cSPaolo Bonzini /* this is slow but works for now */
1367702e47cSPaolo Bonzini
1377702e47cSPaolo Bonzini if (desc->mask_regs) {
1387702e47cSPaolo Bonzini for (i = 0; i < desc->nr_mask_regs; i++) {
13912201fe3SBALATON Zoltan struct intc_mask_reg *mr = &desc->mask_regs[i];
1407702e47cSPaolo Bonzini
1417702e47cSPaolo Bonzini mode = sh_intc_mode(address, mr->set_reg, mr->clr_reg);
142418a221cSBALATON Zoltan if (mode != INTC_MODE_NONE) {
1437702e47cSPaolo Bonzini *modep = mode;
1447702e47cSPaolo Bonzini *datap = &mr->value;
1457702e47cSPaolo Bonzini *enums = mr->enum_ids;
1467702e47cSPaolo Bonzini *first = mr->reg_width - 1;
1477702e47cSPaolo Bonzini *width = 1;
1487702e47cSPaolo Bonzini return;
1497702e47cSPaolo Bonzini }
1507702e47cSPaolo Bonzini }
151418a221cSBALATON Zoltan }
1527702e47cSPaolo Bonzini
1537702e47cSPaolo Bonzini if (desc->prio_regs) {
1547702e47cSPaolo Bonzini for (i = 0; i < desc->nr_prio_regs; i++) {
15512201fe3SBALATON Zoltan struct intc_prio_reg *pr = &desc->prio_regs[i];
1567702e47cSPaolo Bonzini
1577702e47cSPaolo Bonzini mode = sh_intc_mode(address, pr->set_reg, pr->clr_reg);
158418a221cSBALATON Zoltan if (mode != INTC_MODE_NONE) {
1597702e47cSPaolo Bonzini *modep = mode | INTC_MODE_IS_PRIO;
1607702e47cSPaolo Bonzini *datap = &pr->value;
1617702e47cSPaolo Bonzini *enums = pr->enum_ids;
16246ea1f82SBALATON Zoltan *first = pr->reg_width / pr->field_width - 1;
1637702e47cSPaolo Bonzini *width = pr->field_width;
1647702e47cSPaolo Bonzini return;
1657702e47cSPaolo Bonzini }
1667702e47cSPaolo Bonzini }
167418a221cSBALATON Zoltan }
16885208f7aSBALATON Zoltan g_assert_not_reached();
1697702e47cSPaolo Bonzini }
1707702e47cSPaolo Bonzini
sh_intc_toggle_mask(struct intc_desc * desc,intc_enum id,int enable,int is_group)1717702e47cSPaolo Bonzini static void sh_intc_toggle_mask(struct intc_desc *desc, intc_enum id,
1727702e47cSPaolo Bonzini int enable, int is_group)
1737702e47cSPaolo Bonzini {
17412201fe3SBALATON Zoltan struct intc_source *source = &desc->sources[id];
1757702e47cSPaolo Bonzini
176ac3c9e74SBALATON Zoltan if (!id) {
1777702e47cSPaolo Bonzini return;
178ac3c9e74SBALATON Zoltan }
1797702e47cSPaolo Bonzini if (!source->next_enum_id && (!source->enable_max || !source->vect)) {
180ad52cfc1SBALATON Zoltan qemu_log_mask(LOG_UNIMP,
181ad52cfc1SBALATON Zoltan "sh_intc: reserved interrupt source %d modified\n", id);
1827702e47cSPaolo Bonzini return;
1837702e47cSPaolo Bonzini }
1847702e47cSPaolo Bonzini
185ac3c9e74SBALATON Zoltan if (source->vect) {
1867702e47cSPaolo Bonzini sh_intc_toggle_source(source, enable ? 1 : -1, 0);
187ac3c9e74SBALATON Zoltan }
1887702e47cSPaolo Bonzini
1897702e47cSPaolo Bonzini if ((is_group || !source->vect) && source->next_enum_id) {
1907702e47cSPaolo Bonzini sh_intc_toggle_mask(desc, source->next_enum_id, enable, 1);
1917702e47cSPaolo Bonzini }
1927702e47cSPaolo Bonzini
1937702e47cSPaolo Bonzini if (!source->vect) {
194ad52cfc1SBALATON Zoltan trace_sh_intc_set(id, !!enable);
1957702e47cSPaolo Bonzini }
1967702e47cSPaolo Bonzini }
1977702e47cSPaolo Bonzini
sh_intc_read(void * opaque,hwaddr offset,unsigned size)198*32331787SBALATON Zoltan static uint64_t sh_intc_read(void *opaque, hwaddr offset, unsigned size)
1997702e47cSPaolo Bonzini {
2007702e47cSPaolo Bonzini struct intc_desc *desc = opaque;
201*32331787SBALATON Zoltan intc_enum *enum_ids;
202*32331787SBALATON Zoltan unsigned int first;
203*32331787SBALATON Zoltan unsigned int width;
204*32331787SBALATON Zoltan unsigned int mode;
2057702e47cSPaolo Bonzini unsigned long *valuep;
2067702e47cSPaolo Bonzini
2077702e47cSPaolo Bonzini sh_intc_locate(desc, (unsigned long)offset, &valuep,
2087702e47cSPaolo Bonzini &enum_ids, &first, &width, &mode);
209ad52cfc1SBALATON Zoltan trace_sh_intc_read(size, (uint64_t)offset, *valuep);
2107702e47cSPaolo Bonzini return *valuep;
2117702e47cSPaolo Bonzini }
2127702e47cSPaolo Bonzini
sh_intc_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)2137702e47cSPaolo Bonzini static void sh_intc_write(void *opaque, hwaddr offset,
2147702e47cSPaolo Bonzini uint64_t value, unsigned size)
2157702e47cSPaolo Bonzini {
2167702e47cSPaolo Bonzini struct intc_desc *desc = opaque;
217*32331787SBALATON Zoltan intc_enum *enum_ids;
218*32331787SBALATON Zoltan unsigned int first;
219*32331787SBALATON Zoltan unsigned int width;
220*32331787SBALATON Zoltan unsigned int mode;
2217702e47cSPaolo Bonzini unsigned long *valuep;
222*32331787SBALATON Zoltan unsigned int k;
2237702e47cSPaolo Bonzini unsigned long mask;
2247702e47cSPaolo Bonzini
225ad52cfc1SBALATON Zoltan trace_sh_intc_write(size, (uint64_t)offset, value);
2267702e47cSPaolo Bonzini sh_intc_locate(desc, (unsigned long)offset, &valuep,
2277702e47cSPaolo Bonzini &enum_ids, &first, &width, &mode);
2287702e47cSPaolo Bonzini switch (mode) {
229f94bff13SBALATON Zoltan case INTC_MODE_ENABLE_REG | INTC_MODE_IS_PRIO:
230f94bff13SBALATON Zoltan break;
231f94bff13SBALATON Zoltan case INTC_MODE_DUAL_SET:
232f94bff13SBALATON Zoltan value |= *valuep;
233f94bff13SBALATON Zoltan break;
234f94bff13SBALATON Zoltan case INTC_MODE_DUAL_CLR:
235f94bff13SBALATON Zoltan value = *valuep & ~value;
236f94bff13SBALATON Zoltan break;
237f94bff13SBALATON Zoltan default:
23885208f7aSBALATON Zoltan g_assert_not_reached();
2397702e47cSPaolo Bonzini }
2407702e47cSPaolo Bonzini
2417702e47cSPaolo Bonzini for (k = 0; k <= first; k++) {
24246ea1f82SBALATON Zoltan mask = (1 << width) - 1;
24346ea1f82SBALATON Zoltan mask <<= (first - k) * width;
2447702e47cSPaolo Bonzini
245418a221cSBALATON Zoltan if ((*valuep & mask) != (value & mask)) {
2467702e47cSPaolo Bonzini sh_intc_toggle_mask(desc, enum_ids[k], value & mask, 0);
2477702e47cSPaolo Bonzini }
248418a221cSBALATON Zoltan }
2497702e47cSPaolo Bonzini
2507702e47cSPaolo Bonzini *valuep = value;
2517702e47cSPaolo Bonzini }
2527702e47cSPaolo Bonzini
2537702e47cSPaolo Bonzini static const MemoryRegionOps sh_intc_ops = {
2547702e47cSPaolo Bonzini .read = sh_intc_read,
2557702e47cSPaolo Bonzini .write = sh_intc_write,
2567702e47cSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
2577702e47cSPaolo Bonzini };
2587702e47cSPaolo Bonzini
sh_intc_register_source(struct intc_desc * desc,intc_enum source,struct intc_group * groups,int nr_groups)2597702e47cSPaolo Bonzini static void sh_intc_register_source(struct intc_desc *desc,
2607702e47cSPaolo Bonzini intc_enum source,
2617702e47cSPaolo Bonzini struct intc_group *groups,
2627702e47cSPaolo Bonzini int nr_groups)
2637702e47cSPaolo Bonzini {
2647702e47cSPaolo Bonzini unsigned int i, k;
2659b12fb10SBALATON Zoltan intc_enum id;
2667702e47cSPaolo Bonzini
2677702e47cSPaolo Bonzini if (desc->mask_regs) {
2687702e47cSPaolo Bonzini for (i = 0; i < desc->nr_mask_regs; i++) {
26912201fe3SBALATON Zoltan struct intc_mask_reg *mr = &desc->mask_regs[i];
2707702e47cSPaolo Bonzini
2717702e47cSPaolo Bonzini for (k = 0; k < ARRAY_SIZE(mr->enum_ids); k++) {
2729b12fb10SBALATON Zoltan id = mr->enum_ids[k];
2739b12fb10SBALATON Zoltan if (id && id == source) {
2749b12fb10SBALATON Zoltan desc->sources[id].enable_max++;
2757702e47cSPaolo Bonzini }
2767702e47cSPaolo Bonzini }
2777702e47cSPaolo Bonzini }
278ac3c9e74SBALATON Zoltan }
2797702e47cSPaolo Bonzini
2807702e47cSPaolo Bonzini if (desc->prio_regs) {
2817702e47cSPaolo Bonzini for (i = 0; i < desc->nr_prio_regs; i++) {
28212201fe3SBALATON Zoltan struct intc_prio_reg *pr = &desc->prio_regs[i];
2837702e47cSPaolo Bonzini
2847702e47cSPaolo Bonzini for (k = 0; k < ARRAY_SIZE(pr->enum_ids); k++) {
2859b12fb10SBALATON Zoltan id = pr->enum_ids[k];
2869b12fb10SBALATON Zoltan if (id && id == source) {
2879b12fb10SBALATON Zoltan desc->sources[id].enable_max++;
2887702e47cSPaolo Bonzini }
2897702e47cSPaolo Bonzini }
2907702e47cSPaolo Bonzini }
291ac3c9e74SBALATON Zoltan }
2927702e47cSPaolo Bonzini
2937702e47cSPaolo Bonzini if (groups) {
2947702e47cSPaolo Bonzini for (i = 0; i < nr_groups; i++) {
29512201fe3SBALATON Zoltan struct intc_group *gr = &groups[i];
2967702e47cSPaolo Bonzini
2977702e47cSPaolo Bonzini for (k = 0; k < ARRAY_SIZE(gr->enum_ids); k++) {
2989b12fb10SBALATON Zoltan id = gr->enum_ids[k];
2999b12fb10SBALATON Zoltan if (id && id == source) {
3009b12fb10SBALATON Zoltan desc->sources[id].enable_max++;
3017702e47cSPaolo Bonzini }
3027702e47cSPaolo Bonzini }
3037702e47cSPaolo Bonzini }
304ac3c9e74SBALATON Zoltan }
3057702e47cSPaolo Bonzini
3067702e47cSPaolo Bonzini }
3077702e47cSPaolo Bonzini
sh_intc_register_sources(struct intc_desc * desc,struct intc_vect * vectors,int nr_vectors,struct intc_group * groups,int nr_groups)3087702e47cSPaolo Bonzini void sh_intc_register_sources(struct intc_desc *desc,
3097702e47cSPaolo Bonzini struct intc_vect *vectors,
3107702e47cSPaolo Bonzini int nr_vectors,
3117702e47cSPaolo Bonzini struct intc_group *groups,
3127702e47cSPaolo Bonzini int nr_groups)
3137702e47cSPaolo Bonzini {
3147702e47cSPaolo Bonzini unsigned int i, k;
3159b12fb10SBALATON Zoltan intc_enum id;
3167702e47cSPaolo Bonzini struct intc_source *s;
3177702e47cSPaolo Bonzini
3187702e47cSPaolo Bonzini for (i = 0; i < nr_vectors; i++) {
31912201fe3SBALATON Zoltan struct intc_vect *vect = &vectors[i];
3207702e47cSPaolo Bonzini
3217702e47cSPaolo Bonzini sh_intc_register_source(desc, vect->enum_id, groups, nr_groups);
3229b12fb10SBALATON Zoltan id = vect->enum_id;
3239b12fb10SBALATON Zoltan if (id) {
3249b12fb10SBALATON Zoltan s = &desc->sources[id];
3257702e47cSPaolo Bonzini s->vect = vect->vect;
326ad52cfc1SBALATON Zoltan trace_sh_intc_register("source", vect->enum_id, s->vect,
327ad52cfc1SBALATON Zoltan s->enable_count, s->enable_max);
3287702e47cSPaolo Bonzini }
3297702e47cSPaolo Bonzini }
3307702e47cSPaolo Bonzini
3317702e47cSPaolo Bonzini if (groups) {
3327702e47cSPaolo Bonzini for (i = 0; i < nr_groups; i++) {
33312201fe3SBALATON Zoltan struct intc_group *gr = &groups[i];
3347702e47cSPaolo Bonzini
3359b12fb10SBALATON Zoltan id = gr->enum_id;
3369b12fb10SBALATON Zoltan s = &desc->sources[id];
3377702e47cSPaolo Bonzini s->next_enum_id = gr->enum_ids[0];
3387702e47cSPaolo Bonzini
3397702e47cSPaolo Bonzini for (k = 1; k < ARRAY_SIZE(gr->enum_ids); k++) {
340418a221cSBALATON Zoltan if (gr->enum_ids[k]) {
3419b12fb10SBALATON Zoltan id = gr->enum_ids[k - 1];
3429b12fb10SBALATON Zoltan s = &desc->sources[id];
3437702e47cSPaolo Bonzini s->next_enum_id = gr->enum_ids[k];
3447702e47cSPaolo Bonzini }
345418a221cSBALATON Zoltan }
346ad52cfc1SBALATON Zoltan trace_sh_intc_register("group", gr->enum_id, 0xffff,
347ad52cfc1SBALATON Zoltan s->enable_count, s->enable_max);
3487702e47cSPaolo Bonzini }
3497702e47cSPaolo Bonzini }
3507702e47cSPaolo Bonzini }
3517702e47cSPaolo Bonzini
sh_intc_register(MemoryRegion * sysmem,struct intc_desc * desc,const unsigned long address,const char * type,const char * action,const unsigned int index)35251cb902bSBALATON Zoltan static unsigned int sh_intc_register(MemoryRegion *sysmem,
35351cb902bSBALATON Zoltan struct intc_desc *desc,
35451cb902bSBALATON Zoltan const unsigned long address,
35551cb902bSBALATON Zoltan const char *type,
35651cb902bSBALATON Zoltan const char *action,
35751cb902bSBALATON Zoltan const unsigned int index)
35851cb902bSBALATON Zoltan {
35951cb902bSBALATON Zoltan char name[60];
36051cb902bSBALATON Zoltan MemoryRegion *iomem, *iomem_p4, *iomem_a7;
36151cb902bSBALATON Zoltan
36251cb902bSBALATON Zoltan if (!address) {
36351cb902bSBALATON Zoltan return 0;
36451cb902bSBALATON Zoltan }
36551cb902bSBALATON Zoltan
36651cb902bSBALATON Zoltan iomem = &desc->iomem;
36712201fe3SBALATON Zoltan iomem_p4 = &desc->iomem_aliases[index];
36851cb902bSBALATON Zoltan iomem_a7 = iomem_p4 + 1;
36951cb902bSBALATON Zoltan
37051cb902bSBALATON Zoltan snprintf(name, sizeof(name), "intc-%s-%s-%s", type, action, "p4");
37151cb902bSBALATON Zoltan memory_region_init_alias(iomem_p4, NULL, name, iomem, A7ADDR(address), 4);
37251cb902bSBALATON Zoltan memory_region_add_subregion(sysmem, P4ADDR(address), iomem_p4);
37351cb902bSBALATON Zoltan
37451cb902bSBALATON Zoltan snprintf(name, sizeof(name), "intc-%s-%s-%s", type, action, "a7");
37551cb902bSBALATON Zoltan memory_region_init_alias(iomem_a7, NULL, name, iomem, A7ADDR(address), 4);
37651cb902bSBALATON Zoltan memory_region_add_subregion(sysmem, A7ADDR(address), iomem_a7);
37751cb902bSBALATON Zoltan
37851cb902bSBALATON Zoltan /* used to increment aliases index */
37951cb902bSBALATON Zoltan return 2;
38051cb902bSBALATON Zoltan }
38151cb902bSBALATON Zoltan
sh_intc_init(MemoryRegion * sysmem,struct intc_desc * desc,int nr_sources,struct intc_mask_reg * mask_regs,int nr_mask_regs,struct intc_prio_reg * prio_regs,int nr_prio_regs)3827702e47cSPaolo Bonzini int sh_intc_init(MemoryRegion *sysmem,
3837702e47cSPaolo Bonzini struct intc_desc *desc,
3847702e47cSPaolo Bonzini int nr_sources,
3857702e47cSPaolo Bonzini struct intc_mask_reg *mask_regs,
3867702e47cSPaolo Bonzini int nr_mask_regs,
3877702e47cSPaolo Bonzini struct intc_prio_reg *prio_regs,
3887702e47cSPaolo Bonzini int nr_prio_regs)
3897702e47cSPaolo Bonzini {
3907702e47cSPaolo Bonzini unsigned int i, j;
3917702e47cSPaolo Bonzini
3927702e47cSPaolo Bonzini desc->pending = 0;
3937702e47cSPaolo Bonzini desc->nr_sources = nr_sources;
3947702e47cSPaolo Bonzini desc->mask_regs = mask_regs;
3957702e47cSPaolo Bonzini desc->nr_mask_regs = nr_mask_regs;
3967702e47cSPaolo Bonzini desc->prio_regs = prio_regs;
3977702e47cSPaolo Bonzini desc->nr_prio_regs = nr_prio_regs;
39822138965SBALATON Zoltan /* Allocate 4 MemoryRegions per register (2 actions * 2 aliases) */
3997702e47cSPaolo Bonzini desc->iomem_aliases = g_new0(MemoryRegion,
4007702e47cSPaolo Bonzini (nr_mask_regs + nr_prio_regs) * 4);
40136cf5ee8SBALATON Zoltan desc->sources = g_new0(struct intc_source, nr_sources);
40236cf5ee8SBALATON Zoltan for (i = 0; i < nr_sources; i++) {
40336cf5ee8SBALATON Zoltan desc->sources[i].parent = desc;
4047702e47cSPaolo Bonzini }
4057702e47cSPaolo Bonzini desc->irqs = qemu_allocate_irqs(sh_intc_set_irq, desc, nr_sources);
40681d18cd4SBALATON Zoltan memory_region_init_io(&desc->iomem, NULL, &sh_intc_ops, desc, "intc",
40781d18cd4SBALATON Zoltan 0x100000000ULL);
40836cf5ee8SBALATON Zoltan j = 0;
4097702e47cSPaolo Bonzini if (desc->mask_regs) {
4107702e47cSPaolo Bonzini for (i = 0; i < desc->nr_mask_regs; i++) {
41112201fe3SBALATON Zoltan struct intc_mask_reg *mr = &desc->mask_regs[i];
4127702e47cSPaolo Bonzini
41392d1d3adSBALATON Zoltan j += sh_intc_register(sysmem, desc, mr->set_reg, "mask", "set", j);
41492d1d3adSBALATON Zoltan j += sh_intc_register(sysmem, desc, mr->clr_reg, "mask", "clr", j);
4157702e47cSPaolo Bonzini }
4167702e47cSPaolo Bonzini }
4177702e47cSPaolo Bonzini
4187702e47cSPaolo Bonzini if (desc->prio_regs) {
4197702e47cSPaolo Bonzini for (i = 0; i < desc->nr_prio_regs; i++) {
42012201fe3SBALATON Zoltan struct intc_prio_reg *pr = &desc->prio_regs[i];
4217702e47cSPaolo Bonzini
42292d1d3adSBALATON Zoltan j += sh_intc_register(sysmem, desc, pr->set_reg, "prio", "set", j);
42392d1d3adSBALATON Zoltan j += sh_intc_register(sysmem, desc, pr->clr_reg, "prio", "clr", j);
4247702e47cSPaolo Bonzini }
4257702e47cSPaolo Bonzini }
4267702e47cSPaolo Bonzini
4277702e47cSPaolo Bonzini return 0;
4287702e47cSPaolo Bonzini }
4297702e47cSPaolo Bonzini
43022138965SBALATON Zoltan /*
43122138965SBALATON Zoltan * Assert level <n> IRL interrupt.
43222138965SBALATON Zoltan * 0:deassert. 1:lowest priority,... 15:highest priority
43322138965SBALATON Zoltan */
sh_intc_set_irl(void * opaque,int n,int level)4347702e47cSPaolo Bonzini void sh_intc_set_irl(void *opaque, int n, int level)
4357702e47cSPaolo Bonzini {
4367702e47cSPaolo Bonzini struct intc_source *s = opaque;
4377702e47cSPaolo Bonzini int i, irl = level ^ 15;
4389b12fb10SBALATON Zoltan intc_enum id = s->next_enum_id;
4399b12fb10SBALATON Zoltan
4409b12fb10SBALATON Zoltan for (i = 0; id; id = s->next_enum_id, i++) {
4419b12fb10SBALATON Zoltan s = &s->parent->sources[id];
442ac3c9e74SBALATON Zoltan if (i == irl) {
443f94bff13SBALATON Zoltan sh_intc_toggle_source(s, s->enable_count ? 0 : 1,
444f94bff13SBALATON Zoltan s->asserted ? 0 : 1);
445ac3c9e74SBALATON Zoltan } else if (s->asserted) {
4467702e47cSPaolo Bonzini sh_intc_toggle_source(s, 0, -1);
4477702e47cSPaolo Bonzini }
4487702e47cSPaolo Bonzini }
449ac3c9e74SBALATON Zoltan }
450