milkymist-sysctl.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * QEMU model of the Milkymist System Controller.
  3. *
  4. * Copyright (c) 2010-2012 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://milkymist.walle.cc/socdoc/sysctl.pdf
  22. */
  23. #include "qemu/osdep.h"
  24. #include "hw/irq.h"
  25. #include "hw/sysbus.h"
  26. #include "migration/vmstate.h"
  27. #include "trace.h"
  28. #include "qemu/timer.h"
  29. #include "sysemu/runstate.h"
  30. #include "hw/ptimer.h"
  31. #include "hw/qdev-properties.h"
  32. #include "qemu/error-report.h"
  33. #include "qemu/module.h"
  34. #include "qom/object.h"
  35. enum {
  36. CTRL_ENABLE = (1<<0),
  37. CTRL_AUTORESTART = (1<<1),
  38. };
  39. enum {
  40. ICAP_READY = (1<<0),
  41. };
  42. enum {
  43. R_GPIO_IN = 0,
  44. R_GPIO_OUT,
  45. R_GPIO_INTEN,
  46. R_TIMER0_CONTROL = 4,
  47. R_TIMER0_COMPARE,
  48. R_TIMER0_COUNTER,
  49. R_TIMER1_CONTROL = 8,
  50. R_TIMER1_COMPARE,
  51. R_TIMER1_COUNTER,
  52. R_ICAP = 16,
  53. R_DBG_SCRATCHPAD = 20,
  54. R_DBG_WRITE_LOCK,
  55. R_CLK_FREQUENCY = 29,
  56. R_CAPABILITIES,
  57. R_SYSTEM_ID,
  58. R_MAX
  59. };
  60. #define TYPE_MILKYMIST_SYSCTL "milkymist-sysctl"
  61. OBJECT_DECLARE_SIMPLE_TYPE(MilkymistSysctlState, MILKYMIST_SYSCTL)
  62. struct MilkymistSysctlState {
  63. SysBusDevice parent_obj;
  64. MemoryRegion regs_region;
  65. ptimer_state *ptimer0;
  66. ptimer_state *ptimer1;
  67. uint32_t freq_hz;
  68. uint32_t capabilities;
  69. uint32_t systemid;
  70. uint32_t strappings;
  71. uint32_t regs[R_MAX];
  72. qemu_irq gpio_irq;
  73. qemu_irq timer0_irq;
  74. qemu_irq timer1_irq;
  75. };
  76. static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
  77. {
  78. trace_milkymist_sysctl_icap_write(value);
  79. switch (value & 0xffff) {
  80. case 0x000e:
  81. qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
  82. break;
  83. }
  84. }
  85. static uint64_t sysctl_read(void *opaque, hwaddr addr,
  86. unsigned size)
  87. {
  88. MilkymistSysctlState *s = opaque;
  89. uint32_t r = 0;
  90. addr >>= 2;
  91. switch (addr) {
  92. case R_TIMER0_COUNTER:
  93. r = (uint32_t)ptimer_get_count(s->ptimer0);
  94. /* milkymist timer counts up */
  95. r = s->regs[R_TIMER0_COMPARE] - r;
  96. break;
  97. case R_TIMER1_COUNTER:
  98. r = (uint32_t)ptimer_get_count(s->ptimer1);
  99. /* milkymist timer counts up */
  100. r = s->regs[R_TIMER1_COMPARE] - r;
  101. break;
  102. case R_GPIO_IN:
  103. case R_GPIO_OUT:
  104. case R_GPIO_INTEN:
  105. case R_TIMER0_CONTROL:
  106. case R_TIMER0_COMPARE:
  107. case R_TIMER1_CONTROL:
  108. case R_TIMER1_COMPARE:
  109. case R_ICAP:
  110. case R_DBG_SCRATCHPAD:
  111. case R_DBG_WRITE_LOCK:
  112. case R_CLK_FREQUENCY:
  113. case R_CAPABILITIES:
  114. case R_SYSTEM_ID:
  115. r = s->regs[addr];
  116. break;
  117. default:
  118. error_report("milkymist_sysctl: read access to unknown register 0x"
  119. TARGET_FMT_plx, addr << 2);
  120. break;
  121. }
  122. trace_milkymist_sysctl_memory_read(addr << 2, r);
  123. return r;
  124. }
  125. static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
  126. unsigned size)
  127. {
  128. MilkymistSysctlState *s = opaque;
  129. trace_milkymist_sysctl_memory_write(addr, value);
  130. addr >>= 2;
  131. switch (addr) {
  132. case R_GPIO_OUT:
  133. case R_GPIO_INTEN:
  134. case R_TIMER0_COUNTER:
  135. case R_TIMER1_COUNTER:
  136. case R_DBG_SCRATCHPAD:
  137. s->regs[addr] = value;
  138. break;
  139. case R_TIMER0_COMPARE:
  140. ptimer_transaction_begin(s->ptimer0);
  141. ptimer_set_limit(s->ptimer0, value, 0);
  142. s->regs[addr] = value;
  143. ptimer_transaction_commit(s->ptimer0);
  144. break;
  145. case R_TIMER1_COMPARE:
  146. ptimer_transaction_begin(s->ptimer1);
  147. ptimer_set_limit(s->ptimer1, value, 0);
  148. s->regs[addr] = value;
  149. ptimer_transaction_commit(s->ptimer1);
  150. break;
  151. case R_TIMER0_CONTROL:
  152. ptimer_transaction_begin(s->ptimer0);
  153. s->regs[addr] = value;
  154. if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
  155. trace_milkymist_sysctl_start_timer0();
  156. ptimer_set_count(s->ptimer0,
  157. s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
  158. ptimer_run(s->ptimer0, 0);
  159. } else {
  160. trace_milkymist_sysctl_stop_timer0();
  161. ptimer_stop(s->ptimer0);
  162. }
  163. ptimer_transaction_commit(s->ptimer0);
  164. break;
  165. case R_TIMER1_CONTROL:
  166. ptimer_transaction_begin(s->ptimer1);
  167. s->regs[addr] = value;
  168. if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
  169. trace_milkymist_sysctl_start_timer1();
  170. ptimer_set_count(s->ptimer1,
  171. s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
  172. ptimer_run(s->ptimer1, 0);
  173. } else {
  174. trace_milkymist_sysctl_stop_timer1();
  175. ptimer_stop(s->ptimer1);
  176. }
  177. ptimer_transaction_commit(s->ptimer1);
  178. break;
  179. case R_ICAP:
  180. sysctl_icap_write(s, value);
  181. break;
  182. case R_DBG_WRITE_LOCK:
  183. s->regs[addr] = 1;
  184. break;
  185. case R_SYSTEM_ID:
  186. qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
  187. break;
  188. case R_GPIO_IN:
  189. case R_CLK_FREQUENCY:
  190. case R_CAPABILITIES:
  191. error_report("milkymist_sysctl: write to read-only register 0x"
  192. TARGET_FMT_plx, addr << 2);
  193. break;
  194. default:
  195. error_report("milkymist_sysctl: write access to unknown register 0x"
  196. TARGET_FMT_plx, addr << 2);
  197. break;
  198. }
  199. }
  200. static const MemoryRegionOps sysctl_mmio_ops = {
  201. .read = sysctl_read,
  202. .write = sysctl_write,
  203. .valid = {
  204. .min_access_size = 4,
  205. .max_access_size = 4,
  206. },
  207. .endianness = DEVICE_NATIVE_ENDIAN,
  208. };
  209. static void timer0_hit(void *opaque)
  210. {
  211. MilkymistSysctlState *s = opaque;
  212. if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
  213. s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
  214. trace_milkymist_sysctl_stop_timer0();
  215. ptimer_stop(s->ptimer0);
  216. }
  217. trace_milkymist_sysctl_pulse_irq_timer0();
  218. qemu_irq_pulse(s->timer0_irq);
  219. }
  220. static void timer1_hit(void *opaque)
  221. {
  222. MilkymistSysctlState *s = opaque;
  223. if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
  224. s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
  225. trace_milkymist_sysctl_stop_timer1();
  226. ptimer_stop(s->ptimer1);
  227. }
  228. trace_milkymist_sysctl_pulse_irq_timer1();
  229. qemu_irq_pulse(s->timer1_irq);
  230. }
  231. static void milkymist_sysctl_reset(DeviceState *d)
  232. {
  233. MilkymistSysctlState *s = MILKYMIST_SYSCTL(d);
  234. int i;
  235. for (i = 0; i < R_MAX; i++) {
  236. s->regs[i] = 0;
  237. }
  238. ptimer_transaction_begin(s->ptimer0);
  239. ptimer_stop(s->ptimer0);
  240. ptimer_transaction_commit(s->ptimer0);
  241. ptimer_transaction_begin(s->ptimer1);
  242. ptimer_stop(s->ptimer1);
  243. ptimer_transaction_commit(s->ptimer1);
  244. /* defaults */
  245. s->regs[R_ICAP] = ICAP_READY;
  246. s->regs[R_SYSTEM_ID] = s->systemid;
  247. s->regs[R_CLK_FREQUENCY] = s->freq_hz;
  248. s->regs[R_CAPABILITIES] = s->capabilities;
  249. s->regs[R_GPIO_IN] = s->strappings;
  250. }
  251. static void milkymist_sysctl_init(Object *obj)
  252. {
  253. MilkymistSysctlState *s = MILKYMIST_SYSCTL(obj);
  254. SysBusDevice *dev = SYS_BUS_DEVICE(obj);
  255. sysbus_init_irq(dev, &s->gpio_irq);
  256. sysbus_init_irq(dev, &s->timer0_irq);
  257. sysbus_init_irq(dev, &s->timer1_irq);
  258. memory_region_init_io(&s->regs_region, obj, &sysctl_mmio_ops, s,
  259. "milkymist-sysctl", R_MAX * 4);
  260. sysbus_init_mmio(dev, &s->regs_region);
  261. }
  262. static void milkymist_sysctl_realize(DeviceState *dev, Error **errp)
  263. {
  264. MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev);
  265. s->ptimer0 = ptimer_init(timer0_hit, s, PTIMER_POLICY_DEFAULT);
  266. s->ptimer1 = ptimer_init(timer1_hit, s, PTIMER_POLICY_DEFAULT);
  267. ptimer_transaction_begin(s->ptimer0);
  268. ptimer_set_freq(s->ptimer0, s->freq_hz);
  269. ptimer_transaction_commit(s->ptimer0);
  270. ptimer_transaction_begin(s->ptimer1);
  271. ptimer_set_freq(s->ptimer1, s->freq_hz);
  272. ptimer_transaction_commit(s->ptimer1);
  273. }
  274. static const VMStateDescription vmstate_milkymist_sysctl = {
  275. .name = "milkymist-sysctl",
  276. .version_id = 1,
  277. .minimum_version_id = 1,
  278. .fields = (VMStateField[]) {
  279. VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
  280. VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
  281. VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
  282. VMSTATE_END_OF_LIST()
  283. }
  284. };
  285. static Property milkymist_sysctl_properties[] = {
  286. DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
  287. freq_hz, 80000000),
  288. DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
  289. capabilities, 0x00000000),
  290. DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
  291. systemid, 0x10014d31),
  292. DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
  293. strappings, 0x00000001),
  294. DEFINE_PROP_END_OF_LIST(),
  295. };
  296. static void milkymist_sysctl_class_init(ObjectClass *klass, void *data)
  297. {
  298. DeviceClass *dc = DEVICE_CLASS(klass);
  299. dc->realize = milkymist_sysctl_realize;
  300. dc->reset = milkymist_sysctl_reset;
  301. dc->vmsd = &vmstate_milkymist_sysctl;
  302. device_class_set_props(dc, milkymist_sysctl_properties);
  303. }
  304. static const TypeInfo milkymist_sysctl_info = {
  305. .name = TYPE_MILKYMIST_SYSCTL,
  306. .parent = TYPE_SYS_BUS_DEVICE,
  307. .instance_size = sizeof(MilkymistSysctlState),
  308. .instance_init = milkymist_sysctl_init,
  309. .class_init = milkymist_sysctl_class_init,
  310. };
  311. static void milkymist_sysctl_register_types(void)
  312. {
  313. type_register_static(&milkymist_sysctl_info);
  314. }
  315. type_init(milkymist_sysctl_register_types)