a9scu.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. * Cortex-A9MPCore Snoop Control Unit (SCU) emulation.
  3. *
  4. * Copyright (c) 2009 CodeSourcery.
  5. * Copyright (c) 2011 Linaro Limited.
  6. * Written by Paul Brook, Peter Maydell.
  7. *
  8. * This code is licensed under the GPL.
  9. */
  10. #include "qemu/osdep.h"
  11. #include "hw/misc/a9scu.h"
  12. #include "hw/qdev-properties.h"
  13. #include "migration/vmstate.h"
  14. #include "qapi/error.h"
  15. #include "qemu/log.h"
  16. #include "qemu/module.h"
  17. #define A9_SCU_CPU_MAX 4
  18. static uint64_t a9_scu_read(void *opaque, hwaddr offset,
  19. unsigned size)
  20. {
  21. A9SCUState *s = (A9SCUState *)opaque;
  22. switch (offset) {
  23. case 0x00: /* Control */
  24. return s->control;
  25. case 0x04: /* Configuration */
  26. return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
  27. case 0x08: /* CPU Power Status */
  28. return s->status;
  29. case 0x0c: /* Invalidate All Registers In Secure State */
  30. return 0;
  31. case 0x40: /* Filtering Start Address Register */
  32. case 0x44: /* Filtering End Address Register */
  33. /* RAZ/WI, like an implementation with only one AXI master */
  34. return 0;
  35. case 0x50: /* SCU Access Control Register */
  36. case 0x54: /* SCU Non-secure Access Control Register */
  37. /* unimplemented, fall through */
  38. default:
  39. qemu_log_mask(LOG_UNIMP, "%s: Unsupported offset 0x%"HWADDR_PRIx"\n",
  40. __func__, offset);
  41. return 0;
  42. }
  43. }
  44. static void a9_scu_write(void *opaque, hwaddr offset,
  45. uint64_t value, unsigned size)
  46. {
  47. A9SCUState *s = (A9SCUState *)opaque;
  48. switch (offset) {
  49. case 0x00: /* Control */
  50. s->control = value & 1;
  51. break;
  52. case 0x4: /* Configuration: RO */
  53. break;
  54. case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */
  55. s->status = value;
  56. break;
  57. case 0x0c: /* Invalidate All Registers In Secure State */
  58. /* no-op as we do not implement caches */
  59. break;
  60. case 0x40: /* Filtering Start Address Register */
  61. case 0x44: /* Filtering End Address Register */
  62. /* RAZ/WI, like an implementation with only one AXI master */
  63. break;
  64. case 0x50: /* SCU Access Control Register */
  65. case 0x54: /* SCU Non-secure Access Control Register */
  66. /* unimplemented, fall through */
  67. default:
  68. qemu_log_mask(LOG_UNIMP, "%s: Unsupported offset 0x%"HWADDR_PRIx
  69. " value 0x%"PRIx64"\n",
  70. __func__, offset, value);
  71. break;
  72. }
  73. }
  74. static const MemoryRegionOps a9_scu_ops = {
  75. .read = a9_scu_read,
  76. .write = a9_scu_write,
  77. .impl = {
  78. .min_access_size = 4,
  79. .max_access_size = 4,
  80. },
  81. .valid = {
  82. .min_access_size = 1,
  83. .max_access_size = 4,
  84. },
  85. .endianness = DEVICE_NATIVE_ENDIAN,
  86. };
  87. static void a9_scu_reset(DeviceState *dev)
  88. {
  89. A9SCUState *s = A9_SCU(dev);
  90. s->control = 0;
  91. }
  92. static void a9_scu_realize(DeviceState *dev, Error **errp)
  93. {
  94. A9SCUState *s = A9_SCU(dev);
  95. SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
  96. if (!s->num_cpu || s->num_cpu > A9_SCU_CPU_MAX) {
  97. error_setg(errp, "Illegal CPU count: %u", s->num_cpu);
  98. return;
  99. }
  100. memory_region_init_io(&s->iomem, OBJECT(s), &a9_scu_ops, s,
  101. "a9-scu", 0x100);
  102. sysbus_init_mmio(sbd, &s->iomem);
  103. }
  104. static const VMStateDescription vmstate_a9_scu = {
  105. .name = "a9-scu",
  106. .version_id = 1,
  107. .minimum_version_id = 1,
  108. .fields = (VMStateField[]) {
  109. VMSTATE_UINT32(control, A9SCUState),
  110. VMSTATE_UINT32(status, A9SCUState),
  111. VMSTATE_END_OF_LIST()
  112. }
  113. };
  114. static Property a9_scu_properties[] = {
  115. DEFINE_PROP_UINT32("num-cpu", A9SCUState, num_cpu, 1),
  116. DEFINE_PROP_END_OF_LIST(),
  117. };
  118. static void a9_scu_class_init(ObjectClass *klass, void *data)
  119. {
  120. DeviceClass *dc = DEVICE_CLASS(klass);
  121. device_class_set_props(dc, a9_scu_properties);
  122. dc->vmsd = &vmstate_a9_scu;
  123. dc->reset = a9_scu_reset;
  124. dc->realize = a9_scu_realize;
  125. }
  126. static const TypeInfo a9_scu_info = {
  127. .name = TYPE_A9_SCU,
  128. .parent = TYPE_SYS_BUS_DEVICE,
  129. .instance_size = sizeof(A9SCUState),
  130. .class_init = a9_scu_class_init,
  131. };
  132. static void a9mp_register_types(void)
  133. {
  134. type_register_static(&a9_scu_info);
  135. }
  136. type_init(a9mp_register_types)