Add PowerPC power-management state check callback.
[qemu] / hw / mcf_intc.c
1 /*
2  * ColdFire Interrupt Controller emulation.
3  *
4  * Copyright (c) 2007 CodeSourcery.
5  *
6  * This code is licenced under the GPL
7  */
8 #include "vl.h"
9
10 typedef struct {
11     uint64_t ipr;
12     uint64_t imr;
13     uint64_t ifr;
14     uint64_t enabled;
15     uint8_t icr[64];
16     CPUState *env;
17     int active_vector;
18 } mcf_intc_state;
19
20 static void mcf_intc_update(mcf_intc_state *s)
21 {
22     uint64_t active;
23     int i;
24     int best;
25     int best_level;
26
27     active = (s->ipr | s->ifr) & s->enabled & ~s->imr;
28     best_level = 0;
29     best = 64;
30     if (active) {
31         for (i = 0; i < 64; i++) {
32             if ((active & 1) != 0 && s->icr[i] >= best_level) {
33                 best_level = s->icr[i];
34                 best = i;
35             }
36             active >>= 1;
37         }
38     }
39     s->active_vector = ((best == 64) ? 24 : (best + 64));
40     m68k_set_irq_level(s->env, best_level, s->active_vector);
41 }
42
43 static uint32_t mcf_intc_read(void *opaque, target_phys_addr_t addr)
44 {
45     int offset;
46     mcf_intc_state *s = (mcf_intc_state *)opaque;
47     offset = addr & 0xff;
48     if (offset >= 0x40 && offset < 0x80) {
49         return s->icr[offset - 0x40];
50     }
51     switch (offset) {
52     case 0x00:
53         return (uint32_t)(s->ipr >> 32);
54     case 0x04:
55         return (uint32_t)s->ipr;
56     case 0x08:
57         return (uint32_t)(s->imr >> 32);
58     case 0x0c:
59         return (uint32_t)s->imr;
60     case 0x10:
61         return (uint32_t)(s->ifr >> 32);
62     case 0x14:
63         return (uint32_t)s->ifr;
64     case 0xe0: /* SWIACK.  */
65         return s->active_vector;
66     case 0xe1: case 0xe2: case 0xe3: case 0xe4:
67     case 0xe5: case 0xe6: case 0xe7:
68         /* LnIACK */
69         cpu_abort(cpu_single_env, "mcf_intc_read: LnIACK not implemented\n");
70     default:
71         return 0;
72     }
73 }
74
75 static void mcf_intc_write(void *opaque, target_phys_addr_t addr, uint32_t val)
76 {
77     int offset;
78     mcf_intc_state *s = (mcf_intc_state *)opaque;
79     offset = addr & 0xff;
80     if (offset >= 0x40 && offset < 0x80) {
81         int n = offset - 0x40;
82         s->icr[n] = val;
83         if (val == 0)
84             s->enabled &= ~(1ull << n);
85         else
86             s->enabled |= (1ull << n);
87         mcf_intc_update(s);
88         return;
89     }
90     switch (offset) {
91     case 0x00: case 0x04:
92         /* Ignore IPR writes.  */
93         return;
94     case 0x08:
95         s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32);
96         break;
97     case 0x0c:
98         s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val;
99         break;
100     default:
101         cpu_abort(cpu_single_env, "mcf_intc_write: Bad write offset %d\n",
102                   offset);
103         break;
104     }
105     mcf_intc_update(s);
106 }
107
108 static void mcf_intc_set_irq(void *opaque, int irq, int level)
109 {
110     mcf_intc_state *s = (mcf_intc_state *)opaque;
111     if (irq >= 64)
112         return;
113     if (level)
114         s->ipr |= 1ull << irq;
115     else
116         s->ipr &= ~(1ull << irq);
117     mcf_intc_update(s);
118 }
119
120 static void mcf_intc_reset(mcf_intc_state *s)
121 {
122     s->imr = ~0ull;
123     s->ipr = 0;
124     s->ifr = 0;
125     s->enabled = 0;
126     memset(s->icr, 0, 64);
127     s->active_vector = 24;
128 }
129
130 static CPUReadMemoryFunc *mcf_intc_readfn[] = {
131    mcf_intc_read,
132    mcf_intc_read,
133    mcf_intc_read
134 };
135
136 static CPUWriteMemoryFunc *mcf_intc_writefn[] = {
137    mcf_intc_write,
138    mcf_intc_write,
139    mcf_intc_write
140 };
141
142 qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env)
143 {
144     mcf_intc_state *s;
145     int iomemtype;
146
147     s = qemu_mallocz(sizeof(mcf_intc_state));
148     s->env = env;
149     mcf_intc_reset(s);
150
151     iomemtype = cpu_register_io_memory(0, mcf_intc_readfn,
152                                        mcf_intc_writefn, s);
153     cpu_register_physical_memory(base, 0x100, iomemtype);
154
155     return qemu_allocate_irqs(mcf_intc_set_irq, s, 64);
156 }