root / hw / puv3_ost.c @ a1bc20df
History | View | Annotate | Download (3.6 kB)
1 | 56d07a90 | Guan Xuetao | /*
|
---|---|---|---|
2 | 56d07a90 | Guan Xuetao | * OSTimer device simulation in PKUnity SoC
|
3 | 56d07a90 | Guan Xuetao | *
|
4 | 56d07a90 | Guan Xuetao | * Copyright (C) 2010-2012 Guan Xuetao
|
5 | 56d07a90 | Guan Xuetao | *
|
6 | 56d07a90 | Guan Xuetao | * This program is free software; you can redistribute it and/or modify
|
7 | 56d07a90 | Guan Xuetao | * it under the terms of the GNU General Public License version 2 as
|
8 | 56d07a90 | Guan Xuetao | * published by the Free Software Foundation, or any later version.
|
9 | 56d07a90 | Guan Xuetao | * See the COPYING file in the top-level directory.
|
10 | 56d07a90 | Guan Xuetao | */
|
11 | 56d07a90 | Guan Xuetao | #include "sysbus.h" |
12 | 56d07a90 | Guan Xuetao | #include "ptimer.h" |
13 | 56d07a90 | Guan Xuetao | |
14 | 56d07a90 | Guan Xuetao | #undef DEBUG_PUV3
|
15 | 56d07a90 | Guan Xuetao | #include "puv3.h" |
16 | 56d07a90 | Guan Xuetao | |
17 | 56d07a90 | Guan Xuetao | /* puv3 ostimer implementation. */
|
18 | 56d07a90 | Guan Xuetao | typedef struct { |
19 | 56d07a90 | Guan Xuetao | SysBusDevice busdev; |
20 | 56d07a90 | Guan Xuetao | MemoryRegion iomem; |
21 | 56d07a90 | Guan Xuetao | QEMUBH *bh; |
22 | 56d07a90 | Guan Xuetao | qemu_irq irq; |
23 | 56d07a90 | Guan Xuetao | ptimer_state *ptimer; |
24 | 56d07a90 | Guan Xuetao | |
25 | 56d07a90 | Guan Xuetao | uint32_t reg_OSMR0; |
26 | 56d07a90 | Guan Xuetao | uint32_t reg_OSCR; |
27 | 56d07a90 | Guan Xuetao | uint32_t reg_OSSR; |
28 | 56d07a90 | Guan Xuetao | uint32_t reg_OIER; |
29 | 56d07a90 | Guan Xuetao | } PUV3OSTState; |
30 | 56d07a90 | Guan Xuetao | |
31 | a8170e5e | Avi Kivity | static uint64_t puv3_ost_read(void *opaque, hwaddr offset, |
32 | 56d07a90 | Guan Xuetao | unsigned size)
|
33 | 56d07a90 | Guan Xuetao | { |
34 | 56d07a90 | Guan Xuetao | PUV3OSTState *s = opaque; |
35 | 56d07a90 | Guan Xuetao | uint32_t ret = 0;
|
36 | 56d07a90 | Guan Xuetao | |
37 | 56d07a90 | Guan Xuetao | switch (offset) {
|
38 | 56d07a90 | Guan Xuetao | case 0x10: /* Counter Register */ |
39 | 56d07a90 | Guan Xuetao | ret = s->reg_OSMR0 - (uint32_t)ptimer_get_count(s->ptimer); |
40 | 56d07a90 | Guan Xuetao | break;
|
41 | 56d07a90 | Guan Xuetao | case 0x14: /* Status Register */ |
42 | 56d07a90 | Guan Xuetao | ret = s->reg_OSSR; |
43 | 56d07a90 | Guan Xuetao | break;
|
44 | 56d07a90 | Guan Xuetao | case 0x1c: /* Interrupt Enable Register */ |
45 | 56d07a90 | Guan Xuetao | ret = s->reg_OIER; |
46 | 56d07a90 | Guan Xuetao | break;
|
47 | 56d07a90 | Guan Xuetao | default:
|
48 | 56d07a90 | Guan Xuetao | DPRINTF("Bad offset %x\n", (int)offset); |
49 | 56d07a90 | Guan Xuetao | } |
50 | 56d07a90 | Guan Xuetao | DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
|
51 | 56d07a90 | Guan Xuetao | return ret;
|
52 | 56d07a90 | Guan Xuetao | } |
53 | 56d07a90 | Guan Xuetao | |
54 | a8170e5e | Avi Kivity | static void puv3_ost_write(void *opaque, hwaddr offset, |
55 | 56d07a90 | Guan Xuetao | uint64_t value, unsigned size)
|
56 | 56d07a90 | Guan Xuetao | { |
57 | 56d07a90 | Guan Xuetao | PUV3OSTState *s = opaque; |
58 | 56d07a90 | Guan Xuetao | |
59 | 56d07a90 | Guan Xuetao | DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
|
60 | 56d07a90 | Guan Xuetao | switch (offset) {
|
61 | 56d07a90 | Guan Xuetao | case 0x00: /* Match Register 0 */ |
62 | 56d07a90 | Guan Xuetao | s->reg_OSMR0 = value; |
63 | 56d07a90 | Guan Xuetao | if (s->reg_OSMR0 > s->reg_OSCR) {
|
64 | 56d07a90 | Guan Xuetao | ptimer_set_count(s->ptimer, s->reg_OSMR0 - s->reg_OSCR); |
65 | 56d07a90 | Guan Xuetao | } else {
|
66 | 56d07a90 | Guan Xuetao | ptimer_set_count(s->ptimer, s->reg_OSMR0 + |
67 | 56d07a90 | Guan Xuetao | (0xffffffff - s->reg_OSCR));
|
68 | 56d07a90 | Guan Xuetao | } |
69 | 56d07a90 | Guan Xuetao | ptimer_run(s->ptimer, 2);
|
70 | 56d07a90 | Guan Xuetao | break;
|
71 | 56d07a90 | Guan Xuetao | case 0x14: /* Status Register */ |
72 | 56d07a90 | Guan Xuetao | assert(value == 0);
|
73 | 56d07a90 | Guan Xuetao | if (s->reg_OSSR) {
|
74 | 56d07a90 | Guan Xuetao | s->reg_OSSR = value; |
75 | 56d07a90 | Guan Xuetao | qemu_irq_lower(s->irq); |
76 | 56d07a90 | Guan Xuetao | } |
77 | 56d07a90 | Guan Xuetao | break;
|
78 | 56d07a90 | Guan Xuetao | case 0x1c: /* Interrupt Enable Register */ |
79 | 56d07a90 | Guan Xuetao | s->reg_OIER = value; |
80 | 56d07a90 | Guan Xuetao | break;
|
81 | 56d07a90 | Guan Xuetao | default:
|
82 | 56d07a90 | Guan Xuetao | DPRINTF("Bad offset %x\n", (int)offset); |
83 | 56d07a90 | Guan Xuetao | } |
84 | 56d07a90 | Guan Xuetao | } |
85 | 56d07a90 | Guan Xuetao | |
86 | 56d07a90 | Guan Xuetao | static const MemoryRegionOps puv3_ost_ops = { |
87 | 56d07a90 | Guan Xuetao | .read = puv3_ost_read, |
88 | 56d07a90 | Guan Xuetao | .write = puv3_ost_write, |
89 | 56d07a90 | Guan Xuetao | .impl = { |
90 | 56d07a90 | Guan Xuetao | .min_access_size = 4,
|
91 | 56d07a90 | Guan Xuetao | .max_access_size = 4,
|
92 | 56d07a90 | Guan Xuetao | }, |
93 | 56d07a90 | Guan Xuetao | .endianness = DEVICE_NATIVE_ENDIAN, |
94 | 56d07a90 | Guan Xuetao | }; |
95 | 56d07a90 | Guan Xuetao | |
96 | 56d07a90 | Guan Xuetao | static void puv3_ost_tick(void *opaque) |
97 | 56d07a90 | Guan Xuetao | { |
98 | 56d07a90 | Guan Xuetao | PUV3OSTState *s = opaque; |
99 | 56d07a90 | Guan Xuetao | |
100 | 56d07a90 | Guan Xuetao | DPRINTF("ost hit when ptimer counter from 0x%x to 0x%x!\n",
|
101 | 56d07a90 | Guan Xuetao | s->reg_OSCR, s->reg_OSMR0); |
102 | 56d07a90 | Guan Xuetao | |
103 | 56d07a90 | Guan Xuetao | s->reg_OSCR = s->reg_OSMR0; |
104 | 56d07a90 | Guan Xuetao | if (s->reg_OIER) {
|
105 | 56d07a90 | Guan Xuetao | s->reg_OSSR = 1;
|
106 | 56d07a90 | Guan Xuetao | qemu_irq_raise(s->irq); |
107 | 56d07a90 | Guan Xuetao | } |
108 | 56d07a90 | Guan Xuetao | } |
109 | 56d07a90 | Guan Xuetao | |
110 | 56d07a90 | Guan Xuetao | static int puv3_ost_init(SysBusDevice *dev) |
111 | 56d07a90 | Guan Xuetao | { |
112 | 56d07a90 | Guan Xuetao | PUV3OSTState *s = FROM_SYSBUS(PUV3OSTState, dev); |
113 | 56d07a90 | Guan Xuetao | |
114 | 56d07a90 | Guan Xuetao | s->reg_OIER = 0;
|
115 | 56d07a90 | Guan Xuetao | s->reg_OSSR = 0;
|
116 | 56d07a90 | Guan Xuetao | s->reg_OSMR0 = 0;
|
117 | 56d07a90 | Guan Xuetao | s->reg_OSCR = 0;
|
118 | 56d07a90 | Guan Xuetao | |
119 | 56d07a90 | Guan Xuetao | sysbus_init_irq(dev, &s->irq); |
120 | 56d07a90 | Guan Xuetao | |
121 | 56d07a90 | Guan Xuetao | s->bh = qemu_bh_new(puv3_ost_tick, s); |
122 | 56d07a90 | Guan Xuetao | s->ptimer = ptimer_init(s->bh); |
123 | 56d07a90 | Guan Xuetao | ptimer_set_freq(s->ptimer, 50 * 1000 * 1000); |
124 | 56d07a90 | Guan Xuetao | |
125 | 56d07a90 | Guan Xuetao | memory_region_init_io(&s->iomem, &puv3_ost_ops, s, "puv3_ost",
|
126 | 56d07a90 | Guan Xuetao | PUV3_REGS_OFFSET); |
127 | 56d07a90 | Guan Xuetao | sysbus_init_mmio(dev, &s->iomem); |
128 | 56d07a90 | Guan Xuetao | |
129 | 56d07a90 | Guan Xuetao | return 0; |
130 | 56d07a90 | Guan Xuetao | } |
131 | 56d07a90 | Guan Xuetao | |
132 | 56d07a90 | Guan Xuetao | static void puv3_ost_class_init(ObjectClass *klass, void *data) |
133 | 56d07a90 | Guan Xuetao | { |
134 | 56d07a90 | Guan Xuetao | SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); |
135 | 56d07a90 | Guan Xuetao | |
136 | 56d07a90 | Guan Xuetao | sdc->init = puv3_ost_init; |
137 | 56d07a90 | Guan Xuetao | } |
138 | 56d07a90 | Guan Xuetao | |
139 | 56d07a90 | Guan Xuetao | static const TypeInfo puv3_ost_info = { |
140 | 56d07a90 | Guan Xuetao | .name = "puv3_ost",
|
141 | 56d07a90 | Guan Xuetao | .parent = TYPE_SYS_BUS_DEVICE, |
142 | 56d07a90 | Guan Xuetao | .instance_size = sizeof(PUV3OSTState),
|
143 | 56d07a90 | Guan Xuetao | .class_init = puv3_ost_class_init, |
144 | 56d07a90 | Guan Xuetao | }; |
145 | 56d07a90 | Guan Xuetao | |
146 | 56d07a90 | Guan Xuetao | static void puv3_ost_register_type(void) |
147 | 56d07a90 | Guan Xuetao | { |
148 | 56d07a90 | Guan Xuetao | type_register_static(&puv3_ost_info); |
149 | 56d07a90 | Guan Xuetao | } |
150 | 56d07a90 | Guan Xuetao | |
151 | 56d07a90 | Guan Xuetao | type_init(puv3_ost_register_type) |