milkymist-sysctl.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. * QEMU model of the Milkymist System Controller.
  3. *
  4. * Copyright (c) 2010 Michael Walle <michael@walle.cc>
  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 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 <http://www.gnu.org/licenses/>.
  18. *
  19. *
  20. * Specification available at:
  21. * http://www.milkymist.org/socdoc/sysctl.pdf
  22. */
  23. #include "hw.h"
  24. #include "sysbus.h"
  25. #include "sysemu.h"
  26. #include "trace.h"
  27. #include "qemu-timer.h"
  28. #include "qemu-error.h"
  29. enum {
  30. CTRL_ENABLE = (1<<0),
  31. CTRL_AUTORESTART = (1<<1),
  32. };
  33. enum {
  34. ICAP_READY = (1<<0),
  35. };
  36. enum {
  37. R_GPIO_IN = 0,
  38. R_GPIO_OUT,
  39. R_GPIO_INTEN,
  40. R_RESERVED0,
  41. R_TIMER0_CONTROL,
  42. R_TIMER0_COMPARE,
  43. R_TIMER0_COUNTER,
  44. R_RESERVED1,
  45. R_TIMER1_CONTROL,
  46. R_TIMER1_COMPARE,
  47. R_TIMER1_COUNTER,
  48. R_RESERVED2,
  49. R_RESERVED3,
  50. R_ICAP,
  51. R_CAPABILITIES,
  52. R_SYSTEM_ID,
  53. R_MAX
  54. };
  55. struct MilkymistSysctlState {
  56. SysBusDevice busdev;
  57. MemoryRegion regs_region;
  58. QEMUBH *bh0;
  59. QEMUBH *bh1;
  60. ptimer_state *ptimer0;
  61. ptimer_state *ptimer1;
  62. uint32_t freq_hz;
  63. uint32_t capabilities;
  64. uint32_t systemid;
  65. uint32_t strappings;
  66. uint32_t regs[R_MAX];
  67. qemu_irq gpio_irq;
  68. qemu_irq timer0_irq;
  69. qemu_irq timer1_irq;
  70. };
  71. typedef struct MilkymistSysctlState MilkymistSysctlState;
  72. static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
  73. {
  74. trace_milkymist_sysctl_icap_write(value);
  75. switch (value & 0xffff) {
  76. case 0x000e:
  77. qemu_system_shutdown_request();
  78. break;
  79. }
  80. }
  81. static uint64_t sysctl_read(void *opaque, target_phys_addr_t addr,
  82. unsigned size)
  83. {
  84. MilkymistSysctlState *s = opaque;
  85. uint32_t r = 0;
  86. addr >>= 2;
  87. switch (addr) {
  88. case R_TIMER0_COUNTER:
  89. r = (uint32_t)ptimer_get_count(s->ptimer0);
  90. /* milkymist timer counts up */
  91. r = s->regs[R_TIMER0_COMPARE] - r;
  92. break;
  93. case R_TIMER1_COUNTER:
  94. r = (uint32_t)ptimer_get_count(s->ptimer1);
  95. /* milkymist timer counts up */
  96. r = s->regs[R_TIMER1_COMPARE] - r;
  97. break;
  98. case R_GPIO_IN:
  99. case R_GPIO_OUT:
  100. case R_GPIO_INTEN:
  101. case R_TIMER0_CONTROL:
  102. case R_TIMER0_COMPARE:
  103. case R_TIMER1_CONTROL:
  104. case R_TIMER1_COMPARE:
  105. case R_ICAP:
  106. case R_CAPABILITIES:
  107. case R_SYSTEM_ID:
  108. r = s->regs[addr];
  109. break;
  110. default:
  111. error_report("milkymist_sysctl: read access to unknown register 0x"
  112. TARGET_FMT_plx, addr << 2);
  113. break;
  114. }
  115. trace_milkymist_sysctl_memory_read(addr << 2, r);
  116. return r;
  117. }
  118. static void sysctl_write(void *opaque, target_phys_addr_t addr, uint64_t value,
  119. unsigned size)
  120. {
  121. MilkymistSysctlState *s = opaque;
  122. trace_milkymist_sysctl_memory_write(addr, value);
  123. addr >>= 2;
  124. switch (addr) {
  125. case R_GPIO_OUT:
  126. case R_GPIO_INTEN:
  127. case R_TIMER0_COUNTER:
  128. case R_TIMER1_COUNTER:
  129. s->regs[addr] = value;
  130. break;
  131. case R_TIMER0_COMPARE:
  132. ptimer_set_limit(s->ptimer0, value, 0);
  133. s->regs[addr] = value;
  134. break;
  135. case R_TIMER1_COMPARE:
  136. ptimer_set_limit(s->ptimer1, value, 0);
  137. s->regs[addr] = value;
  138. break;
  139. case R_TIMER0_CONTROL:
  140. s->regs[addr] = value;
  141. if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
  142. trace_milkymist_sysctl_start_timer0();
  143. ptimer_set_count(s->ptimer0,
  144. s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
  145. ptimer_run(s->ptimer0, 0);
  146. } else {
  147. trace_milkymist_sysctl_stop_timer0();
  148. ptimer_stop(s->ptimer0);
  149. }
  150. break;
  151. case R_TIMER1_CONTROL:
  152. s->regs[addr] = value;
  153. if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
  154. trace_milkymist_sysctl_start_timer1();
  155. ptimer_set_count(s->ptimer1,
  156. s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
  157. ptimer_run(s->ptimer1, 0);
  158. } else {
  159. trace_milkymist_sysctl_stop_timer1();
  160. ptimer_stop(s->ptimer1);
  161. }
  162. break;
  163. case R_ICAP:
  164. sysctl_icap_write(s, value);
  165. break;
  166. case R_SYSTEM_ID:
  167. qemu_system_reset_request();
  168. break;
  169. case R_GPIO_IN:
  170. case R_CAPABILITIES:
  171. error_report("milkymist_sysctl: write to read-only register 0x"
  172. TARGET_FMT_plx, addr << 2);
  173. break;
  174. default:
  175. error_report("milkymist_sysctl: write access to unknown register 0x"
  176. TARGET_FMT_plx, addr << 2);
  177. break;
  178. }
  179. }
  180. static const MemoryRegionOps sysctl_mmio_ops = {
  181. .read = sysctl_read,
  182. .write = sysctl_write,
  183. .valid = {
  184. .min_access_size = 4,
  185. .max_access_size = 4,
  186. },
  187. .endianness = DEVICE_NATIVE_ENDIAN,
  188. };
  189. static void timer0_hit(void *opaque)
  190. {
  191. MilkymistSysctlState *s = opaque;
  192. if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
  193. s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
  194. trace_milkymist_sysctl_stop_timer0();
  195. ptimer_stop(s->ptimer0);
  196. }
  197. trace_milkymist_sysctl_pulse_irq_timer0();
  198. qemu_irq_pulse(s->timer0_irq);
  199. }
  200. static void timer1_hit(void *opaque)
  201. {
  202. MilkymistSysctlState *s = opaque;
  203. if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
  204. s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
  205. trace_milkymist_sysctl_stop_timer1();
  206. ptimer_stop(s->ptimer1);
  207. }
  208. trace_milkymist_sysctl_pulse_irq_timer1();
  209. qemu_irq_pulse(s->timer1_irq);
  210. }
  211. static void milkymist_sysctl_reset(DeviceState *d)
  212. {
  213. MilkymistSysctlState *s =
  214. container_of(d, MilkymistSysctlState, busdev.qdev);
  215. int i;
  216. for (i = 0; i < R_MAX; i++) {
  217. s->regs[i] = 0;
  218. }
  219. ptimer_stop(s->ptimer0);
  220. ptimer_stop(s->ptimer1);
  221. /* defaults */
  222. s->regs[R_ICAP] = ICAP_READY;
  223. s->regs[R_SYSTEM_ID] = s->systemid;
  224. s->regs[R_CAPABILITIES] = s->capabilities;
  225. s->regs[R_GPIO_IN] = s->strappings;
  226. }
  227. static int milkymist_sysctl_init(SysBusDevice *dev)
  228. {
  229. MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
  230. sysbus_init_irq(dev, &s->gpio_irq);
  231. sysbus_init_irq(dev, &s->timer0_irq);
  232. sysbus_init_irq(dev, &s->timer1_irq);
  233. s->bh0 = qemu_bh_new(timer0_hit, s);
  234. s->bh1 = qemu_bh_new(timer1_hit, s);
  235. s->ptimer0 = ptimer_init(s->bh0);
  236. s->ptimer1 = ptimer_init(s->bh1);
  237. ptimer_set_freq(s->ptimer0, s->freq_hz);
  238. ptimer_set_freq(s->ptimer1, s->freq_hz);
  239. memory_region_init_io(&s->regs_region, &sysctl_mmio_ops, s,
  240. "milkymist-sysctl", R_MAX * 4);
  241. sysbus_init_mmio_region(dev, &s->regs_region);
  242. return 0;
  243. }
  244. static const VMStateDescription vmstate_milkymist_sysctl = {
  245. .name = "milkymist-sysctl",
  246. .version_id = 1,
  247. .minimum_version_id = 1,
  248. .minimum_version_id_old = 1,
  249. .fields = (VMStateField[]) {
  250. VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
  251. VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
  252. VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
  253. VMSTATE_END_OF_LIST()
  254. }
  255. };
  256. static SysBusDeviceInfo milkymist_sysctl_info = {
  257. .init = milkymist_sysctl_init,
  258. .qdev.name = "milkymist-sysctl",
  259. .qdev.size = sizeof(MilkymistSysctlState),
  260. .qdev.vmsd = &vmstate_milkymist_sysctl,
  261. .qdev.reset = milkymist_sysctl_reset,
  262. .qdev.props = (Property[]) {
  263. DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
  264. freq_hz, 80000000),
  265. DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
  266. capabilities, 0x00000000),
  267. DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
  268. systemid, 0x10014d31),
  269. DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
  270. strappings, 0x00000001),
  271. DEFINE_PROP_END_OF_LIST(),
  272. }
  273. };
  274. static void milkymist_sysctl_register(void)
  275. {
  276. sysbus_register_withprop(&milkymist_sysctl_info);
  277. }
  278. device_init(milkymist_sysctl_register)