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