blob: 5511313687c2048ce130ec13cc6a8a8be18db21e [file] [log] [blame]
bellarde80cfcf2004-12-19 23:18:01 +00001/*
2 * QEMU Sparc SLAVIO timer controller emulation
3 *
bellard66321a12005-04-06 20:47:48 +00004 * Copyright (c) 2003-2005 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellarde80cfcf2004-12-19 23:18:01 +00006 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
Blue Swirlc70c59e2009-07-15 08:53:09 +000024
pbrook87ecb682007-11-17 17:14:51 +000025#include "sun4m.h"
26#include "qemu-timer.h"
Blue Swirlc70c59e2009-07-15 08:53:09 +000027#include "sysbus.h"
Blue Swirl97bf4852010-10-31 09:24:14 +000028#include "trace.h"
bellard66321a12005-04-06 20:47:48 +000029
bellarde80cfcf2004-12-19 23:18:01 +000030/*
31 * Registers of hardware timer in sun4m.
32 *
33 * This is the timer/counter part of chip STP2001 (Slave I/O), also
34 * produced as NCR89C105. See
35 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
ths5fafdf22007-09-16 21:08:06 +000036 *
bellarde80cfcf2004-12-19 23:18:01 +000037 * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
38 * are zero. Bit 31 is 1 when count has been reached.
39 *
bellardba3c64f2005-12-05 20:31:52 +000040 * Per-CPU timers interrupt local CPU, system timer uses normal
41 * interrupt routing.
42 *
bellarde80cfcf2004-12-19 23:18:01 +000043 */
44
blueswir181732d12007-10-06 11:25:43 +000045#define MAX_CPUS 16
46
Blue Swirl7204ff92009-08-08 20:08:15 +000047typedef struct CPUTimerState {
blueswir1d7edfd22007-05-27 16:37:49 +000048 qemu_irq irq;
blueswir18d05ea82007-05-24 19:48:41 +000049 ptimer_state *timer;
50 uint32_t count, counthigh, reached;
51 uint64_t limit;
blueswir1115646b2007-10-07 10:00:55 +000052 // processor only
blueswir122548762008-05-10 10:12:00 +000053 uint32_t running;
Blue Swirl7204ff92009-08-08 20:08:15 +000054} CPUTimerState;
55
56typedef struct SLAVIO_TIMERState {
57 SysBusDevice busdev;
58 uint32_t num_cpus;
59 CPUTimerState cputimer[MAX_CPUS + 1];
60 uint32_t cputimer_mode;
bellarde80cfcf2004-12-19 23:18:01 +000061} SLAVIO_TIMERState;
62
Blue Swirl7204ff92009-08-08 20:08:15 +000063typedef struct TimerContext {
64 SLAVIO_TIMERState *s;
65 unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */
66} TimerContext;
67
blueswir1115646b2007-10-07 10:00:55 +000068#define SYS_TIMER_SIZE 0x14
blueswir181732d12007-10-06 11:25:43 +000069#define CPU_TIMER_SIZE 0x10
bellarde80cfcf2004-12-19 23:18:01 +000070
blueswir1d2c38b22007-12-01 15:58:22 +000071#define TIMER_LIMIT 0
72#define TIMER_COUNTER 1
73#define TIMER_COUNTER_NORST 2
74#define TIMER_STATUS 3
75#define TIMER_MODE 4
76
77#define TIMER_COUNT_MASK32 0xfffffe00
78#define TIMER_LIMIT_MASK32 0x7fffffff
79#define TIMER_MAX_COUNT64 0x7ffffffffffffe00ULL
80#define TIMER_MAX_COUNT32 0x7ffffe00ULL
81#define TIMER_REACHED 0x80000000
82#define TIMER_PERIOD 500ULL // 500ns
Blue Swirl68fb89a2010-04-03 06:17:35 +000083#define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1)
84#define PERIODS_TO_LIMIT(l) (((l) + 1) << 9)
blueswir1d2c38b22007-12-01 15:58:22 +000085
Blue Swirl7204ff92009-08-08 20:08:15 +000086static int slavio_timer_is_user(TimerContext *tc)
blueswir1115646b2007-10-07 10:00:55 +000087{
Blue Swirl7204ff92009-08-08 20:08:15 +000088 SLAVIO_TIMERState *s = tc->s;
89 unsigned int timer_index = tc->timer_index;
90
91 return timer_index != 0 && (s->cputimer_mode & (1 << (timer_index - 1)));
blueswir1115646b2007-10-07 10:00:55 +000092}
93
bellarde80cfcf2004-12-19 23:18:01 +000094// Update count, set irq, update expire_time
blueswir18d05ea82007-05-24 19:48:41 +000095// Convert from ptimer countdown units
Blue Swirl7204ff92009-08-08 20:08:15 +000096static void slavio_timer_get_out(CPUTimerState *t)
bellarde80cfcf2004-12-19 23:18:01 +000097{
blueswir1bd7e2872007-12-19 17:58:24 +000098 uint64_t count, limit;
bellarde80cfcf2004-12-19 23:18:01 +000099
Blue Swirl7204ff92009-08-08 20:08:15 +0000100 if (t->limit == 0) { /* free-run system or processor counter */
blueswir1bd7e2872007-12-19 17:58:24 +0000101 limit = TIMER_MAX_COUNT32;
Blue Swirl7204ff92009-08-08 20:08:15 +0000102 } else {
103 limit = t->limit;
104 }
Blue Swirl9ebec282009-08-31 19:30:17 +0000105 count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer));
106
Blue Swirl97bf4852010-10-31 09:24:14 +0000107 trace_slavio_timer_get_out(t->limit, t->counthigh, t->count);
Blue Swirl7204ff92009-08-08 20:08:15 +0000108 t->count = count & TIMER_COUNT_MASK32;
109 t->counthigh = count >> 32;
bellarde80cfcf2004-12-19 23:18:01 +0000110}
111
112// timer callback
113static void slavio_timer_irq(void *opaque)
114{
Blue Swirl7204ff92009-08-08 20:08:15 +0000115 TimerContext *tc = opaque;
116 SLAVIO_TIMERState *s = tc->s;
117 CPUTimerState *t = &s->cputimer[tc->timer_index];
bellarde80cfcf2004-12-19 23:18:01 +0000118
Blue Swirl7204ff92009-08-08 20:08:15 +0000119 slavio_timer_get_out(t);
Blue Swirl97bf4852010-10-31 09:24:14 +0000120 trace_slavio_timer_irq(t->counthigh, t->count);
Blue Swirl68fb89a2010-04-03 06:17:35 +0000121 /* if limit is 0 (free-run), there will be no match */
122 if (t->limit != 0) {
123 t->reached = TIMER_REACHED;
124 }
Blue Swirl452efba2010-01-24 14:28:21 +0000125 /* there is no interrupt if user timer or free-run */
126 if (!slavio_timer_is_user(tc) && t->limit != 0) {
Blue Swirl7204ff92009-08-08 20:08:15 +0000127 qemu_irq_raise(t->irq);
128 }
bellarde80cfcf2004-12-19 23:18:01 +0000129}
130
Anthony Liguoric227f092009-10-01 16:12:16 -0500131static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
bellarde80cfcf2004-12-19 23:18:01 +0000132{
Blue Swirl7204ff92009-08-08 20:08:15 +0000133 TimerContext *tc = opaque;
134 SLAVIO_TIMERState *s = tc->s;
blueswir18d05ea82007-05-24 19:48:41 +0000135 uint32_t saddr, ret;
Blue Swirl7204ff92009-08-08 20:08:15 +0000136 unsigned int timer_index = tc->timer_index;
137 CPUTimerState *t = &s->cputimer[timer_index];
bellarde80cfcf2004-12-19 23:18:01 +0000138
blueswir1e64d7d52008-12-02 17:47:02 +0000139 saddr = addr >> 2;
bellarde80cfcf2004-12-19 23:18:01 +0000140 switch (saddr) {
blueswir1d2c38b22007-12-01 15:58:22 +0000141 case TIMER_LIMIT:
blueswir1f930d072007-10-06 11:28:21 +0000142 // read limit (system counter mode) or read most signifying
143 // part of counter (user mode)
Blue Swirl7204ff92009-08-08 20:08:15 +0000144 if (slavio_timer_is_user(tc)) {
blueswir1115646b2007-10-07 10:00:55 +0000145 // read user timer MSW
Blue Swirl7204ff92009-08-08 20:08:15 +0000146 slavio_timer_get_out(t);
147 ret = t->counthigh | t->reached;
blueswir1115646b2007-10-07 10:00:55 +0000148 } else {
149 // read limit
blueswir1f930d072007-10-06 11:28:21 +0000150 // clear irq
Blue Swirl7204ff92009-08-08 20:08:15 +0000151 qemu_irq_lower(t->irq);
152 t->reached = 0;
153 ret = t->limit & TIMER_LIMIT_MASK32;
blueswir1f930d072007-10-06 11:28:21 +0000154 }
blueswir18d05ea82007-05-24 19:48:41 +0000155 break;
blueswir1d2c38b22007-12-01 15:58:22 +0000156 case TIMER_COUNTER:
blueswir1f930d072007-10-06 11:28:21 +0000157 // read counter and reached bit (system mode) or read lsbits
158 // of counter (user mode)
Blue Swirl7204ff92009-08-08 20:08:15 +0000159 slavio_timer_get_out(t);
160 if (slavio_timer_is_user(tc)) { // read user timer LSW
161 ret = t->count & TIMER_MAX_COUNT64;
162 } else { // read limit
163 ret = (t->count & TIMER_MAX_COUNT32) |
164 t->reached;
165 }
blueswir18d05ea82007-05-24 19:48:41 +0000166 break;
blueswir1d2c38b22007-12-01 15:58:22 +0000167 case TIMER_STATUS:
blueswir1115646b2007-10-07 10:00:55 +0000168 // only available in processor counter/timer
blueswir1f930d072007-10-06 11:28:21 +0000169 // read start/stop status
Blue Swirl7204ff92009-08-08 20:08:15 +0000170 if (timer_index > 0) {
171 ret = t->running;
172 } else {
173 ret = 0;
174 }
blueswir18d05ea82007-05-24 19:48:41 +0000175 break;
blueswir1d2c38b22007-12-01 15:58:22 +0000176 case TIMER_MODE:
blueswir1115646b2007-10-07 10:00:55 +0000177 // only available in system counter
blueswir1f930d072007-10-06 11:28:21 +0000178 // read user/system mode
Blue Swirl7204ff92009-08-08 20:08:15 +0000179 ret = s->cputimer_mode;
blueswir18d05ea82007-05-24 19:48:41 +0000180 break;
bellarde80cfcf2004-12-19 23:18:01 +0000181 default:
Blue Swirl97bf4852010-10-31 09:24:14 +0000182 trace_slavio_timer_mem_readl_invalid(addr);
blueswir18d05ea82007-05-24 19:48:41 +0000183 ret = 0;
184 break;
bellarde80cfcf2004-12-19 23:18:01 +0000185 }
Blue Swirl97bf4852010-10-31 09:24:14 +0000186 trace_slavio_timer_mem_readl(addr, ret);
blueswir18d05ea82007-05-24 19:48:41 +0000187 return ret;
bellarde80cfcf2004-12-19 23:18:01 +0000188}
189
Anthony Liguoric227f092009-10-01 16:12:16 -0500190static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
blueswir1d2c38b22007-12-01 15:58:22 +0000191 uint32_t val)
bellarde80cfcf2004-12-19 23:18:01 +0000192{
Blue Swirl7204ff92009-08-08 20:08:15 +0000193 TimerContext *tc = opaque;
194 SLAVIO_TIMERState *s = tc->s;
bellarde80cfcf2004-12-19 23:18:01 +0000195 uint32_t saddr;
Blue Swirl7204ff92009-08-08 20:08:15 +0000196 unsigned int timer_index = tc->timer_index;
197 CPUTimerState *t = &s->cputimer[timer_index];
bellarde80cfcf2004-12-19 23:18:01 +0000198
Blue Swirl97bf4852010-10-31 09:24:14 +0000199 trace_slavio_timer_mem_writel(addr, val);
blueswir1e64d7d52008-12-02 17:47:02 +0000200 saddr = addr >> 2;
bellarde80cfcf2004-12-19 23:18:01 +0000201 switch (saddr) {
blueswir1d2c38b22007-12-01 15:58:22 +0000202 case TIMER_LIMIT:
Blue Swirl7204ff92009-08-08 20:08:15 +0000203 if (slavio_timer_is_user(tc)) {
blueswir1e1cb9502008-01-25 19:51:27 +0000204 uint64_t count;
205
blueswir1115646b2007-10-07 10:00:55 +0000206 // set user counter MSW, reset counter
Blue Swirl7204ff92009-08-08 20:08:15 +0000207 t->limit = TIMER_MAX_COUNT64;
208 t->counthigh = val & (TIMER_MAX_COUNT64 >> 32);
209 t->reached = 0;
210 count = ((uint64_t)t->counthigh << 32) | t->count;
Blue Swirl97bf4852010-10-31 09:24:14 +0000211 trace_slavio_timer_mem_writel_limit(timer_index, count);
Blue Swirl9ebec282009-08-31 19:30:17 +0000212 ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
blueswir1115646b2007-10-07 10:00:55 +0000213 } else {
214 // set limit, reset counter
Blue Swirl7204ff92009-08-08 20:08:15 +0000215 qemu_irq_lower(t->irq);
216 t->limit = val & TIMER_MAX_COUNT32;
217 if (t->timer) {
218 if (t->limit == 0) { /* free-run */
219 ptimer_set_limit(t->timer,
blueswir177f193d2008-05-12 16:13:33 +0000220 LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
Blue Swirl7204ff92009-08-08 20:08:15 +0000221 } else {
222 ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1);
223 }
blueswir185e30232007-12-27 20:23:20 +0000224 }
blueswir181732d12007-10-06 11:25:43 +0000225 }
blueswir1115646b2007-10-07 10:00:55 +0000226 break;
blueswir1d2c38b22007-12-01 15:58:22 +0000227 case TIMER_COUNTER:
Blue Swirl7204ff92009-08-08 20:08:15 +0000228 if (slavio_timer_is_user(tc)) {
blueswir1e1cb9502008-01-25 19:51:27 +0000229 uint64_t count;
230
blueswir1115646b2007-10-07 10:00:55 +0000231 // set user counter LSW, reset counter
Blue Swirl7204ff92009-08-08 20:08:15 +0000232 t->limit = TIMER_MAX_COUNT64;
233 t->count = val & TIMER_MAX_COUNT64;
234 t->reached = 0;
235 count = ((uint64_t)t->counthigh) << 32 | t->count;
Blue Swirl97bf4852010-10-31 09:24:14 +0000236 trace_slavio_timer_mem_writel_limit(timer_index, count);
Blue Swirl9ebec282009-08-31 19:30:17 +0000237 ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
Blue Swirl97bf4852010-10-31 09:24:14 +0000238 } else {
239 trace_slavio_timer_mem_writel_counter_invalid();
240 }
blueswir1115646b2007-10-07 10:00:55 +0000241 break;
blueswir1d2c38b22007-12-01 15:58:22 +0000242 case TIMER_COUNTER_NORST:
blueswir1f930d072007-10-06 11:28:21 +0000243 // set limit without resetting counter
Blue Swirl7204ff92009-08-08 20:08:15 +0000244 t->limit = val & TIMER_MAX_COUNT32;
Blue Swirl9ebec282009-08-31 19:30:17 +0000245 if (t->limit == 0) { /* free-run */
246 ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
247 } else {
248 ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
blueswir185e30232007-12-27 20:23:20 +0000249 }
blueswir1f930d072007-10-06 11:28:21 +0000250 break;
blueswir1d2c38b22007-12-01 15:58:22 +0000251 case TIMER_STATUS:
Blue Swirl7204ff92009-08-08 20:08:15 +0000252 if (slavio_timer_is_user(tc)) {
blueswir1115646b2007-10-07 10:00:55 +0000253 // start/stop user counter
Blue Swirl7204ff92009-08-08 20:08:15 +0000254 if ((val & 1) && !t->running) {
Blue Swirl97bf4852010-10-31 09:24:14 +0000255 trace_slavio_timer_mem_writel_status_start(timer_index);
Blue Swirl9ebec282009-08-31 19:30:17 +0000256 ptimer_run(t->timer, 0);
Blue Swirl7204ff92009-08-08 20:08:15 +0000257 t->running = 1;
258 } else if (!(val & 1) && t->running) {
Blue Swirl97bf4852010-10-31 09:24:14 +0000259 trace_slavio_timer_mem_writel_status_stop(timer_index);
Blue Swirl9ebec282009-08-31 19:30:17 +0000260 ptimer_stop(t->timer);
Blue Swirl7204ff92009-08-08 20:08:15 +0000261 t->running = 0;
blueswir1f930d072007-10-06 11:28:21 +0000262 }
263 }
264 break;
blueswir1d2c38b22007-12-01 15:58:22 +0000265 case TIMER_MODE:
Blue Swirl7204ff92009-08-08 20:08:15 +0000266 if (timer_index == 0) {
blueswir181732d12007-10-06 11:25:43 +0000267 unsigned int i;
268
Blue Swirl7204ff92009-08-08 20:08:15 +0000269 for (i = 0; i < s->num_cpus; i++) {
blueswir167e42752008-01-26 09:13:46 +0000270 unsigned int processor = 1 << i;
Blue Swirl7204ff92009-08-08 20:08:15 +0000271 CPUTimerState *curr_timer = &s->cputimer[i + 1];
blueswir167e42752008-01-26 09:13:46 +0000272
273 // check for a change in timer mode for this processor
Blue Swirl7204ff92009-08-08 20:08:15 +0000274 if ((val & processor) != (s->cputimer_mode & processor)) {
blueswir167e42752008-01-26 09:13:46 +0000275 if (val & processor) { // counter -> user timer
Blue Swirl7204ff92009-08-08 20:08:15 +0000276 qemu_irq_lower(curr_timer->irq);
blueswir167e42752008-01-26 09:13:46 +0000277 // counters are always running
Blue Swirl7204ff92009-08-08 20:08:15 +0000278 ptimer_stop(curr_timer->timer);
279 curr_timer->running = 0;
blueswir167e42752008-01-26 09:13:46 +0000280 // user timer limit is always the same
Blue Swirl7204ff92009-08-08 20:08:15 +0000281 curr_timer->limit = TIMER_MAX_COUNT64;
282 ptimer_set_limit(curr_timer->timer,
283 LIMIT_TO_PERIODS(curr_timer->limit),
blueswir177f193d2008-05-12 16:13:33 +0000284 1);
blueswir167e42752008-01-26 09:13:46 +0000285 // set this processors user timer bit in config
286 // register
Blue Swirl7204ff92009-08-08 20:08:15 +0000287 s->cputimer_mode |= processor;
Blue Swirl97bf4852010-10-31 09:24:14 +0000288 trace_slavio_timer_mem_writel_mode_user(timer_index);
blueswir167e42752008-01-26 09:13:46 +0000289 } else { // user timer -> counter
290 // stop the user timer if it is running
Blue Swirl7204ff92009-08-08 20:08:15 +0000291 if (curr_timer->running) {
292 ptimer_stop(curr_timer->timer);
293 }
blueswir167e42752008-01-26 09:13:46 +0000294 // start the counter
Blue Swirl7204ff92009-08-08 20:08:15 +0000295 ptimer_run(curr_timer->timer, 0);
296 curr_timer->running = 1;
blueswir167e42752008-01-26 09:13:46 +0000297 // clear this processors user timer bit in config
298 // register
Blue Swirl7204ff92009-08-08 20:08:15 +0000299 s->cputimer_mode &= ~processor;
Blue Swirl97bf4852010-10-31 09:24:14 +0000300 trace_slavio_timer_mem_writel_mode_counter(timer_index);
blueswir167e42752008-01-26 09:13:46 +0000301 }
blueswir1115646b2007-10-07 10:00:55 +0000302 }
blueswir181732d12007-10-06 11:25:43 +0000303 }
Blue Swirl7204ff92009-08-08 20:08:15 +0000304 } else {
Blue Swirl97bf4852010-10-31 09:24:14 +0000305 trace_slavio_timer_mem_writel_mode_invalid();
Blue Swirl7204ff92009-08-08 20:08:15 +0000306 }
blueswir1f930d072007-10-06 11:28:21 +0000307 break;
bellarde80cfcf2004-12-19 23:18:01 +0000308 default:
Blue Swirl97bf4852010-10-31 09:24:14 +0000309 trace_slavio_timer_mem_writel_invalid(addr);
blueswir1f930d072007-10-06 11:28:21 +0000310 break;
bellarde80cfcf2004-12-19 23:18:01 +0000311 }
312}
313
Blue Swirld60efc62009-08-25 18:29:31 +0000314static CPUReadMemoryFunc * const slavio_timer_mem_read[3] = {
blueswir17c560452008-01-01 17:06:38 +0000315 NULL,
316 NULL,
bellarde80cfcf2004-12-19 23:18:01 +0000317 slavio_timer_mem_readl,
318};
319
Blue Swirld60efc62009-08-25 18:29:31 +0000320static CPUWriteMemoryFunc * const slavio_timer_mem_write[3] = {
blueswir17c560452008-01-01 17:06:38 +0000321 NULL,
322 NULL,
bellarde80cfcf2004-12-19 23:18:01 +0000323 slavio_timer_mem_writel,
324};
325
Blue Swirlf4b19cd2009-08-31 19:30:18 +0000326static const VMStateDescription vmstate_timer = {
327 .name ="timer",
328 .version_id = 3,
329 .minimum_version_id = 3,
330 .minimum_version_id_old = 3,
331 .fields = (VMStateField []) {
332 VMSTATE_UINT64(limit, CPUTimerState),
333 VMSTATE_UINT32(count, CPUTimerState),
334 VMSTATE_UINT32(counthigh, CPUTimerState),
335 VMSTATE_UINT32(reached, CPUTimerState),
336 VMSTATE_UINT32(running, CPUTimerState),
337 VMSTATE_PTIMER(timer, CPUTimerState),
338 VMSTATE_END_OF_LIST()
Blue Swirl7204ff92009-08-08 20:08:15 +0000339 }
Blue Swirlf4b19cd2009-08-31 19:30:18 +0000340};
bellarde80cfcf2004-12-19 23:18:01 +0000341
Blue Swirlf4b19cd2009-08-31 19:30:18 +0000342static const VMStateDescription vmstate_slavio_timer = {
343 .name ="slavio_timer",
344 .version_id = 3,
345 .minimum_version_id = 3,
346 .minimum_version_id_old = 3,
347 .fields = (VMStateField []) {
348 VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3,
349 vmstate_timer, CPUTimerState),
350 VMSTATE_END_OF_LIST()
Blue Swirl7204ff92009-08-08 20:08:15 +0000351 }
Blue Swirlf4b19cd2009-08-31 19:30:18 +0000352};
bellarde80cfcf2004-12-19 23:18:01 +0000353
Blue Swirl0e0bfee2009-10-24 17:35:13 +0000354static void slavio_timer_reset(DeviceState *d)
bellarde80cfcf2004-12-19 23:18:01 +0000355{
Blue Swirl0e0bfee2009-10-24 17:35:13 +0000356 SLAVIO_TIMERState *s = container_of(d, SLAVIO_TIMERState, busdev.qdev);
Blue Swirl7204ff92009-08-08 20:08:15 +0000357 unsigned int i;
358 CPUTimerState *curr_timer;
bellarde80cfcf2004-12-19 23:18:01 +0000359
Blue Swirl7204ff92009-08-08 20:08:15 +0000360 for (i = 0; i <= MAX_CPUS; i++) {
361 curr_timer = &s->cputimer[i];
362 curr_timer->limit = 0;
363 curr_timer->count = 0;
364 curr_timer->reached = 0;
Artyom Tarasenko5933e8a2010-08-02 19:58:21 +0200365 if (i <= s->num_cpus) {
Blue Swirl7204ff92009-08-08 20:08:15 +0000366 ptimer_set_limit(curr_timer->timer,
367 LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
368 ptimer_run(curr_timer->timer, 0);
Artyom Tarasenko5933e8a2010-08-02 19:58:21 +0200369 curr_timer->running = 1;
Blue Swirl7204ff92009-08-08 20:08:15 +0000370 }
blueswir185e30232007-12-27 20:23:20 +0000371 }
Blue Swirl7204ff92009-08-08 20:08:15 +0000372 s->cputimer_mode = 0;
bellarde80cfcf2004-12-19 23:18:01 +0000373}
374
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200375static int slavio_timer_init1(SysBusDevice *dev)
Blue Swirlc70c59e2009-07-15 08:53:09 +0000376{
377 int io;
378 SLAVIO_TIMERState *s = FROM_SYSBUS(SLAVIO_TIMERState, dev);
blueswir18d05ea82007-05-24 19:48:41 +0000379 QEMUBH *bh;
Blue Swirl7204ff92009-08-08 20:08:15 +0000380 unsigned int i;
381 TimerContext *tc;
bellarde80cfcf2004-12-19 23:18:01 +0000382
Blue Swirl7204ff92009-08-08 20:08:15 +0000383 for (i = 0; i <= MAX_CPUS; i++) {
384 tc = qemu_mallocz(sizeof(TimerContext));
385 tc->s = s;
386 tc->timer_index = i;
Blue Swirlc70c59e2009-07-15 08:53:09 +0000387
Blue Swirl7204ff92009-08-08 20:08:15 +0000388 bh = qemu_bh_new(slavio_timer_irq, tc);
389 s->cputimer[i].timer = ptimer_init(bh);
390 ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
bellarde80cfcf2004-12-19 23:18:01 +0000391
Blue Swirl7204ff92009-08-08 20:08:15 +0000392 io = cpu_register_io_memory(slavio_timer_mem_read,
Alexander Graf2507c122010-12-08 12:05:37 +0100393 slavio_timer_mem_write, tc,
394 DEVICE_NATIVE_ENDIAN);
Blue Swirl7204ff92009-08-08 20:08:15 +0000395 if (i == 0) {
396 sysbus_init_mmio(dev, SYS_TIMER_SIZE, io);
397 } else {
398 sysbus_init_mmio(dev, CPU_TIMER_SIZE, io);
399 }
400
401 sysbus_init_irq(dev, &s->cputimer[i].irq);
Blue Swirlc70c59e2009-07-15 08:53:09 +0000402 }
403
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200404 return 0;
blueswir181732d12007-10-06 11:25:43 +0000405}
406
Blue Swirlc70c59e2009-07-15 08:53:09 +0000407static SysBusDeviceInfo slavio_timer_info = {
408 .init = slavio_timer_init1,
409 .qdev.name = "slavio_timer",
410 .qdev.size = sizeof(SLAVIO_TIMERState),
Blue Swirl0e0bfee2009-10-24 17:35:13 +0000411 .qdev.vmsd = &vmstate_slavio_timer,
412 .qdev.reset = slavio_timer_reset,
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200413 .qdev.props = (Property[]) {
Gerd Hoffmann18c637d2009-08-03 17:35:32 +0200414 DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0),
415 DEFINE_PROP_END_OF_LIST(),
Blue Swirlc70c59e2009-07-15 08:53:09 +0000416 }
417};
418
419static void slavio_timer_register_devices(void)
420{
421 sysbus_register_withprop(&slavio_timer_info);
422}
423
424device_init(slavio_timer_register_devices)