File:  [Qemu by Fabrice Bellard] / qemu / hw / a9mpcore.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:48:09 2018 UTC (2 years, 2 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu1101, HEAD
qemu 1.1.1

    1: /*
    2:  * Cortex-A9MPCore internal peripheral 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: 
   11: #include "sysbus.h"
   12: 
   13: /* A9MP private memory region.  */
   14: 
   15: typedef struct a9mp_priv_state {
   16:     SysBusDevice busdev;
   17:     uint32_t scu_control;
   18:     uint32_t scu_status;
   19:     uint32_t old_timer_status[8];
   20:     uint32_t num_cpu;
   21:     MemoryRegion scu_iomem;
   22:     MemoryRegion ptimer_iomem;
   23:     MemoryRegion container;
   24:     DeviceState *mptimer;
   25:     DeviceState *gic;
   26:     uint32_t num_irq;
   27: } a9mp_priv_state;
   28: 
   29: static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset,
   30:                             unsigned size)
   31: {
   32:     a9mp_priv_state *s = (a9mp_priv_state *)opaque;
   33:     switch (offset) {
   34:     case 0x00: /* Control */
   35:         return s->scu_control;
   36:     case 0x04: /* Configuration */
   37:         return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
   38:     case 0x08: /* CPU Power Status */
   39:         return s->scu_status;
   40:     case 0x09: /* CPU status.  */
   41:         return s->scu_status >> 8;
   42:     case 0x0a: /* CPU status.  */
   43:         return s->scu_status >> 16;
   44:     case 0x0b: /* CPU status.  */
   45:         return s->scu_status >> 24;
   46:     case 0x0c: /* Invalidate All Registers In Secure State */
   47:         return 0;
   48:     case 0x40: /* Filtering Start Address Register */
   49:     case 0x44: /* Filtering End Address Register */
   50:         /* RAZ/WI, like an implementation with only one AXI master */
   51:         return 0;
   52:     case 0x50: /* SCU Access Control Register */
   53:     case 0x54: /* SCU Non-secure Access Control Register */
   54:         /* unimplemented, fall through */
   55:     default:
   56:         return 0;
   57:     }
   58: }
   59: 
   60: static void a9_scu_write(void *opaque, target_phys_addr_t offset,
   61:                          uint64_t value, unsigned size)
   62: {
   63:     a9mp_priv_state *s = (a9mp_priv_state *)opaque;
   64:     uint32_t mask;
   65:     uint32_t shift;
   66:     switch (size) {
   67:     case 1:
   68:         mask = 0xff;
   69:         break;
   70:     case 2:
   71:         mask = 0xffff;
   72:         break;
   73:     case 4:
   74:         mask = 0xffffffff;
   75:         break;
   76:     default:
   77:         fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n",
   78:                 size, offset);
   79:         return;
   80:     }
   81: 
   82:     switch (offset) {
   83:     case 0x00: /* Control */
   84:         s->scu_control = value & 1;
   85:         break;
   86:     case 0x4: /* Configuration: RO */
   87:         break;
   88:     case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */
   89:         shift = (offset - 0x8) * 8;
   90:         s->scu_status &= ~(mask << shift);
   91:         s->scu_status |= ((value & mask) << shift);
   92:         break;
   93:     case 0x0c: /* Invalidate All Registers In Secure State */
   94:         /* no-op as we do not implement caches */
   95:         break;
   96:     case 0x40: /* Filtering Start Address Register */
   97:     case 0x44: /* Filtering End Address Register */
   98:         /* RAZ/WI, like an implementation with only one AXI master */
   99:         break;
  100:     case 0x50: /* SCU Access Control Register */
  101:     case 0x54: /* SCU Non-secure Access Control Register */
  102:         /* unimplemented, fall through */
  103:     default:
  104:         break;
  105:     }
  106: }
  107: 
  108: static const MemoryRegionOps a9_scu_ops = {
  109:     .read = a9_scu_read,
  110:     .write = a9_scu_write,
  111:     .endianness = DEVICE_NATIVE_ENDIAN,
  112: };
  113: 
  114: static void a9mp_priv_reset(DeviceState *dev)
  115: {
  116:     a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, sysbus_from_qdev(dev));
  117:     int i;
  118:     s->scu_control = 0;
  119:     for (i = 0; i < ARRAY_SIZE(s->old_timer_status); i++) {
  120:         s->old_timer_status[i] = 0;
  121:     }
  122: }
  123: 
  124: static void a9mp_priv_set_irq(void *opaque, int irq, int level)
  125: {
  126:     a9mp_priv_state *s = (a9mp_priv_state *)opaque;
  127:     qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
  128: }
  129: 
  130: static int a9mp_priv_init(SysBusDevice *dev)
  131: {
  132:     a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, dev);
  133:     SysBusDevice *busdev, *gicbusdev;
  134:     int i;
  135: 
  136:     s->gic = qdev_create(NULL, "arm_gic");
  137:     qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
  138:     qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
  139:     qdev_init_nofail(s->gic);
  140:     gicbusdev = sysbus_from_qdev(s->gic);
  141: 
  142:     /* Pass through outbound IRQ lines from the GIC */
  143:     sysbus_pass_irq(dev, gicbusdev);
  144: 
  145:     /* Pass through inbound GPIO lines to the GIC */
  146:     qdev_init_gpio_in(&s->busdev.qdev, a9mp_priv_set_irq, s->num_irq - 32);
  147: 
  148:     s->mptimer = qdev_create(NULL, "arm_mptimer");
  149:     qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
  150:     qdev_init_nofail(s->mptimer);
  151:     busdev = sysbus_from_qdev(s->mptimer);
  152: 
  153:     /* Memory map (addresses are offsets from PERIPHBASE):
  154:      *  0x0000-0x00ff -- Snoop Control Unit
  155:      *  0x0100-0x01ff -- GIC CPU interface
  156:      *  0x0200-0x02ff -- Global Timer
  157:      *  0x0300-0x05ff -- nothing
  158:      *  0x0600-0x06ff -- private timers and watchdogs
  159:      *  0x0700-0x0fff -- nothing
  160:      *  0x1000-0x1fff -- GIC Distributor
  161:      *
  162:      * We should implement the global timer but don't currently do so.
  163:      */
  164:     memory_region_init(&s->container, "a9mp-priv-container", 0x2000);
  165:     memory_region_init_io(&s->scu_iomem, &a9_scu_ops, s, "a9mp-scu", 0x100);
  166:     memory_region_add_subregion(&s->container, 0, &s->scu_iomem);
  167:     /* GIC CPU interface */
  168:     memory_region_add_subregion(&s->container, 0x100,
  169:                                 sysbus_mmio_get_region(gicbusdev, 1));
  170:     /* Note that the A9 exposes only the "timer/watchdog for this core"
  171:      * memory region, not the "timer/watchdog for core X" ones 11MPcore has.
  172:      */
  173:     memory_region_add_subregion(&s->container, 0x600,
  174:                                 sysbus_mmio_get_region(busdev, 0));
  175:     memory_region_add_subregion(&s->container, 0x620,
  176:                                 sysbus_mmio_get_region(busdev, 1));
  177:     memory_region_add_subregion(&s->container, 0x1000,
  178:                                 sysbus_mmio_get_region(gicbusdev, 0));
  179: 
  180:     sysbus_init_mmio(dev, &s->container);
  181: 
  182:     /* Wire up the interrupt from each watchdog and timer.
  183:      * For each core the timer is PPI 29 and the watchdog PPI 30.
  184:      */
  185:     for (i = 0; i < s->num_cpu; i++) {
  186:         int ppibase = (s->num_irq - 32) + i * 32;
  187:         sysbus_connect_irq(busdev, i * 2,
  188:                            qdev_get_gpio_in(s->gic, ppibase + 29));
  189:         sysbus_connect_irq(busdev, i * 2 + 1,
  190:                            qdev_get_gpio_in(s->gic, ppibase + 30));
  191:     }
  192:     return 0;
  193: }
  194: 
  195: static const VMStateDescription vmstate_a9mp_priv = {
  196:     .name = "a9mpcore_priv",
  197:     .version_id = 2,
  198:     .minimum_version_id = 1,
  199:     .fields = (VMStateField[]) {
  200:         VMSTATE_UINT32(scu_control, a9mp_priv_state),
  201:         VMSTATE_UINT32_ARRAY(old_timer_status, a9mp_priv_state, 8),
  202:         VMSTATE_UINT32_V(scu_status, a9mp_priv_state, 2),
  203:         VMSTATE_END_OF_LIST()
  204:     }
  205: };
  206: 
  207: static Property a9mp_priv_properties[] = {
  208:     DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
  209:     /* The Cortex-A9MP may have anything from 0 to 224 external interrupt
  210:      * IRQ lines (with another 32 internal). We default to 64+32, which
  211:      * is the number provided by the Cortex-A9MP test chip in the
  212:      * Realview PBX-A9 and Versatile Express A9 development boards.
  213:      * Other boards may differ and should set this property appropriately.
  214:      */
  215:     DEFINE_PROP_UINT32("num-irq", a9mp_priv_state, num_irq, 96),
  216:     DEFINE_PROP_END_OF_LIST(),
  217: };
  218: 
  219: static void a9mp_priv_class_init(ObjectClass *klass, void *data)
  220: {
  221:     DeviceClass *dc = DEVICE_CLASS(klass);
  222:     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
  223: 
  224:     k->init = a9mp_priv_init;
  225:     dc->props = a9mp_priv_properties;
  226:     dc->vmsd = &vmstate_a9mp_priv;
  227:     dc->reset = a9mp_priv_reset;
  228: }
  229: 
  230: static TypeInfo a9mp_priv_info = {
  231:     .name          = "a9mpcore_priv",
  232:     .parent        = TYPE_SYS_BUS_DEVICE,
  233:     .instance_size = sizeof(a9mp_priv_state),
  234:     .class_init    = a9mp_priv_class_init,
  235: };
  236: 
  237: static void a9mp_register_types(void)
  238: {
  239:     type_register_static(&a9mp_priv_info);
  240: }
  241: 
  242: type_init(a9mp_register_types)

unix.superglobalmegacorp.com