|
|
1.1 root 1: /*
2: * QEMU model of the Milkymist System Controller.
3: *
1.1.1.3 ! root 4: * Copyright (c) 2010-2012 Michael Walle <[email protected]>
1.1 root 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"
1.1.1.3 ! root 29: #include "ptimer.h"
1.1 root 30: #include "qemu-error.h"
31:
32: enum {
33: CTRL_ENABLE = (1<<0),
34: CTRL_AUTORESTART = (1<<1),
35: };
36:
37: enum {
38: ICAP_READY = (1<<0),
39: };
40:
41: enum {
1.1.1.3 ! root 42: R_GPIO_IN = 0,
1.1 root 43: R_GPIO_OUT,
44: R_GPIO_INTEN,
1.1.1.3 ! root 45: R_TIMER0_CONTROL = 4,
1.1 root 46: R_TIMER0_COMPARE,
47: R_TIMER0_COUNTER,
1.1.1.3 ! root 48: R_TIMER1_CONTROL = 8,
1.1 root 49: R_TIMER1_COMPARE,
50: R_TIMER1_COUNTER,
1.1.1.3 ! root 51: R_ICAP = 16,
! 52: R_DBG_SCRATCHPAD = 20,
! 53: R_DBG_WRITE_LOCK,
! 54: R_CLK_FREQUENCY = 29,
1.1 root 55: R_CAPABILITIES,
56: R_SYSTEM_ID,
57: R_MAX
58: };
59:
60: struct MilkymistSysctlState {
61: SysBusDevice busdev;
1.1.1.2 root 62: MemoryRegion regs_region;
1.1 root 63:
64: QEMUBH *bh0;
65: QEMUBH *bh1;
66: ptimer_state *ptimer0;
67: ptimer_state *ptimer1;
68:
69: uint32_t freq_hz;
70: uint32_t capabilities;
71: uint32_t systemid;
72: uint32_t strappings;
73:
74: uint32_t regs[R_MAX];
75:
76: qemu_irq gpio_irq;
77: qemu_irq timer0_irq;
78: qemu_irq timer1_irq;
79: };
80: typedef struct MilkymistSysctlState MilkymistSysctlState;
81:
82: static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
83: {
84: trace_milkymist_sysctl_icap_write(value);
85: switch (value & 0xffff) {
86: case 0x000e:
87: qemu_system_shutdown_request();
88: break;
89: }
90: }
91:
1.1.1.2 root 92: static uint64_t sysctl_read(void *opaque, target_phys_addr_t addr,
93: unsigned size)
1.1 root 94: {
95: MilkymistSysctlState *s = opaque;
96: uint32_t r = 0;
97:
98: addr >>= 2;
99: switch (addr) {
100: case R_TIMER0_COUNTER:
101: r = (uint32_t)ptimer_get_count(s->ptimer0);
102: /* milkymist timer counts up */
103: r = s->regs[R_TIMER0_COMPARE] - r;
104: break;
105: case R_TIMER1_COUNTER:
106: r = (uint32_t)ptimer_get_count(s->ptimer1);
107: /* milkymist timer counts up */
108: r = s->regs[R_TIMER1_COMPARE] - r;
109: break;
110: case R_GPIO_IN:
111: case R_GPIO_OUT:
112: case R_GPIO_INTEN:
113: case R_TIMER0_CONTROL:
114: case R_TIMER0_COMPARE:
115: case R_TIMER1_CONTROL:
116: case R_TIMER1_COMPARE:
117: case R_ICAP:
1.1.1.3 ! root 118: case R_DBG_SCRATCHPAD:
! 119: case R_DBG_WRITE_LOCK:
! 120: case R_CLK_FREQUENCY:
1.1 root 121: case R_CAPABILITIES:
122: case R_SYSTEM_ID:
123: r = s->regs[addr];
124: break;
125:
126: default:
127: error_report("milkymist_sysctl: read access to unknown register 0x"
128: TARGET_FMT_plx, addr << 2);
129: break;
130: }
131:
132: trace_milkymist_sysctl_memory_read(addr << 2, r);
133:
134: return r;
135: }
136:
1.1.1.2 root 137: static void sysctl_write(void *opaque, target_phys_addr_t addr, uint64_t value,
138: unsigned size)
1.1 root 139: {
140: MilkymistSysctlState *s = opaque;
141:
142: trace_milkymist_sysctl_memory_write(addr, value);
143:
144: addr >>= 2;
145: switch (addr) {
146: case R_GPIO_OUT:
147: case R_GPIO_INTEN:
148: case R_TIMER0_COUNTER:
149: case R_TIMER1_COUNTER:
1.1.1.3 ! root 150: case R_DBG_SCRATCHPAD:
1.1 root 151: s->regs[addr] = value;
152: break;
153: case R_TIMER0_COMPARE:
154: ptimer_set_limit(s->ptimer0, value, 0);
155: s->regs[addr] = value;
156: break;
157: case R_TIMER1_COMPARE:
158: ptimer_set_limit(s->ptimer1, value, 0);
159: s->regs[addr] = value;
160: break;
161: case R_TIMER0_CONTROL:
162: s->regs[addr] = value;
163: if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
164: trace_milkymist_sysctl_start_timer0();
165: ptimer_set_count(s->ptimer0,
166: s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
167: ptimer_run(s->ptimer0, 0);
168: } else {
169: trace_milkymist_sysctl_stop_timer0();
170: ptimer_stop(s->ptimer0);
171: }
172: break;
173: case R_TIMER1_CONTROL:
174: s->regs[addr] = value;
175: if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
176: trace_milkymist_sysctl_start_timer1();
177: ptimer_set_count(s->ptimer1,
178: s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
179: ptimer_run(s->ptimer1, 0);
180: } else {
181: trace_milkymist_sysctl_stop_timer1();
182: ptimer_stop(s->ptimer1);
183: }
184: break;
185: case R_ICAP:
186: sysctl_icap_write(s, value);
187: break;
1.1.1.3 ! root 188: case R_DBG_WRITE_LOCK:
! 189: s->regs[addr] = 1;
! 190: break;
1.1 root 191: case R_SYSTEM_ID:
192: qemu_system_reset_request();
193: break;
194:
195: case R_GPIO_IN:
1.1.1.3 ! root 196: case R_CLK_FREQUENCY:
1.1 root 197: case R_CAPABILITIES:
198: error_report("milkymist_sysctl: write to read-only register 0x"
199: TARGET_FMT_plx, addr << 2);
200: break;
201:
202: default:
203: error_report("milkymist_sysctl: write access to unknown register 0x"
204: TARGET_FMT_plx, addr << 2);
205: break;
206: }
207: }
208:
1.1.1.2 root 209: static const MemoryRegionOps sysctl_mmio_ops = {
210: .read = sysctl_read,
211: .write = sysctl_write,
212: .valid = {
213: .min_access_size = 4,
214: .max_access_size = 4,
215: },
216: .endianness = DEVICE_NATIVE_ENDIAN,
1.1 root 217: };
218:
219: static void timer0_hit(void *opaque)
220: {
221: MilkymistSysctlState *s = opaque;
222:
223: if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
224: s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
225: trace_milkymist_sysctl_stop_timer0();
226: ptimer_stop(s->ptimer0);
227: }
228:
229: trace_milkymist_sysctl_pulse_irq_timer0();
230: qemu_irq_pulse(s->timer0_irq);
231: }
232:
233: static void timer1_hit(void *opaque)
234: {
235: MilkymistSysctlState *s = opaque;
236:
237: if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
238: s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
239: trace_milkymist_sysctl_stop_timer1();
240: ptimer_stop(s->ptimer1);
241: }
242:
243: trace_milkymist_sysctl_pulse_irq_timer1();
244: qemu_irq_pulse(s->timer1_irq);
245: }
246:
247: static void milkymist_sysctl_reset(DeviceState *d)
248: {
249: MilkymistSysctlState *s =
250: container_of(d, MilkymistSysctlState, busdev.qdev);
251: int i;
252:
253: for (i = 0; i < R_MAX; i++) {
254: s->regs[i] = 0;
255: }
256:
257: ptimer_stop(s->ptimer0);
258: ptimer_stop(s->ptimer1);
259:
260: /* defaults */
261: s->regs[R_ICAP] = ICAP_READY;
262: s->regs[R_SYSTEM_ID] = s->systemid;
1.1.1.3 ! root 263: s->regs[R_CLK_FREQUENCY] = s->freq_hz;
1.1 root 264: s->regs[R_CAPABILITIES] = s->capabilities;
265: s->regs[R_GPIO_IN] = s->strappings;
266: }
267:
268: static int milkymist_sysctl_init(SysBusDevice *dev)
269: {
270: MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
271:
272: sysbus_init_irq(dev, &s->gpio_irq);
273: sysbus_init_irq(dev, &s->timer0_irq);
274: sysbus_init_irq(dev, &s->timer1_irq);
275:
276: s->bh0 = qemu_bh_new(timer0_hit, s);
277: s->bh1 = qemu_bh_new(timer1_hit, s);
278: s->ptimer0 = ptimer_init(s->bh0);
279: s->ptimer1 = ptimer_init(s->bh1);
280: ptimer_set_freq(s->ptimer0, s->freq_hz);
281: ptimer_set_freq(s->ptimer1, s->freq_hz);
282:
1.1.1.2 root 283: memory_region_init_io(&s->regs_region, &sysctl_mmio_ops, s,
284: "milkymist-sysctl", R_MAX * 4);
1.1.1.3 ! root 285: sysbus_init_mmio(dev, &s->regs_region);
1.1 root 286:
287: return 0;
288: }
289:
290: static const VMStateDescription vmstate_milkymist_sysctl = {
291: .name = "milkymist-sysctl",
292: .version_id = 1,
293: .minimum_version_id = 1,
294: .minimum_version_id_old = 1,
295: .fields = (VMStateField[]) {
296: VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
297: VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
298: VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
299: VMSTATE_END_OF_LIST()
300: }
301: };
302:
1.1.1.3 ! root 303: static Property milkymist_sysctl_properties[] = {
! 304: DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
! 305: freq_hz, 80000000),
! 306: DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
! 307: capabilities, 0x00000000),
! 308: DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
! 309: systemid, 0x10014d31),
! 310: DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
! 311: strappings, 0x00000001),
! 312: DEFINE_PROP_END_OF_LIST(),
! 313: };
! 314:
! 315: static void milkymist_sysctl_class_init(ObjectClass *klass, void *data)
! 316: {
! 317: DeviceClass *dc = DEVICE_CLASS(klass);
! 318: SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
! 319:
! 320: k->init = milkymist_sysctl_init;
! 321: dc->reset = milkymist_sysctl_reset;
! 322: dc->vmsd = &vmstate_milkymist_sysctl;
! 323: dc->props = milkymist_sysctl_properties;
! 324: }
! 325:
! 326: static TypeInfo milkymist_sysctl_info = {
! 327: .name = "milkymist-sysctl",
! 328: .parent = TYPE_SYS_BUS_DEVICE,
! 329: .instance_size = sizeof(MilkymistSysctlState),
! 330: .class_init = milkymist_sysctl_class_init,
1.1 root 331: };
332:
1.1.1.3 ! root 333: static void milkymist_sysctl_register_types(void)
1.1 root 334: {
1.1.1.3 ! root 335: type_register_static(&milkymist_sysctl_info);
1.1 root 336: }
337:
1.1.1.3 ! root 338: type_init(milkymist_sysctl_register_types)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.