2
0

altera_timer.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /*
  2. * QEMU model of the Altera timer.
  3. *
  4. * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, see
  18. * <http://www.gnu.org/licenses/lgpl-2.1.html>
  19. */
  20. #include "qemu/osdep.h"
  21. #include "qemu/module.h"
  22. #include "qapi/error.h"
  23. #include "hw/sysbus.h"
  24. #include "hw/irq.h"
  25. #include "hw/ptimer.h"
  26. #include "hw/qdev-properties.h"
  27. #define R_STATUS 0
  28. #define R_CONTROL 1
  29. #define R_PERIODL 2
  30. #define R_PERIODH 3
  31. #define R_SNAPL 4
  32. #define R_SNAPH 5
  33. #define R_MAX 6
  34. #define STATUS_TO 0x0001
  35. #define STATUS_RUN 0x0002
  36. #define CONTROL_ITO 0x0001
  37. #define CONTROL_CONT 0x0002
  38. #define CONTROL_START 0x0004
  39. #define CONTROL_STOP 0x0008
  40. #define TYPE_ALTERA_TIMER "ALTR.timer"
  41. #define ALTERA_TIMER(obj) \
  42. OBJECT_CHECK(AlteraTimer, (obj), TYPE_ALTERA_TIMER)
  43. typedef struct AlteraTimer {
  44. SysBusDevice busdev;
  45. MemoryRegion mmio;
  46. qemu_irq irq;
  47. uint32_t freq_hz;
  48. ptimer_state *ptimer;
  49. uint32_t regs[R_MAX];
  50. } AlteraTimer;
  51. static int timer_irq_state(AlteraTimer *t)
  52. {
  53. bool irq = (t->regs[R_STATUS] & STATUS_TO) &&
  54. (t->regs[R_CONTROL] & CONTROL_ITO);
  55. return irq;
  56. }
  57. static uint64_t timer_read(void *opaque, hwaddr addr,
  58. unsigned int size)
  59. {
  60. AlteraTimer *t = opaque;
  61. uint64_t r = 0;
  62. addr >>= 2;
  63. switch (addr) {
  64. case R_CONTROL:
  65. r = t->regs[R_CONTROL] & (CONTROL_ITO | CONTROL_CONT);
  66. break;
  67. default:
  68. if (addr < ARRAY_SIZE(t->regs)) {
  69. r = t->regs[addr];
  70. }
  71. break;
  72. }
  73. return r;
  74. }
  75. static void timer_write(void *opaque, hwaddr addr,
  76. uint64_t value, unsigned int size)
  77. {
  78. AlteraTimer *t = opaque;
  79. uint64_t tvalue;
  80. uint32_t count = 0;
  81. int irqState = timer_irq_state(t);
  82. addr >>= 2;
  83. switch (addr) {
  84. case R_STATUS:
  85. /* The timeout bit is cleared by writing the status register. */
  86. t->regs[R_STATUS] &= ~STATUS_TO;
  87. break;
  88. case R_CONTROL:
  89. ptimer_transaction_begin(t->ptimer);
  90. t->regs[R_CONTROL] = value & (CONTROL_ITO | CONTROL_CONT);
  91. if ((value & CONTROL_START) &&
  92. !(t->regs[R_STATUS] & STATUS_RUN)) {
  93. ptimer_run(t->ptimer, 1);
  94. t->regs[R_STATUS] |= STATUS_RUN;
  95. }
  96. if ((value & CONTROL_STOP) && (t->regs[R_STATUS] & STATUS_RUN)) {
  97. ptimer_stop(t->ptimer);
  98. t->regs[R_STATUS] &= ~STATUS_RUN;
  99. }
  100. ptimer_transaction_commit(t->ptimer);
  101. break;
  102. case R_PERIODL:
  103. case R_PERIODH:
  104. ptimer_transaction_begin(t->ptimer);
  105. t->regs[addr] = value & 0xFFFF;
  106. if (t->regs[R_STATUS] & STATUS_RUN) {
  107. ptimer_stop(t->ptimer);
  108. t->regs[R_STATUS] &= ~STATUS_RUN;
  109. }
  110. tvalue = (t->regs[R_PERIODH] << 16) | t->regs[R_PERIODL];
  111. ptimer_set_limit(t->ptimer, tvalue + 1, 1);
  112. ptimer_transaction_commit(t->ptimer);
  113. break;
  114. case R_SNAPL:
  115. case R_SNAPH:
  116. count = ptimer_get_count(t->ptimer);
  117. t->regs[R_SNAPL] = count & 0xFFFF;
  118. t->regs[R_SNAPH] = count >> 16;
  119. break;
  120. default:
  121. break;
  122. }
  123. if (irqState != timer_irq_state(t)) {
  124. qemu_set_irq(t->irq, timer_irq_state(t));
  125. }
  126. }
  127. static const MemoryRegionOps timer_ops = {
  128. .read = timer_read,
  129. .write = timer_write,
  130. .endianness = DEVICE_NATIVE_ENDIAN,
  131. .valid = {
  132. .min_access_size = 1,
  133. .max_access_size = 4
  134. }
  135. };
  136. static void timer_hit(void *opaque)
  137. {
  138. AlteraTimer *t = opaque;
  139. const uint64_t tvalue = (t->regs[R_PERIODH] << 16) | t->regs[R_PERIODL];
  140. t->regs[R_STATUS] |= STATUS_TO;
  141. ptimer_set_limit(t->ptimer, tvalue + 1, 1);
  142. if (!(t->regs[R_CONTROL] & CONTROL_CONT)) {
  143. t->regs[R_STATUS] &= ~STATUS_RUN;
  144. ptimer_set_count(t->ptimer, tvalue);
  145. } else {
  146. ptimer_run(t->ptimer, 1);
  147. }
  148. qemu_set_irq(t->irq, timer_irq_state(t));
  149. }
  150. static void altera_timer_realize(DeviceState *dev, Error **errp)
  151. {
  152. AlteraTimer *t = ALTERA_TIMER(dev);
  153. SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
  154. if (t->freq_hz == 0) {
  155. error_setg(errp, "\"clock-frequency\" property must be provided.");
  156. return;
  157. }
  158. t->ptimer = ptimer_init(timer_hit, t, PTIMER_POLICY_DEFAULT);
  159. ptimer_transaction_begin(t->ptimer);
  160. ptimer_set_freq(t->ptimer, t->freq_hz);
  161. ptimer_transaction_commit(t->ptimer);
  162. memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t,
  163. TYPE_ALTERA_TIMER, R_MAX * sizeof(uint32_t));
  164. sysbus_init_mmio(sbd, &t->mmio);
  165. }
  166. static void altera_timer_init(Object *obj)
  167. {
  168. AlteraTimer *t = ALTERA_TIMER(obj);
  169. SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  170. sysbus_init_irq(sbd, &t->irq);
  171. }
  172. static void altera_timer_reset(DeviceState *dev)
  173. {
  174. AlteraTimer *t = ALTERA_TIMER(dev);
  175. ptimer_transaction_begin(t->ptimer);
  176. ptimer_stop(t->ptimer);
  177. ptimer_set_limit(t->ptimer, 0xffffffff, 1);
  178. ptimer_transaction_commit(t->ptimer);
  179. memset(t->regs, 0, sizeof(t->regs));
  180. }
  181. static Property altera_timer_properties[] = {
  182. DEFINE_PROP_UINT32("clock-frequency", AlteraTimer, freq_hz, 0),
  183. DEFINE_PROP_END_OF_LIST(),
  184. };
  185. static void altera_timer_class_init(ObjectClass *klass, void *data)
  186. {
  187. DeviceClass *dc = DEVICE_CLASS(klass);
  188. dc->realize = altera_timer_realize;
  189. dc->props = altera_timer_properties;
  190. dc->reset = altera_timer_reset;
  191. }
  192. static const TypeInfo altera_timer_info = {
  193. .name = TYPE_ALTERA_TIMER,
  194. .parent = TYPE_SYS_BUS_DEVICE,
  195. .instance_size = sizeof(AlteraTimer),
  196. .instance_init = altera_timer_init,
  197. .class_init = altera_timer_class_init,
  198. };
  199. static void altera_timer_register(void)
  200. {
  201. type_register_static(&altera_timer_info);
  202. }
  203. type_init(altera_timer_register)