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