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