Commit 80f515e63688f43b7800027c233ec7139cf3375b
1 parent
30d6eaca
sh775x interrupt controller by Magnus Damm.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3327 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
631 additions
and
91 deletions
Makefile.target
@@ -484,7 +484,7 @@ CPPFLAGS += -DHAS_AUDIO | @@ -484,7 +484,7 @@ CPPFLAGS += -DHAS_AUDIO | ||
484 | endif | 484 | endif |
485 | ifeq ($(TARGET_BASE_ARCH), sh4) | 485 | ifeq ($(TARGET_BASE_ARCH), sh4) |
486 | VL_OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o | 486 | VL_OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o |
487 | -VL_OBJS+= sh_timer.o ptimer.o sh_serial.o | 487 | +VL_OBJS+= sh_timer.o ptimer.o sh_serial.o sh_intc.o |
488 | endif | 488 | endif |
489 | ifeq ($(TARGET_BASE_ARCH), m68k) | 489 | ifeq ($(TARGET_BASE_ARCH), m68k) |
490 | VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o | 490 | VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o |
hw/sh7750.c
1 | /* | 1 | /* |
2 | * SH7750 device | 2 | * SH7750 device |
3 | * | 3 | * |
4 | + * Copyright (c) 2007 Magnus Damm | ||
4 | * Copyright (c) 2005 Samuel Tardieu | 5 | * Copyright (c) 2005 Samuel Tardieu |
5 | * | 6 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
@@ -26,6 +27,7 @@ | @@ -26,6 +27,7 @@ | ||
26 | #include "vl.h" | 27 | #include "vl.h" |
27 | #include "sh7750_regs.h" | 28 | #include "sh7750_regs.h" |
28 | #include "sh7750_regnames.h" | 29 | #include "sh7750_regnames.h" |
30 | +#include "sh_intc.h" | ||
29 | 31 | ||
30 | #define NB_DEVICES 4 | 32 | #define NB_DEVICES 4 |
31 | 33 | ||
@@ -53,15 +55,10 @@ typedef struct SH7750State { | @@ -53,15 +55,10 @@ typedef struct SH7750State { | ||
53 | sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ | 55 | sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ |
54 | 56 | ||
55 | uint16_t icr; | 57 | uint16_t icr; |
56 | - uint16_t ipra; | ||
57 | - uint16_t iprb; | ||
58 | - uint16_t iprc; | ||
59 | - uint16_t iprd; | ||
60 | - uint32_t intpri00; | ||
61 | - uint32_t intmsk00; | ||
62 | /* Cache */ | 58 | /* Cache */ |
63 | uint32_t ccr; | 59 | uint32_t ccr; |
64 | 60 | ||
61 | + struct intc_desc intc; | ||
65 | } SH7750State; | 62 | } SH7750State; |
66 | 63 | ||
67 | 64 | ||
@@ -219,14 +216,6 @@ static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr) | @@ -219,14 +216,6 @@ static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr) | ||
219 | return portb_lines(s); | 216 | return portb_lines(s); |
220 | case 0x1fd00000: | 217 | case 0x1fd00000: |
221 | return s->icr; | 218 | return s->icr; |
222 | - case 0x1fd00004: | ||
223 | - return s->ipra; | ||
224 | - case 0x1fd00008: | ||
225 | - return s->iprb; | ||
226 | - case 0x1fd0000c: | ||
227 | - return s->iprc; | ||
228 | - case 0x1fd00010: | ||
229 | - return s->iprd; | ||
230 | default: | 219 | default: |
231 | error_access("word read", addr); | 220 | error_access("word read", addr); |
232 | assert(0); | 221 | assert(0); |
@@ -262,14 +251,6 @@ static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr) | @@ -262,14 +251,6 @@ static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr) | ||
262 | return 0x00110000; /* Minimum caches */ | 251 | return 0x00110000; /* Minimum caches */ |
263 | case 0x1f000044: /* Processor version PRR */ | 252 | case 0x1f000044: /* Processor version PRR */ |
264 | return 0x00000100; /* SH7750R */ | 253 | return 0x00000100; /* SH7750R */ |
265 | - case 0x1e080000: | ||
266 | - return s->intpri00; | ||
267 | - case 0x1e080020: | ||
268 | - return 0; | ||
269 | - case 0x1e080040: | ||
270 | - return s->intmsk00; | ||
271 | - case 0x1e080060: | ||
272 | - return 0; | ||
273 | default: | 254 | default: |
274 | error_access("long read", addr); | 255 | error_access("long read", addr); |
275 | assert(0); | 256 | assert(0); |
@@ -331,18 +312,6 @@ static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr, | @@ -331,18 +312,6 @@ static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr, | ||
331 | case 0x1fd00000: | 312 | case 0x1fd00000: |
332 | s->icr = mem_value; | 313 | s->icr = mem_value; |
333 | return; | 314 | return; |
334 | - case 0x1fd00004: | ||
335 | - s->ipra = mem_value; | ||
336 | - return; | ||
337 | - case 0x1fd00008: | ||
338 | - s->iprb = mem_value; | ||
339 | - return; | ||
340 | - case 0x1fd0000c: | ||
341 | - s->iprc = mem_value; | ||
342 | - return; | ||
343 | - case 0x1fd00010: | ||
344 | - s->iprd = mem_value; | ||
345 | - return; | ||
346 | default: | 315 | default: |
347 | error_access("word write", addr); | 316 | error_access("word write", addr); |
348 | assert(0); | 317 | assert(0); |
@@ -407,16 +376,6 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, | @@ -407,16 +376,6 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, | ||
407 | case SH7750_CCR_A7: | 376 | case SH7750_CCR_A7: |
408 | s->ccr = mem_value; | 377 | s->ccr = mem_value; |
409 | return; | 378 | return; |
410 | - case 0x1e080000: | ||
411 | - s->intpri00 = mem_value; | ||
412 | - return; | ||
413 | - case 0x1e080020: | ||
414 | - return; | ||
415 | - case 0x1e080040: | ||
416 | - s->intmsk00 = mem_value; | ||
417 | - return; | ||
418 | - case 0x1e080060: | ||
419 | - return; | ||
420 | default: | 379 | default: |
421 | error_access("long write", addr); | 380 | error_access("long write", addr); |
422 | assert(0); | 381 | assert(0); |
@@ -435,10 +394,144 @@ static CPUWriteMemoryFunc *sh7750_mem_write[] = { | @@ -435,10 +394,144 @@ static CPUWriteMemoryFunc *sh7750_mem_write[] = { | ||
435 | sh7750_mem_writel | 394 | sh7750_mem_writel |
436 | }; | 395 | }; |
437 | 396 | ||
397 | +/* sh775x interrupt controller tables for sh_intc.c | ||
398 | + * stolen from linux/arch/sh/kernel/cpu/sh4/setup-sh7750.c | ||
399 | + */ | ||
400 | + | ||
401 | +enum { | ||
402 | + UNUSED = 0, | ||
403 | + | ||
404 | + /* interrupt sources */ | ||
405 | + IRL0, IRL1, IRL2, IRL3, /* only IRLM mode supported */ | ||
406 | + HUDI, GPIOI, | ||
407 | + DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3, | ||
408 | + DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7, | ||
409 | + DMAC_DMAE, | ||
410 | + PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, | ||
411 | + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3, | ||
412 | + TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI, | ||
413 | + RTC_ATI, RTC_PRI, RTC_CUI, | ||
414 | + SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI, | ||
415 | + SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI, | ||
416 | + WDT, | ||
417 | + REF_RCMI, REF_ROVI, | ||
418 | + | ||
419 | + /* interrupt groups */ | ||
420 | + DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF, | ||
421 | + | ||
422 | + NR_SOURCES, | ||
423 | +}; | ||
424 | + | ||
425 | +static struct intc_vect vectors[] = { | ||
426 | + INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620), | ||
427 | + INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), | ||
428 | + INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460), | ||
429 | + INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0), | ||
430 | + INTC_VECT(RTC_CUI, 0x4c0), | ||
431 | + INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500), | ||
432 | + INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540), | ||
433 | + INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720), | ||
434 | + INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760), | ||
435 | + INTC_VECT(WDT, 0x560), | ||
436 | + INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0), | ||
437 | +}; | ||
438 | + | ||
439 | +static struct intc_group groups[] = { | ||
440 | + INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI), | ||
441 | + INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), | ||
442 | + INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI), | ||
443 | + INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI), | ||
444 | + INTC_GROUP(REF, REF_RCMI, REF_ROVI), | ||
445 | +}; | ||
446 | + | ||
447 | +static struct intc_prio_reg prio_registers[] = { | ||
448 | + { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, | ||
449 | + { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } }, | ||
450 | + { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } }, | ||
451 | + { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } }, | ||
452 | + { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0, | ||
453 | + TMU4, TMU3, | ||
454 | + PCIC1, PCIC0_PCISERR } }, | ||
455 | +}; | ||
456 | + | ||
457 | +/* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */ | ||
458 | + | ||
459 | +static struct intc_vect vectors_dma4[] = { | ||
460 | + INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), | ||
461 | + INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), | ||
462 | + INTC_VECT(DMAC_DMAE, 0x6c0), | ||
463 | +}; | ||
464 | + | ||
465 | +static struct intc_group groups_dma4[] = { | ||
466 | + INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, | ||
467 | + DMAC_DMTE3, DMAC_DMAE), | ||
468 | +}; | ||
469 | + | ||
470 | +/* SH7750R and SH7751R both have 8-channel DMA controllers */ | ||
471 | + | ||
472 | +static struct intc_vect vectors_dma8[] = { | ||
473 | + INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660), | ||
474 | + INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0), | ||
475 | + INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0), | ||
476 | + INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0), | ||
477 | + INTC_VECT(DMAC_DMAE, 0x6c0), | ||
478 | +}; | ||
479 | + | ||
480 | +static struct intc_group groups_dma8[] = { | ||
481 | + INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, | ||
482 | + DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5, | ||
483 | + DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE), | ||
484 | +}; | ||
485 | + | ||
486 | +/* SH7750R, SH7751 and SH7751R all have two extra timer channels */ | ||
487 | + | ||
488 | +static struct intc_vect vectors_tmu34[] = { | ||
489 | + INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80), | ||
490 | +}; | ||
491 | + | ||
492 | +static struct intc_mask_reg mask_registers[] = { | ||
493 | + { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */ | ||
494 | + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
495 | + 0, 0, 0, 0, 0, 0, TMU4, TMU3, | ||
496 | + PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, | ||
497 | + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, | ||
498 | + PCIC1_PCIDMA3, PCIC0_PCISERR } }, | ||
499 | +}; | ||
500 | + | ||
501 | +/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */ | ||
502 | + | ||
503 | +static struct intc_vect vectors_irlm[] = { | ||
504 | + INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0), | ||
505 | + INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360), | ||
506 | +}; | ||
507 | + | ||
508 | +/* SH7751 and SH7751R both have PCI */ | ||
509 | + | ||
510 | +static struct intc_vect vectors_pci[] = { | ||
511 | + INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0), | ||
512 | + INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0), | ||
513 | + INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60), | ||
514 | + INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20), | ||
515 | +}; | ||
516 | + | ||
517 | +static struct intc_group groups_pci[] = { | ||
518 | + INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON, | ||
519 | + PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3), | ||
520 | +}; | ||
521 | + | ||
522 | +#define SH_CPU_SH7750 (1 << 0) | ||
523 | +#define SH_CPU_SH7750S (1 << 1) | ||
524 | +#define SH_CPU_SH7750R (1 << 2) | ||
525 | +#define SH_CPU_SH7751 (1 << 3) | ||
526 | +#define SH_CPU_SH7751R (1 << 4) | ||
527 | +#define SH_CPU_SH7750_ALL (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7750R) | ||
528 | +#define SH_CPU_SH7751_ALL (SH_CPU_SH7751 | SH_CPU_SH7751R) | ||
529 | + | ||
438 | SH7750State *sh7750_init(CPUSH4State * cpu) | 530 | SH7750State *sh7750_init(CPUSH4State * cpu) |
439 | { | 531 | { |
440 | SH7750State *s; | 532 | SH7750State *s; |
441 | int sh7750_io_memory; | 533 | int sh7750_io_memory; |
534 | + int cpu_model = SH_CPU_SH7751R; /* for now */ | ||
442 | 535 | ||
443 | s = qemu_mallocz(sizeof(SH7750State)); | 536 | s = qemu_mallocz(sizeof(SH7750State)); |
444 | s->cpu = cpu; | 537 | s->cpu = cpu; |
@@ -448,6 +541,14 @@ SH7750State *sh7750_init(CPUSH4State * cpu) | @@ -448,6 +541,14 @@ SH7750State *sh7750_init(CPUSH4State * cpu) | ||
448 | sh7750_mem_write, s); | 541 | sh7750_mem_write, s); |
449 | cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory); | 542 | cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory); |
450 | 543 | ||
544 | + sh_intc_init(&s->intc, NR_SOURCES, | ||
545 | + _INTC_ARRAY(mask_registers), | ||
546 | + _INTC_ARRAY(prio_registers)); | ||
547 | + | ||
548 | + sh_intc_register_sources(&s->intc, | ||
549 | + _INTC_ARRAY(vectors), | ||
550 | + _INTC_ARRAY(groups)); | ||
551 | + | ||
451 | sh_serial_init(0x1fe00000, 0, s->periph_freq, serial_hds[0]); | 552 | sh_serial_init(0x1fe00000, 0, s->periph_freq, serial_hds[0]); |
452 | sh_serial_init(0x1fe80000, SH_SERIAL_FEAT_SCIF, | 553 | sh_serial_init(0x1fe80000, SH_SERIAL_FEAT_SCIF, |
453 | s->periph_freq, serial_hds[1]); | 554 | s->periph_freq, serial_hds[1]); |
@@ -455,6 +556,38 @@ SH7750State *sh7750_init(CPUSH4State * cpu) | @@ -455,6 +556,38 @@ SH7750State *sh7750_init(CPUSH4State * cpu) | ||
455 | tmu012_init(0x1fd80000, | 556 | tmu012_init(0x1fd80000, |
456 | TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, | 557 | TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, |
457 | s->periph_freq); | 558 | s->periph_freq); |
458 | - tmu012_init(0x1e100000, 0, s->periph_freq); | 559 | + |
560 | + | ||
561 | + if (cpu_model & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) { | ||
562 | + sh_intc_register_sources(&s->intc, | ||
563 | + _INTC_ARRAY(vectors_dma4), | ||
564 | + _INTC_ARRAY(groups_dma4)); | ||
565 | + } | ||
566 | + | ||
567 | + if (cpu_model & (SH_CPU_SH7750R | SH_CPU_SH7751R)) { | ||
568 | + sh_intc_register_sources(&s->intc, | ||
569 | + _INTC_ARRAY(vectors_dma8), | ||
570 | + _INTC_ARRAY(groups_dma8)); | ||
571 | + } | ||
572 | + | ||
573 | + if (cpu_model & (SH_CPU_SH7750R | SH_CPU_SH7751 | SH_CPU_SH7751R)) { | ||
574 | + sh_intc_register_sources(&s->intc, | ||
575 | + _INTC_ARRAY(vectors_tmu34), | ||
576 | + _INTC_ARRAY(NULL)); | ||
577 | + tmu012_init(0x1e100000, 0, s->periph_freq); | ||
578 | + } | ||
579 | + | ||
580 | + if (cpu_model & (SH_CPU_SH7751_ALL)) { | ||
581 | + sh_intc_register_sources(&s->intc, | ||
582 | + _INTC_ARRAY(vectors_pci), | ||
583 | + _INTC_ARRAY(groups_pci)); | ||
584 | + } | ||
585 | + | ||
586 | + if (cpu_model & (SH_CPU_SH7750S | SH_CPU_SH7750R | SH_CPU_SH7751_ALL)) { | ||
587 | + sh_intc_register_sources(&s->intc, | ||
588 | + _INTC_ARRAY(vectors_irlm), | ||
589 | + _INTC_ARRAY(NULL)); | ||
590 | + } | ||
591 | + | ||
459 | return s; | 592 | return s; |
460 | } | 593 | } |
hw/sh7750_regnames.c
@@ -76,9 +76,6 @@ static regname_t regnames[] = { | @@ -76,9 +76,6 @@ static regname_t regnames[] = { | ||
76 | REGNAME(SH7750_PDTRB_A7) | 76 | REGNAME(SH7750_PDTRB_A7) |
77 | REGNAME(SH7750_GPIOIC_A7) | 77 | REGNAME(SH7750_GPIOIC_A7) |
78 | REGNAME(SH7750_ICR_A7) | 78 | REGNAME(SH7750_ICR_A7) |
79 | - REGNAME(SH7750_IPRA_A7) | ||
80 | - REGNAME(SH7750_IPRB_A7) | ||
81 | - REGNAME(SH7750_IPRC_A7) | ||
82 | REGNAME(SH7750_BCR3_A7) | 79 | REGNAME(SH7750_BCR3_A7) |
83 | REGNAME(SH7750_BCR4_A7) | 80 | REGNAME(SH7750_BCR4_A7) |
84 | REGNAME(SH7750_PRECHARGE0_A7) | 81 | REGNAME(SH7750_PRECHARGE0_A7) |
hw/sh7750_regs.h
@@ -1241,48 +1241,6 @@ | @@ -1241,48 +1241,6 @@ | ||
1241 | #define SH7750_ICR_IRLM_RAW 0x0080 /* IRL\ pins used as a four independent | 1241 | #define SH7750_ICR_IRLM_RAW 0x0080 /* IRL\ pins used as a four independent |
1242 | interrupt requests */ | 1242 | interrupt requests */ |
1243 | 1243 | ||
1244 | -/* Interrupt Priority Register A - IPRA (half) */ | ||
1245 | -#define SH7750_IPRA_REGOFS 0xD00004 /* offset */ | ||
1246 | -#define SH7750_IPRA SH7750_P4_REG32(SH7750_IPRA_REGOFS) | ||
1247 | -#define SH7750_IPRA_A7 SH7750_A7_REG32(SH7750_IPRA_REGOFS) | ||
1248 | - | ||
1249 | -#define SH7750_IPRA_TMU0 0xF000 /* TMU0 interrupt priority */ | ||
1250 | -#define SH7750_IPRA_TMU0_S 12 | ||
1251 | -#define SH7750_IPRA_TMU1 0x0F00 /* TMU1 interrupt priority */ | ||
1252 | -#define SH7750_IPRA_TMU1_S 8 | ||
1253 | -#define SH7750_IPRA_TMU2 0x00F0 /* TMU2 interrupt priority */ | ||
1254 | -#define SH7750_IPRA_TMU2_S 4 | ||
1255 | -#define SH7750_IPRA_RTC 0x000F /* RTC interrupt priority */ | ||
1256 | -#define SH7750_IPRA_RTC_S 0 | ||
1257 | - | ||
1258 | -/* Interrupt Priority Register B - IPRB (half) */ | ||
1259 | -#define SH7750_IPRB_REGOFS 0xD00008 /* offset */ | ||
1260 | -#define SH7750_IPRB SH7750_P4_REG32(SH7750_IPRB_REGOFS) | ||
1261 | -#define SH7750_IPRB_A7 SH7750_A7_REG32(SH7750_IPRB_REGOFS) | ||
1262 | - | ||
1263 | -#define SH7750_IPRB_WDT 0xF000 /* WDT interrupt priority */ | ||
1264 | -#define SH7750_IPRB_WDT_S 12 | ||
1265 | -#define SH7750_IPRB_REF 0x0F00 /* Memory Refresh unit interrupt | ||
1266 | - priority */ | ||
1267 | -#define SH7750_IPRB_REF_S 8 | ||
1268 | -#define SH7750_IPRB_SCI1 0x00F0 /* SCI1 interrupt priority */ | ||
1269 | -#define SH7750_IPRB_SCI1_S 4 | ||
1270 | - | ||
1271 | -/* Interrupt Priority Register ó - IPRó (half) */ | ||
1272 | -#define SH7750_IPRC_REGOFS 0xD00004 /* offset */ | ||
1273 | -#define SH7750_IPRC SH7750_P4_REG32(SH7750_IPRC_REGOFS) | ||
1274 | -#define SH7750_IPRC_A7 SH7750_A7_REG32(SH7750_IPRC_REGOFS) | ||
1275 | - | ||
1276 | -#define SH7750_IPRC_GPIO 0xF000 /* GPIO interrupt priority */ | ||
1277 | -#define SH7750_IPRC_GPIO_S 12 | ||
1278 | -#define SH7750_IPRC_DMAC 0x0F00 /* DMAC interrupt priority */ | ||
1279 | -#define SH7750_IPRC_DMAC_S 8 | ||
1280 | -#define SH7750_IPRC_SCIF 0x00F0 /* SCIF interrupt priority */ | ||
1281 | -#define SH7750_IPRC_SCIF_S 4 | ||
1282 | -#define SH7750_IPRC_HUDI 0x000F /* H-UDI interrupt priority */ | ||
1283 | -#define SH7750_IPRC_HUDI_S 0 | ||
1284 | - | ||
1285 | - | ||
1286 | /* | 1244 | /* |
1287 | * User Break Controller registers | 1245 | * User Break Controller registers |
1288 | */ | 1246 | */ |
hw/sh_intc.c
0 → 100644
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 | + | ||
11 | +#include <assert.h> | ||
12 | +#include "sh_intc.h" | ||
13 | +#include "vl.h" | ||
14 | + | ||
15 | +//#define DEBUG_INTC | ||
16 | + | ||
17 | +#define INTC_A7(x) ((x) & 0x1fffffff) | ||
18 | +#define INTC_ARRAY(x) (sizeof(x) / sizeof(x[0])) | ||
19 | + | ||
20 | +#define INTC_MODE_NONE 0 | ||
21 | +#define INTC_MODE_DUAL_SET 1 | ||
22 | +#define INTC_MODE_DUAL_CLR 2 | ||
23 | +#define INTC_MODE_ENABLE_REG 3 | ||
24 | +#define INTC_MODE_MASK_REG 4 | ||
25 | +#define INTC_MODE_IS_PRIO 8 | ||
26 | + | ||
27 | +static unsigned int sh_intc_mode(unsigned long address, | ||
28 | + unsigned long set_reg, unsigned long clr_reg) | ||
29 | +{ | ||
30 | + if ((address != INTC_A7(set_reg)) && | ||
31 | + (address != INTC_A7(clr_reg))) | ||
32 | + return INTC_MODE_NONE; | ||
33 | + | ||
34 | + if (set_reg && clr_reg) { | ||
35 | + if (address == INTC_A7(set_reg)) | ||
36 | + return INTC_MODE_DUAL_SET; | ||
37 | + else | ||
38 | + return INTC_MODE_DUAL_CLR; | ||
39 | + } | ||
40 | + | ||
41 | + if (set_reg) | ||
42 | + return INTC_MODE_ENABLE_REG; | ||
43 | + else | ||
44 | + return INTC_MODE_MASK_REG; | ||
45 | +} | ||
46 | + | ||
47 | +static void sh_intc_locate(struct intc_desc *desc, | ||
48 | + unsigned long address, | ||
49 | + unsigned long **datap, | ||
50 | + intc_enum **enums, | ||
51 | + unsigned int *first, | ||
52 | + unsigned int *width, | ||
53 | + unsigned int *modep) | ||
54 | +{ | ||
55 | + unsigned int i, mode; | ||
56 | + | ||
57 | + /* this is slow but works for now */ | ||
58 | + | ||
59 | + if (desc->mask_regs) { | ||
60 | + for (i = 0; i < desc->nr_mask_regs; i++) { | ||
61 | + struct intc_mask_reg *mr = desc->mask_regs + i; | ||
62 | + | ||
63 | + mode = sh_intc_mode(address, mr->set_reg, mr->clr_reg); | ||
64 | + if (mode == INTC_MODE_NONE) | ||
65 | + continue; | ||
66 | + | ||
67 | + *modep = mode; | ||
68 | + *datap = &mr->value; | ||
69 | + *enums = mr->enum_ids; | ||
70 | + *first = mr->reg_width - 1; | ||
71 | + *width = 1; | ||
72 | + return; | ||
73 | + } | ||
74 | + } | ||
75 | + | ||
76 | + if (desc->prio_regs) { | ||
77 | + for (i = 0; i < desc->nr_prio_regs; i++) { | ||
78 | + struct intc_prio_reg *pr = desc->prio_regs + i; | ||
79 | + | ||
80 | + mode = sh_intc_mode(address, pr->set_reg, pr->clr_reg); | ||
81 | + if (mode == INTC_MODE_NONE) | ||
82 | + continue; | ||
83 | + | ||
84 | + *modep = mode | INTC_MODE_IS_PRIO; | ||
85 | + *datap = &pr->value; | ||
86 | + *enums = pr->enum_ids; | ||
87 | + *first = (pr->reg_width / pr->field_width) - 1; | ||
88 | + *width = pr->field_width; | ||
89 | + return; | ||
90 | + } | ||
91 | + } | ||
92 | + | ||
93 | + assert(0); | ||
94 | +} | ||
95 | + | ||
96 | +static void sh_intc_toggle(struct intc_desc *desc, intc_enum id, | ||
97 | + int enable, int is_group) | ||
98 | +{ | ||
99 | + struct intc_source *source = desc->sources + id; | ||
100 | + int old = source->enable_count; | ||
101 | + | ||
102 | + if (!id) | ||
103 | + return; | ||
104 | + | ||
105 | + if (!source->next_enum_id && (!source->enable_max || !source->vect)) { | ||
106 | +#ifdef DEBUG_INTC | ||
107 | + printf("sh_intc: reserved interrupt source %d modified\n", id); | ||
108 | +#endif | ||
109 | + return; | ||
110 | + } | ||
111 | + | ||
112 | + if (source->vect) { | ||
113 | + if (enable) | ||
114 | + source->enable_count++; | ||
115 | + else | ||
116 | + source->enable_count--; | ||
117 | + | ||
118 | + if (source->enable_count == source->enable_max) { | ||
119 | +#ifdef DEBUG_INTC | ||
120 | + printf("sh_intc: enabling interrupt source %d -> 0x%04x\n", | ||
121 | + id, source->vect); | ||
122 | +#endif | ||
123 | + } | ||
124 | + | ||
125 | + if (old == source->enable_max) { | ||
126 | +#ifdef DEBUG_INTC | ||
127 | + printf("sh_intc: disabling interrupt source %d -> 0x%04x\n", | ||
128 | + id, source->vect); | ||
129 | +#endif | ||
130 | + } | ||
131 | + } | ||
132 | +#ifdef DEBUG_INTC | ||
133 | + else { | ||
134 | + printf("setting interrupt group %d to %d\n", id, !!enable); | ||
135 | + } | ||
136 | +#endif | ||
137 | + | ||
138 | + if ((is_group || !source->vect) && source->next_enum_id) { | ||
139 | + sh_intc_toggle(desc, source->next_enum_id, enable, 1); | ||
140 | + } | ||
141 | + | ||
142 | +#ifdef DEBUG_INTC | ||
143 | + if (!source->vect) { | ||
144 | + printf("setting interrupt group %d to %d - done\n", id, !!enable); | ||
145 | + } | ||
146 | +#endif | ||
147 | +} | ||
148 | + | ||
149 | +static uint32_t sh_intc_read(void *opaque, target_phys_addr_t offset) | ||
150 | +{ | ||
151 | + struct intc_desc *desc = opaque; | ||
152 | + intc_enum *enum_ids = NULL; | ||
153 | + unsigned int first = 0; | ||
154 | + unsigned int width = 0; | ||
155 | + unsigned int mode = 0; | ||
156 | + unsigned long *valuep; | ||
157 | + | ||
158 | +#ifdef DEBUG_INTC | ||
159 | + printf("sh_intc_read 0x%lx\n", (unsigned long) offset); | ||
160 | +#endif | ||
161 | + | ||
162 | + sh_intc_locate(desc, (unsigned long)offset, &valuep, | ||
163 | + &enum_ids, &first, &width, &mode); | ||
164 | + return *valuep; | ||
165 | +} | ||
166 | + | ||
167 | +static void sh_intc_write(void *opaque, target_phys_addr_t offset, | ||
168 | + uint32_t value) | ||
169 | +{ | ||
170 | + struct intc_desc *desc = opaque; | ||
171 | + intc_enum *enum_ids = NULL; | ||
172 | + unsigned int first = 0; | ||
173 | + unsigned int width = 0; | ||
174 | + unsigned int mode = 0; | ||
175 | + unsigned int k; | ||
176 | + unsigned long *valuep; | ||
177 | + unsigned long mask; | ||
178 | + | ||
179 | +#ifdef DEBUG_INTC | ||
180 | + printf("sh_intc_write 0x%lx 0x%08x\n", (unsigned long) offset, value); | ||
181 | +#endif | ||
182 | + | ||
183 | + sh_intc_locate(desc, (unsigned long)offset, &valuep, | ||
184 | + &enum_ids, &first, &width, &mode); | ||
185 | + | ||
186 | + switch (mode) { | ||
187 | + case INTC_MODE_ENABLE_REG | INTC_MODE_IS_PRIO: break; | ||
188 | + case INTC_MODE_DUAL_SET: value |= *valuep; break; | ||
189 | + case INTC_MODE_DUAL_CLR: value = *valuep & ~value; break; | ||
190 | + default: assert(0); | ||
191 | + } | ||
192 | + | ||
193 | + for (k = 0; k <= first; k++) { | ||
194 | + mask = ((1 << width) - 1) << ((first - k) * width); | ||
195 | + | ||
196 | + if ((*valuep & mask) == (value & mask)) | ||
197 | + continue; | ||
198 | +#if 0 | ||
199 | + printf("k = %d, first = %d, enum = %d, mask = 0x%08x\n", | ||
200 | + k, first, enum_ids[k], (unsigned int)mask); | ||
201 | +#endif | ||
202 | + sh_intc_toggle(desc, enum_ids[k], value & mask, 0); | ||
203 | + } | ||
204 | + | ||
205 | + *valuep = value; | ||
206 | + | ||
207 | +#ifdef DEBUG_INTC | ||
208 | + printf("sh_intc_write 0x%lx -> 0x%08x\n", (unsigned long) offset, value); | ||
209 | +#endif | ||
210 | +} | ||
211 | + | ||
212 | +static CPUReadMemoryFunc *sh_intc_readfn[] = { | ||
213 | + sh_intc_read, | ||
214 | + sh_intc_read, | ||
215 | + sh_intc_read | ||
216 | +}; | ||
217 | + | ||
218 | +static CPUWriteMemoryFunc *sh_intc_writefn[] = { | ||
219 | + sh_intc_write, | ||
220 | + sh_intc_write, | ||
221 | + sh_intc_write | ||
222 | +}; | ||
223 | + | ||
224 | +struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id) | ||
225 | +{ | ||
226 | + if (id) | ||
227 | + return desc->sources + id; | ||
228 | + | ||
229 | + return NULL; | ||
230 | +} | ||
231 | + | ||
232 | +static void sh_intc_register(struct intc_desc *desc, | ||
233 | + unsigned long address) | ||
234 | +{ | ||
235 | + if (address) | ||
236 | + cpu_register_physical_memory(INTC_A7(address), 4, desc->iomemtype); | ||
237 | +} | ||
238 | + | ||
239 | +static void sh_intc_register_source(struct intc_desc *desc, | ||
240 | + intc_enum source, | ||
241 | + struct intc_group *groups, | ||
242 | + int nr_groups) | ||
243 | +{ | ||
244 | + unsigned int i, k; | ||
245 | + struct intc_source *s; | ||
246 | + | ||
247 | + if (desc->mask_regs) { | ||
248 | + for (i = 0; i < desc->nr_mask_regs; i++) { | ||
249 | + struct intc_mask_reg *mr = desc->mask_regs + i; | ||
250 | + | ||
251 | + for (k = 0; k < INTC_ARRAY(mr->enum_ids); k++) { | ||
252 | + if (mr->enum_ids[k] != source) | ||
253 | + continue; | ||
254 | + | ||
255 | + s = sh_intc_source(desc, mr->enum_ids[k]); | ||
256 | + if (s) | ||
257 | + s->enable_max++; | ||
258 | + } | ||
259 | + } | ||
260 | + } | ||
261 | + | ||
262 | + if (desc->prio_regs) { | ||
263 | + for (i = 0; i < desc->nr_prio_regs; i++) { | ||
264 | + struct intc_prio_reg *pr = desc->prio_regs + i; | ||
265 | + | ||
266 | + for (k = 0; k < INTC_ARRAY(pr->enum_ids); k++) { | ||
267 | + if (pr->enum_ids[k] != source) | ||
268 | + continue; | ||
269 | + | ||
270 | + s = sh_intc_source(desc, pr->enum_ids[k]); | ||
271 | + if (s) | ||
272 | + s->enable_max++; | ||
273 | + } | ||
274 | + } | ||
275 | + } | ||
276 | + | ||
277 | + if (groups) { | ||
278 | + for (i = 0; i < nr_groups; i++) { | ||
279 | + struct intc_group *gr = groups + i; | ||
280 | + | ||
281 | + for (k = 0; k < INTC_ARRAY(gr->enum_ids); k++) { | ||
282 | + if (gr->enum_ids[k] != source) | ||
283 | + continue; | ||
284 | + | ||
285 | + s = sh_intc_source(desc, gr->enum_ids[k]); | ||
286 | + if (s) | ||
287 | + s->enable_max++; | ||
288 | + } | ||
289 | + } | ||
290 | + } | ||
291 | + | ||
292 | +} | ||
293 | + | ||
294 | +void sh_intc_register_sources(struct intc_desc *desc, | ||
295 | + struct intc_vect *vectors, | ||
296 | + int nr_vectors, | ||
297 | + struct intc_group *groups, | ||
298 | + int nr_groups) | ||
299 | +{ | ||
300 | + unsigned int i, k; | ||
301 | + struct intc_source *s; | ||
302 | + | ||
303 | + for (i = 0; i < nr_vectors; i++) { | ||
304 | + struct intc_vect *vect = vectors + i; | ||
305 | + | ||
306 | + sh_intc_register_source(desc, vect->enum_id, groups, nr_groups); | ||
307 | + s = sh_intc_source(desc, vect->enum_id); | ||
308 | + if (s) | ||
309 | + s->vect = vect->vect; | ||
310 | + | ||
311 | +#ifdef DEBUG_INTC | ||
312 | + printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n", | ||
313 | + vect->enum_id, s->vect, s->enable_count, s->enable_max); | ||
314 | +#endif | ||
315 | + } | ||
316 | + | ||
317 | + if (groups) { | ||
318 | + for (i = 0; i < nr_groups; i++) { | ||
319 | + struct intc_group *gr = groups + i; | ||
320 | + | ||
321 | + s = sh_intc_source(desc, gr->enum_id); | ||
322 | + s->next_enum_id = gr->enum_ids[0]; | ||
323 | + | ||
324 | + for (k = 1; k < INTC_ARRAY(gr->enum_ids); k++) { | ||
325 | + if (!gr->enum_ids[k]) | ||
326 | + continue; | ||
327 | + | ||
328 | + s = sh_intc_source(desc, gr->enum_ids[k - 1]); | ||
329 | + s->next_enum_id = gr->enum_ids[k]; | ||
330 | + } | ||
331 | + | ||
332 | +#ifdef DEBUG_INTC | ||
333 | + printf("sh_intc: registered group %d (%d/%d)\n", | ||
334 | + gr->enum_id, s->enable_count, s->enable_max); | ||
335 | +#endif | ||
336 | + } | ||
337 | + } | ||
338 | +} | ||
339 | + | ||
340 | +int sh_intc_init(struct intc_desc *desc, | ||
341 | + int nr_sources, | ||
342 | + struct intc_mask_reg *mask_regs, | ||
343 | + int nr_mask_regs, | ||
344 | + struct intc_prio_reg *prio_regs, | ||
345 | + int nr_prio_regs) | ||
346 | +{ | ||
347 | + unsigned int i; | ||
348 | + | ||
349 | + desc->nr_sources = nr_sources; | ||
350 | + desc->mask_regs = mask_regs; | ||
351 | + desc->nr_mask_regs = nr_mask_regs; | ||
352 | + desc->prio_regs = prio_regs; | ||
353 | + desc->nr_prio_regs = nr_prio_regs; | ||
354 | + | ||
355 | + i = sizeof(struct intc_source) * nr_sources; | ||
356 | + desc->sources = malloc(i); | ||
357 | + if (!desc->sources) | ||
358 | + return -1; | ||
359 | + | ||
360 | + memset(desc->sources, 0, i); | ||
361 | + | ||
362 | + desc->iomemtype = cpu_register_io_memory(0, sh_intc_readfn, | ||
363 | + sh_intc_writefn, desc); | ||
364 | + if (desc->mask_regs) { | ||
365 | + for (i = 0; i < desc->nr_mask_regs; i++) { | ||
366 | + struct intc_mask_reg *mr = desc->mask_regs + i; | ||
367 | + | ||
368 | + sh_intc_register(desc, mr->set_reg); | ||
369 | + sh_intc_register(desc, mr->clr_reg); | ||
370 | + } | ||
371 | + } | ||
372 | + | ||
373 | + if (desc->prio_regs) { | ||
374 | + for (i = 0; i < desc->nr_prio_regs; i++) { | ||
375 | + struct intc_prio_reg *pr = desc->prio_regs + i; | ||
376 | + | ||
377 | + sh_intc_register(desc, pr->set_reg); | ||
378 | + sh_intc_register(desc, pr->clr_reg); | ||
379 | + } | ||
380 | + } | ||
381 | + | ||
382 | + return 0; | ||
383 | +} |
hw/sh_intc.h
0 → 100644
1 | +#ifndef __SH_INTC_H__ | ||
2 | +#define __SH_INTC_H__ | ||
3 | + | ||
4 | +typedef unsigned char intc_enum; | ||
5 | + | ||
6 | +struct intc_vect { | ||
7 | + intc_enum enum_id; | ||
8 | + unsigned short vect; | ||
9 | +}; | ||
10 | + | ||
11 | +#define INTC_VECT(enum_id, vect) { enum_id, vect } | ||
12 | + | ||
13 | +struct intc_group { | ||
14 | + intc_enum enum_id; | ||
15 | + intc_enum enum_ids[32]; | ||
16 | +}; | ||
17 | + | ||
18 | +#define INTC_GROUP(enum_id, ids...) { enum_id, { ids } } | ||
19 | + | ||
20 | +struct intc_mask_reg { | ||
21 | + unsigned long set_reg, clr_reg, reg_width; | ||
22 | + intc_enum enum_ids[32]; | ||
23 | + unsigned long value; | ||
24 | +}; | ||
25 | + | ||
26 | +struct intc_prio_reg { | ||
27 | + unsigned long set_reg, clr_reg, reg_width, field_width; | ||
28 | + intc_enum enum_ids[16]; | ||
29 | + unsigned long value; | ||
30 | +}; | ||
31 | + | ||
32 | +#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a) | ||
33 | + | ||
34 | +struct intc_source { | ||
35 | + unsigned short vect; | ||
36 | + intc_enum next_enum_id; | ||
37 | + | ||
38 | + int asserted; | ||
39 | + int enable_count; | ||
40 | + int enable_max; | ||
41 | +}; | ||
42 | + | ||
43 | +struct intc_desc { | ||
44 | + struct intc_source *sources; | ||
45 | + int nr_sources; | ||
46 | + struct intc_mask_reg *mask_regs; | ||
47 | + int nr_mask_regs; | ||
48 | + struct intc_prio_reg *prio_regs; | ||
49 | + int nr_prio_regs; | ||
50 | + | ||
51 | + int iomemtype; | ||
52 | +}; | ||
53 | + | ||
54 | +struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id); | ||
55 | + | ||
56 | +void sh_intc_register_sources(struct intc_desc *desc, | ||
57 | + struct intc_vect *vectors, | ||
58 | + int nr_vectors, | ||
59 | + struct intc_group *groups, | ||
60 | + int nr_groups); | ||
61 | + | ||
62 | +int sh_intc_init(struct intc_desc *desc, | ||
63 | + int nr_sources, | ||
64 | + struct intc_mask_reg *mask_regs, | ||
65 | + int nr_mask_regs, | ||
66 | + struct intc_prio_reg *prio_regs, | ||
67 | + int nr_prio_regs); | ||
68 | + | ||
69 | +#endif /* __SH_INTC_H__ */ |