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 | 484 | endif |
| 485 | 485 | ifeq ($(TARGET_BASE_ARCH), sh4) |
| 486 | 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 | 488 | endif |
| 489 | 489 | ifeq ($(TARGET_BASE_ARCH), m68k) |
| 490 | 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 | 2 | * SH7750 device |
| 3 | 3 | * |
| 4 | + * Copyright (c) 2007 Magnus Damm | |
| 4 | 5 | * Copyright (c) 2005 Samuel Tardieu |
| 5 | 6 | * |
| 6 | 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| ... | ... | @@ -26,6 +27,7 @@ |
| 26 | 27 | #include "vl.h" |
| 27 | 28 | #include "sh7750_regs.h" |
| 28 | 29 | #include "sh7750_regnames.h" |
| 30 | +#include "sh_intc.h" | |
| 29 | 31 | |
| 30 | 32 | #define NB_DEVICES 4 |
| 31 | 33 | |
| ... | ... | @@ -53,15 +55,10 @@ typedef struct SH7750State { |
| 53 | 55 | sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ |
| 54 | 56 | |
| 55 | 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 | 58 | /* Cache */ |
| 63 | 59 | uint32_t ccr; |
| 64 | 60 | |
| 61 | + struct intc_desc intc; | |
| 65 | 62 | } SH7750State; |
| 66 | 63 | |
| 67 | 64 | |
| ... | ... | @@ -219,14 +216,6 @@ static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr) |
| 219 | 216 | return portb_lines(s); |
| 220 | 217 | case 0x1fd00000: |
| 221 | 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 | 219 | default: |
| 231 | 220 | error_access("word read", addr); |
| 232 | 221 | assert(0); |
| ... | ... | @@ -262,14 +251,6 @@ static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr) |
| 262 | 251 | return 0x00110000; /* Minimum caches */ |
| 263 | 252 | case 0x1f000044: /* Processor version PRR */ |
| 264 | 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 | 254 | default: |
| 274 | 255 | error_access("long read", addr); |
| 275 | 256 | assert(0); |
| ... | ... | @@ -331,18 +312,6 @@ static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr, |
| 331 | 312 | case 0x1fd00000: |
| 332 | 313 | s->icr = mem_value; |
| 333 | 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 | 315 | default: |
| 347 | 316 | error_access("word write", addr); |
| 348 | 317 | assert(0); |
| ... | ... | @@ -407,16 +376,6 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, |
| 407 | 376 | case SH7750_CCR_A7: |
| 408 | 377 | s->ccr = mem_value; |
| 409 | 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 | 379 | default: |
| 421 | 380 | error_access("long write", addr); |
| 422 | 381 | assert(0); |
| ... | ... | @@ -435,10 +394,144 @@ static CPUWriteMemoryFunc *sh7750_mem_write[] = { |
| 435 | 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 | 530 | SH7750State *sh7750_init(CPUSH4State * cpu) |
| 439 | 531 | { |
| 440 | 532 | SH7750State *s; |
| 441 | 533 | int sh7750_io_memory; |
| 534 | + int cpu_model = SH_CPU_SH7751R; /* for now */ | |
| 442 | 535 | |
| 443 | 536 | s = qemu_mallocz(sizeof(SH7750State)); |
| 444 | 537 | s->cpu = cpu; |
| ... | ... | @@ -448,6 +541,14 @@ SH7750State *sh7750_init(CPUSH4State * cpu) |
| 448 | 541 | sh7750_mem_write, s); |
| 449 | 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 | 552 | sh_serial_init(0x1fe00000, 0, s->periph_freq, serial_hds[0]); |
| 452 | 553 | sh_serial_init(0x1fe80000, SH_SERIAL_FEAT_SCIF, |
| 453 | 554 | s->periph_freq, serial_hds[1]); |
| ... | ... | @@ -455,6 +556,38 @@ SH7750State *sh7750_init(CPUSH4State * cpu) |
| 455 | 556 | tmu012_init(0x1fd80000, |
| 456 | 557 | TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, |
| 457 | 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 | 592 | return s; |
| 460 | 593 | } | ... | ... |
hw/sh7750_regnames.c
| ... | ... | @@ -76,9 +76,6 @@ static regname_t regnames[] = { |
| 76 | 76 | REGNAME(SH7750_PDTRB_A7) |
| 77 | 77 | REGNAME(SH7750_GPIOIC_A7) |
| 78 | 78 | REGNAME(SH7750_ICR_A7) |
| 79 | - REGNAME(SH7750_IPRA_A7) | |
| 80 | - REGNAME(SH7750_IPRB_A7) | |
| 81 | - REGNAME(SH7750_IPRC_A7) | |
| 82 | 79 | REGNAME(SH7750_BCR3_A7) |
| 83 | 80 | REGNAME(SH7750_BCR4_A7) |
| 84 | 81 | REGNAME(SH7750_PRECHARGE0_A7) | ... | ... |
hw/sh7750_regs.h
| ... | ... | @@ -1241,48 +1241,6 @@ |
| 1241 | 1241 | #define SH7750_ICR_IRLM_RAW 0x0080 /* IRL\ pins used as a four independent |
| 1242 | 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 | 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__ */ | ... | ... |