Commit 80f515e63688f43b7800027c233ec7139cf3375b

Authored by balrog
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
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__ */
... ...