1 /* 2 * TI OMAP2 general purpose timers emulation. 3 * 4 * Copyright (C) 2007-2008 Nokia Corporation 5 * Written by Andrzej Zaborowski <andrew@openedhand.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 or 10 * (at your option) any later version of the License. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 #include "hw/hw.h" 21 #include "qemu/timer.h" 22 #include "hw/arm/omap.h" 23 24 /* GP timers */ 25 struct omap_gp_timer_s { 26 MemoryRegion iomem; 27 qemu_irq irq; 28 qemu_irq wkup; 29 qemu_irq in; 30 qemu_irq out; 31 omap_clk clk; 32 QEMUTimer *timer; 33 QEMUTimer *match; 34 struct omap_target_agent_s *ta; 35 36 int in_val; 37 int out_val; 38 int64_t time; 39 int64_t rate; 40 int64_t ticks_per_sec; 41 42 int16_t config; 43 int status; 44 int it_ena; 45 int wu_ena; 46 int enable; 47 int inout; 48 int capt2; 49 int pt; 50 enum { 51 gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both 52 } trigger; 53 enum { 54 gpt_capture_none, gpt_capture_rising, 55 gpt_capture_falling, gpt_capture_both 56 } capture; 57 int scpwm; 58 int ce; 59 int pre; 60 int ptv; 61 int ar; 62 int st; 63 int posted; 64 uint32_t val; 65 uint32_t load_val; 66 uint32_t capture_val[2]; 67 uint32_t match_val; 68 int capt_num; 69 70 uint16_t writeh; /* LSB */ 71 uint16_t readh; /* MSB */ 72 }; 73 74 #define GPT_TCAR_IT (1 << 2) 75 #define GPT_OVF_IT (1 << 1) 76 #define GPT_MAT_IT (1 << 0) 77 78 static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it) 79 { 80 if (timer->it_ena & it) { 81 if (!timer->status) 82 qemu_irq_raise(timer->irq); 83 84 timer->status |= it; 85 /* Or are the status bits set even when masked? 86 * i.e. is masking applied before or after the status register? */ 87 } 88 89 if (timer->wu_ena & it) 90 qemu_irq_pulse(timer->wkup); 91 } 92 93 static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level) 94 { 95 if (!timer->inout && timer->out_val != level) { 96 timer->out_val = level; 97 qemu_set_irq(timer->out, level); 98 } 99 } 100 101 static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer) 102 { 103 uint64_t distance; 104 105 if (timer->st && timer->rate) { 106 distance = qemu_get_clock_ns(vm_clock) - timer->time; 107 distance = muldiv64(distance, timer->rate, timer->ticks_per_sec); 108 109 if (distance >= 0xffffffff - timer->val) 110 return 0xffffffff; 111 else 112 return timer->val + distance; 113 } else 114 return timer->val; 115 } 116 117 static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer) 118 { 119 if (timer->st) { 120 timer->val = omap_gp_timer_read(timer); 121 timer->time = qemu_get_clock_ns(vm_clock); 122 } 123 } 124 125 static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer) 126 { 127 int64_t expires, matches; 128 129 if (timer->st && timer->rate) { 130 expires = muldiv64(0x100000000ll - timer->val, 131 timer->ticks_per_sec, timer->rate); 132 qemu_mod_timer(timer->timer, timer->time + expires); 133 134 if (timer->ce && timer->match_val >= timer->val) { 135 matches = muldiv64(timer->match_val - timer->val, 136 timer->ticks_per_sec, timer->rate); 137 qemu_mod_timer(timer->match, timer->time + matches); 138 } else 139 qemu_del_timer(timer->match); 140 } else { 141 qemu_del_timer(timer->timer); 142 qemu_del_timer(timer->match); 143 omap_gp_timer_out(timer, timer->scpwm); 144 } 145 } 146 147 static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer) 148 { 149 if (timer->pt) 150 /* TODO in overflow-and-match mode if the first event to 151 * occur is the match, don't toggle. */ 152 omap_gp_timer_out(timer, !timer->out_val); 153 else 154 /* TODO inverted pulse on timer->out_val == 1? */ 155 qemu_irq_pulse(timer->out); 156 } 157 158 static void omap_gp_timer_tick(void *opaque) 159 { 160 struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; 161 162 if (!timer->ar) { 163 timer->st = 0; 164 timer->val = 0; 165 } else { 166 timer->val = timer->load_val; 167 timer->time = qemu_get_clock_ns(vm_clock); 168 } 169 170 if (timer->trigger == gpt_trigger_overflow || 171 timer->trigger == gpt_trigger_both) 172 omap_gp_timer_trigger(timer); 173 174 omap_gp_timer_intr(timer, GPT_OVF_IT); 175 omap_gp_timer_update(timer); 176 } 177 178 static void omap_gp_timer_match(void *opaque) 179 { 180 struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; 181 182 if (timer->trigger == gpt_trigger_both) 183 omap_gp_timer_trigger(timer); 184 185 omap_gp_timer_intr(timer, GPT_MAT_IT); 186 } 187 188 static void omap_gp_timer_input(void *opaque, int line, int on) 189 { 190 struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 191 int trigger; 192 193 switch (s->capture) { 194 default: 195 case gpt_capture_none: 196 trigger = 0; 197 break; 198 case gpt_capture_rising: 199 trigger = !s->in_val && on; 200 break; 201 case gpt_capture_falling: 202 trigger = s->in_val && !on; 203 break; 204 case gpt_capture_both: 205 trigger = (s->in_val == !on); 206 break; 207 } 208 s->in_val = on; 209 210 if (s->inout && trigger && s->capt_num < 2) { 211 s->capture_val[s->capt_num] = omap_gp_timer_read(s); 212 213 if (s->capt2 == s->capt_num ++) 214 omap_gp_timer_intr(s, GPT_TCAR_IT); 215 } 216 } 217 218 static void omap_gp_timer_clk_update(void *opaque, int line, int on) 219 { 220 struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; 221 222 omap_gp_timer_sync(timer); 223 timer->rate = on ? omap_clk_getrate(timer->clk) : 0; 224 omap_gp_timer_update(timer); 225 } 226 227 static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer) 228 { 229 omap_clk_adduser(timer->clk, 230 qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]); 231 timer->rate = omap_clk_getrate(timer->clk); 232 } 233 234 void omap_gp_timer_reset(struct omap_gp_timer_s *s) 235 { 236 s->config = 0x000; 237 s->status = 0; 238 s->it_ena = 0; 239 s->wu_ena = 0; 240 s->inout = 0; 241 s->capt2 = 0; 242 s->capt_num = 0; 243 s->pt = 0; 244 s->trigger = gpt_trigger_none; 245 s->capture = gpt_capture_none; 246 s->scpwm = 0; 247 s->ce = 0; 248 s->pre = 0; 249 s->ptv = 0; 250 s->ar = 0; 251 s->st = 0; 252 s->posted = 1; 253 s->val = 0x00000000; 254 s->load_val = 0x00000000; 255 s->capture_val[0] = 0x00000000; 256 s->capture_val[1] = 0x00000000; 257 s->match_val = 0x00000000; 258 omap_gp_timer_update(s); 259 } 260 261 static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr) 262 { 263 struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 264 265 switch (addr) { 266 case 0x00: /* TIDR */ 267 return 0x21; 268 269 case 0x10: /* TIOCP_CFG */ 270 return s->config; 271 272 case 0x14: /* TISTAT */ 273 /* ??? When's this bit reset? */ 274 return 1; /* RESETDONE */ 275 276 case 0x18: /* TISR */ 277 return s->status; 278 279 case 0x1c: /* TIER */ 280 return s->it_ena; 281 282 case 0x20: /* TWER */ 283 return s->wu_ena; 284 285 case 0x24: /* TCLR */ 286 return (s->inout << 14) | 287 (s->capt2 << 13) | 288 (s->pt << 12) | 289 (s->trigger << 10) | 290 (s->capture << 8) | 291 (s->scpwm << 7) | 292 (s->ce << 6) | 293 (s->pre << 5) | 294 (s->ptv << 2) | 295 (s->ar << 1) | 296 (s->st << 0); 297 298 case 0x28: /* TCRR */ 299 return omap_gp_timer_read(s); 300 301 case 0x2c: /* TLDR */ 302 return s->load_val; 303 304 case 0x30: /* TTGR */ 305 return 0xffffffff; 306 307 case 0x34: /* TWPS */ 308 return 0x00000000; /* No posted writes pending. */ 309 310 case 0x38: /* TMAR */ 311 return s->match_val; 312 313 case 0x3c: /* TCAR1 */ 314 return s->capture_val[0]; 315 316 case 0x40: /* TSICR */ 317 return s->posted << 2; 318 319 case 0x44: /* TCAR2 */ 320 return s->capture_val[1]; 321 } 322 323 OMAP_BAD_REG(addr); 324 return 0; 325 } 326 327 static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr) 328 { 329 struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 330 uint32_t ret; 331 332 if (addr & 2) 333 return s->readh; 334 else { 335 ret = omap_gp_timer_readw(opaque, addr); 336 s->readh = ret >> 16; 337 return ret & 0xffff; 338 } 339 } 340 341 static void omap_gp_timer_write(void *opaque, hwaddr addr, 342 uint32_t value) 343 { 344 struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 345 346 switch (addr) { 347 case 0x00: /* TIDR */ 348 case 0x14: /* TISTAT */ 349 case 0x34: /* TWPS */ 350 case 0x3c: /* TCAR1 */ 351 case 0x44: /* TCAR2 */ 352 OMAP_RO_REG(addr); 353 break; 354 355 case 0x10: /* TIOCP_CFG */ 356 s->config = value & 0x33d; 357 if (((value >> 3) & 3) == 3) /* IDLEMODE */ 358 fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n", 359 __FUNCTION__); 360 if (value & 2) /* SOFTRESET */ 361 omap_gp_timer_reset(s); 362 break; 363 364 case 0x18: /* TISR */ 365 if (value & GPT_TCAR_IT) 366 s->capt_num = 0; 367 if (s->status && !(s->status &= ~value)) 368 qemu_irq_lower(s->irq); 369 break; 370 371 case 0x1c: /* TIER */ 372 s->it_ena = value & 7; 373 break; 374 375 case 0x20: /* TWER */ 376 s->wu_ena = value & 7; 377 break; 378 379 case 0x24: /* TCLR */ 380 omap_gp_timer_sync(s); 381 s->inout = (value >> 14) & 1; 382 s->capt2 = (value >> 13) & 1; 383 s->pt = (value >> 12) & 1; 384 s->trigger = (value >> 10) & 3; 385 if (s->capture == gpt_capture_none && 386 ((value >> 8) & 3) != gpt_capture_none) 387 s->capt_num = 0; 388 s->capture = (value >> 8) & 3; 389 s->scpwm = (value >> 7) & 1; 390 s->ce = (value >> 6) & 1; 391 s->pre = (value >> 5) & 1; 392 s->ptv = (value >> 2) & 7; 393 s->ar = (value >> 1) & 1; 394 s->st = (value >> 0) & 1; 395 if (s->inout && s->trigger != gpt_trigger_none) 396 fprintf(stderr, "%s: GP timer pin must be an output " 397 "for this trigger mode\n", __FUNCTION__); 398 if (!s->inout && s->capture != gpt_capture_none) 399 fprintf(stderr, "%s: GP timer pin must be an input " 400 "for this capture mode\n", __FUNCTION__); 401 if (s->trigger == gpt_trigger_none) 402 omap_gp_timer_out(s, s->scpwm); 403 /* TODO: make sure this doesn't overflow 32-bits */ 404 s->ticks_per_sec = get_ticks_per_sec() << (s->pre ? s->ptv + 1 : 0); 405 omap_gp_timer_update(s); 406 break; 407 408 case 0x28: /* TCRR */ 409 s->time = qemu_get_clock_ns(vm_clock); 410 s->val = value; 411 omap_gp_timer_update(s); 412 break; 413 414 case 0x2c: /* TLDR */ 415 s->load_val = value; 416 break; 417 418 case 0x30: /* TTGR */ 419 s->time = qemu_get_clock_ns(vm_clock); 420 s->val = s->load_val; 421 omap_gp_timer_update(s); 422 break; 423 424 case 0x38: /* TMAR */ 425 omap_gp_timer_sync(s); 426 s->match_val = value; 427 omap_gp_timer_update(s); 428 break; 429 430 case 0x40: /* TSICR */ 431 s->posted = (value >> 2) & 1; 432 if (value & 2) /* How much exactly are we supposed to reset? */ 433 omap_gp_timer_reset(s); 434 break; 435 436 default: 437 OMAP_BAD_REG(addr); 438 } 439 } 440 441 static void omap_gp_timer_writeh(void *opaque, hwaddr addr, 442 uint32_t value) 443 { 444 struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 445 446 if (addr & 2) 447 return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh); 448 else 449 s->writeh = (uint16_t) value; 450 } 451 452 static const MemoryRegionOps omap_gp_timer_ops = { 453 .old_mmio = { 454 .read = { 455 omap_badwidth_read32, 456 omap_gp_timer_readh, 457 omap_gp_timer_readw, 458 }, 459 .write = { 460 omap_badwidth_write32, 461 omap_gp_timer_writeh, 462 omap_gp_timer_write, 463 }, 464 }, 465 .endianness = DEVICE_NATIVE_ENDIAN, 466 }; 467 468 struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta, 469 qemu_irq irq, omap_clk fclk, omap_clk iclk) 470 { 471 struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) 472 g_malloc0(sizeof(struct omap_gp_timer_s)); 473 474 s->ta = ta; 475 s->irq = irq; 476 s->clk = fclk; 477 s->timer = qemu_new_timer_ns(vm_clock, omap_gp_timer_tick, s); 478 s->match = qemu_new_timer_ns(vm_clock, omap_gp_timer_match, s); 479 s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0]; 480 omap_gp_timer_reset(s); 481 omap_gp_timer_clk_setup(s); 482 483 memory_region_init_io(&s->iomem, &omap_gp_timer_ops, s, "omap.gptimer", 484 omap_l4_region_size(ta, 0)); 485 omap_l4_attach(ta, 0, &s->iomem); 486 487 return s; 488 } 489