balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 1 | /* |
| 2 | * SuperH interrupt controller module |
| 3 | * |
| 4 | * Copyright (c) 2007 Magnus Damm |
| 5 | * Based on sh_timer.c and arm_timer.c by Paul Brook |
| 6 | * Copyright (c) 2005-2006 CodeSourcery. |
| 7 | * |
| 8 | * This code is licenced under the GPL. |
| 9 | */ |
| 10 | |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 11 | #include "sh_intc.h" |
pbrook | 87ecb68 | 2007-11-17 17:14:51 +0000 | [diff] [blame] | 12 | #include "hw.h" |
| 13 | #include "sh.h" |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 14 | |
| 15 | //#define DEBUG_INTC |
ths | e96e204 | 2007-12-02 06:18:24 +0000 | [diff] [blame] | 16 | //#define DEBUG_INTC_SOURCES |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 17 | |
| 18 | #define INTC_A7(x) ((x) & 0x1fffffff) |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 19 | |
ths | e96e204 | 2007-12-02 06:18:24 +0000 | [diff] [blame] | 20 | void sh_intc_toggle_source(struct intc_source *source, |
| 21 | int enable_adj, int assert_adj) |
| 22 | { |
| 23 | int enable_changed = 0; |
| 24 | int pending_changed = 0; |
| 25 | int old_pending; |
| 26 | |
| 27 | if ((source->enable_count == source->enable_max) && (enable_adj == -1)) |
| 28 | enable_changed = -1; |
| 29 | |
| 30 | source->enable_count += enable_adj; |
| 31 | |
| 32 | if (source->enable_count == source->enable_max) |
| 33 | enable_changed = 1; |
| 34 | |
| 35 | source->asserted += assert_adj; |
| 36 | |
| 37 | old_pending = source->pending; |
| 38 | source->pending = source->asserted && |
| 39 | (source->enable_count == source->enable_max); |
| 40 | |
| 41 | if (old_pending != source->pending) |
| 42 | pending_changed = 1; |
| 43 | |
| 44 | if (pending_changed) { |
| 45 | if (source->pending) { |
| 46 | source->parent->pending++; |
| 47 | if (source->parent->pending == 1) |
| 48 | cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); |
| 49 | } |
| 50 | else { |
| 51 | source->parent->pending--; |
| 52 | if (source->parent->pending == 0) |
| 53 | cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD); |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | if (enable_changed || assert_adj || pending_changed) { |
| 58 | #ifdef DEBUG_INTC_SOURCES |
| 59 | printf("sh_intc: (%d/%d/%d/%d) interrupt source 0x%x %s%s%s\n", |
| 60 | source->parent->pending, |
| 61 | source->asserted, |
| 62 | source->enable_count, |
| 63 | source->enable_max, |
| 64 | source->vect, |
| 65 | source->asserted ? "asserted " : |
| 66 | assert_adj ? "deasserted" : "", |
| 67 | enable_changed == 1 ? "enabled " : |
| 68 | enable_changed == -1 ? "disabled " : "", |
| 69 | source->pending ? "pending" : ""); |
| 70 | #endif |
| 71 | } |
| 72 | } |
| 73 | |
aurel32 | b79e175 | 2008-12-07 22:46:42 +0000 | [diff] [blame] | 74 | static void sh_intc_set_irq (void *opaque, int n, int level) |
aurel32 | 96e2fc4 | 2008-11-21 21:06:42 +0000 | [diff] [blame] | 75 | { |
| 76 | struct intc_desc *desc = opaque; |
| 77 | struct intc_source *source = &(desc->sources[n]); |
| 78 | |
aurel32 | 4e7ed2d | 2008-11-21 21:06:51 +0000 | [diff] [blame] | 79 | if (level && !source->asserted) |
| 80 | sh_intc_toggle_source(source, 0, 1); |
| 81 | else if (!level && source->asserted) |
| 82 | sh_intc_toggle_source(source, 0, -1); |
aurel32 | 96e2fc4 | 2008-11-21 21:06:42 +0000 | [diff] [blame] | 83 | } |
| 84 | |
ths | e96e204 | 2007-12-02 06:18:24 +0000 | [diff] [blame] | 85 | int sh_intc_get_pending_vector(struct intc_desc *desc, int imask) |
| 86 | { |
| 87 | unsigned int i; |
| 88 | |
| 89 | /* slow: use a linked lists of pending sources instead */ |
| 90 | /* wrong: take interrupt priority into account (one list per priority) */ |
| 91 | |
| 92 | if (imask == 0x0f) { |
| 93 | return -1; /* FIXME, update code to include priority per source */ |
| 94 | } |
| 95 | |
| 96 | for (i = 0; i < desc->nr_sources; i++) { |
| 97 | struct intc_source *source = desc->sources + i; |
| 98 | |
| 99 | if (source->pending) { |
| 100 | #ifdef DEBUG_INTC_SOURCES |
| 101 | printf("sh_intc: (%d) returning interrupt source 0x%x\n", |
| 102 | desc->pending, source->vect); |
| 103 | #endif |
| 104 | return source->vect; |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | assert(0); |
| 109 | } |
| 110 | |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 111 | #define INTC_MODE_NONE 0 |
| 112 | #define INTC_MODE_DUAL_SET 1 |
| 113 | #define INTC_MODE_DUAL_CLR 2 |
| 114 | #define INTC_MODE_ENABLE_REG 3 |
| 115 | #define INTC_MODE_MASK_REG 4 |
| 116 | #define INTC_MODE_IS_PRIO 8 |
| 117 | |
| 118 | static unsigned int sh_intc_mode(unsigned long address, |
| 119 | unsigned long set_reg, unsigned long clr_reg) |
| 120 | { |
| 121 | if ((address != INTC_A7(set_reg)) && |
| 122 | (address != INTC_A7(clr_reg))) |
| 123 | return INTC_MODE_NONE; |
| 124 | |
| 125 | if (set_reg && clr_reg) { |
| 126 | if (address == INTC_A7(set_reg)) |
| 127 | return INTC_MODE_DUAL_SET; |
| 128 | else |
| 129 | return INTC_MODE_DUAL_CLR; |
| 130 | } |
| 131 | |
| 132 | if (set_reg) |
| 133 | return INTC_MODE_ENABLE_REG; |
| 134 | else |
| 135 | return INTC_MODE_MASK_REG; |
| 136 | } |
| 137 | |
| 138 | static void sh_intc_locate(struct intc_desc *desc, |
| 139 | unsigned long address, |
| 140 | unsigned long **datap, |
| 141 | intc_enum **enums, |
| 142 | unsigned int *first, |
| 143 | unsigned int *width, |
| 144 | unsigned int *modep) |
| 145 | { |
| 146 | unsigned int i, mode; |
| 147 | |
| 148 | /* this is slow but works for now */ |
| 149 | |
| 150 | if (desc->mask_regs) { |
| 151 | for (i = 0; i < desc->nr_mask_regs; i++) { |
| 152 | struct intc_mask_reg *mr = desc->mask_regs + i; |
| 153 | |
| 154 | mode = sh_intc_mode(address, mr->set_reg, mr->clr_reg); |
| 155 | if (mode == INTC_MODE_NONE) |
| 156 | continue; |
| 157 | |
| 158 | *modep = mode; |
| 159 | *datap = &mr->value; |
| 160 | *enums = mr->enum_ids; |
| 161 | *first = mr->reg_width - 1; |
| 162 | *width = 1; |
| 163 | return; |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | if (desc->prio_regs) { |
| 168 | for (i = 0; i < desc->nr_prio_regs; i++) { |
| 169 | struct intc_prio_reg *pr = desc->prio_regs + i; |
| 170 | |
| 171 | mode = sh_intc_mode(address, pr->set_reg, pr->clr_reg); |
| 172 | if (mode == INTC_MODE_NONE) |
| 173 | continue; |
| 174 | |
| 175 | *modep = mode | INTC_MODE_IS_PRIO; |
| 176 | *datap = &pr->value; |
| 177 | *enums = pr->enum_ids; |
| 178 | *first = (pr->reg_width / pr->field_width) - 1; |
| 179 | *width = pr->field_width; |
| 180 | return; |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | assert(0); |
| 185 | } |
| 186 | |
ths | e96e204 | 2007-12-02 06:18:24 +0000 | [diff] [blame] | 187 | static void sh_intc_toggle_mask(struct intc_desc *desc, intc_enum id, |
| 188 | int enable, int is_group) |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 189 | { |
| 190 | struct intc_source *source = desc->sources + id; |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 191 | |
| 192 | if (!id) |
| 193 | return; |
| 194 | |
| 195 | if (!source->next_enum_id && (!source->enable_max || !source->vect)) { |
ths | e96e204 | 2007-12-02 06:18:24 +0000 | [diff] [blame] | 196 | #ifdef DEBUG_INTC_SOURCES |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 197 | printf("sh_intc: reserved interrupt source %d modified\n", id); |
| 198 | #endif |
| 199 | return; |
| 200 | } |
| 201 | |
ths | e96e204 | 2007-12-02 06:18:24 +0000 | [diff] [blame] | 202 | if (source->vect) |
| 203 | sh_intc_toggle_source(source, enable ? 1 : -1, 0); |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 204 | |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 205 | #ifdef DEBUG_INTC |
| 206 | else { |
| 207 | printf("setting interrupt group %d to %d\n", id, !!enable); |
| 208 | } |
| 209 | #endif |
| 210 | |
| 211 | if ((is_group || !source->vect) && source->next_enum_id) { |
ths | e96e204 | 2007-12-02 06:18:24 +0000 | [diff] [blame] | 212 | sh_intc_toggle_mask(desc, source->next_enum_id, enable, 1); |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 213 | } |
| 214 | |
| 215 | #ifdef DEBUG_INTC |
| 216 | if (!source->vect) { |
| 217 | printf("setting interrupt group %d to %d - done\n", id, !!enable); |
| 218 | } |
| 219 | #endif |
| 220 | } |
| 221 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 222 | static uint32_t sh_intc_read(void *opaque, target_phys_addr_t offset) |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 223 | { |
| 224 | struct intc_desc *desc = opaque; |
| 225 | intc_enum *enum_ids = NULL; |
| 226 | unsigned int first = 0; |
| 227 | unsigned int width = 0; |
| 228 | unsigned int mode = 0; |
| 229 | unsigned long *valuep; |
| 230 | |
| 231 | #ifdef DEBUG_INTC |
| 232 | printf("sh_intc_read 0x%lx\n", (unsigned long) offset); |
| 233 | #endif |
| 234 | |
| 235 | sh_intc_locate(desc, (unsigned long)offset, &valuep, |
| 236 | &enum_ids, &first, &width, &mode); |
| 237 | return *valuep; |
| 238 | } |
| 239 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 240 | static void sh_intc_write(void *opaque, target_phys_addr_t offset, |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 241 | uint32_t value) |
| 242 | { |
| 243 | struct intc_desc *desc = opaque; |
| 244 | intc_enum *enum_ids = NULL; |
| 245 | unsigned int first = 0; |
| 246 | unsigned int width = 0; |
| 247 | unsigned int mode = 0; |
| 248 | unsigned int k; |
| 249 | unsigned long *valuep; |
| 250 | unsigned long mask; |
| 251 | |
| 252 | #ifdef DEBUG_INTC |
| 253 | printf("sh_intc_write 0x%lx 0x%08x\n", (unsigned long) offset, value); |
| 254 | #endif |
| 255 | |
| 256 | sh_intc_locate(desc, (unsigned long)offset, &valuep, |
| 257 | &enum_ids, &first, &width, &mode); |
| 258 | |
| 259 | switch (mode) { |
| 260 | case INTC_MODE_ENABLE_REG | INTC_MODE_IS_PRIO: break; |
| 261 | case INTC_MODE_DUAL_SET: value |= *valuep; break; |
| 262 | case INTC_MODE_DUAL_CLR: value = *valuep & ~value; break; |
| 263 | default: assert(0); |
| 264 | } |
| 265 | |
| 266 | for (k = 0; k <= first; k++) { |
| 267 | mask = ((1 << width) - 1) << ((first - k) * width); |
| 268 | |
| 269 | if ((*valuep & mask) == (value & mask)) |
| 270 | continue; |
| 271 | #if 0 |
| 272 | printf("k = %d, first = %d, enum = %d, mask = 0x%08x\n", |
| 273 | k, first, enum_ids[k], (unsigned int)mask); |
| 274 | #endif |
ths | e96e204 | 2007-12-02 06:18:24 +0000 | [diff] [blame] | 275 | sh_intc_toggle_mask(desc, enum_ids[k], value & mask, 0); |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 276 | } |
| 277 | |
| 278 | *valuep = value; |
| 279 | |
| 280 | #ifdef DEBUG_INTC |
| 281 | printf("sh_intc_write 0x%lx -> 0x%08x\n", (unsigned long) offset, value); |
| 282 | #endif |
| 283 | } |
| 284 | |
Blue Swirl | d60efc6 | 2009-08-25 18:29:31 +0000 | [diff] [blame] | 285 | static CPUReadMemoryFunc * const sh_intc_readfn[] = { |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 286 | sh_intc_read, |
| 287 | sh_intc_read, |
| 288 | sh_intc_read |
| 289 | }; |
| 290 | |
Blue Swirl | d60efc6 | 2009-08-25 18:29:31 +0000 | [diff] [blame] | 291 | static CPUWriteMemoryFunc * const sh_intc_writefn[] = { |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 292 | sh_intc_write, |
| 293 | sh_intc_write, |
| 294 | sh_intc_write |
| 295 | }; |
| 296 | |
| 297 | struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id) |
| 298 | { |
| 299 | if (id) |
| 300 | return desc->sources + id; |
| 301 | |
| 302 | return NULL; |
| 303 | } |
| 304 | |
| 305 | static void sh_intc_register(struct intc_desc *desc, |
| 306 | unsigned long address) |
| 307 | { |
balrog | 5c16736 | 2008-12-07 19:39:58 +0000 | [diff] [blame] | 308 | if (address) { |
| 309 | cpu_register_physical_memory_offset(P4ADDR(address), 4, |
pbrook | 8da3ff1 | 2008-12-01 18:59:50 +0000 | [diff] [blame] | 310 | desc->iomemtype, INTC_A7(address)); |
balrog | 5c16736 | 2008-12-07 19:39:58 +0000 | [diff] [blame] | 311 | cpu_register_physical_memory_offset(A7ADDR(address), 4, |
| 312 | desc->iomemtype, INTC_A7(address)); |
| 313 | } |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 314 | } |
| 315 | |
| 316 | static void sh_intc_register_source(struct intc_desc *desc, |
| 317 | intc_enum source, |
| 318 | struct intc_group *groups, |
| 319 | int nr_groups) |
| 320 | { |
| 321 | unsigned int i, k; |
| 322 | struct intc_source *s; |
| 323 | |
| 324 | if (desc->mask_regs) { |
| 325 | for (i = 0; i < desc->nr_mask_regs; i++) { |
| 326 | struct intc_mask_reg *mr = desc->mask_regs + i; |
| 327 | |
malc | b1503cd | 2008-12-22 20:33:55 +0000 | [diff] [blame] | 328 | for (k = 0; k < ARRAY_SIZE(mr->enum_ids); k++) { |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 329 | if (mr->enum_ids[k] != source) |
| 330 | continue; |
| 331 | |
| 332 | s = sh_intc_source(desc, mr->enum_ids[k]); |
| 333 | if (s) |
| 334 | s->enable_max++; |
| 335 | } |
| 336 | } |
| 337 | } |
| 338 | |
| 339 | if (desc->prio_regs) { |
| 340 | for (i = 0; i < desc->nr_prio_regs; i++) { |
| 341 | struct intc_prio_reg *pr = desc->prio_regs + i; |
| 342 | |
malc | b1503cd | 2008-12-22 20:33:55 +0000 | [diff] [blame] | 343 | for (k = 0; k < ARRAY_SIZE(pr->enum_ids); k++) { |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 344 | if (pr->enum_ids[k] != source) |
| 345 | continue; |
| 346 | |
| 347 | s = sh_intc_source(desc, pr->enum_ids[k]); |
| 348 | if (s) |
| 349 | s->enable_max++; |
| 350 | } |
| 351 | } |
| 352 | } |
| 353 | |
| 354 | if (groups) { |
| 355 | for (i = 0; i < nr_groups; i++) { |
| 356 | struct intc_group *gr = groups + i; |
| 357 | |
malc | b1503cd | 2008-12-22 20:33:55 +0000 | [diff] [blame] | 358 | for (k = 0; k < ARRAY_SIZE(gr->enum_ids); k++) { |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 359 | if (gr->enum_ids[k] != source) |
| 360 | continue; |
| 361 | |
| 362 | s = sh_intc_source(desc, gr->enum_ids[k]); |
| 363 | if (s) |
| 364 | s->enable_max++; |
| 365 | } |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | } |
| 370 | |
| 371 | void sh_intc_register_sources(struct intc_desc *desc, |
| 372 | struct intc_vect *vectors, |
| 373 | int nr_vectors, |
| 374 | struct intc_group *groups, |
| 375 | int nr_groups) |
| 376 | { |
| 377 | unsigned int i, k; |
| 378 | struct intc_source *s; |
| 379 | |
| 380 | for (i = 0; i < nr_vectors; i++) { |
| 381 | struct intc_vect *vect = vectors + i; |
| 382 | |
| 383 | sh_intc_register_source(desc, vect->enum_id, groups, nr_groups); |
| 384 | s = sh_intc_source(desc, vect->enum_id); |
| 385 | if (s) |
| 386 | s->vect = vect->vect; |
| 387 | |
ths | e96e204 | 2007-12-02 06:18:24 +0000 | [diff] [blame] | 388 | #ifdef DEBUG_INTC_SOURCES |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 389 | printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n", |
| 390 | vect->enum_id, s->vect, s->enable_count, s->enable_max); |
| 391 | #endif |
| 392 | } |
| 393 | |
| 394 | if (groups) { |
| 395 | for (i = 0; i < nr_groups; i++) { |
| 396 | struct intc_group *gr = groups + i; |
| 397 | |
| 398 | s = sh_intc_source(desc, gr->enum_id); |
| 399 | s->next_enum_id = gr->enum_ids[0]; |
| 400 | |
malc | b1503cd | 2008-12-22 20:33:55 +0000 | [diff] [blame] | 401 | for (k = 1; k < ARRAY_SIZE(gr->enum_ids); k++) { |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 402 | if (!gr->enum_ids[k]) |
| 403 | continue; |
| 404 | |
| 405 | s = sh_intc_source(desc, gr->enum_ids[k - 1]); |
| 406 | s->next_enum_id = gr->enum_ids[k]; |
| 407 | } |
| 408 | |
ths | e96e204 | 2007-12-02 06:18:24 +0000 | [diff] [blame] | 409 | #ifdef DEBUG_INTC_SOURCES |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 410 | printf("sh_intc: registered group %d (%d/%d)\n", |
| 411 | gr->enum_id, s->enable_count, s->enable_max); |
| 412 | #endif |
| 413 | } |
| 414 | } |
| 415 | } |
| 416 | |
| 417 | int sh_intc_init(struct intc_desc *desc, |
| 418 | int nr_sources, |
| 419 | struct intc_mask_reg *mask_regs, |
| 420 | int nr_mask_regs, |
| 421 | struct intc_prio_reg *prio_regs, |
| 422 | int nr_prio_regs) |
| 423 | { |
| 424 | unsigned int i; |
| 425 | |
ths | e96e204 | 2007-12-02 06:18:24 +0000 | [diff] [blame] | 426 | desc->pending = 0; |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 427 | desc->nr_sources = nr_sources; |
| 428 | desc->mask_regs = mask_regs; |
| 429 | desc->nr_mask_regs = nr_mask_regs; |
| 430 | desc->prio_regs = prio_regs; |
| 431 | desc->nr_prio_regs = nr_prio_regs; |
| 432 | |
| 433 | i = sizeof(struct intc_source) * nr_sources; |
aliguori | 487414f | 2009-02-05 22:06:05 +0000 | [diff] [blame] | 434 | desc->sources = qemu_malloc(i); |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 435 | |
| 436 | memset(desc->sources, 0, i); |
ths | e96e204 | 2007-12-02 06:18:24 +0000 | [diff] [blame] | 437 | for (i = 0; i < desc->nr_sources; i++) { |
| 438 | struct intc_source *source = desc->sources + i; |
| 439 | |
| 440 | source->parent = desc; |
| 441 | } |
aurel32 | 96e2fc4 | 2008-11-21 21:06:42 +0000 | [diff] [blame] | 442 | |
| 443 | desc->irqs = qemu_allocate_irqs(sh_intc_set_irq, desc, nr_sources); |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 444 | |
Avi Kivity | 1eed09c | 2009-06-14 11:38:51 +0300 | [diff] [blame] | 445 | desc->iomemtype = cpu_register_io_memory(sh_intc_readfn, |
balrog | 80f515e | 2007-10-04 21:53:55 +0000 | [diff] [blame] | 446 | sh_intc_writefn, desc); |
| 447 | if (desc->mask_regs) { |
| 448 | for (i = 0; i < desc->nr_mask_regs; i++) { |
| 449 | struct intc_mask_reg *mr = desc->mask_regs + i; |
| 450 | |
| 451 | sh_intc_register(desc, mr->set_reg); |
| 452 | sh_intc_register(desc, mr->clr_reg); |
| 453 | } |
| 454 | } |
| 455 | |
| 456 | if (desc->prio_regs) { |
| 457 | for (i = 0; i < desc->nr_prio_regs; i++) { |
| 458 | struct intc_prio_reg *pr = desc->prio_regs + i; |
| 459 | |
| 460 | sh_intc_register(desc, pr->set_reg); |
| 461 | sh_intc_register(desc, pr->clr_reg); |
| 462 | } |
| 463 | } |
| 464 | |
| 465 | return 0; |
| 466 | } |
balrog | c6d86a3 | 2008-12-07 18:49:57 +0000 | [diff] [blame] | 467 | |
| 468 | /* Assert level <n> IRL interrupt. |
| 469 | 0:deassert. 1:lowest priority,... 15:highest priority. */ |
| 470 | void sh_intc_set_irl(void *opaque, int n, int level) |
| 471 | { |
| 472 | struct intc_source *s = opaque; |
| 473 | int i, irl = level ^ 15; |
| 474 | for (i = 0; (s = sh_intc_source(s->parent, s->next_enum_id)); i++) { |
| 475 | if (i == irl) |
| 476 | sh_intc_toggle_source(s, s->enable_count?0:1, s->asserted?0:1); |
| 477 | else |
| 478 | if (s->asserted) |
| 479 | sh_intc_toggle_source(s, 0, -1); |
| 480 | } |
| 481 | } |