milkymist-hpdmc.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * QEMU model of the Milkymist High Performance Dynamic Memory 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://milkymist.walle.cc/socdoc/hpdmc.pdf
  22. */
  23. #include "qemu/osdep.h"
  24. #include "hw/sysbus.h"
  25. #include "migration/vmstate.h"
  26. #include "trace.h"
  27. #include "qemu/error-report.h"
  28. #include "qemu/module.h"
  29. enum {
  30. R_SYSTEM = 0,
  31. R_BYPASS,
  32. R_TIMING,
  33. R_IODELAY,
  34. R_MAX
  35. };
  36. enum {
  37. IODELAY_DQSDELAY_RDY = (1<<5),
  38. IODELAY_PLL1_LOCKED = (1<<6),
  39. IODELAY_PLL2_LOCKED = (1<<7),
  40. };
  41. #define TYPE_MILKYMIST_HPDMC "milkymist-hpdmc"
  42. #define MILKYMIST_HPDMC(obj) \
  43. OBJECT_CHECK(MilkymistHpdmcState, (obj), TYPE_MILKYMIST_HPDMC)
  44. struct MilkymistHpdmcState {
  45. SysBusDevice parent_obj;
  46. MemoryRegion regs_region;
  47. uint32_t regs[R_MAX];
  48. };
  49. typedef struct MilkymistHpdmcState MilkymistHpdmcState;
  50. static uint64_t hpdmc_read(void *opaque, hwaddr addr,
  51. unsigned size)
  52. {
  53. MilkymistHpdmcState *s = opaque;
  54. uint32_t r = 0;
  55. addr >>= 2;
  56. switch (addr) {
  57. case R_SYSTEM:
  58. case R_BYPASS:
  59. case R_TIMING:
  60. case R_IODELAY:
  61. r = s->regs[addr];
  62. break;
  63. default:
  64. error_report("milkymist_hpdmc: read access to unknown register 0x"
  65. TARGET_FMT_plx, addr << 2);
  66. break;
  67. }
  68. trace_milkymist_hpdmc_memory_read(addr << 2, r);
  69. return r;
  70. }
  71. static void hpdmc_write(void *opaque, hwaddr addr, uint64_t value,
  72. unsigned size)
  73. {
  74. MilkymistHpdmcState *s = opaque;
  75. trace_milkymist_hpdmc_memory_write(addr, value);
  76. addr >>= 2;
  77. switch (addr) {
  78. case R_SYSTEM:
  79. case R_BYPASS:
  80. case R_TIMING:
  81. s->regs[addr] = value;
  82. break;
  83. case R_IODELAY:
  84. /* ignore writes */
  85. break;
  86. default:
  87. error_report("milkymist_hpdmc: write access to unknown register 0x"
  88. TARGET_FMT_plx, addr << 2);
  89. break;
  90. }
  91. }
  92. static const MemoryRegionOps hpdmc_mmio_ops = {
  93. .read = hpdmc_read,
  94. .write = hpdmc_write,
  95. .valid = {
  96. .min_access_size = 4,
  97. .max_access_size = 4,
  98. },
  99. .endianness = DEVICE_NATIVE_ENDIAN,
  100. };
  101. static void milkymist_hpdmc_reset(DeviceState *d)
  102. {
  103. MilkymistHpdmcState *s = MILKYMIST_HPDMC(d);
  104. int i;
  105. for (i = 0; i < R_MAX; i++) {
  106. s->regs[i] = 0;
  107. }
  108. /* defaults */
  109. s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED
  110. | IODELAY_PLL2_LOCKED;
  111. }
  112. static void milkymist_hpdmc_realize(DeviceState *dev, Error **errp)
  113. {
  114. MilkymistHpdmcState *s = MILKYMIST_HPDMC(dev);
  115. memory_region_init_io(&s->regs_region, OBJECT(dev), &hpdmc_mmio_ops, s,
  116. "milkymist-hpdmc", R_MAX * 4);
  117. sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->regs_region);
  118. }
  119. static const VMStateDescription vmstate_milkymist_hpdmc = {
  120. .name = "milkymist-hpdmc",
  121. .version_id = 1,
  122. .minimum_version_id = 1,
  123. .fields = (VMStateField[]) {
  124. VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX),
  125. VMSTATE_END_OF_LIST()
  126. }
  127. };
  128. static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data)
  129. {
  130. DeviceClass *dc = DEVICE_CLASS(klass);
  131. dc->realize = milkymist_hpdmc_realize;
  132. dc->reset = milkymist_hpdmc_reset;
  133. dc->vmsd = &vmstate_milkymist_hpdmc;
  134. }
  135. static const TypeInfo milkymist_hpdmc_info = {
  136. .name = TYPE_MILKYMIST_HPDMC,
  137. .parent = TYPE_SYS_BUS_DEVICE,
  138. .instance_size = sizeof(MilkymistHpdmcState),
  139. .class_init = milkymist_hpdmc_class_init,
  140. };
  141. static void milkymist_hpdmc_register_types(void)
  142. {
  143. type_register_static(&milkymist_hpdmc_info);
  144. }
  145. type_init(milkymist_hpdmc_register_types)