arm_sysctl.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /*
  2. * Status and system control registers for ARM RealView/Versatile boards.
  3. *
  4. * Copyright (c) 2006-2007 CodeSourcery.
  5. * Written by Paul Brook
  6. *
  7. * This code is licensed under the GPL.
  8. */
  9. #include "hw.h"
  10. #include "qemu-timer.h"
  11. #include "sysbus.h"
  12. #include "primecell.h"
  13. #include "sysemu.h"
  14. #define LOCK_VALUE 0xa05f
  15. typedef struct {
  16. SysBusDevice busdev;
  17. uint32_t sys_id;
  18. uint32_t leds;
  19. uint16_t lockval;
  20. uint32_t cfgdata1;
  21. uint32_t cfgdata2;
  22. uint32_t flags;
  23. uint32_t nvflags;
  24. uint32_t resetlevel;
  25. uint32_t proc_id;
  26. uint32_t sys_mci;
  27. uint32_t sys_cfgdata;
  28. uint32_t sys_cfgctrl;
  29. uint32_t sys_cfgstat;
  30. } arm_sysctl_state;
  31. static const VMStateDescription vmstate_arm_sysctl = {
  32. .name = "realview_sysctl",
  33. .version_id = 2,
  34. .minimum_version_id = 1,
  35. .fields = (VMStateField[]) {
  36. VMSTATE_UINT32(leds, arm_sysctl_state),
  37. VMSTATE_UINT16(lockval, arm_sysctl_state),
  38. VMSTATE_UINT32(cfgdata1, arm_sysctl_state),
  39. VMSTATE_UINT32(cfgdata2, arm_sysctl_state),
  40. VMSTATE_UINT32(flags, arm_sysctl_state),
  41. VMSTATE_UINT32(nvflags, arm_sysctl_state),
  42. VMSTATE_UINT32(resetlevel, arm_sysctl_state),
  43. VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2),
  44. VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2),
  45. VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2),
  46. VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2),
  47. VMSTATE_END_OF_LIST()
  48. }
  49. };
  50. /* The PB926 actually uses a different format for
  51. * its SYS_ID register. Fortunately the bits which are
  52. * board type on later boards are distinct.
  53. */
  54. #define BOARD_ID_PB926 0x100
  55. #define BOARD_ID_EB 0x140
  56. #define BOARD_ID_PBA8 0x178
  57. #define BOARD_ID_PBX 0x182
  58. #define BOARD_ID_VEXPRESS 0x190
  59. static int board_id(arm_sysctl_state *s)
  60. {
  61. /* Extract the board ID field from the SYS_ID register value */
  62. return (s->sys_id >> 16) & 0xfff;
  63. }
  64. static void arm_sysctl_reset(DeviceState *d)
  65. {
  66. arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sysbus_from_qdev(d));
  67. s->leds = 0;
  68. s->lockval = 0;
  69. s->cfgdata1 = 0;
  70. s->cfgdata2 = 0;
  71. s->flags = 0;
  72. s->resetlevel = 0;
  73. }
  74. static uint32_t arm_sysctl_read(void *opaque, target_phys_addr_t offset)
  75. {
  76. arm_sysctl_state *s = (arm_sysctl_state *)opaque;
  77. switch (offset) {
  78. case 0x00: /* ID */
  79. return s->sys_id;
  80. case 0x04: /* SW */
  81. /* General purpose hardware switches.
  82. We don't have a useful way of exposing these to the user. */
  83. return 0;
  84. case 0x08: /* LED */
  85. return s->leds;
  86. case 0x20: /* LOCK */
  87. return s->lockval;
  88. case 0x0c: /* OSC0 */
  89. case 0x10: /* OSC1 */
  90. case 0x14: /* OSC2 */
  91. case 0x18: /* OSC3 */
  92. case 0x1c: /* OSC4 */
  93. case 0x24: /* 100HZ */
  94. /* ??? Implement these. */
  95. return 0;
  96. case 0x28: /* CFGDATA1 */
  97. return s->cfgdata1;
  98. case 0x2c: /* CFGDATA2 */
  99. return s->cfgdata2;
  100. case 0x30: /* FLAGS */
  101. return s->flags;
  102. case 0x38: /* NVFLAGS */
  103. return s->nvflags;
  104. case 0x40: /* RESETCTL */
  105. if (board_id(s) == BOARD_ID_VEXPRESS) {
  106. /* reserved: RAZ/WI */
  107. return 0;
  108. }
  109. return s->resetlevel;
  110. case 0x44: /* PCICTL */
  111. return 1;
  112. case 0x48: /* MCI */
  113. return s->sys_mci;
  114. case 0x4c: /* FLASH */
  115. return 0;
  116. case 0x50: /* CLCD */
  117. return 0x1000;
  118. case 0x54: /* CLCDSER */
  119. return 0;
  120. case 0x58: /* BOOTCS */
  121. return 0;
  122. case 0x5c: /* 24MHz */
  123. return muldiv64(qemu_get_clock_ns(vm_clock), 24000000, get_ticks_per_sec());
  124. case 0x60: /* MISC */
  125. return 0;
  126. case 0x84: /* PROCID0 */
  127. return s->proc_id;
  128. case 0x88: /* PROCID1 */
  129. return 0xff000000;
  130. case 0x64: /* DMAPSR0 */
  131. case 0x68: /* DMAPSR1 */
  132. case 0x6c: /* DMAPSR2 */
  133. case 0x70: /* IOSEL */
  134. case 0x74: /* PLDCTL */
  135. case 0x80: /* BUSID */
  136. case 0x8c: /* OSCRESET0 */
  137. case 0x90: /* OSCRESET1 */
  138. case 0x94: /* OSCRESET2 */
  139. case 0x98: /* OSCRESET3 */
  140. case 0x9c: /* OSCRESET4 */
  141. case 0xc0: /* SYS_TEST_OSC0 */
  142. case 0xc4: /* SYS_TEST_OSC1 */
  143. case 0xc8: /* SYS_TEST_OSC2 */
  144. case 0xcc: /* SYS_TEST_OSC3 */
  145. case 0xd0: /* SYS_TEST_OSC4 */
  146. return 0;
  147. case 0xa0: /* SYS_CFGDATA */
  148. if (board_id(s) != BOARD_ID_VEXPRESS) {
  149. goto bad_reg;
  150. }
  151. return s->sys_cfgdata;
  152. case 0xa4: /* SYS_CFGCTRL */
  153. if (board_id(s) != BOARD_ID_VEXPRESS) {
  154. goto bad_reg;
  155. }
  156. return s->sys_cfgctrl;
  157. case 0xa8: /* SYS_CFGSTAT */
  158. if (board_id(s) != BOARD_ID_VEXPRESS) {
  159. goto bad_reg;
  160. }
  161. return s->sys_cfgstat;
  162. default:
  163. bad_reg:
  164. printf ("arm_sysctl_read: Bad register offset 0x%x\n", (int)offset);
  165. return 0;
  166. }
  167. }
  168. static void arm_sysctl_write(void *opaque, target_phys_addr_t offset,
  169. uint32_t val)
  170. {
  171. arm_sysctl_state *s = (arm_sysctl_state *)opaque;
  172. switch (offset) {
  173. case 0x08: /* LED */
  174. s->leds = val;
  175. case 0x0c: /* OSC0 */
  176. case 0x10: /* OSC1 */
  177. case 0x14: /* OSC2 */
  178. case 0x18: /* OSC3 */
  179. case 0x1c: /* OSC4 */
  180. /* ??? */
  181. break;
  182. case 0x20: /* LOCK */
  183. if (val == LOCK_VALUE)
  184. s->lockval = val;
  185. else
  186. s->lockval = val & 0x7fff;
  187. break;
  188. case 0x28: /* CFGDATA1 */
  189. /* ??? Need to implement this. */
  190. s->cfgdata1 = val;
  191. break;
  192. case 0x2c: /* CFGDATA2 */
  193. /* ??? Need to implement this. */
  194. s->cfgdata2 = val;
  195. break;
  196. case 0x30: /* FLAGSSET */
  197. s->flags |= val;
  198. break;
  199. case 0x34: /* FLAGSCLR */
  200. s->flags &= ~val;
  201. break;
  202. case 0x38: /* NVFLAGSSET */
  203. s->nvflags |= val;
  204. break;
  205. case 0x3c: /* NVFLAGSCLR */
  206. s->nvflags &= ~val;
  207. break;
  208. case 0x40: /* RESETCTL */
  209. if (board_id(s) == BOARD_ID_VEXPRESS) {
  210. /* reserved: RAZ/WI */
  211. break;
  212. }
  213. if (s->lockval == LOCK_VALUE) {
  214. s->resetlevel = val;
  215. if (val & 0x100)
  216. qemu_system_reset_request ();
  217. }
  218. break;
  219. case 0x44: /* PCICTL */
  220. /* nothing to do. */
  221. break;
  222. case 0x4c: /* FLASH */
  223. case 0x50: /* CLCD */
  224. case 0x54: /* CLCDSER */
  225. case 0x64: /* DMAPSR0 */
  226. case 0x68: /* DMAPSR1 */
  227. case 0x6c: /* DMAPSR2 */
  228. case 0x70: /* IOSEL */
  229. case 0x74: /* PLDCTL */
  230. case 0x80: /* BUSID */
  231. case 0x84: /* PROCID0 */
  232. case 0x88: /* PROCID1 */
  233. case 0x8c: /* OSCRESET0 */
  234. case 0x90: /* OSCRESET1 */
  235. case 0x94: /* OSCRESET2 */
  236. case 0x98: /* OSCRESET3 */
  237. case 0x9c: /* OSCRESET4 */
  238. break;
  239. case 0xa0: /* SYS_CFGDATA */
  240. if (board_id(s) != BOARD_ID_VEXPRESS) {
  241. goto bad_reg;
  242. }
  243. s->sys_cfgdata = val;
  244. return;
  245. case 0xa4: /* SYS_CFGCTRL */
  246. if (board_id(s) != BOARD_ID_VEXPRESS) {
  247. goto bad_reg;
  248. }
  249. s->sys_cfgctrl = val & ~(3 << 18);
  250. s->sys_cfgstat = 1; /* complete */
  251. switch (s->sys_cfgctrl) {
  252. case 0xc0800000: /* SYS_CFG_SHUTDOWN to motherboard */
  253. qemu_system_shutdown_request();
  254. break;
  255. case 0xc0900000: /* SYS_CFG_REBOOT to motherboard */
  256. qemu_system_reset_request();
  257. break;
  258. default:
  259. s->sys_cfgstat |= 2; /* error */
  260. }
  261. return;
  262. case 0xa8: /* SYS_CFGSTAT */
  263. if (board_id(s) != BOARD_ID_VEXPRESS) {
  264. goto bad_reg;
  265. }
  266. s->sys_cfgstat = val & 3;
  267. return;
  268. default:
  269. bad_reg:
  270. printf ("arm_sysctl_write: Bad register offset 0x%x\n", (int)offset);
  271. return;
  272. }
  273. }
  274. static CPUReadMemoryFunc * const arm_sysctl_readfn[] = {
  275. arm_sysctl_read,
  276. arm_sysctl_read,
  277. arm_sysctl_read
  278. };
  279. static CPUWriteMemoryFunc * const arm_sysctl_writefn[] = {
  280. arm_sysctl_write,
  281. arm_sysctl_write,
  282. arm_sysctl_write
  283. };
  284. static void arm_sysctl_gpio_set(void *opaque, int line, int level)
  285. {
  286. arm_sysctl_state *s = (arm_sysctl_state *)opaque;
  287. switch (line) {
  288. case ARM_SYSCTL_GPIO_MMC_WPROT:
  289. {
  290. /* For PB926 and EB write-protect is bit 2 of SYS_MCI;
  291. * for all later boards it is bit 1.
  292. */
  293. int bit = 2;
  294. if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) {
  295. bit = 4;
  296. }
  297. s->sys_mci &= ~bit;
  298. if (level) {
  299. s->sys_mci |= bit;
  300. }
  301. break;
  302. }
  303. case ARM_SYSCTL_GPIO_MMC_CARDIN:
  304. s->sys_mci &= ~1;
  305. if (level) {
  306. s->sys_mci |= 1;
  307. }
  308. break;
  309. }
  310. }
  311. static int arm_sysctl_init1(SysBusDevice *dev)
  312. {
  313. arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev);
  314. int iomemtype;
  315. iomemtype = cpu_register_io_memory(arm_sysctl_readfn,
  316. arm_sysctl_writefn, s,
  317. DEVICE_NATIVE_ENDIAN);
  318. sysbus_init_mmio(dev, 0x1000, iomemtype);
  319. qdev_init_gpio_in(&s->busdev.qdev, arm_sysctl_gpio_set, 2);
  320. /* ??? Save/restore. */
  321. return 0;
  322. }
  323. /* Legacy helper function. */
  324. void arm_sysctl_init(uint32_t base, uint32_t sys_id, uint32_t proc_id)
  325. {
  326. DeviceState *dev;
  327. dev = qdev_create(NULL, "realview_sysctl");
  328. qdev_prop_set_uint32(dev, "sys_id", sys_id);
  329. qdev_init_nofail(dev);
  330. qdev_prop_set_uint32(dev, "proc_id", proc_id);
  331. sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
  332. }
  333. static SysBusDeviceInfo arm_sysctl_info = {
  334. .init = arm_sysctl_init1,
  335. .qdev.name = "realview_sysctl",
  336. .qdev.size = sizeof(arm_sysctl_state),
  337. .qdev.vmsd = &vmstate_arm_sysctl,
  338. .qdev.reset = arm_sysctl_reset,
  339. .qdev.props = (Property[]) {
  340. DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
  341. DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
  342. DEFINE_PROP_END_OF_LIST(),
  343. }
  344. };
  345. static void arm_sysctl_register_devices(void)
  346. {
  347. sysbus_register_withprop(&arm_sysctl_info);
  348. }
  349. device_init(arm_sysctl_register_devices)