2
0

omap_gptimer.c 13 KB

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