|
|
1.1 root 1: /*
2: * QEMU Sparc SLAVIO timer controller emulation
3: *
4: * Copyright (c) 2003-2005 Fabrice Bellard
1.1.1.4 ! root 5: *
1.1 root 6: * 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: */
1.1.1.4 ! root 24: #include "hw.h"
! 25: #include "sun4m.h"
! 26: #include "qemu-timer.h"
1.1 root 27:
28: //#define DEBUG_TIMER
29:
30: #ifdef DEBUG_TIMER
31: #define DPRINTF(fmt, args...) \
32: do { printf("TIMER: " fmt , ##args); } while (0)
33: #else
34: #define DPRINTF(fmt, args...)
35: #endif
36:
37: /*
38: * Registers of hardware timer in sun4m.
39: *
40: * This is the timer/counter part of chip STP2001 (Slave I/O), also
41: * produced as NCR89C105. See
42: * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
1.1.1.4 ! root 43: *
1.1 root 44: * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
45: * are zero. Bit 31 is 1 when count has been reached.
46: *
1.1.1.2 root 47: * Per-CPU timers interrupt local CPU, system timer uses normal
48: * interrupt routing.
49: *
1.1 root 50: */
51:
1.1.1.4 ! root 52: #define MAX_CPUS 16
! 53:
1.1 root 54: typedef struct SLAVIO_TIMERState {
1.1.1.4 ! root 55: qemu_irq irq;
! 56: ptimer_state *timer;
! 57: uint32_t count, counthigh, reached;
! 58: uint64_t limit;
! 59: // processor only
! 60: int running;
! 61: struct SLAVIO_TIMERState *master;
! 62: int slave_index;
! 63: // system only
! 64: unsigned int num_slaves;
! 65: struct SLAVIO_TIMERState *slave[MAX_CPUS];
! 66: uint32_t slave_mode;
1.1 root 67: } SLAVIO_TIMERState;
68:
69: #define TIMER_MAXADDR 0x1f
1.1.1.4 ! root 70: #define SYS_TIMER_SIZE 0x14
! 71: #define CPU_TIMER_SIZE 0x10
! 72:
! 73: #define SYS_TIMER_OFFSET 0x10000ULL
! 74: #define CPU_TIMER_OFFSET(cpu) (0x1000ULL * cpu)
! 75:
! 76: #define TIMER_LIMIT 0
! 77: #define TIMER_COUNTER 1
! 78: #define TIMER_COUNTER_NORST 2
! 79: #define TIMER_STATUS 3
! 80: #define TIMER_MODE 4
! 81:
! 82: #define TIMER_COUNT_MASK32 0xfffffe00
! 83: #define TIMER_LIMIT_MASK32 0x7fffffff
! 84: #define TIMER_MAX_COUNT64 0x7ffffffffffffe00ULL
! 85: #define TIMER_MAX_COUNT32 0x7ffffe00ULL
! 86: #define TIMER_REACHED 0x80000000
! 87: #define TIMER_PERIOD 500ULL // 500ns
! 88: #define LIMIT_TO_PERIODS(l) ((l) >> 9)
! 89: #define PERIODS_TO_LIMIT(l) ((l) << 9)
! 90:
! 91: static int slavio_timer_is_user(SLAVIO_TIMERState *s)
! 92: {
! 93: return s->master && (s->master->slave_mode & (1 << s->slave_index));
! 94: }
1.1 root 95:
96: // Update count, set irq, update expire_time
1.1.1.4 ! root 97: // Convert from ptimer countdown units
1.1 root 98: static void slavio_timer_get_out(SLAVIO_TIMERState *s)
99: {
1.1.1.4 ! root 100: uint64_t count, limit;
1.1 root 101:
1.1.1.4 ! root 102: if (s->limit == 0) /* free-run processor or system counter */
! 103: limit = TIMER_MAX_COUNT32;
1.1 root 104: else
1.1.1.4 ! root 105: limit = s->limit;
1.1 root 106:
1.1.1.4 ! root 107: if (s->timer)
! 108: count = limit - PERIODS_TO_LIMIT(ptimer_get_count(s->timer));
! 109: else
! 110: count = 0;
1.1 root 111:
1.1.1.4 ! root 112: DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", s->limit,
! 113: s->counthigh, s->count);
! 114: s->count = count & TIMER_COUNT_MASK32;
! 115: s->counthigh = count >> 32;
1.1 root 116: }
117:
118: // timer callback
119: static void slavio_timer_irq(void *opaque)
120: {
121: SLAVIO_TIMERState *s = opaque;
122:
123: slavio_timer_get_out(s);
1.1.1.4 ! root 124: DPRINTF("callback: count %x%08x\n", s->counthigh, s->count);
! 125: if (!slavio_timer_is_user(s)) {
! 126: s->reached = TIMER_REACHED;
! 127: qemu_irq_raise(s->irq);
! 128: }
1.1 root 129: }
130:
131: static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
132: {
133: SLAVIO_TIMERState *s = opaque;
1.1.1.4 ! root 134: uint32_t saddr, ret;
1.1 root 135:
136: saddr = (addr & TIMER_MAXADDR) >> 2;
137: switch (saddr) {
1.1.1.4 ! root 138: case TIMER_LIMIT:
! 139: // read limit (system counter mode) or read most signifying
! 140: // part of counter (user mode)
! 141: if (slavio_timer_is_user(s)) {
! 142: // read user timer MSW
! 143: slavio_timer_get_out(s);
! 144: ret = s->counthigh;
! 145: } else {
! 146: // read limit
! 147: // clear irq
! 148: qemu_irq_lower(s->irq);
! 149: s->reached = 0;
! 150: ret = s->limit & TIMER_LIMIT_MASK32;
! 151: }
! 152: break;
! 153: case TIMER_COUNTER:
! 154: // read counter and reached bit (system mode) or read lsbits
! 155: // of counter (user mode)
! 156: slavio_timer_get_out(s);
! 157: if (slavio_timer_is_user(s)) // read user timer LSW
! 158: ret = s->count & TIMER_COUNT_MASK32;
! 159: else // read limit
! 160: ret = (s->count & TIMER_MAX_COUNT32) | s->reached;
! 161: break;
! 162: case TIMER_STATUS:
! 163: // only available in processor counter/timer
! 164: // read start/stop status
! 165: ret = s->running;
! 166: break;
! 167: case TIMER_MODE:
! 168: // only available in system counter
! 169: // read user/system mode
! 170: ret = s->slave_mode;
! 171: break;
1.1 root 172: default:
1.1.1.4 ! root 173: DPRINTF("invalid read address " TARGET_FMT_plx "\n", addr);
! 174: ret = 0;
! 175: break;
1.1 root 176: }
1.1.1.4 ! root 177: DPRINTF("read " TARGET_FMT_plx " = %08x\n", addr, ret);
! 178:
! 179: return ret;
1.1 root 180: }
181:
1.1.1.4 ! root 182: static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr,
! 183: uint32_t val)
1.1 root 184: {
185: SLAVIO_TIMERState *s = opaque;
186: uint32_t saddr;
187:
1.1.1.4 ! root 188: DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val);
1.1 root 189: saddr = (addr & TIMER_MAXADDR) >> 2;
190: switch (saddr) {
1.1.1.4 ! root 191: case TIMER_LIMIT:
! 192: if (slavio_timer_is_user(s)) {
! 193: // set user counter MSW, reset counter
! 194: qemu_irq_lower(s->irq);
! 195: s->limit = TIMER_MAX_COUNT64;
! 196: DPRINTF("processor %d user timer reset\n", s->slave_index);
! 197: if (s->timer)
! 198: ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
! 199: } else {
! 200: // set limit, reset counter
! 201: qemu_irq_lower(s->irq);
! 202: s->limit = val & TIMER_MAX_COUNT32;
! 203: if (s->timer) {
! 204: if (s->limit == 0) /* free-run */
! 205: ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
! 206: else
! 207: ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
! 208: }
! 209: }
! 210: break;
! 211: case TIMER_COUNTER:
! 212: if (slavio_timer_is_user(s)) {
! 213: // set user counter LSW, reset counter
! 214: qemu_irq_lower(s->irq);
! 215: s->limit = TIMER_MAX_COUNT64;
! 216: DPRINTF("processor %d user timer reset\n", s->slave_index);
! 217: if (s->timer)
! 218: ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 1);
! 219: } else
! 220: DPRINTF("not user timer\n");
! 221: break;
! 222: case TIMER_COUNTER_NORST:
! 223: // set limit without resetting counter
! 224: s->limit = val & TIMER_MAX_COUNT32;
! 225: if (s->timer) {
! 226: if (s->limit == 0) /* free-run */
! 227: ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
! 228: else
! 229: ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(s->limit), 0);
! 230: }
! 231: break;
! 232: case TIMER_STATUS:
! 233: if (slavio_timer_is_user(s)) {
! 234: // start/stop user counter
! 235: if ((val & 1) && !s->running) {
! 236: DPRINTF("processor %d user timer started\n", s->slave_index);
! 237: if (s->timer)
! 238: ptimer_run(s->timer, 0);
! 239: s->running = 1;
! 240: } else if (!(val & 1) && s->running) {
! 241: DPRINTF("processor %d user timer stopped\n", s->slave_index);
! 242: if (s->timer)
! 243: ptimer_stop(s->timer);
! 244: s->running = 0;
! 245: }
! 246: }
! 247: break;
! 248: case TIMER_MODE:
! 249: if (s->master == NULL) {
! 250: unsigned int i;
! 251:
! 252: for (i = 0; i < s->num_slaves; i++) {
! 253: if (val & (1 << i)) {
! 254: qemu_irq_lower(s->slave[i]->irq);
! 255: s->slave[i]->limit = -1ULL;
! 256: } else {
! 257: ptimer_stop(s->slave[i]->timer);
! 258: }
! 259: if ((val & (1 << i)) != (s->slave_mode & (1 << i))) {
! 260: ptimer_stop(s->slave[i]->timer);
! 261: ptimer_set_limit(s->slave[i]->timer,
! 262: LIMIT_TO_PERIODS(s->slave[i]->limit), 1);
! 263: DPRINTF("processor %d timer changed\n",
! 264: s->slave[i]->slave_index);
! 265: ptimer_run(s->slave[i]->timer, 0);
! 266: }
! 267: }
! 268: s->slave_mode = val & ((1 << s->num_slaves) - 1);
! 269: } else
! 270: DPRINTF("not system timer\n");
! 271: break;
1.1 root 272: default:
1.1.1.4 ! root 273: DPRINTF("invalid write address " TARGET_FMT_plx "\n", addr);
! 274: break;
1.1 root 275: }
276: }
277:
278: static CPUReadMemoryFunc *slavio_timer_mem_read[3] = {
1.1.1.4 ! root 279: NULL,
! 280: NULL,
1.1 root 281: slavio_timer_mem_readl,
282: };
283:
284: static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = {
1.1.1.4 ! root 285: NULL,
! 286: NULL,
1.1 root 287: slavio_timer_mem_writel,
288: };
289:
290: static void slavio_timer_save(QEMUFile *f, void *opaque)
291: {
292: SLAVIO_TIMERState *s = opaque;
293:
1.1.1.4 ! root 294: qemu_put_be64s(f, &s->limit);
1.1 root 295: qemu_put_be32s(f, &s->count);
296: qemu_put_be32s(f, &s->counthigh);
297: qemu_put_be32s(f, &s->reached);
1.1.1.4 ! root 298: qemu_put_be32s(f, &s->running);
! 299: if (s->timer)
! 300: qemu_put_ptimer(f, s->timer);
1.1 root 301: }
302:
303: static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
304: {
305: SLAVIO_TIMERState *s = opaque;
1.1.1.4 ! root 306:
! 307: if (version_id != 3)
1.1 root 308: return -EINVAL;
309:
1.1.1.4 ! root 310: qemu_get_be64s(f, &s->limit);
1.1 root 311: qemu_get_be32s(f, &s->count);
312: qemu_get_be32s(f, &s->counthigh);
313: qemu_get_be32s(f, &s->reached);
1.1.1.4 ! root 314: qemu_get_be32s(f, &s->running);
! 315: if (s->timer)
! 316: qemu_get_ptimer(f, s->timer);
! 317:
1.1 root 318: return 0;
319: }
320:
321: static void slavio_timer_reset(void *opaque)
322: {
323: SLAVIO_TIMERState *s = opaque;
324:
325: s->limit = 0;
326: s->count = 0;
327: s->reached = 0;
1.1.1.4 ! root 328: s->slave_mode = 0;
! 329: if (!s->master || s->slave_index < s->master->num_slaves) {
! 330: ptimer_set_limit(s->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
! 331: ptimer_run(s->timer, 0);
! 332: }
! 333: s->running = 1;
! 334: qemu_irq_lower(s->irq);
1.1 root 335: }
336:
1.1.1.4 ! root 337: static SLAVIO_TIMERState *slavio_timer_init(target_phys_addr_t addr,
! 338: qemu_irq irq,
! 339: SLAVIO_TIMERState *master,
! 340: int slave_index)
1.1 root 341: {
342: int slavio_timer_io_memory;
343: SLAVIO_TIMERState *s;
1.1.1.4 ! root 344: QEMUBH *bh;
1.1 root 345:
346: s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
347: if (!s)
1.1.1.4 ! root 348: return s;
1.1 root 349: s->irq = irq;
1.1.1.4 ! root 350: s->master = master;
! 351: s->slave_index = slave_index;
! 352: if (!master || slave_index < master->num_slaves) {
! 353: bh = qemu_bh_new(slavio_timer_irq, s);
! 354: s->timer = ptimer_init(bh);
! 355: ptimer_set_period(s->timer, TIMER_PERIOD);
! 356: }
1.1 root 357:
358: slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
1.1.1.4 ! root 359: slavio_timer_mem_write, s);
! 360: if (master)
! 361: cpu_register_physical_memory(addr, CPU_TIMER_SIZE,
! 362: slavio_timer_io_memory);
! 363: else
! 364: cpu_register_physical_memory(addr, SYS_TIMER_SIZE,
! 365: slavio_timer_io_memory);
! 366: register_savevm("slavio_timer", addr, 3, slavio_timer_save,
! 367: slavio_timer_load, s);
1.1 root 368: qemu_register_reset(slavio_timer_reset, s);
369: slavio_timer_reset(s);
1.1.1.4 ! root 370:
! 371: return s;
! 372: }
! 373:
! 374: void slavio_timer_init_all(target_phys_addr_t base, qemu_irq master_irq,
! 375: qemu_irq *cpu_irqs, unsigned int num_cpus)
! 376: {
! 377: SLAVIO_TIMERState *master;
! 378: unsigned int i;
! 379:
! 380: master = slavio_timer_init(base + SYS_TIMER_OFFSET, master_irq, NULL, 0);
! 381:
! 382: master->num_slaves = num_cpus;
! 383:
! 384: for (i = 0; i < MAX_CPUS; i++) {
! 385: master->slave[i] = slavio_timer_init(base + (target_phys_addr_t)
! 386: CPU_TIMER_OFFSET(i),
! 387: cpu_irqs[i], master, i);
! 388: }
1.1 root 389: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.