root / hw / imx_timer.c @ 7e0a9247
History | View | Annotate | Download (18.3 kB)
1 | 78d1404d | Peter Chubb | /*
|
---|---|---|---|
2 | 78d1404d | Peter Chubb | * IMX31 Timer
|
3 | 78d1404d | Peter Chubb | *
|
4 | 78d1404d | Peter Chubb | * Copyright (c) 2008 OK Labs
|
5 | 78d1404d | Peter Chubb | * Copyright (c) 2011 NICTA Pty Ltd
|
6 | aade7b91 | Stefan Weil | * Originally written by Hans Jiang
|
7 | 78d1404d | Peter Chubb | * Updated by Peter Chubb
|
8 | 78d1404d | Peter Chubb | *
|
9 | aade7b91 | Stefan Weil | * This code is licensed under GPL version 2 or later. See
|
10 | 78d1404d | Peter Chubb | * the COPYING file in the top-level directory.
|
11 | 78d1404d | Peter Chubb | *
|
12 | 78d1404d | Peter Chubb | */
|
13 | 78d1404d | Peter Chubb | |
14 | 78d1404d | Peter Chubb | #include "hw.h" |
15 | 78d1404d | Peter Chubb | #include "qemu-timer.h" |
16 | 78d1404d | Peter Chubb | #include "ptimer.h" |
17 | 78d1404d | Peter Chubb | #include "sysbus.h" |
18 | 78d1404d | Peter Chubb | #include "imx.h" |
19 | 78d1404d | Peter Chubb | |
20 | 78d1404d | Peter Chubb | //#define DEBUG_TIMER 1
|
21 | 78d1404d | Peter Chubb | #ifdef DEBUG_TIMER
|
22 | 78d1404d | Peter Chubb | # define DPRINTF(fmt, args...) \
|
23 | 78d1404d | Peter Chubb | do { printf("imx_timer: " fmt , ##args); } while (0) |
24 | 78d1404d | Peter Chubb | #else
|
25 | 78d1404d | Peter Chubb | # define DPRINTF(fmt, args...) do {} while (0) |
26 | 78d1404d | Peter Chubb | #endif
|
27 | 78d1404d | Peter Chubb | |
28 | 78d1404d | Peter Chubb | /*
|
29 | 78d1404d | Peter Chubb | * Define to 1 for messages about attempts to
|
30 | 78d1404d | Peter Chubb | * access unimplemented registers or similar.
|
31 | 78d1404d | Peter Chubb | */
|
32 | 78d1404d | Peter Chubb | #define DEBUG_IMPLEMENTATION 1 |
33 | 78d1404d | Peter Chubb | #if DEBUG_IMPLEMENTATION
|
34 | 78d1404d | Peter Chubb | # define IPRINTF(fmt, args...) \
|
35 | 78d1404d | Peter Chubb | do { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0) |
36 | 78d1404d | Peter Chubb | #else
|
37 | 78d1404d | Peter Chubb | # define IPRINTF(fmt, args...) do {} while (0) |
38 | 78d1404d | Peter Chubb | #endif
|
39 | 78d1404d | Peter Chubb | |
40 | 78d1404d | Peter Chubb | /*
|
41 | 78d1404d | Peter Chubb | * GPT : General purpose timer
|
42 | 78d1404d | Peter Chubb | *
|
43 | 78d1404d | Peter Chubb | * This timer counts up continuously while it is enabled, resetting itself
|
44 | 78d1404d | Peter Chubb | * to 0 when it reaches TIMER_MAX (in freerun mode) or when it
|
45 | 78d1404d | Peter Chubb | * reaches the value of ocr1 (in periodic mode). WE simulate this using a
|
46 | 78d1404d | Peter Chubb | * QEMU ptimer counting down from ocr1 and reloading from ocr1 in
|
47 | 78d1404d | Peter Chubb | * periodic mode, or counting from ocr1 to zero, then TIMER_MAX - ocr1.
|
48 | 78d1404d | Peter Chubb | * waiting_rov is set when counting from TIMER_MAX.
|
49 | 78d1404d | Peter Chubb | *
|
50 | 78d1404d | Peter Chubb | * In the real hardware, there are three comparison registers that can
|
51 | 78d1404d | Peter Chubb | * trigger interrupts, and compare channel 1 can be used to
|
52 | 78d1404d | Peter Chubb | * force-reset the timer. However, this is a `bare-bones'
|
53 | 78d1404d | Peter Chubb | * implementation: only what Linux 3.x uses has been implemented
|
54 | 78d1404d | Peter Chubb | * (free-running timer from 0 to OCR1 or TIMER_MAX) .
|
55 | 78d1404d | Peter Chubb | */
|
56 | 78d1404d | Peter Chubb | |
57 | 78d1404d | Peter Chubb | |
58 | 78d1404d | Peter Chubb | #define TIMER_MAX 0XFFFFFFFFUL |
59 | 78d1404d | Peter Chubb | |
60 | 78d1404d | Peter Chubb | /* Control register. Not all of these bits have any effect (yet) */
|
61 | 78d1404d | Peter Chubb | #define GPT_CR_EN (1 << 0) /* GPT Enable */ |
62 | 78d1404d | Peter Chubb | #define GPT_CR_ENMOD (1 << 1) /* GPT Enable Mode */ |
63 | 78d1404d | Peter Chubb | #define GPT_CR_DBGEN (1 << 2) /* GPT Debug mode enable */ |
64 | 78d1404d | Peter Chubb | #define GPT_CR_WAITEN (1 << 3) /* GPT Wait Mode Enable */ |
65 | 78d1404d | Peter Chubb | #define GPT_CR_DOZEN (1 << 4) /* GPT Doze mode enable */ |
66 | 78d1404d | Peter Chubb | #define GPT_CR_STOPEN (1 << 5) /* GPT Stop Mode Enable */ |
67 | 78d1404d | Peter Chubb | #define GPT_CR_CLKSRC_SHIFT (6) |
68 | 78d1404d | Peter Chubb | #define GPT_CR_CLKSRC_MASK (0x7) |
69 | 78d1404d | Peter Chubb | |
70 | 78d1404d | Peter Chubb | #define GPT_CR_FRR (1 << 9) /* Freerun or Restart */ |
71 | 78d1404d | Peter Chubb | #define GPT_CR_SWR (1 << 15) /* Software Reset */ |
72 | 78d1404d | Peter Chubb | #define GPT_CR_IM1 (3 << 16) /* Input capture channel 1 mode (2 bits) */ |
73 | 78d1404d | Peter Chubb | #define GPT_CR_IM2 (3 << 18) /* Input capture channel 2 mode (2 bits) */ |
74 | 78d1404d | Peter Chubb | #define GPT_CR_OM1 (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */ |
75 | 78d1404d | Peter Chubb | #define GPT_CR_OM2 (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */ |
76 | 78d1404d | Peter Chubb | #define GPT_CR_OM3 (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */ |
77 | 78d1404d | Peter Chubb | #define GPT_CR_FO1 (1 << 29) /* Force Output Compare Channel 1 */ |
78 | 78d1404d | Peter Chubb | #define GPT_CR_FO2 (1 << 30) /* Force Output Compare Channel 2 */ |
79 | 78d1404d | Peter Chubb | #define GPT_CR_FO3 (1 << 31) /* Force Output Compare Channel 3 */ |
80 | 78d1404d | Peter Chubb | |
81 | 78d1404d | Peter Chubb | #define GPT_SR_OF1 (1 << 0) |
82 | 78d1404d | Peter Chubb | #define GPT_SR_ROV (1 << 5) |
83 | 78d1404d | Peter Chubb | |
84 | 78d1404d | Peter Chubb | #define GPT_IR_OF1IE (1 << 0) |
85 | 78d1404d | Peter Chubb | #define GPT_IR_ROVIE (1 << 5) |
86 | 78d1404d | Peter Chubb | |
87 | 78d1404d | Peter Chubb | typedef struct { |
88 | 78d1404d | Peter Chubb | SysBusDevice busdev; |
89 | 78d1404d | Peter Chubb | ptimer_state *timer; |
90 | 78d1404d | Peter Chubb | MemoryRegion iomem; |
91 | 78d1404d | Peter Chubb | DeviceState *ccm; |
92 | 78d1404d | Peter Chubb | |
93 | 78d1404d | Peter Chubb | uint32_t cr; |
94 | 78d1404d | Peter Chubb | uint32_t pr; |
95 | 78d1404d | Peter Chubb | uint32_t sr; |
96 | 78d1404d | Peter Chubb | uint32_t ir; |
97 | 78d1404d | Peter Chubb | uint32_t ocr1; |
98 | 78d1404d | Peter Chubb | uint32_t cnt; |
99 | 78d1404d | Peter Chubb | |
100 | 78d1404d | Peter Chubb | uint32_t waiting_rov; |
101 | 78d1404d | Peter Chubb | qemu_irq irq; |
102 | 78d1404d | Peter Chubb | } IMXTimerGState; |
103 | 78d1404d | Peter Chubb | |
104 | 78d1404d | Peter Chubb | static const VMStateDescription vmstate_imx_timerg = { |
105 | 78d1404d | Peter Chubb | .name = "imx-timerg",
|
106 | 78d1404d | Peter Chubb | .version_id = 1,
|
107 | 78d1404d | Peter Chubb | .minimum_version_id = 1,
|
108 | 78d1404d | Peter Chubb | .minimum_version_id_old = 1,
|
109 | 78d1404d | Peter Chubb | .fields = (VMStateField[]) { |
110 | 78d1404d | Peter Chubb | VMSTATE_UINT32(cr, IMXTimerGState), |
111 | 78d1404d | Peter Chubb | VMSTATE_UINT32(pr, IMXTimerGState), |
112 | 78d1404d | Peter Chubb | VMSTATE_UINT32(sr, IMXTimerGState), |
113 | 78d1404d | Peter Chubb | VMSTATE_UINT32(ir, IMXTimerGState), |
114 | 78d1404d | Peter Chubb | VMSTATE_UINT32(ocr1, IMXTimerGState), |
115 | 78d1404d | Peter Chubb | VMSTATE_UINT32(cnt, IMXTimerGState), |
116 | 78d1404d | Peter Chubb | VMSTATE_UINT32(waiting_rov, IMXTimerGState), |
117 | 78d1404d | Peter Chubb | VMSTATE_PTIMER(timer, IMXTimerGState), |
118 | 78d1404d | Peter Chubb | VMSTATE_END_OF_LIST() |
119 | 78d1404d | Peter Chubb | } |
120 | 78d1404d | Peter Chubb | }; |
121 | 78d1404d | Peter Chubb | |
122 | 78d1404d | Peter Chubb | static const IMXClk imx_timerg_clocks[] = { |
123 | 78d1404d | Peter Chubb | NOCLK, /* 000 No clock source */
|
124 | 78d1404d | Peter Chubb | IPG, /* 001 ipg_clk, 532MHz*/
|
125 | 78d1404d | Peter Chubb | IPG, /* 010 ipg_clk_highfreq */
|
126 | 78d1404d | Peter Chubb | NOCLK, /* 011 not defined */
|
127 | 78d1404d | Peter Chubb | CLK_32k, /* 100 ipg_clk_32k */
|
128 | 78d1404d | Peter Chubb | NOCLK, /* 101 not defined */
|
129 | 78d1404d | Peter Chubb | NOCLK, /* 110 not defined */
|
130 | 78d1404d | Peter Chubb | NOCLK, /* 111 not defined */
|
131 | 78d1404d | Peter Chubb | }; |
132 | 78d1404d | Peter Chubb | |
133 | 78d1404d | Peter Chubb | |
134 | 78d1404d | Peter Chubb | static void imx_timerg_set_freq(IMXTimerGState *s) |
135 | 78d1404d | Peter Chubb | { |
136 | 78d1404d | Peter Chubb | int clksrc;
|
137 | 78d1404d | Peter Chubb | uint32_t freq; |
138 | 78d1404d | Peter Chubb | |
139 | 78d1404d | Peter Chubb | clksrc = (s->cr >> GPT_CR_CLKSRC_SHIFT) & GPT_CR_CLKSRC_MASK; |
140 | 78d1404d | Peter Chubb | freq = imx_clock_frequency(s->ccm, imx_timerg_clocks[clksrc]) / (1 + s->pr);
|
141 | 78d1404d | Peter Chubb | |
142 | 78d1404d | Peter Chubb | DPRINTF("Setting gtimer clksrc %d to frequency %d\n", clksrc, freq);
|
143 | 78d1404d | Peter Chubb | if (freq) {
|
144 | 78d1404d | Peter Chubb | ptimer_set_freq(s->timer, freq); |
145 | 78d1404d | Peter Chubb | } |
146 | 78d1404d | Peter Chubb | } |
147 | 78d1404d | Peter Chubb | |
148 | 78d1404d | Peter Chubb | static void imx_timerg_update(IMXTimerGState *s) |
149 | 78d1404d | Peter Chubb | { |
150 | 78d1404d | Peter Chubb | uint32_t flags = s->sr & s->ir & (GPT_SR_OF1 | GPT_SR_ROV); |
151 | 78d1404d | Peter Chubb | |
152 | 78d1404d | Peter Chubb | DPRINTF("g-timer SR: %s %s IR=%s %s, %s\n",
|
153 | 78d1404d | Peter Chubb | s->sr & GPT_SR_OF1 ? "OF1" : "", |
154 | 78d1404d | Peter Chubb | s->sr & GPT_SR_ROV ? "ROV" : "", |
155 | 78d1404d | Peter Chubb | s->ir & GPT_SR_OF1 ? "OF1" : "", |
156 | 78d1404d | Peter Chubb | s->ir & GPT_SR_ROV ? "ROV" : "", |
157 | 78d1404d | Peter Chubb | s->cr & GPT_CR_EN ? "CR_EN" : "Not Enabled"); |
158 | 78d1404d | Peter Chubb | |
159 | 78d1404d | Peter Chubb | |
160 | 78d1404d | Peter Chubb | qemu_set_irq(s->irq, (s->cr & GPT_CR_EN) && flags); |
161 | 78d1404d | Peter Chubb | } |
162 | 78d1404d | Peter Chubb | |
163 | 78d1404d | Peter Chubb | static uint32_t imx_timerg_update_counts(IMXTimerGState *s)
|
164 | 78d1404d | Peter Chubb | { |
165 | 78d1404d | Peter Chubb | uint64_t target = s->waiting_rov ? TIMER_MAX : s->ocr1; |
166 | 78d1404d | Peter Chubb | uint64_t cnt = ptimer_get_count(s->timer); |
167 | 78d1404d | Peter Chubb | s->cnt = target - cnt; |
168 | 78d1404d | Peter Chubb | return s->cnt;
|
169 | 78d1404d | Peter Chubb | } |
170 | 78d1404d | Peter Chubb | |
171 | 78d1404d | Peter Chubb | static void imx_timerg_reload(IMXTimerGState *s, uint32_t timeout) |
172 | 78d1404d | Peter Chubb | { |
173 | 78d1404d | Peter Chubb | uint64_t diff_cnt; |
174 | 78d1404d | Peter Chubb | |
175 | 78d1404d | Peter Chubb | if (!(s->cr & GPT_CR_FRR)) {
|
176 | 78d1404d | Peter Chubb | IPRINTF("IMX_timerg_reload --- called in reset-mode\n");
|
177 | 78d1404d | Peter Chubb | return;
|
178 | 78d1404d | Peter Chubb | } |
179 | 78d1404d | Peter Chubb | |
180 | 78d1404d | Peter Chubb | /*
|
181 | 78d1404d | Peter Chubb | * For small timeouts, qemu sometimes runs too slow.
|
182 | 78d1404d | Peter Chubb | * Better deliver a late interrupt than none.
|
183 | 78d1404d | Peter Chubb | *
|
184 | 78d1404d | Peter Chubb | * In Reset mode (FRR bit clear)
|
185 | 78d1404d | Peter Chubb | * the ptimer reloads itself from OCR1;
|
186 | 78d1404d | Peter Chubb | * in free-running mode we need to fake
|
187 | 78d1404d | Peter Chubb | * running from 0 to ocr1 to TIMER_MAX
|
188 | 78d1404d | Peter Chubb | */
|
189 | 78d1404d | Peter Chubb | if (timeout > s->cnt) {
|
190 | 78d1404d | Peter Chubb | diff_cnt = timeout - s->cnt; |
191 | 78d1404d | Peter Chubb | } else {
|
192 | 78d1404d | Peter Chubb | diff_cnt = 0;
|
193 | 78d1404d | Peter Chubb | } |
194 | 78d1404d | Peter Chubb | ptimer_set_count(s->timer, diff_cnt); |
195 | 78d1404d | Peter Chubb | } |
196 | 78d1404d | Peter Chubb | |
197 | a8170e5e | Avi Kivity | static uint64_t imx_timerg_read(void *opaque, hwaddr offset, |
198 | 78d1404d | Peter Chubb | unsigned size)
|
199 | 78d1404d | Peter Chubb | { |
200 | 78d1404d | Peter Chubb | IMXTimerGState *s = (IMXTimerGState *)opaque; |
201 | 78d1404d | Peter Chubb | |
202 | 78d1404d | Peter Chubb | DPRINTF("g-read(offset=%x)", offset >> 2); |
203 | 78d1404d | Peter Chubb | switch (offset >> 2) { |
204 | 78d1404d | Peter Chubb | case 0: /* Control Register */ |
205 | 78d1404d | Peter Chubb | DPRINTF(" cr = %x\n", s->cr);
|
206 | 78d1404d | Peter Chubb | return s->cr;
|
207 | 78d1404d | Peter Chubb | |
208 | 78d1404d | Peter Chubb | case 1: /* prescaler */ |
209 | 78d1404d | Peter Chubb | DPRINTF(" pr = %x\n", s->pr);
|
210 | 78d1404d | Peter Chubb | return s->pr;
|
211 | 78d1404d | Peter Chubb | |
212 | 78d1404d | Peter Chubb | case 2: /* Status Register */ |
213 | 78d1404d | Peter Chubb | DPRINTF(" sr = %x\n", s->sr);
|
214 | 78d1404d | Peter Chubb | return s->sr;
|
215 | 78d1404d | Peter Chubb | |
216 | 78d1404d | Peter Chubb | case 3: /* Interrupt Register */ |
217 | 78d1404d | Peter Chubb | DPRINTF(" ir = %x\n", s->ir);
|
218 | 78d1404d | Peter Chubb | return s->ir;
|
219 | 78d1404d | Peter Chubb | |
220 | 78d1404d | Peter Chubb | case 4: /* Output Compare Register 1 */ |
221 | 78d1404d | Peter Chubb | DPRINTF(" ocr1 = %x\n", s->ocr1);
|
222 | 78d1404d | Peter Chubb | return s->ocr1;
|
223 | 78d1404d | Peter Chubb | |
224 | 78d1404d | Peter Chubb | |
225 | 78d1404d | Peter Chubb | case 9: /* cnt */ |
226 | 78d1404d | Peter Chubb | imx_timerg_update_counts(s); |
227 | 78d1404d | Peter Chubb | DPRINTF(" cnt = %x\n", s->cnt);
|
228 | 78d1404d | Peter Chubb | return s->cnt;
|
229 | 78d1404d | Peter Chubb | } |
230 | 78d1404d | Peter Chubb | |
231 | 78d1404d | Peter Chubb | IPRINTF("imx_timerg_read: Bad offset %x\n",
|
232 | 78d1404d | Peter Chubb | (int)offset >> 2); |
233 | 78d1404d | Peter Chubb | return 0; |
234 | 78d1404d | Peter Chubb | } |
235 | 78d1404d | Peter Chubb | |
236 | 78d1404d | Peter Chubb | static void imx_timerg_reset(DeviceState *dev) |
237 | 78d1404d | Peter Chubb | { |
238 | 78d1404d | Peter Chubb | IMXTimerGState *s = container_of(dev, IMXTimerGState, busdev.qdev); |
239 | 78d1404d | Peter Chubb | |
240 | 78d1404d | Peter Chubb | /*
|
241 | 78d1404d | Peter Chubb | * Soft reset doesn't touch some bits; hard reset clears them
|
242 | 78d1404d | Peter Chubb | */
|
243 | 78d1404d | Peter Chubb | s->cr &= ~(GPT_CR_EN|GPT_CR_DOZEN|GPT_CR_WAITEN|GPT_CR_DBGEN); |
244 | 78d1404d | Peter Chubb | s->sr = 0;
|
245 | 78d1404d | Peter Chubb | s->pr = 0;
|
246 | 78d1404d | Peter Chubb | s->ir = 0;
|
247 | 78d1404d | Peter Chubb | s->cnt = 0;
|
248 | 78d1404d | Peter Chubb | s->ocr1 = TIMER_MAX; |
249 | 78d1404d | Peter Chubb | ptimer_stop(s->timer); |
250 | 78d1404d | Peter Chubb | ptimer_set_limit(s->timer, TIMER_MAX, 1);
|
251 | 78d1404d | Peter Chubb | imx_timerg_set_freq(s); |
252 | 78d1404d | Peter Chubb | } |
253 | 78d1404d | Peter Chubb | |
254 | a8170e5e | Avi Kivity | static void imx_timerg_write(void *opaque, hwaddr offset, |
255 | 78d1404d | Peter Chubb | uint64_t value, unsigned size)
|
256 | 78d1404d | Peter Chubb | { |
257 | 78d1404d | Peter Chubb | IMXTimerGState *s = (IMXTimerGState *)opaque; |
258 | 78d1404d | Peter Chubb | DPRINTF("g-write(offset=%x, value = 0x%x)\n", (unsigned int)offset >> 2, |
259 | 78d1404d | Peter Chubb | (unsigned int)value); |
260 | 78d1404d | Peter Chubb | |
261 | 78d1404d | Peter Chubb | switch (offset >> 2) { |
262 | 78d1404d | Peter Chubb | case 0: { |
263 | 78d1404d | Peter Chubb | uint32_t oldcr = s->cr; |
264 | 78d1404d | Peter Chubb | /* CR */
|
265 | 78d1404d | Peter Chubb | if (value & GPT_CR_SWR) { /* force reset */ |
266 | 78d1404d | Peter Chubb | value &= ~GPT_CR_SWR; |
267 | 78d1404d | Peter Chubb | imx_timerg_reset(&s->busdev.qdev); |
268 | 78d1404d | Peter Chubb | imx_timerg_update(s); |
269 | 78d1404d | Peter Chubb | } |
270 | 78d1404d | Peter Chubb | |
271 | 78d1404d | Peter Chubb | s->cr = value & ~0x7c00;
|
272 | 78d1404d | Peter Chubb | imx_timerg_set_freq(s); |
273 | 78d1404d | Peter Chubb | if ((oldcr ^ value) & GPT_CR_EN) {
|
274 | 78d1404d | Peter Chubb | if (value & GPT_CR_EN) {
|
275 | 78d1404d | Peter Chubb | if (value & GPT_CR_ENMOD) {
|
276 | 78d1404d | Peter Chubb | ptimer_set_count(s->timer, s->ocr1); |
277 | 78d1404d | Peter Chubb | s->cnt = 0;
|
278 | 78d1404d | Peter Chubb | } |
279 | 78d1404d | Peter Chubb | ptimer_run(s->timer, |
280 | 78d1404d | Peter Chubb | (value & GPT_CR_FRR) && (s->ocr1 != TIMER_MAX)); |
281 | 78d1404d | Peter Chubb | } else {
|
282 | 78d1404d | Peter Chubb | ptimer_stop(s->timer); |
283 | 78d1404d | Peter Chubb | }; |
284 | 78d1404d | Peter Chubb | } |
285 | 78d1404d | Peter Chubb | return;
|
286 | 78d1404d | Peter Chubb | } |
287 | 78d1404d | Peter Chubb | |
288 | 78d1404d | Peter Chubb | case 1: /* Prescaler */ |
289 | 78d1404d | Peter Chubb | s->pr = value & 0xfff;
|
290 | 78d1404d | Peter Chubb | imx_timerg_set_freq(s); |
291 | 78d1404d | Peter Chubb | return;
|
292 | 78d1404d | Peter Chubb | |
293 | 78d1404d | Peter Chubb | case 2: /* SR */ |
294 | 78d1404d | Peter Chubb | /*
|
295 | 78d1404d | Peter Chubb | * No point in implementing the status register bits to do with
|
296 | 78d1404d | Peter Chubb | * external interrupt sources.
|
297 | 78d1404d | Peter Chubb | */
|
298 | 78d1404d | Peter Chubb | value &= GPT_SR_OF1 | GPT_SR_ROV; |
299 | 78d1404d | Peter Chubb | s->sr &= ~value; |
300 | 78d1404d | Peter Chubb | imx_timerg_update(s); |
301 | 78d1404d | Peter Chubb | return;
|
302 | 78d1404d | Peter Chubb | |
303 | 78d1404d | Peter Chubb | case 3: /* IR -- interrupt register */ |
304 | 78d1404d | Peter Chubb | s->ir = value & 0x3f;
|
305 | 78d1404d | Peter Chubb | imx_timerg_update(s); |
306 | 78d1404d | Peter Chubb | return;
|
307 | 78d1404d | Peter Chubb | |
308 | 78d1404d | Peter Chubb | case 4: /* OCR1 -- output compare register */ |
309 | 78d1404d | Peter Chubb | /* In non-freerun mode, reset count when this register is written */
|
310 | 78d1404d | Peter Chubb | if (!(s->cr & GPT_CR_FRR)) {
|
311 | 78d1404d | Peter Chubb | s->waiting_rov = 0;
|
312 | 78d1404d | Peter Chubb | ptimer_set_limit(s->timer, value, 1);
|
313 | 78d1404d | Peter Chubb | } else {
|
314 | 78d1404d | Peter Chubb | imx_timerg_update_counts(s); |
315 | 78d1404d | Peter Chubb | if (value > s->cnt) {
|
316 | 78d1404d | Peter Chubb | s->waiting_rov = 0;
|
317 | 78d1404d | Peter Chubb | imx_timerg_reload(s, value); |
318 | 78d1404d | Peter Chubb | } else {
|
319 | 78d1404d | Peter Chubb | s->waiting_rov = 1;
|
320 | 78d1404d | Peter Chubb | imx_timerg_reload(s, TIMER_MAX - s->cnt); |
321 | 78d1404d | Peter Chubb | } |
322 | 78d1404d | Peter Chubb | } |
323 | 78d1404d | Peter Chubb | s->ocr1 = value; |
324 | 78d1404d | Peter Chubb | return;
|
325 | 78d1404d | Peter Chubb | |
326 | 78d1404d | Peter Chubb | default:
|
327 | 78d1404d | Peter Chubb | IPRINTF("imx_timerg_write: Bad offset %x\n",
|
328 | 78d1404d | Peter Chubb | (int)offset >> 2); |
329 | 78d1404d | Peter Chubb | } |
330 | 78d1404d | Peter Chubb | } |
331 | 78d1404d | Peter Chubb | |
332 | 78d1404d | Peter Chubb | static void imx_timerg_timeout(void *opaque) |
333 | 78d1404d | Peter Chubb | { |
334 | 78d1404d | Peter Chubb | IMXTimerGState *s = (IMXTimerGState *)opaque; |
335 | 78d1404d | Peter Chubb | |
336 | 78d1404d | Peter Chubb | DPRINTF("imx_timerg_timeout, waiting rov=%d\n", s->waiting_rov);
|
337 | 78d1404d | Peter Chubb | if (s->cr & GPT_CR_FRR) {
|
338 | 78d1404d | Peter Chubb | /*
|
339 | 78d1404d | Peter Chubb | * Free running timer from 0 -> TIMERMAX
|
340 | 78d1404d | Peter Chubb | * Generates interrupt at TIMER_MAX and at cnt==ocr1
|
341 | 78d1404d | Peter Chubb | * If ocr1 == TIMER_MAX, then no need to reload timer.
|
342 | 78d1404d | Peter Chubb | */
|
343 | 78d1404d | Peter Chubb | if (s->ocr1 == TIMER_MAX) {
|
344 | 78d1404d | Peter Chubb | DPRINTF("s->ocr1 == TIMER_MAX, FRR\n");
|
345 | 78d1404d | Peter Chubb | s->sr |= GPT_SR_OF1 | GPT_SR_ROV; |
346 | 78d1404d | Peter Chubb | imx_timerg_update(s); |
347 | 78d1404d | Peter Chubb | return;
|
348 | 78d1404d | Peter Chubb | } |
349 | 78d1404d | Peter Chubb | |
350 | 78d1404d | Peter Chubb | if (s->waiting_rov) {
|
351 | 78d1404d | Peter Chubb | /*
|
352 | 78d1404d | Peter Chubb | * We were waiting for cnt==TIMER_MAX
|
353 | 78d1404d | Peter Chubb | */
|
354 | 78d1404d | Peter Chubb | s->sr |= GPT_SR_ROV; |
355 | 78d1404d | Peter Chubb | s->waiting_rov = 0;
|
356 | 78d1404d | Peter Chubb | s->cnt = 0;
|
357 | 78d1404d | Peter Chubb | imx_timerg_reload(s, s->ocr1); |
358 | 78d1404d | Peter Chubb | } else {
|
359 | 78d1404d | Peter Chubb | /* Must have got a cnt==ocr1 timeout. */
|
360 | 78d1404d | Peter Chubb | s->sr |= GPT_SR_OF1; |
361 | 78d1404d | Peter Chubb | s->cnt = s->ocr1; |
362 | 78d1404d | Peter Chubb | s->waiting_rov = 1;
|
363 | 78d1404d | Peter Chubb | imx_timerg_reload(s, TIMER_MAX); |
364 | 78d1404d | Peter Chubb | } |
365 | 78d1404d | Peter Chubb | imx_timerg_update(s); |
366 | 78d1404d | Peter Chubb | return;
|
367 | 78d1404d | Peter Chubb | } |
368 | 78d1404d | Peter Chubb | |
369 | 78d1404d | Peter Chubb | s->sr |= GPT_SR_OF1; |
370 | 78d1404d | Peter Chubb | imx_timerg_update(s); |
371 | 78d1404d | Peter Chubb | } |
372 | 78d1404d | Peter Chubb | |
373 | 78d1404d | Peter Chubb | static const MemoryRegionOps imx_timerg_ops = { |
374 | 78d1404d | Peter Chubb | .read = imx_timerg_read, |
375 | 78d1404d | Peter Chubb | .write = imx_timerg_write, |
376 | 78d1404d | Peter Chubb | .endianness = DEVICE_NATIVE_ENDIAN, |
377 | 78d1404d | Peter Chubb | }; |
378 | 78d1404d | Peter Chubb | |
379 | 78d1404d | Peter Chubb | |
380 | 78d1404d | Peter Chubb | static int imx_timerg_init(SysBusDevice *dev) |
381 | 78d1404d | Peter Chubb | { |
382 | 78d1404d | Peter Chubb | IMXTimerGState *s = FROM_SYSBUS(IMXTimerGState, dev); |
383 | 78d1404d | Peter Chubb | QEMUBH *bh; |
384 | 78d1404d | Peter Chubb | |
385 | 78d1404d | Peter Chubb | sysbus_init_irq(dev, &s->irq); |
386 | 78d1404d | Peter Chubb | memory_region_init_io(&s->iomem, &imx_timerg_ops, |
387 | 78d1404d | Peter Chubb | s, "imxg-timer",
|
388 | 78d1404d | Peter Chubb | 0x00001000);
|
389 | 78d1404d | Peter Chubb | sysbus_init_mmio(dev, &s->iomem); |
390 | 78d1404d | Peter Chubb | |
391 | 78d1404d | Peter Chubb | bh = qemu_bh_new(imx_timerg_timeout, s); |
392 | 78d1404d | Peter Chubb | s->timer = ptimer_init(bh); |
393 | 78d1404d | Peter Chubb | |
394 | 78d1404d | Peter Chubb | /* Hard reset resets extra bits in CR */
|
395 | 78d1404d | Peter Chubb | s->cr = 0;
|
396 | 78d1404d | Peter Chubb | return 0; |
397 | 78d1404d | Peter Chubb | } |
398 | 78d1404d | Peter Chubb | |
399 | 78d1404d | Peter Chubb | |
400 | 78d1404d | Peter Chubb | |
401 | 78d1404d | Peter Chubb | /*
|
402 | 78d1404d | Peter Chubb | * EPIT: Enhanced periodic interrupt timer
|
403 | 78d1404d | Peter Chubb | */
|
404 | 78d1404d | Peter Chubb | |
405 | 78d1404d | Peter Chubb | #define CR_EN (1 << 0) |
406 | 78d1404d | Peter Chubb | #define CR_ENMOD (1 << 1) |
407 | 78d1404d | Peter Chubb | #define CR_OCIEN (1 << 2) |
408 | 78d1404d | Peter Chubb | #define CR_RLD (1 << 3) |
409 | 78d1404d | Peter Chubb | #define CR_PRESCALE_SHIFT (4) |
410 | 78d1404d | Peter Chubb | #define CR_PRESCALE_MASK (0xfff) |
411 | 78d1404d | Peter Chubb | #define CR_SWR (1 << 16) |
412 | 78d1404d | Peter Chubb | #define CR_IOVW (1 << 17) |
413 | 78d1404d | Peter Chubb | #define CR_DBGEN (1 << 18) |
414 | 78d1404d | Peter Chubb | #define CR_EPIT (1 << 19) |
415 | 78d1404d | Peter Chubb | #define CR_DOZEN (1 << 20) |
416 | 78d1404d | Peter Chubb | #define CR_STOPEN (1 << 21) |
417 | 78d1404d | Peter Chubb | #define CR_CLKSRC_SHIFT (24) |
418 | 78d1404d | Peter Chubb | #define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT) |
419 | 78d1404d | Peter Chubb | |
420 | 78d1404d | Peter Chubb | |
421 | 78d1404d | Peter Chubb | /*
|
422 | 78d1404d | Peter Chubb | * Exact clock frequencies vary from board to board.
|
423 | 78d1404d | Peter Chubb | * These are typical.
|
424 | 78d1404d | Peter Chubb | */
|
425 | 78d1404d | Peter Chubb | static const IMXClk imx_timerp_clocks[] = { |
426 | 78d1404d | Peter Chubb | 0, /* disabled */ |
427 | 78d1404d | Peter Chubb | IPG, /* ipg_clk, ~532MHz */
|
428 | 78d1404d | Peter Chubb | IPG, /* ipg_clk_highfreq */
|
429 | 78d1404d | Peter Chubb | CLK_32k, /* ipg_clk_32k -- ~32kHz */
|
430 | 78d1404d | Peter Chubb | }; |
431 | 78d1404d | Peter Chubb | |
432 | 78d1404d | Peter Chubb | typedef struct { |
433 | 78d1404d | Peter Chubb | SysBusDevice busdev; |
434 | 78d1404d | Peter Chubb | ptimer_state *timer; |
435 | 78d1404d | Peter Chubb | MemoryRegion iomem; |
436 | 78d1404d | Peter Chubb | DeviceState *ccm; |
437 | 78d1404d | Peter Chubb | |
438 | 78d1404d | Peter Chubb | uint32_t cr; |
439 | 78d1404d | Peter Chubb | uint32_t lr; |
440 | 78d1404d | Peter Chubb | uint32_t cmp; |
441 | 78d1404d | Peter Chubb | |
442 | 78d1404d | Peter Chubb | uint32_t freq; |
443 | 78d1404d | Peter Chubb | int int_level;
|
444 | 78d1404d | Peter Chubb | qemu_irq irq; |
445 | 78d1404d | Peter Chubb | } IMXTimerPState; |
446 | 78d1404d | Peter Chubb | |
447 | 78d1404d | Peter Chubb | /*
|
448 | 78d1404d | Peter Chubb | * Update interrupt status
|
449 | 78d1404d | Peter Chubb | */
|
450 | 78d1404d | Peter Chubb | static void imx_timerp_update(IMXTimerPState *s) |
451 | 78d1404d | Peter Chubb | { |
452 | 78d1404d | Peter Chubb | if (s->int_level && (s->cr & CR_OCIEN)) {
|
453 | 78d1404d | Peter Chubb | qemu_irq_raise(s->irq); |
454 | 78d1404d | Peter Chubb | } else {
|
455 | 78d1404d | Peter Chubb | qemu_irq_lower(s->irq); |
456 | 78d1404d | Peter Chubb | } |
457 | 78d1404d | Peter Chubb | } |
458 | 78d1404d | Peter Chubb | |
459 | 78d1404d | Peter Chubb | static void imx_timerp_reset(DeviceState *dev) |
460 | 78d1404d | Peter Chubb | { |
461 | 78d1404d | Peter Chubb | IMXTimerPState *s = container_of(dev, IMXTimerPState, busdev.qdev); |
462 | 78d1404d | Peter Chubb | |
463 | 78d1404d | Peter Chubb | s->cr = 0;
|
464 | 78d1404d | Peter Chubb | s->lr = TIMER_MAX; |
465 | 78d1404d | Peter Chubb | s->int_level = 0;
|
466 | 78d1404d | Peter Chubb | s->cmp = 0;
|
467 | 78d1404d | Peter Chubb | ptimer_stop(s->timer); |
468 | 78d1404d | Peter Chubb | ptimer_set_count(s->timer, TIMER_MAX); |
469 | 78d1404d | Peter Chubb | } |
470 | 78d1404d | Peter Chubb | |
471 | a8170e5e | Avi Kivity | static uint64_t imx_timerp_read(void *opaque, hwaddr offset, |
472 | 78d1404d | Peter Chubb | unsigned size)
|
473 | 78d1404d | Peter Chubb | { |
474 | 78d1404d | Peter Chubb | IMXTimerPState *s = (IMXTimerPState *)opaque; |
475 | 78d1404d | Peter Chubb | |
476 | 78d1404d | Peter Chubb | DPRINTF("p-read(offset=%x)", offset >> 2); |
477 | 78d1404d | Peter Chubb | switch (offset >> 2) { |
478 | 78d1404d | Peter Chubb | case 0: /* Control Register */ |
479 | 78d1404d | Peter Chubb | DPRINTF("cr %x\n", s->cr);
|
480 | 78d1404d | Peter Chubb | return s->cr;
|
481 | 78d1404d | Peter Chubb | |
482 | 78d1404d | Peter Chubb | case 1: /* Status Register */ |
483 | 78d1404d | Peter Chubb | DPRINTF("int_level %x\n", s->int_level);
|
484 | 78d1404d | Peter Chubb | return s->int_level;
|
485 | 78d1404d | Peter Chubb | |
486 | 78d1404d | Peter Chubb | case 2: /* LR - ticks*/ |
487 | 78d1404d | Peter Chubb | DPRINTF("lr %x\n", s->lr);
|
488 | 78d1404d | Peter Chubb | return s->lr;
|
489 | 78d1404d | Peter Chubb | |
490 | 78d1404d | Peter Chubb | case 3: /* CMP */ |
491 | 78d1404d | Peter Chubb | DPRINTF("cmp %x\n", s->cmp);
|
492 | 78d1404d | Peter Chubb | return s->cmp;
|
493 | 78d1404d | Peter Chubb | |
494 | 78d1404d | Peter Chubb | case 4: /* CNT */ |
495 | 78d1404d | Peter Chubb | return ptimer_get_count(s->timer);
|
496 | 78d1404d | Peter Chubb | } |
497 | 78d1404d | Peter Chubb | IPRINTF("imx_timerp_read: Bad offset %x\n",
|
498 | 78d1404d | Peter Chubb | (int)offset >> 2); |
499 | 78d1404d | Peter Chubb | return 0; |
500 | 78d1404d | Peter Chubb | } |
501 | 78d1404d | Peter Chubb | |
502 | 78d1404d | Peter Chubb | static void set_timerp_freq(IMXTimerPState *s) |
503 | 78d1404d | Peter Chubb | { |
504 | 78d1404d | Peter Chubb | int clksrc;
|
505 | 78d1404d | Peter Chubb | unsigned prescaler;
|
506 | 78d1404d | Peter Chubb | uint32_t freq; |
507 | 78d1404d | Peter Chubb | |
508 | 78d1404d | Peter Chubb | clksrc = (s->cr & CR_CLKSRC_MASK) >> CR_CLKSRC_SHIFT; |
509 | 78d1404d | Peter Chubb | prescaler = 1 + ((s->cr >> CR_PRESCALE_SHIFT) & CR_PRESCALE_MASK);
|
510 | 78d1404d | Peter Chubb | freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler; |
511 | 78d1404d | Peter Chubb | |
512 | 78d1404d | Peter Chubb | s->freq = freq; |
513 | 78d1404d | Peter Chubb | DPRINTF("Setting ptimer frequency to %u\n", freq);
|
514 | 78d1404d | Peter Chubb | |
515 | 78d1404d | Peter Chubb | if (freq) {
|
516 | 78d1404d | Peter Chubb | ptimer_set_freq(s->timer, freq); |
517 | 78d1404d | Peter Chubb | } |
518 | 78d1404d | Peter Chubb | } |
519 | 78d1404d | Peter Chubb | |
520 | a8170e5e | Avi Kivity | static void imx_timerp_write(void *opaque, hwaddr offset, |
521 | 78d1404d | Peter Chubb | uint64_t value, unsigned size)
|
522 | 78d1404d | Peter Chubb | { |
523 | 78d1404d | Peter Chubb | IMXTimerPState *s = (IMXTimerPState *)opaque; |
524 | 78d1404d | Peter Chubb | DPRINTF("p-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2, |
525 | 78d1404d | Peter Chubb | (unsigned int)value); |
526 | 78d1404d | Peter Chubb | |
527 | 78d1404d | Peter Chubb | switch (offset >> 2) { |
528 | 78d1404d | Peter Chubb | case 0: /* CR */ |
529 | 78d1404d | Peter Chubb | if (value & CR_SWR) {
|
530 | 78d1404d | Peter Chubb | imx_timerp_reset(&s->busdev.qdev); |
531 | 78d1404d | Peter Chubb | value &= ~CR_SWR; |
532 | 78d1404d | Peter Chubb | } |
533 | 78d1404d | Peter Chubb | s->cr = value & 0x03ffffff;
|
534 | 78d1404d | Peter Chubb | set_timerp_freq(s); |
535 | 78d1404d | Peter Chubb | |
536 | 78d1404d | Peter Chubb | if (s->freq && (s->cr & CR_EN)) {
|
537 | 78d1404d | Peter Chubb | if (!(s->cr & CR_ENMOD)) {
|
538 | 78d1404d | Peter Chubb | ptimer_set_count(s->timer, s->lr); |
539 | 78d1404d | Peter Chubb | } |
540 | 78d1404d | Peter Chubb | ptimer_run(s->timer, 0);
|
541 | 78d1404d | Peter Chubb | } else {
|
542 | 78d1404d | Peter Chubb | ptimer_stop(s->timer); |
543 | 78d1404d | Peter Chubb | } |
544 | 78d1404d | Peter Chubb | break;
|
545 | 78d1404d | Peter Chubb | |
546 | 78d1404d | Peter Chubb | case 1: /* SR - ACK*/ |
547 | 78d1404d | Peter Chubb | s->int_level = 0;
|
548 | 78d1404d | Peter Chubb | imx_timerp_update(s); |
549 | 78d1404d | Peter Chubb | break;
|
550 | 78d1404d | Peter Chubb | |
551 | 78d1404d | Peter Chubb | case 2: /* LR - set ticks */ |
552 | 78d1404d | Peter Chubb | s->lr = value; |
553 | 78d1404d | Peter Chubb | ptimer_set_limit(s->timer, value, !!(s->cr & CR_IOVW)); |
554 | 78d1404d | Peter Chubb | break;
|
555 | 78d1404d | Peter Chubb | |
556 | 78d1404d | Peter Chubb | case 3: /* CMP */ |
557 | 78d1404d | Peter Chubb | s->cmp = value; |
558 | 78d1404d | Peter Chubb | if (value) {
|
559 | 78d1404d | Peter Chubb | IPRINTF( |
560 | 78d1404d | Peter Chubb | "Values for EPIT comparison other than zero not supported\n"
|
561 | 78d1404d | Peter Chubb | ); |
562 | 78d1404d | Peter Chubb | } |
563 | 78d1404d | Peter Chubb | break;
|
564 | 78d1404d | Peter Chubb | |
565 | 78d1404d | Peter Chubb | default:
|
566 | 78d1404d | Peter Chubb | IPRINTF("imx_timerp_write: Bad offset %x\n",
|
567 | 78d1404d | Peter Chubb | (int)offset >> 2); |
568 | 78d1404d | Peter Chubb | } |
569 | 78d1404d | Peter Chubb | } |
570 | 78d1404d | Peter Chubb | |
571 | 78d1404d | Peter Chubb | static void imx_timerp_tick(void *opaque) |
572 | 78d1404d | Peter Chubb | { |
573 | 78d1404d | Peter Chubb | IMXTimerPState *s = (IMXTimerPState *)opaque; |
574 | 78d1404d | Peter Chubb | |
575 | 78d1404d | Peter Chubb | DPRINTF("imxp tick\n");
|
576 | 78d1404d | Peter Chubb | if (!(s->cr & CR_RLD)) {
|
577 | 78d1404d | Peter Chubb | ptimer_set_count(s->timer, TIMER_MAX); |
578 | 78d1404d | Peter Chubb | } |
579 | 78d1404d | Peter Chubb | s->int_level = 1;
|
580 | 78d1404d | Peter Chubb | imx_timerp_update(s); |
581 | 78d1404d | Peter Chubb | } |
582 | 78d1404d | Peter Chubb | |
583 | a8170e5e | Avi Kivity | void imx_timerp_create(const hwaddr addr, |
584 | 78d1404d | Peter Chubb | qemu_irq irq, |
585 | 78d1404d | Peter Chubb | DeviceState *ccm) |
586 | 78d1404d | Peter Chubb | { |
587 | 78d1404d | Peter Chubb | IMXTimerPState *pp; |
588 | 78d1404d | Peter Chubb | DeviceState *dev; |
589 | 78d1404d | Peter Chubb | |
590 | 78d1404d | Peter Chubb | dev = sysbus_create_simple("imx_timerp", addr, irq);
|
591 | 78d1404d | Peter Chubb | pp = container_of(dev, IMXTimerPState, busdev.qdev); |
592 | 78d1404d | Peter Chubb | pp->ccm = ccm; |
593 | 78d1404d | Peter Chubb | } |
594 | 78d1404d | Peter Chubb | |
595 | 78d1404d | Peter Chubb | static const MemoryRegionOps imx_timerp_ops = { |
596 | 78d1404d | Peter Chubb | .read = imx_timerp_read, |
597 | 78d1404d | Peter Chubb | .write = imx_timerp_write, |
598 | 78d1404d | Peter Chubb | .endianness = DEVICE_NATIVE_ENDIAN, |
599 | 78d1404d | Peter Chubb | }; |
600 | 78d1404d | Peter Chubb | |
601 | 78d1404d | Peter Chubb | static const VMStateDescription vmstate_imx_timerp = { |
602 | 78d1404d | Peter Chubb | .name = "imx-timerp",
|
603 | 78d1404d | Peter Chubb | .version_id = 1,
|
604 | 78d1404d | Peter Chubb | .minimum_version_id = 1,
|
605 | 78d1404d | Peter Chubb | .minimum_version_id_old = 1,
|
606 | 78d1404d | Peter Chubb | .fields = (VMStateField[]) { |
607 | 78d1404d | Peter Chubb | VMSTATE_UINT32(cr, IMXTimerPState), |
608 | 78d1404d | Peter Chubb | VMSTATE_UINT32(lr, IMXTimerPState), |
609 | 78d1404d | Peter Chubb | VMSTATE_UINT32(cmp, IMXTimerPState), |
610 | 78d1404d | Peter Chubb | VMSTATE_UINT32(freq, IMXTimerPState), |
611 | 78d1404d | Peter Chubb | VMSTATE_INT32(int_level, IMXTimerPState), |
612 | 78d1404d | Peter Chubb | VMSTATE_PTIMER(timer, IMXTimerPState), |
613 | 78d1404d | Peter Chubb | VMSTATE_END_OF_LIST() |
614 | 78d1404d | Peter Chubb | } |
615 | 78d1404d | Peter Chubb | }; |
616 | 78d1404d | Peter Chubb | |
617 | 78d1404d | Peter Chubb | static int imx_timerp_init(SysBusDevice *dev) |
618 | 78d1404d | Peter Chubb | { |
619 | 78d1404d | Peter Chubb | IMXTimerPState *s = FROM_SYSBUS(IMXTimerPState, dev); |
620 | 78d1404d | Peter Chubb | QEMUBH *bh; |
621 | 78d1404d | Peter Chubb | |
622 | 78d1404d | Peter Chubb | DPRINTF("imx_timerp_init\n");
|
623 | 78d1404d | Peter Chubb | |
624 | 78d1404d | Peter Chubb | sysbus_init_irq(dev, &s->irq); |
625 | 78d1404d | Peter Chubb | memory_region_init_io(&s->iomem, &imx_timerp_ops, |
626 | 78d1404d | Peter Chubb | s, "imxp-timer",
|
627 | 78d1404d | Peter Chubb | 0x00001000);
|
628 | 78d1404d | Peter Chubb | sysbus_init_mmio(dev, &s->iomem); |
629 | 78d1404d | Peter Chubb | |
630 | 78d1404d | Peter Chubb | bh = qemu_bh_new(imx_timerp_tick, s); |
631 | 78d1404d | Peter Chubb | s->timer = ptimer_init(bh); |
632 | 78d1404d | Peter Chubb | |
633 | 78d1404d | Peter Chubb | return 0; |
634 | 78d1404d | Peter Chubb | } |
635 | 78d1404d | Peter Chubb | |
636 | 78d1404d | Peter Chubb | |
637 | a8170e5e | Avi Kivity | void imx_timerg_create(const hwaddr addr, |
638 | 78d1404d | Peter Chubb | qemu_irq irq, |
639 | 78d1404d | Peter Chubb | DeviceState *ccm) |
640 | 78d1404d | Peter Chubb | { |
641 | 78d1404d | Peter Chubb | IMXTimerGState *pp; |
642 | 78d1404d | Peter Chubb | DeviceState *dev; |
643 | 78d1404d | Peter Chubb | |
644 | 78d1404d | Peter Chubb | dev = sysbus_create_simple("imx_timerg", addr, irq);
|
645 | 78d1404d | Peter Chubb | pp = container_of(dev, IMXTimerGState, busdev.qdev); |
646 | 78d1404d | Peter Chubb | pp->ccm = ccm; |
647 | 78d1404d | Peter Chubb | } |
648 | 78d1404d | Peter Chubb | |
649 | 78d1404d | Peter Chubb | static void imx_timerg_class_init(ObjectClass *klass, void *data) |
650 | 78d1404d | Peter Chubb | { |
651 | 78d1404d | Peter Chubb | DeviceClass *dc = DEVICE_CLASS(klass); |
652 | 78d1404d | Peter Chubb | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
653 | 78d1404d | Peter Chubb | k->init = imx_timerg_init; |
654 | 78d1404d | Peter Chubb | dc->vmsd = &vmstate_imx_timerg; |
655 | 78d1404d | Peter Chubb | dc->reset = imx_timerg_reset; |
656 | 78d1404d | Peter Chubb | dc->desc = "i.MX general timer";
|
657 | 78d1404d | Peter Chubb | } |
658 | 78d1404d | Peter Chubb | |
659 | 78d1404d | Peter Chubb | static void imx_timerp_class_init(ObjectClass *klass, void *data) |
660 | 78d1404d | Peter Chubb | { |
661 | 78d1404d | Peter Chubb | DeviceClass *dc = DEVICE_CLASS(klass); |
662 | 78d1404d | Peter Chubb | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
663 | 78d1404d | Peter Chubb | k->init = imx_timerp_init; |
664 | 78d1404d | Peter Chubb | dc->vmsd = &vmstate_imx_timerp; |
665 | 78d1404d | Peter Chubb | dc->reset = imx_timerp_reset; |
666 | 78d1404d | Peter Chubb | dc->desc = "i.MX periodic timer";
|
667 | 78d1404d | Peter Chubb | } |
668 | 78d1404d | Peter Chubb | |
669 | 78d1404d | Peter Chubb | static const TypeInfo imx_timerp_info = { |
670 | 78d1404d | Peter Chubb | .name = "imx_timerp",
|
671 | 78d1404d | Peter Chubb | .parent = TYPE_SYS_BUS_DEVICE, |
672 | 78d1404d | Peter Chubb | .instance_size = sizeof(IMXTimerPState),
|
673 | 78d1404d | Peter Chubb | .class_init = imx_timerp_class_init, |
674 | 78d1404d | Peter Chubb | }; |
675 | 78d1404d | Peter Chubb | |
676 | 78d1404d | Peter Chubb | static const TypeInfo imx_timerg_info = { |
677 | 78d1404d | Peter Chubb | .name = "imx_timerg",
|
678 | 78d1404d | Peter Chubb | .parent = TYPE_SYS_BUS_DEVICE, |
679 | 78d1404d | Peter Chubb | .instance_size = sizeof(IMXTimerGState),
|
680 | 78d1404d | Peter Chubb | .class_init = imx_timerg_class_init, |
681 | 78d1404d | Peter Chubb | }; |
682 | 78d1404d | Peter Chubb | |
683 | 78d1404d | Peter Chubb | static void imx_timer_register_types(void) |
684 | 78d1404d | Peter Chubb | { |
685 | 78d1404d | Peter Chubb | type_register_static(&imx_timerp_info); |
686 | 78d1404d | Peter Chubb | type_register_static(&imx_timerg_info); |
687 | 78d1404d | Peter Chubb | } |
688 | 78d1404d | Peter Chubb | |
689 | 78d1404d | Peter Chubb | type_init(imx_timer_register_types) |