2
0

zynq-xadc.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*
  2. * ADC registers for Xilinx Zynq Platform
  3. *
  4. * Copyright (c) 2015 Guenter Roeck
  5. * Based on hw/misc/zynq_slcr.c, written by Michal Simek
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version
  10. * 2 of the License, or (at your option) any later version.
  11. *
  12. * You should have received a copy of the GNU General Public License along
  13. * with this program; if not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #include "qemu/osdep.h"
  16. #include "hw/irq.h"
  17. #include "hw/misc/zynq-xadc.h"
  18. #include "migration/vmstate.h"
  19. #include "qemu/timer.h"
  20. #include "qemu/log.h"
  21. #include "qemu/module.h"
  22. enum {
  23. CFG = 0x000 / 4,
  24. INT_STS,
  25. INT_MASK,
  26. MSTS,
  27. CMDFIFO,
  28. RDFIFO,
  29. MCTL,
  30. };
  31. #define CFG_ENABLE BIT(31)
  32. #define CFG_CFIFOTH_SHIFT 20
  33. #define CFG_CFIFOTH_LENGTH 4
  34. #define CFG_DFIFOTH_SHIFT 16
  35. #define CFG_DFIFOTH_LENGTH 4
  36. #define CFG_WEDGE BIT(13)
  37. #define CFG_REDGE BIT(12)
  38. #define CFG_TCKRATE_SHIFT 8
  39. #define CFG_TCKRATE_LENGTH 2
  40. #define CFG_TCKRATE_DIV(x) (0x1 << (x - 1))
  41. #define CFG_IGAP_SHIFT 0
  42. #define CFG_IGAP_LENGTH 5
  43. #define INT_CFIFO_LTH BIT(9)
  44. #define INT_DFIFO_GTH BIT(8)
  45. #define INT_OT BIT(7)
  46. #define INT_ALM_SHIFT 0
  47. #define INT_ALM_LENGTH 7
  48. #define INT_ALM_MASK (((1 << INT_ALM_LENGTH) - 1) << INT_ALM_SHIFT)
  49. #define INT_ALL (INT_CFIFO_LTH | INT_DFIFO_GTH | INT_OT | INT_ALM_MASK)
  50. #define MSTS_CFIFO_LVL_SHIFT 16
  51. #define MSTS_CFIFO_LVL_LENGTH 4
  52. #define MSTS_DFIFO_LVL_SHIFT 12
  53. #define MSTS_DFIFO_LVL_LENGTH 4
  54. #define MSTS_CFIFOF BIT(11)
  55. #define MSTS_CFIFOE BIT(10)
  56. #define MSTS_DFIFOF BIT(9)
  57. #define MSTS_DFIFOE BIT(8)
  58. #define MSTS_OT BIT(7)
  59. #define MSTS_ALM_SHIFT 0
  60. #define MSTS_ALM_LENGTH 7
  61. #define MCTL_RESET BIT(4)
  62. #define CMD_NOP 0x00
  63. #define CMD_READ 0x01
  64. #define CMD_WRITE 0x02
  65. static void zynq_xadc_update_ints(ZynqXADCState *s)
  66. {
  67. /* We are fast, commands are actioned instantly so the CFIFO is always
  68. * empty (and below threshold).
  69. */
  70. s->regs[INT_STS] |= INT_CFIFO_LTH;
  71. if (s->xadc_dfifo_entries >
  72. extract32(s->regs[CFG], CFG_DFIFOTH_SHIFT, CFG_DFIFOTH_LENGTH)) {
  73. s->regs[INT_STS] |= INT_DFIFO_GTH;
  74. }
  75. qemu_set_irq(s->qemu_irq, !!(s->regs[INT_STS] & ~s->regs[INT_MASK]));
  76. }
  77. static void zynq_xadc_reset(DeviceState *d)
  78. {
  79. ZynqXADCState *s = ZYNQ_XADC(d);
  80. s->regs[CFG] = 0x14 << CFG_IGAP_SHIFT |
  81. CFG_TCKRATE_DIV(4) << CFG_TCKRATE_SHIFT | CFG_REDGE;
  82. s->regs[INT_STS] = INT_CFIFO_LTH;
  83. s->regs[INT_MASK] = 0xffffffff;
  84. s->regs[CMDFIFO] = 0;
  85. s->regs[RDFIFO] = 0;
  86. s->regs[MCTL] = MCTL_RESET;
  87. memset(s->xadc_regs, 0, sizeof(s->xadc_regs));
  88. memset(s->xadc_dfifo, 0, sizeof(s->xadc_dfifo));
  89. s->xadc_dfifo_entries = 0;
  90. zynq_xadc_update_ints(s);
  91. }
  92. static uint16_t xadc_pop_dfifo(ZynqXADCState *s)
  93. {
  94. uint16_t rv = s->xadc_dfifo[0];
  95. int i;
  96. if (s->xadc_dfifo_entries > 0) {
  97. s->xadc_dfifo_entries--;
  98. }
  99. for (i = 0; i < s->xadc_dfifo_entries; i++) {
  100. s->xadc_dfifo[i] = s->xadc_dfifo[i + 1];
  101. }
  102. s->xadc_dfifo[s->xadc_dfifo_entries] = 0;
  103. zynq_xadc_update_ints(s);
  104. return rv;
  105. }
  106. static void xadc_push_dfifo(ZynqXADCState *s, uint16_t regval)
  107. {
  108. if (s->xadc_dfifo_entries < ZYNQ_XADC_FIFO_DEPTH) {
  109. s->xadc_dfifo[s->xadc_dfifo_entries++] = s->xadc_read_reg_previous;
  110. }
  111. s->xadc_read_reg_previous = regval;
  112. zynq_xadc_update_ints(s);
  113. }
  114. static bool zynq_xadc_check_offset(hwaddr offset, bool rnw)
  115. {
  116. switch (offset) {
  117. case CFG:
  118. case INT_MASK:
  119. case INT_STS:
  120. case MCTL:
  121. return true;
  122. case RDFIFO:
  123. case MSTS:
  124. return rnw; /* read only */
  125. case CMDFIFO:
  126. return !rnw; /* write only */
  127. default:
  128. return false;
  129. }
  130. }
  131. static uint64_t zynq_xadc_read(void *opaque, hwaddr offset, unsigned size)
  132. {
  133. ZynqXADCState *s = opaque;
  134. int reg = offset / 4;
  135. uint32_t rv = 0;
  136. if (!zynq_xadc_check_offset(reg, true)) {
  137. qemu_log_mask(LOG_GUEST_ERROR, "zynq_xadc: Invalid read access to "
  138. "addr %" HWADDR_PRIx "\n", offset);
  139. return 0;
  140. }
  141. switch (reg) {
  142. case CFG:
  143. case INT_MASK:
  144. case INT_STS:
  145. case MCTL:
  146. rv = s->regs[reg];
  147. break;
  148. case MSTS:
  149. rv = MSTS_CFIFOE;
  150. rv |= s->xadc_dfifo_entries << MSTS_DFIFO_LVL_SHIFT;
  151. if (!s->xadc_dfifo_entries) {
  152. rv |= MSTS_DFIFOE;
  153. } else if (s->xadc_dfifo_entries == ZYNQ_XADC_FIFO_DEPTH) {
  154. rv |= MSTS_DFIFOF;
  155. }
  156. break;
  157. case RDFIFO:
  158. rv = xadc_pop_dfifo(s);
  159. break;
  160. }
  161. return rv;
  162. }
  163. static void zynq_xadc_write(void *opaque, hwaddr offset, uint64_t val,
  164. unsigned size)
  165. {
  166. ZynqXADCState *s = (ZynqXADCState *)opaque;
  167. int reg = offset / 4;
  168. int xadc_reg;
  169. int xadc_cmd;
  170. int xadc_data;
  171. if (!zynq_xadc_check_offset(reg, false)) {
  172. qemu_log_mask(LOG_GUEST_ERROR, "zynq_xadc: Invalid write access "
  173. "to addr %" HWADDR_PRIx "\n", offset);
  174. return;
  175. }
  176. switch (reg) {
  177. case CFG:
  178. s->regs[CFG] = val;
  179. break;
  180. case INT_STS:
  181. s->regs[INT_STS] &= ~val;
  182. break;
  183. case INT_MASK:
  184. s->regs[INT_MASK] = val & INT_ALL;
  185. break;
  186. case CMDFIFO:
  187. xadc_cmd = extract32(val, 26, 4);
  188. xadc_reg = extract32(val, 16, 10);
  189. xadc_data = extract32(val, 0, 16);
  190. if (s->regs[MCTL] & MCTL_RESET) {
  191. qemu_log_mask(LOG_GUEST_ERROR, "zynq_xadc: Sending command "
  192. "while comm channel held in reset: %" PRIx32 "\n",
  193. (uint32_t) val);
  194. break;
  195. }
  196. if (xadc_reg >= ZYNQ_XADC_NUM_ADC_REGS && xadc_cmd != CMD_NOP) {
  197. qemu_log_mask(LOG_GUEST_ERROR, "read/write op to invalid xadc "
  198. "reg 0x%x\n", xadc_reg);
  199. break;
  200. }
  201. switch (xadc_cmd) {
  202. case CMD_READ:
  203. xadc_push_dfifo(s, s->xadc_regs[xadc_reg]);
  204. break;
  205. case CMD_WRITE:
  206. s->xadc_regs[xadc_reg] = xadc_data;
  207. /* fallthrough */
  208. case CMD_NOP:
  209. xadc_push_dfifo(s, 0);
  210. break;
  211. }
  212. break;
  213. case MCTL:
  214. s->regs[MCTL] = val & 0x00fffeff;
  215. break;
  216. }
  217. zynq_xadc_update_ints(s);
  218. }
  219. static const MemoryRegionOps xadc_ops = {
  220. .read = zynq_xadc_read,
  221. .write = zynq_xadc_write,
  222. .endianness = DEVICE_NATIVE_ENDIAN,
  223. };
  224. static void zynq_xadc_init(Object *obj)
  225. {
  226. SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  227. ZynqXADCState *s = ZYNQ_XADC(obj);
  228. memory_region_init_io(&s->iomem, obj, &xadc_ops, s, "zynq-xadc",
  229. ZYNQ_XADC_MMIO_SIZE);
  230. sysbus_init_mmio(sbd, &s->iomem);
  231. sysbus_init_irq(sbd, &s->qemu_irq);
  232. }
  233. static const VMStateDescription vmstate_zynq_xadc = {
  234. .name = "zynq-xadc",
  235. .version_id = 1,
  236. .minimum_version_id = 1,
  237. .fields = (VMStateField[]) {
  238. VMSTATE_UINT32_ARRAY(regs, ZynqXADCState, ZYNQ_XADC_NUM_IO_REGS),
  239. VMSTATE_UINT16_ARRAY(xadc_regs, ZynqXADCState,
  240. ZYNQ_XADC_NUM_ADC_REGS),
  241. VMSTATE_UINT16_ARRAY(xadc_dfifo, ZynqXADCState,
  242. ZYNQ_XADC_FIFO_DEPTH),
  243. VMSTATE_UINT16(xadc_read_reg_previous, ZynqXADCState),
  244. VMSTATE_UINT16(xadc_dfifo_entries, ZynqXADCState),
  245. VMSTATE_END_OF_LIST()
  246. }
  247. };
  248. static void zynq_xadc_class_init(ObjectClass *klass, void *data)
  249. {
  250. DeviceClass *dc = DEVICE_CLASS(klass);
  251. dc->vmsd = &vmstate_zynq_xadc;
  252. dc->reset = zynq_xadc_reset;
  253. }
  254. static const TypeInfo zynq_xadc_info = {
  255. .class_init = zynq_xadc_class_init,
  256. .name = TYPE_ZYNQ_XADC,
  257. .parent = TYPE_SYS_BUS_DEVICE,
  258. .instance_size = sizeof(ZynqXADCState),
  259. .instance_init = zynq_xadc_init,
  260. };
  261. static void zynq_xadc_register_types(void)
  262. {
  263. type_register_static(&zynq_xadc_info);
  264. }
  265. type_init(zynq_xadc_register_types)