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