altera_timer.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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-common.h"
  22. #include "qapi/error.h"
  23. #include "hw/sysbus.h"
  24. #include "sysemu/sysemu.h"
  25. #include "hw/ptimer.h"
  26. #define R_STATUS 0
  27. #define R_CONTROL 1
  28. #define R_PERIODL 2
  29. #define R_PERIODH 3
  30. #define R_SNAPL 4
  31. #define R_SNAPH 5
  32. #define R_MAX 6
  33. #define STATUS_TO 0x0001
  34. #define STATUS_RUN 0x0002
  35. #define CONTROL_ITO 0x0001
  36. #define CONTROL_CONT 0x0002
  37. #define CONTROL_START 0x0004
  38. #define CONTROL_STOP 0x0008
  39. #define TYPE_ALTERA_TIMER "ALTR.timer"
  40. #define ALTERA_TIMER(obj) \
  41. OBJECT_CHECK(AlteraTimer, (obj), TYPE_ALTERA_TIMER)
  42. typedef struct AlteraTimer {
  43. SysBusDevice busdev;
  44. MemoryRegion mmio;
  45. qemu_irq irq;
  46. uint32_t freq_hz;
  47. QEMUBH *bh;
  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. t->regs[R_CONTROL] = value & (CONTROL_ITO | CONTROL_CONT);
  90. if ((value & CONTROL_START) &&
  91. !(t->regs[R_STATUS] & STATUS_RUN)) {
  92. ptimer_run(t->ptimer, 1);
  93. t->regs[R_STATUS] |= STATUS_RUN;
  94. }
  95. if ((value & CONTROL_STOP) && (t->regs[R_STATUS] & STATUS_RUN)) {
  96. ptimer_stop(t->ptimer);
  97. t->regs[R_STATUS] &= ~STATUS_RUN;
  98. }
  99. break;
  100. case R_PERIODL:
  101. case R_PERIODH:
  102. t->regs[addr] = value & 0xFFFF;
  103. if (t->regs[R_STATUS] & STATUS_RUN) {
  104. ptimer_stop(t->ptimer);
  105. t->regs[R_STATUS] &= ~STATUS_RUN;
  106. }
  107. tvalue = (t->regs[R_PERIODH] << 16) | t->regs[R_PERIODL];
  108. ptimer_set_limit(t->ptimer, tvalue + 1, 1);
  109. break;
  110. case R_SNAPL:
  111. case R_SNAPH:
  112. count = ptimer_get_count(t->ptimer);
  113. t->regs[R_SNAPL] = count & 0xFFFF;
  114. t->regs[R_SNAPH] = count >> 16;
  115. break;
  116. default:
  117. break;
  118. }
  119. if (irqState != timer_irq_state(t)) {
  120. qemu_set_irq(t->irq, timer_irq_state(t));
  121. }
  122. }
  123. static const MemoryRegionOps timer_ops = {
  124. .read = timer_read,
  125. .write = timer_write,
  126. .endianness = DEVICE_NATIVE_ENDIAN,
  127. .valid = {
  128. .min_access_size = 1,
  129. .max_access_size = 4
  130. }
  131. };
  132. static void timer_hit(void *opaque)
  133. {
  134. AlteraTimer *t = opaque;
  135. const uint64_t tvalue = (t->regs[R_PERIODH] << 16) | t->regs[R_PERIODL];
  136. t->regs[R_STATUS] |= STATUS_TO;
  137. ptimer_set_limit(t->ptimer, tvalue + 1, 1);
  138. if (!(t->regs[R_CONTROL] & CONTROL_CONT)) {
  139. t->regs[R_STATUS] &= ~STATUS_RUN;
  140. ptimer_set_count(t->ptimer, tvalue);
  141. } else {
  142. ptimer_run(t->ptimer, 1);
  143. }
  144. qemu_set_irq(t->irq, timer_irq_state(t));
  145. }
  146. static void altera_timer_realize(DeviceState *dev, Error **errp)
  147. {
  148. AlteraTimer *t = ALTERA_TIMER(dev);
  149. SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
  150. if (t->freq_hz == 0) {
  151. error_setg(errp, "\"clock-frequency\" property must be provided.");
  152. return;
  153. }
  154. t->bh = qemu_bh_new(timer_hit, t);
  155. t->ptimer = ptimer_init(t->bh, PTIMER_POLICY_DEFAULT);
  156. ptimer_set_freq(t->ptimer, t->freq_hz);
  157. memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t,
  158. TYPE_ALTERA_TIMER, R_MAX * sizeof(uint32_t));
  159. sysbus_init_mmio(sbd, &t->mmio);
  160. }
  161. static void altera_timer_init(Object *obj)
  162. {
  163. AlteraTimer *t = ALTERA_TIMER(obj);
  164. SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  165. sysbus_init_irq(sbd, &t->irq);
  166. }
  167. static void altera_timer_reset(DeviceState *dev)
  168. {
  169. AlteraTimer *t = ALTERA_TIMER(dev);
  170. ptimer_stop(t->ptimer);
  171. ptimer_set_limit(t->ptimer, 0xffffffff, 1);
  172. memset(t->regs, 0, ARRAY_SIZE(t->regs));
  173. }
  174. static Property altera_timer_properties[] = {
  175. DEFINE_PROP_UINT32("clock-frequency", AlteraTimer, freq_hz, 0),
  176. DEFINE_PROP_END_OF_LIST(),
  177. };
  178. static void altera_timer_class_init(ObjectClass *klass, void *data)
  179. {
  180. DeviceClass *dc = DEVICE_CLASS(klass);
  181. dc->realize = altera_timer_realize;
  182. dc->props = altera_timer_properties;
  183. dc->reset = altera_timer_reset;
  184. }
  185. static const TypeInfo altera_timer_info = {
  186. .name = TYPE_ALTERA_TIMER,
  187. .parent = TYPE_SYS_BUS_DEVICE,
  188. .instance_size = sizeof(AlteraTimer),
  189. .instance_init = altera_timer_init,
  190. .class_init = altera_timer_class_init,
  191. };
  192. static void altera_timer_register(void)
  193. {
  194. type_register_static(&altera_timer_info);
  195. }
  196. type_init(altera_timer_register)