milkymist-sysctl.c 10.0 KB

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