1 /* 2 * QEMU model of the Altera timer. 3 * 4 * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see 18 * <http://www.gnu.org/licenses/lgpl-2.1.html> 19 */ 20 21 #include "qemu/osdep.h" 22 #include "qemu/module.h" 23 #include "qapi/error.h" 24 25 #include "hw/sysbus.h" 26 #include "sysemu/sysemu.h" 27 #include "hw/ptimer.h" 28 29 #define R_STATUS 0 30 #define R_CONTROL 1 31 #define R_PERIODL 2 32 #define R_PERIODH 3 33 #define R_SNAPL 4 34 #define R_SNAPH 5 35 #define R_MAX 6 36 37 #define STATUS_TO 0x0001 38 #define STATUS_RUN 0x0002 39 40 #define CONTROL_ITO 0x0001 41 #define CONTROL_CONT 0x0002 42 #define CONTROL_START 0x0004 43 #define CONTROL_STOP 0x0008 44 45 #define TYPE_ALTERA_TIMER "ALTR.timer" 46 #define ALTERA_TIMER(obj) \ 47 OBJECT_CHECK(AlteraTimer, (obj), TYPE_ALTERA_TIMER) 48 49 typedef struct AlteraTimer { 50 SysBusDevice busdev; 51 MemoryRegion mmio; 52 qemu_irq irq; 53 uint32_t freq_hz; 54 QEMUBH *bh; 55 ptimer_state *ptimer; 56 uint32_t regs[R_MAX]; 57 } AlteraTimer; 58 59 static int timer_irq_state(AlteraTimer *t) 60 { 61 bool irq = (t->regs[R_STATUS] & STATUS_TO) && 62 (t->regs[R_CONTROL] & CONTROL_ITO); 63 return irq; 64 } 65 66 static uint64_t timer_read(void *opaque, hwaddr addr, 67 unsigned int size) 68 { 69 AlteraTimer *t = opaque; 70 uint64_t r = 0; 71 72 addr >>= 2; 73 74 switch (addr) { 75 case R_CONTROL: 76 r = t->regs[R_CONTROL] & (CONTROL_ITO | CONTROL_CONT); 77 break; 78 79 default: 80 if (addr < ARRAY_SIZE(t->regs)) { 81 r = t->regs[addr]; 82 } 83 break; 84 } 85 86 return r; 87 } 88 89 static void timer_write(void *opaque, hwaddr addr, 90 uint64_t value, unsigned int size) 91 { 92 AlteraTimer *t = opaque; 93 uint64_t tvalue; 94 uint32_t count = 0; 95 int irqState = timer_irq_state(t); 96 97 addr >>= 2; 98 99 switch (addr) { 100 case R_STATUS: 101 /* The timeout bit is cleared by writing the status register. */ 102 t->regs[R_STATUS] &= ~STATUS_TO; 103 break; 104 105 case R_CONTROL: 106 t->regs[R_CONTROL] = value & (CONTROL_ITO | CONTROL_CONT); 107 if ((value & CONTROL_START) && 108 !(t->regs[R_STATUS] & STATUS_RUN)) { 109 ptimer_run(t->ptimer, 1); 110 t->regs[R_STATUS] |= STATUS_RUN; 111 } 112 if ((value & CONTROL_STOP) && (t->regs[R_STATUS] & STATUS_RUN)) { 113 ptimer_stop(t->ptimer); 114 t->regs[R_STATUS] &= ~STATUS_RUN; 115 } 116 break; 117 118 case R_PERIODL: 119 case R_PERIODH: 120 t->regs[addr] = value & 0xFFFF; 121 if (t->regs[R_STATUS] & STATUS_RUN) { 122 ptimer_stop(t->ptimer); 123 t->regs[R_STATUS] &= ~STATUS_RUN; 124 } 125 tvalue = (t->regs[R_PERIODH] << 16) | t->regs[R_PERIODL]; 126 ptimer_set_limit(t->ptimer, tvalue + 1, 1); 127 break; 128 129 case R_SNAPL: 130 case R_SNAPH: 131 count = ptimer_get_count(t->ptimer); 132 t->regs[R_SNAPL] = count & 0xFFFF; 133 t->regs[R_SNAPH] = count >> 16; 134 break; 135 136 default: 137 break; 138 } 139 140 if (irqState != timer_irq_state(t)) { 141 qemu_set_irq(t->irq, timer_irq_state(t)); 142 } 143 } 144 145 static const MemoryRegionOps timer_ops = { 146 .read = timer_read, 147 .write = timer_write, 148 .endianness = DEVICE_NATIVE_ENDIAN, 149 .valid = { 150 .min_access_size = 1, 151 .max_access_size = 4 152 } 153 }; 154 155 static void timer_hit(void *opaque) 156 { 157 AlteraTimer *t = opaque; 158 const uint64_t tvalue = (t->regs[R_PERIODH] << 16) | t->regs[R_PERIODL]; 159 160 t->regs[R_STATUS] |= STATUS_TO; 161 162 ptimer_set_limit(t->ptimer, tvalue + 1, 1); 163 164 if (!(t->regs[R_CONTROL] & CONTROL_CONT)) { 165 t->regs[R_STATUS] &= ~STATUS_RUN; 166 ptimer_set_count(t->ptimer, tvalue); 167 } else { 168 ptimer_run(t->ptimer, 1); 169 } 170 171 qemu_set_irq(t->irq, timer_irq_state(t)); 172 } 173 174 static void altera_timer_realize(DeviceState *dev, Error **errp) 175 { 176 AlteraTimer *t = ALTERA_TIMER(dev); 177 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 178 179 if (t->freq_hz == 0) { 180 error_setg(errp, "\"clock-frequency\" property must be provided."); 181 return; 182 } 183 184 t->bh = qemu_bh_new(timer_hit, t); 185 t->ptimer = ptimer_init(t->bh, PTIMER_POLICY_DEFAULT); 186 ptimer_set_freq(t->ptimer, t->freq_hz); 187 188 memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, 189 TYPE_ALTERA_TIMER, R_MAX * sizeof(uint32_t)); 190 sysbus_init_mmio(sbd, &t->mmio); 191 } 192 193 static void altera_timer_init(Object *obj) 194 { 195 AlteraTimer *t = ALTERA_TIMER(obj); 196 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 197 198 sysbus_init_irq(sbd, &t->irq); 199 } 200 201 static void altera_timer_reset(DeviceState *dev) 202 { 203 AlteraTimer *t = ALTERA_TIMER(dev); 204 205 ptimer_stop(t->ptimer); 206 ptimer_set_limit(t->ptimer, 0xffffffff, 1); 207 memset(t->regs, 0, sizeof(t->regs)); 208 } 209 210 static Property altera_timer_properties[] = { 211 DEFINE_PROP_UINT32("clock-frequency", AlteraTimer, freq_hz, 0), 212 DEFINE_PROP_END_OF_LIST(), 213 }; 214 215 static void altera_timer_class_init(ObjectClass *klass, void *data) 216 { 217 DeviceClass *dc = DEVICE_CLASS(klass); 218 219 dc->realize = altera_timer_realize; 220 dc->props = altera_timer_properties; 221 dc->reset = altera_timer_reset; 222 } 223 224 static const TypeInfo altera_timer_info = { 225 .name = TYPE_ALTERA_TIMER, 226 .parent = TYPE_SYS_BUS_DEVICE, 227 .instance_size = sizeof(AlteraTimer), 228 .instance_init = altera_timer_init, 229 .class_init = altera_timer_class_init, 230 }; 231 232 static void altera_timer_register(void) 233 { 234 type_register_static(&altera_timer_info); 235 } 236 237 type_init(altera_timer_register) 238