|
|
1.1 root 1: /*
2: * QEMU model of the Milkymist System Controller.
3: *
4: * Copyright (c) 2010 Michael Walle <[email protected]>
5: *
6: * This library is free software; you can redistribute it and/or
7: * modify it under the terms of the GNU Lesser General Public
8: * License as published by the Free Software Foundation; either
9: * version 2 of the License, or (at your option) any later version.
10: *
11: * This library is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14: * Lesser General Public License for more details.
15: *
16: * You should have received a copy of the GNU Lesser General Public
17: * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18: *
19: *
20: * Specification available at:
21: * http://www.milkymist.org/socdoc/sysctl.pdf
22: */
23:
24: #include "hw.h"
25: #include "sysbus.h"
26: #include "sysemu.h"
27: #include "trace.h"
28: #include "qemu-timer.h"
29: #include "qemu-error.h"
30:
31: enum {
32: CTRL_ENABLE = (1<<0),
33: CTRL_AUTORESTART = (1<<1),
34: };
35:
36: enum {
37: ICAP_READY = (1<<0),
38: };
39:
40: enum {
41: R_GPIO_IN = 0,
42: R_GPIO_OUT,
43: R_GPIO_INTEN,
44: R_RESERVED0,
45: R_TIMER0_CONTROL,
46: R_TIMER0_COMPARE,
47: R_TIMER0_COUNTER,
48: R_RESERVED1,
49: R_TIMER1_CONTROL,
50: R_TIMER1_COMPARE,
51: R_TIMER1_COUNTER,
52: R_RESERVED2,
53: R_RESERVED3,
54: R_ICAP,
55: R_CAPABILITIES,
56: R_SYSTEM_ID,
57: R_MAX
58: };
59:
60: struct MilkymistSysctlState {
61: SysBusDevice busdev;
62:
63: QEMUBH *bh0;
64: QEMUBH *bh1;
65: ptimer_state *ptimer0;
66: ptimer_state *ptimer1;
67:
68: uint32_t freq_hz;
69: uint32_t capabilities;
70: uint32_t systemid;
71: uint32_t strappings;
72:
73: uint32_t regs[R_MAX];
74:
75: qemu_irq gpio_irq;
76: qemu_irq timer0_irq;
77: qemu_irq timer1_irq;
78: };
79: typedef struct MilkymistSysctlState MilkymistSysctlState;
80:
81: static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
82: {
83: trace_milkymist_sysctl_icap_write(value);
84: switch (value & 0xffff) {
85: case 0x000e:
86: qemu_system_shutdown_request();
87: break;
88: }
89: }
90:
91: static uint32_t sysctl_read(void *opaque, target_phys_addr_t addr)
92: {
93: MilkymistSysctlState *s = opaque;
94: uint32_t r = 0;
95:
96: addr >>= 2;
97: switch (addr) {
98: case R_TIMER0_COUNTER:
99: r = (uint32_t)ptimer_get_count(s->ptimer0);
100: /* milkymist timer counts up */
101: r = s->regs[R_TIMER0_COMPARE] - r;
102: break;
103: case R_TIMER1_COUNTER:
104: r = (uint32_t)ptimer_get_count(s->ptimer1);
105: /* milkymist timer counts up */
106: r = s->regs[R_TIMER1_COMPARE] - r;
107: break;
108: case R_GPIO_IN:
109: case R_GPIO_OUT:
110: case R_GPIO_INTEN:
111: case R_TIMER0_CONTROL:
112: case R_TIMER0_COMPARE:
113: case R_TIMER1_CONTROL:
114: case R_TIMER1_COMPARE:
115: case R_ICAP:
116: case R_CAPABILITIES:
117: case R_SYSTEM_ID:
118: r = s->regs[addr];
119: break;
120:
121: default:
122: error_report("milkymist_sysctl: read access to unknown register 0x"
123: TARGET_FMT_plx, addr << 2);
124: break;
125: }
126:
127: trace_milkymist_sysctl_memory_read(addr << 2, r);
128:
129: return r;
130: }
131:
132: static void sysctl_write(void *opaque, target_phys_addr_t addr, uint32_t value)
133: {
134: MilkymistSysctlState *s = opaque;
135:
136: trace_milkymist_sysctl_memory_write(addr, value);
137:
138: addr >>= 2;
139: switch (addr) {
140: case R_GPIO_OUT:
141: case R_GPIO_INTEN:
142: case R_TIMER0_COUNTER:
143: case R_TIMER1_COUNTER:
144: s->regs[addr] = value;
145: break;
146: case R_TIMER0_COMPARE:
147: ptimer_set_limit(s->ptimer0, value, 0);
148: s->regs[addr] = value;
149: break;
150: case R_TIMER1_COMPARE:
151: ptimer_set_limit(s->ptimer1, value, 0);
152: s->regs[addr] = value;
153: break;
154: case R_TIMER0_CONTROL:
155: s->regs[addr] = value;
156: if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
157: trace_milkymist_sysctl_start_timer0();
158: ptimer_set_count(s->ptimer0,
159: s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
160: ptimer_run(s->ptimer0, 0);
161: } else {
162: trace_milkymist_sysctl_stop_timer0();
163: ptimer_stop(s->ptimer0);
164: }
165: break;
166: case R_TIMER1_CONTROL:
167: s->regs[addr] = value;
168: if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
169: trace_milkymist_sysctl_start_timer1();
170: ptimer_set_count(s->ptimer1,
171: s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
172: ptimer_run(s->ptimer1, 0);
173: } else {
174: trace_milkymist_sysctl_stop_timer1();
175: ptimer_stop(s->ptimer1);
176: }
177: break;
178: case R_ICAP:
179: sysctl_icap_write(s, value);
180: break;
181: case R_SYSTEM_ID:
182: qemu_system_reset_request();
183: break;
184:
185: case R_GPIO_IN:
186: case R_CAPABILITIES:
187: error_report("milkymist_sysctl: write to read-only register 0x"
188: TARGET_FMT_plx, addr << 2);
189: break;
190:
191: default:
192: error_report("milkymist_sysctl: write access to unknown register 0x"
193: TARGET_FMT_plx, addr << 2);
194: break;
195: }
196: }
197:
198: static CPUReadMemoryFunc * const sysctl_read_fn[] = {
199: NULL,
200: NULL,
201: &sysctl_read,
202: };
203:
204: static CPUWriteMemoryFunc * const sysctl_write_fn[] = {
205: NULL,
206: NULL,
207: &sysctl_write,
208: };
209:
210: static void timer0_hit(void *opaque)
211: {
212: MilkymistSysctlState *s = opaque;
213:
214: if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
215: s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
216: trace_milkymist_sysctl_stop_timer0();
217: ptimer_stop(s->ptimer0);
218: }
219:
220: trace_milkymist_sysctl_pulse_irq_timer0();
221: qemu_irq_pulse(s->timer0_irq);
222: }
223:
224: static void timer1_hit(void *opaque)
225: {
226: MilkymistSysctlState *s = opaque;
227:
228: if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
229: s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
230: trace_milkymist_sysctl_stop_timer1();
231: ptimer_stop(s->ptimer1);
232: }
233:
234: trace_milkymist_sysctl_pulse_irq_timer1();
235: qemu_irq_pulse(s->timer1_irq);
236: }
237:
238: static void milkymist_sysctl_reset(DeviceState *d)
239: {
240: MilkymistSysctlState *s =
241: container_of(d, MilkymistSysctlState, busdev.qdev);
242: int i;
243:
244: for (i = 0; i < R_MAX; i++) {
245: s->regs[i] = 0;
246: }
247:
248: ptimer_stop(s->ptimer0);
249: ptimer_stop(s->ptimer1);
250:
251: /* defaults */
252: s->regs[R_ICAP] = ICAP_READY;
253: s->regs[R_SYSTEM_ID] = s->systemid;
254: s->regs[R_CAPABILITIES] = s->capabilities;
255: s->regs[R_GPIO_IN] = s->strappings;
256: }
257:
258: static int milkymist_sysctl_init(SysBusDevice *dev)
259: {
260: MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
261: int sysctl_regs;
262:
263: sysbus_init_irq(dev, &s->gpio_irq);
264: sysbus_init_irq(dev, &s->timer0_irq);
265: sysbus_init_irq(dev, &s->timer1_irq);
266:
267: s->bh0 = qemu_bh_new(timer0_hit, s);
268: s->bh1 = qemu_bh_new(timer1_hit, s);
269: s->ptimer0 = ptimer_init(s->bh0);
270: s->ptimer1 = ptimer_init(s->bh1);
271: ptimer_set_freq(s->ptimer0, s->freq_hz);
272: ptimer_set_freq(s->ptimer1, s->freq_hz);
273:
274: sysctl_regs = cpu_register_io_memory(sysctl_read_fn, sysctl_write_fn, s,
275: DEVICE_NATIVE_ENDIAN);
276: sysbus_init_mmio(dev, R_MAX * 4, sysctl_regs);
277:
278: return 0;
279: }
280:
281: static const VMStateDescription vmstate_milkymist_sysctl = {
282: .name = "milkymist-sysctl",
283: .version_id = 1,
284: .minimum_version_id = 1,
285: .minimum_version_id_old = 1,
286: .fields = (VMStateField[]) {
287: VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
288: VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
289: VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
290: VMSTATE_END_OF_LIST()
291: }
292: };
293:
294: static SysBusDeviceInfo milkymist_sysctl_info = {
295: .init = milkymist_sysctl_init,
296: .qdev.name = "milkymist-sysctl",
297: .qdev.size = sizeof(MilkymistSysctlState),
298: .qdev.vmsd = &vmstate_milkymist_sysctl,
299: .qdev.reset = milkymist_sysctl_reset,
300: .qdev.props = (Property[]) {
301: DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
302: freq_hz, 80000000),
303: DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
304: capabilities, 0x00000000),
305: DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
306: systemid, 0x10014d31),
307: DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
308: strappings, 0x00000001),
309: DEFINE_PROP_END_OF_LIST(),
310: }
311: };
312:
313: static void milkymist_sysctl_register(void)
314: {
315: sysbus_register_withprop(&milkymist_sysctl_info);
316: }
317:
318: device_init(milkymist_sysctl_register)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.