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