|
|
1.1 ! root 1: /* ! 2: * QEMU GRLIB GPTimer Emulator ! 3: * ! 4: * Copyright (c) 2010-2011 AdaCore ! 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: ! 25: #include "sysbus.h" ! 26: #include "qemu-timer.h" ! 27: ! 28: #include "trace.h" ! 29: ! 30: #define UNIT_REG_SIZE 16 /* Size of memory mapped regs for the unit */ ! 31: #define GPTIMER_REG_SIZE 16 /* Size of memory mapped regs for a GPTimer */ ! 32: ! 33: #define GPTIMER_MAX_TIMERS 8 ! 34: ! 35: /* GPTimer Config register fields */ ! 36: #define GPTIMER_ENABLE (1 << 0) ! 37: #define GPTIMER_RESTART (1 << 1) ! 38: #define GPTIMER_LOAD (1 << 2) ! 39: #define GPTIMER_INT_ENABLE (1 << 3) ! 40: #define GPTIMER_INT_PENDING (1 << 4) ! 41: #define GPTIMER_CHAIN (1 << 5) /* Not supported */ ! 42: #define GPTIMER_DEBUG_HALT (1 << 6) /* Not supported */ ! 43: ! 44: /* Memory mapped register offsets */ ! 45: #define SCALER_OFFSET 0x00 ! 46: #define SCALER_RELOAD_OFFSET 0x04 ! 47: #define CONFIG_OFFSET 0x08 ! 48: #define COUNTER_OFFSET 0x00 ! 49: #define COUNTER_RELOAD_OFFSET 0x04 ! 50: #define TIMER_BASE 0x10 ! 51: ! 52: typedef struct GPTimer GPTimer; ! 53: typedef struct GPTimerUnit GPTimerUnit; ! 54: ! 55: struct GPTimer { ! 56: QEMUBH *bh; ! 57: struct ptimer_state *ptimer; ! 58: ! 59: qemu_irq irq; ! 60: int id; ! 61: GPTimerUnit *unit; ! 62: ! 63: /* registers */ ! 64: uint32_t counter; ! 65: uint32_t reload; ! 66: uint32_t config; ! 67: }; ! 68: ! 69: struct GPTimerUnit { ! 70: SysBusDevice busdev; ! 71: ! 72: uint32_t nr_timers; /* Number of timers available */ ! 73: uint32_t freq_hz; /* System frequency */ ! 74: uint32_t irq_line; /* Base irq line */ ! 75: ! 76: GPTimer *timers; ! 77: ! 78: /* registers */ ! 79: uint32_t scaler; ! 80: uint32_t reload; ! 81: uint32_t config; ! 82: }; ! 83: ! 84: static void grlib_gptimer_enable(GPTimer *timer) ! 85: { ! 86: assert(timer != NULL); ! 87: ! 88: ! 89: ptimer_stop(timer->ptimer); ! 90: ! 91: if (!(timer->config & GPTIMER_ENABLE)) { ! 92: /* Timer disabled */ ! 93: trace_grlib_gptimer_disabled(timer->id, timer->config); ! 94: return; ! 95: } ! 96: ! 97: /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at ! 98: underflow. Set count + 1 to simulate the GPTimer behavior. */ ! 99: ! 100: trace_grlib_gptimer_enable(timer->id, timer->counter + 1); ! 101: ! 102: ptimer_set_count(timer->ptimer, timer->counter + 1); ! 103: ptimer_run(timer->ptimer, 1); ! 104: } ! 105: ! 106: static void grlib_gptimer_restart(GPTimer *timer) ! 107: { ! 108: assert(timer != NULL); ! 109: ! 110: trace_grlib_gptimer_restart(timer->id, timer->reload); ! 111: ! 112: timer->counter = timer->reload; ! 113: grlib_gptimer_enable(timer); ! 114: } ! 115: ! 116: static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler) ! 117: { ! 118: int i = 0; ! 119: uint32_t value = 0; ! 120: ! 121: assert(unit != NULL); ! 122: ! 123: if (scaler > 0) { ! 124: value = unit->freq_hz / (scaler + 1); ! 125: } else { ! 126: value = unit->freq_hz; ! 127: } ! 128: ! 129: trace_grlib_gptimer_set_scaler(scaler, value); ! 130: ! 131: for (i = 0; i < unit->nr_timers; i++) { ! 132: ptimer_set_freq(unit->timers[i].ptimer, value); ! 133: } ! 134: } ! 135: ! 136: static void grlib_gptimer_hit(void *opaque) ! 137: { ! 138: GPTimer *timer = opaque; ! 139: assert(timer != NULL); ! 140: ! 141: trace_grlib_gptimer_hit(timer->id); ! 142: ! 143: /* Timer expired */ ! 144: ! 145: if (timer->config & GPTIMER_INT_ENABLE) { ! 146: /* Set the pending bit (only unset by write in the config register) */ ! 147: timer->config |= GPTIMER_INT_PENDING; ! 148: qemu_irq_pulse(timer->irq); ! 149: } ! 150: ! 151: if (timer->config & GPTIMER_RESTART) { ! 152: grlib_gptimer_restart(timer); ! 153: } ! 154: } ! 155: ! 156: static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr) ! 157: { ! 158: GPTimerUnit *unit = opaque; ! 159: target_phys_addr_t timer_addr; ! 160: int id; ! 161: uint32_t value = 0; ! 162: ! 163: addr &= 0xff; ! 164: ! 165: /* Unit registers */ ! 166: switch (addr) { ! 167: case SCALER_OFFSET: ! 168: trace_grlib_gptimer_readl(-1, "scaler:", unit->scaler); ! 169: return unit->scaler; ! 170: ! 171: case SCALER_RELOAD_OFFSET: ! 172: trace_grlib_gptimer_readl(-1, "reload:", unit->reload); ! 173: return unit->reload; ! 174: ! 175: case CONFIG_OFFSET: ! 176: trace_grlib_gptimer_readl(-1, "config:", unit->config); ! 177: return unit->config; ! 178: ! 179: default: ! 180: break; ! 181: } ! 182: ! 183: timer_addr = (addr % TIMER_BASE); ! 184: id = (addr - TIMER_BASE) / TIMER_BASE; ! 185: ! 186: if (id >= 0 && id < unit->nr_timers) { ! 187: ! 188: /* GPTimer registers */ ! 189: switch (timer_addr) { ! 190: case COUNTER_OFFSET: ! 191: value = ptimer_get_count(unit->timers[id].ptimer); ! 192: trace_grlib_gptimer_readl(id, "counter value:", value); ! 193: return value; ! 194: ! 195: case COUNTER_RELOAD_OFFSET: ! 196: value = unit->timers[id].reload; ! 197: trace_grlib_gptimer_readl(id, "reload value:", value); ! 198: return value; ! 199: ! 200: case CONFIG_OFFSET: ! 201: trace_grlib_gptimer_readl(id, "scaler value:", ! 202: unit->timers[id].config); ! 203: return unit->timers[id].config; ! 204: ! 205: default: ! 206: break; ! 207: } ! 208: ! 209: } ! 210: ! 211: trace_grlib_gptimer_unknown_register("read", addr); ! 212: return 0; ! 213: } ! 214: ! 215: static void ! 216: grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value) ! 217: { ! 218: GPTimerUnit *unit = opaque; ! 219: target_phys_addr_t timer_addr; ! 220: int id; ! 221: ! 222: addr &= 0xff; ! 223: ! 224: /* Unit registers */ ! 225: switch (addr) { ! 226: case SCALER_OFFSET: ! 227: value &= 0xFFFF; /* clean up the value */ ! 228: unit->scaler = value; ! 229: trace_grlib_gptimer_writel(-1, "scaler:", unit->scaler); ! 230: return; ! 231: ! 232: case SCALER_RELOAD_OFFSET: ! 233: value &= 0xFFFF; /* clean up the value */ ! 234: unit->reload = value; ! 235: trace_grlib_gptimer_writel(-1, "reload:", unit->reload); ! 236: grlib_gptimer_set_scaler(unit, value); ! 237: return; ! 238: ! 239: case CONFIG_OFFSET: ! 240: /* Read Only (disable timer freeze not supported) */ ! 241: trace_grlib_gptimer_writel(-1, "config (Read Only):", 0); ! 242: return; ! 243: ! 244: default: ! 245: break; ! 246: } ! 247: ! 248: timer_addr = (addr % TIMER_BASE); ! 249: id = (addr - TIMER_BASE) / TIMER_BASE; ! 250: ! 251: if (id >= 0 && id < unit->nr_timers) { ! 252: ! 253: /* GPTimer registers */ ! 254: switch (timer_addr) { ! 255: case COUNTER_OFFSET: ! 256: trace_grlib_gptimer_writel(id, "counter:", value); ! 257: unit->timers[id].counter = value; ! 258: grlib_gptimer_enable(&unit->timers[id]); ! 259: return; ! 260: ! 261: case COUNTER_RELOAD_OFFSET: ! 262: trace_grlib_gptimer_writel(id, "reload:", value); ! 263: unit->timers[id].reload = value; ! 264: return; ! 265: ! 266: case CONFIG_OFFSET: ! 267: trace_grlib_gptimer_writel(id, "config:", value); ! 268: ! 269: if (value & GPTIMER_INT_PENDING) { ! 270: /* clear pending bit */ ! 271: value &= ~GPTIMER_INT_PENDING; ! 272: } else { ! 273: /* keep pending bit */ ! 274: value |= unit->timers[id].config & GPTIMER_INT_PENDING; ! 275: } ! 276: ! 277: unit->timers[id].config = value; ! 278: ! 279: /* gptimer_restart calls gptimer_enable, so if "enable" and "load" ! 280: bits are present, we just have to call restart. */ ! 281: ! 282: if (value & GPTIMER_LOAD) { ! 283: grlib_gptimer_restart(&unit->timers[id]); ! 284: } else if (value & GPTIMER_ENABLE) { ! 285: grlib_gptimer_enable(&unit->timers[id]); ! 286: } ! 287: ! 288: /* These fields must always be read as 0 */ ! 289: value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT); ! 290: ! 291: unit->timers[id].config = value; ! 292: return; ! 293: ! 294: default: ! 295: break; ! 296: } ! 297: ! 298: } ! 299: ! 300: trace_grlib_gptimer_unknown_register("write", addr); ! 301: } ! 302: ! 303: static CPUReadMemoryFunc * const grlib_gptimer_read[] = { ! 304: NULL, NULL, grlib_gptimer_readl, ! 305: }; ! 306: ! 307: static CPUWriteMemoryFunc * const grlib_gptimer_write[] = { ! 308: NULL, NULL, grlib_gptimer_writel, ! 309: }; ! 310: ! 311: static void grlib_gptimer_reset(DeviceState *d) ! 312: { ! 313: GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev); ! 314: int i = 0; ! 315: ! 316: assert(unit != NULL); ! 317: ! 318: unit->scaler = 0; ! 319: unit->reload = 0; ! 320: unit->config = 0; ! 321: ! 322: unit->config = unit->nr_timers; ! 323: unit->config |= unit->irq_line << 3; ! 324: unit->config |= 1 << 8; /* separate interrupt */ ! 325: unit->config |= 1 << 9; /* Disable timer freeze */ ! 326: ! 327: ! 328: for (i = 0; i < unit->nr_timers; i++) { ! 329: GPTimer *timer = &unit->timers[i]; ! 330: ! 331: timer->counter = 0; ! 332: timer->reload = 0; ! 333: timer->config = 0; ! 334: ptimer_stop(timer->ptimer); ! 335: ptimer_set_count(timer->ptimer, 0); ! 336: ptimer_set_freq(timer->ptimer, unit->freq_hz); ! 337: } ! 338: } ! 339: ! 340: static int grlib_gptimer_init(SysBusDevice *dev) ! 341: { ! 342: GPTimerUnit *unit = FROM_SYSBUS(typeof(*unit), dev); ! 343: unsigned int i; ! 344: int timer_regs; ! 345: ! 346: assert(unit->nr_timers > 0); ! 347: assert(unit->nr_timers <= GPTIMER_MAX_TIMERS); ! 348: ! 349: unit->timers = qemu_mallocz(sizeof unit->timers[0] * unit->nr_timers); ! 350: ! 351: for (i = 0; i < unit->nr_timers; i++) { ! 352: GPTimer *timer = &unit->timers[i]; ! 353: ! 354: timer->unit = unit; ! 355: timer->bh = qemu_bh_new(grlib_gptimer_hit, timer); ! 356: timer->ptimer = ptimer_init(timer->bh); ! 357: timer->id = i; ! 358: ! 359: /* One IRQ line for each timer */ ! 360: sysbus_init_irq(dev, &timer->irq); ! 361: ! 362: ptimer_set_freq(timer->ptimer, unit->freq_hz); ! 363: } ! 364: ! 365: timer_regs = cpu_register_io_memory(grlib_gptimer_read, ! 366: grlib_gptimer_write, ! 367: unit, DEVICE_NATIVE_ENDIAN); ! 368: if (timer_regs < 0) { ! 369: return -1; ! 370: } ! 371: ! 372: sysbus_init_mmio(dev, UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers, ! 373: timer_regs); ! 374: return 0; ! 375: } ! 376: ! 377: static SysBusDeviceInfo grlib_gptimer_info = { ! 378: .init = grlib_gptimer_init, ! 379: .qdev.name = "grlib,gptimer", ! 380: .qdev.reset = grlib_gptimer_reset, ! 381: .qdev.size = sizeof(GPTimerUnit), ! 382: .qdev.props = (Property[]) { ! 383: DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000), ! 384: DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8), ! 385: DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2), ! 386: DEFINE_PROP_END_OF_LIST() ! 387: } ! 388: }; ! 389: ! 390: static void grlib_gptimer_register(void) ! 391: { ! 392: sysbus_register_withprop(&grlib_gptimer_info); ! 393: } ! 394: ! 395: device_init(grlib_gptimer_register)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.