Annotation of qemu/hw/a9mpcore.c, revision 1.1.1.3

1.1       root        1: /*
                      2:  * Cortex-A9MPCore internal peripheral emulation.
                      3:  *
                      4:  * Copyright (c) 2009 CodeSourcery.
1.1.1.3 ! root        5:  * Copyright (c) 2011 Linaro Limited.
        !             6:  * Written by Paul Brook, Peter Maydell.
1.1       root        7:  *
1.1.1.2   root        8:  * This code is licensed under the GPL.
1.1       root        9:  */
                     10: 
1.1.1.3 ! root       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;
1.1       root       57:     }
1.1.1.3 ! root       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,
1.1       root      235: };
                    236: 
1.1.1.3 ! root      237: static void a9mp_register_types(void)
1.1       root      238: {
1.1.1.3 ! root      239:     type_register_static(&a9mp_priv_info);
1.1       root      240: }
                    241: 
1.1.1.3 ! root      242: type_init(a9mp_register_types)

unix.superglobalmegacorp.com