|
|
1.1 root 1: /*
1.1.1.2 root 2: * QEMU ETRAX Timers
1.1 root 3: *
4: * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
5: *
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.3 ! root 24: #include "sysbus.h"
1.1.1.2 root 25: #include "sysemu.h"
1.1 root 26: #include "qemu-timer.h"
27:
1.1.1.2 root 28: #define D(x)
1.1 root 29:
1.1.1.2 root 30: #define RW_TMR0_DIV 0x00
31: #define R_TMR0_DATA 0x04
32: #define RW_TMR0_CTRL 0x08
33: #define RW_TMR1_DIV 0x10
34: #define R_TMR1_DATA 0x14
35: #define RW_TMR1_CTRL 0x18
36: #define R_TIME 0x38
37: #define RW_WD_CTRL 0x40
38: #define R_WD_STAT 0x44
39: #define RW_INTR_MASK 0x48
40: #define RW_ACK_INTR 0x4c
41: #define R_INTR 0x50
42: #define R_MASKED_INTR 0x54
1.1 root 43:
1.1.1.3 ! root 44: struct etrax_timer {
! 45: SysBusDevice busdev;
! 46: qemu_irq irq;
! 47: qemu_irq nmi;
! 48:
! 49: QEMUBH *bh_t0;
! 50: QEMUBH *bh_t1;
! 51: QEMUBH *bh_wd;
! 52: ptimer_state *ptimer_t0;
! 53: ptimer_state *ptimer_t1;
! 54: ptimer_state *ptimer_wd;
! 55:
! 56: int wd_hits;
! 57:
! 58: /* Control registers. */
! 59: uint32_t rw_tmr0_div;
! 60: uint32_t r_tmr0_data;
! 61: uint32_t rw_tmr0_ctrl;
! 62:
! 63: uint32_t rw_tmr1_div;
! 64: uint32_t r_tmr1_data;
! 65: uint32_t rw_tmr1_ctrl;
! 66:
! 67: uint32_t rw_wd_ctrl;
! 68:
! 69: uint32_t rw_intr_mask;
! 70: uint32_t rw_ack_intr;
! 71: uint32_t r_intr;
! 72: uint32_t r_masked_intr;
1.1.1.2 root 73: };
1.1 root 74:
75: static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
76: {
1.1.1.3 ! root 77: struct etrax_timer *t = opaque;
! 78: uint32_t r = 0;
1.1 root 79:
1.1.1.3 ! root 80: switch (addr) {
! 81: case R_TMR0_DATA:
! 82: r = ptimer_get_count(t->ptimer_t0);
! 83: break;
! 84: case R_TMR1_DATA:
! 85: r = ptimer_get_count(t->ptimer_t1);
! 86: break;
! 87: case R_TIME:
! 88: r = qemu_get_clock(vm_clock) / 10;
! 89: break;
! 90: case RW_INTR_MASK:
! 91: r = t->rw_intr_mask;
! 92: break;
! 93: case R_MASKED_INTR:
! 94: r = t->r_intr & t->rw_intr_mask;
! 95: break;
! 96: default:
! 97: D(printf ("%s %x\n", __func__, addr));
! 98: break;
! 99: }
! 100: return r;
1.1 root 101: }
102:
1.1.1.2 root 103: #define TIMER_SLOWDOWN 1
1.1.1.3 ! root 104: static void update_ctrl(struct etrax_timer *t, int tnum)
1.1 root 105: {
1.1.1.3 ! root 106: unsigned int op;
! 107: unsigned int freq;
! 108: unsigned int freq_hz;
! 109: unsigned int div;
! 110: uint32_t ctrl;
! 111:
! 112: ptimer_state *timer;
! 113:
! 114: if (tnum == 0) {
! 115: ctrl = t->rw_tmr0_ctrl;
! 116: div = t->rw_tmr0_div;
! 117: timer = t->ptimer_t0;
! 118: } else {
! 119: ctrl = t->rw_tmr1_ctrl;
! 120: div = t->rw_tmr1_div;
! 121: timer = t->ptimer_t1;
! 122: }
! 123:
! 124:
! 125: op = ctrl & 3;
! 126: freq = ctrl >> 2;
! 127: freq_hz = 32000000;
! 128:
! 129: switch (freq)
! 130: {
! 131: case 0:
! 132: case 1:
! 133: D(printf ("extern or disabled timer clock?\n"));
! 134: break;
! 135: case 4: freq_hz = 29493000; break;
! 136: case 5: freq_hz = 32000000; break;
! 137: case 6: freq_hz = 32768000; break;
! 138: case 7: freq_hz = 100000000; break;
! 139: default:
! 140: abort();
! 141: break;
! 142: }
! 143:
! 144: D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
! 145: div = div * TIMER_SLOWDOWN;
! 146: div /= 1000;
! 147: freq_hz /= 1000;
! 148: ptimer_set_freq(timer, freq_hz);
! 149: ptimer_set_limit(timer, div, 0);
! 150:
! 151: switch (op)
! 152: {
! 153: case 0:
! 154: /* Load. */
! 155: ptimer_set_limit(timer, div, 1);
! 156: break;
! 157: case 1:
! 158: /* Hold. */
! 159: ptimer_stop(timer);
! 160: break;
! 161: case 2:
! 162: /* Run. */
! 163: ptimer_run(timer, 0);
! 164: break;
! 165: default:
! 166: abort();
! 167: break;
! 168: }
! 169: }
! 170:
! 171: static void timer_update_irq(struct etrax_timer *t)
! 172: {
! 173: t->r_intr &= ~(t->rw_ack_intr);
! 174: t->r_masked_intr = t->r_intr & t->rw_intr_mask;
! 175:
! 176: D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr));
! 177: qemu_set_irq(t->irq, !!t->r_masked_intr);
1.1.1.2 root 178: }
179:
180: static void timer0_hit(void *opaque)
181: {
1.1.1.3 ! root 182: struct etrax_timer *t = opaque;
! 183: t->r_intr |= 1;
! 184: timer_update_irq(t);
1.1.1.2 root 185: }
186:
187: static void timer1_hit(void *opaque)
1.1 root 188: {
1.1.1.3 ! root 189: struct etrax_timer *t = opaque;
! 190: t->r_intr |= 2;
! 191: timer_update_irq(t);
1.1.1.2 root 192: }
193:
194: static void watchdog_hit(void *opaque)
195: {
1.1.1.3 ! root 196: struct etrax_timer *t = opaque;
! 197: if (t->wd_hits == 0) {
! 198: /* real hw gives a single tick before reseting but we are
! 199: a bit friendlier to compensate for our slower execution. */
! 200: ptimer_set_count(t->ptimer_wd, 10);
! 201: ptimer_run(t->ptimer_wd, 1);
! 202: qemu_irq_raise(t->nmi);
! 203: }
! 204: else
! 205: qemu_system_reset_request();
1.1.1.2 root 206:
1.1.1.3 ! root 207: t->wd_hits++;
! 208: }
! 209:
! 210: static inline void timer_watchdog_update(struct etrax_timer *t, uint32_t value)
! 211: {
! 212: unsigned int wd_en = t->rw_wd_ctrl & (1 << 8);
! 213: unsigned int wd_key = t->rw_wd_ctrl >> 9;
! 214: unsigned int wd_cnt = t->rw_wd_ctrl & 511;
! 215: unsigned int new_key = value >> 9 & ((1 << 7) - 1);
! 216: unsigned int new_cmd = (value >> 8) & 1;
! 217:
! 218: /* If the watchdog is enabled, they written key must match the
! 219: complement of the previous. */
! 220: wd_key = ~wd_key & ((1 << 7) - 1);
! 221:
! 222: if (wd_en && wd_key != new_key)
! 223: return;
! 224:
! 225: D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n",
! 226: wd_en, new_key, wd_key, new_cmd, wd_cnt));
! 227:
! 228: if (t->wd_hits)
! 229: qemu_irq_lower(t->nmi);
! 230:
! 231: t->wd_hits = 0;
! 232:
! 233: ptimer_set_freq(t->ptimer_wd, 760);
! 234: if (wd_cnt == 0)
! 235: wd_cnt = 256;
! 236: ptimer_set_count(t->ptimer_wd, wd_cnt);
! 237: if (new_cmd)
! 238: ptimer_run(t->ptimer_wd, 1);
! 239: else
! 240: ptimer_stop(t->ptimer_wd);
! 241:
! 242: t->rw_wd_ctrl = value;
1.1 root 243: }
244:
245: static void
246: timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
247: {
1.1.1.3 ! root 248: struct etrax_timer *t = opaque;
1.1.1.2 root 249:
1.1.1.3 ! root 250: switch (addr)
! 251: {
! 252: case RW_TMR0_DIV:
! 253: t->rw_tmr0_div = value;
! 254: break;
! 255: case RW_TMR0_CTRL:
! 256: D(printf ("RW_TMR0_CTRL=%x\n", value));
! 257: t->rw_tmr0_ctrl = value;
! 258: update_ctrl(t, 0);
! 259: break;
! 260: case RW_TMR1_DIV:
! 261: t->rw_tmr1_div = value;
! 262: break;
! 263: case RW_TMR1_CTRL:
! 264: D(printf ("RW_TMR1_CTRL=%x\n", value));
! 265: t->rw_tmr1_ctrl = value;
! 266: update_ctrl(t, 1);
! 267: break;
! 268: case RW_INTR_MASK:
! 269: D(printf ("RW_INTR_MASK=%x\n", value));
! 270: t->rw_intr_mask = value;
! 271: timer_update_irq(t);
! 272: break;
! 273: case RW_WD_CTRL:
! 274: timer_watchdog_update(t, value);
! 275: break;
! 276: case RW_ACK_INTR:
! 277: t->rw_ack_intr = value;
! 278: timer_update_irq(t);
! 279: t->rw_ack_intr = 0;
! 280: break;
! 281: default:
! 282: printf ("%s " TARGET_FMT_plx " %x\n",
! 283: __func__, addr, value);
! 284: break;
! 285: }
1.1 root 286: }
287:
288: static CPUReadMemoryFunc *timer_read[] = {
1.1.1.3 ! root 289: NULL, NULL,
! 290: &timer_readl,
1.1 root 291: };
292:
293: static CPUWriteMemoryFunc *timer_write[] = {
1.1.1.3 ! root 294: NULL, NULL,
! 295: &timer_writel,
1.1 root 296: };
297:
1.1.1.2 root 298: static void etraxfs_timer_reset(void *opaque)
1.1 root 299: {
1.1.1.3 ! root 300: struct etrax_timer *t = opaque;
1.1 root 301:
1.1.1.3 ! root 302: ptimer_stop(t->ptimer_t0);
! 303: ptimer_stop(t->ptimer_t1);
! 304: ptimer_stop(t->ptimer_wd);
! 305: t->rw_wd_ctrl = 0;
! 306: t->r_intr = 0;
! 307: t->rw_intr_mask = 0;
! 308: qemu_irq_lower(t->irq);
! 309: }
1.1.1.2 root 310:
1.1.1.3 ! root 311: static void etraxfs_timer_init(SysBusDevice *dev)
! 312: {
! 313: struct etrax_timer *t = FROM_SYSBUS(typeof (*t), dev);
! 314: int timer_regs;
! 315:
! 316: t->bh_t0 = qemu_bh_new(timer0_hit, t);
! 317: t->bh_t1 = qemu_bh_new(timer1_hit, t);
! 318: t->bh_wd = qemu_bh_new(watchdog_hit, t);
! 319: t->ptimer_t0 = ptimer_init(t->bh_t0);
! 320: t->ptimer_t1 = ptimer_init(t->bh_t1);
! 321: t->ptimer_wd = ptimer_init(t->bh_wd);
! 322:
! 323: sysbus_init_irq(dev, &t->irq);
! 324: sysbus_init_irq(dev, &t->nmi);
! 325:
! 326: timer_regs = cpu_register_io_memory(timer_read, timer_write, t);
! 327: sysbus_init_mmio(dev, 0x5c, timer_regs);
1.1 root 328:
1.1.1.3 ! root 329: qemu_register_reset(etraxfs_timer_reset, t);
1.1 root 330: }
1.1.1.3 ! root 331:
! 332: static void etraxfs_timer_register(void)
! 333: {
! 334: sysbus_register_dev("etraxfs,timer", sizeof (struct etrax_timer),
! 335: etraxfs_timer_init);
! 336: }
! 337:
! 338: device_init(etraxfs_timer_register)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.