Statistics
| Branch: | Revision:

root / hw / a9mpcore.c @ 57c83dac

History | View | Annotate | Download (7.5 kB)

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
/* Configuration for arm_gic.c:
14
 * max number of CPUs, how to ID current CPU
15
 */
16
#define NCPU 4
17

    
18
static inline int
19
gic_get_current_cpu(void)
20
{
21
  return cpu_single_env->cpu_index;
22
}
23

    
24
#include "arm_gic.c"
25

    
26
/* A9MP private memory region.  */
27

    
28
typedef struct a9mp_priv_state {
29
    gic_state gic;
30
    uint32_t scu_control;
31
    uint32_t scu_status;
32
    uint32_t old_timer_status[8];
33
    uint32_t num_cpu;
34
    qemu_irq *timer_irq;
35
    MemoryRegion scu_iomem;
36
    MemoryRegion ptimer_iomem;
37
    MemoryRegion container;
38
    DeviceState *mptimer;
39
    uint32_t num_irq;
40
} a9mp_priv_state;
41

    
42
static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset,
43
                            unsigned size)
44
{
45
    a9mp_priv_state *s = (a9mp_priv_state *)opaque;
46
    switch (offset) {
47
    case 0x00: /* Control */
48
        return s->scu_control;
49
    case 0x04: /* Configuration */
50
        return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
51
    case 0x08: /* CPU Power Status */
52
        return s->scu_status;
53
    case 0x09: /* CPU status.  */
54
        return s->scu_status >> 8;
55
    case 0x0a: /* CPU status.  */
56
        return s->scu_status >> 16;
57
    case 0x0b: /* CPU status.  */
58
        return s->scu_status >> 24;
59
    case 0x0c: /* Invalidate All Registers In Secure State */
60
        return 0;
61
    case 0x40: /* Filtering Start Address Register */
62
    case 0x44: /* Filtering End Address Register */
63
        /* RAZ/WI, like an implementation with only one AXI master */
64
        return 0;
65
    case 0x50: /* SCU Access Control Register */
66
    case 0x54: /* SCU Non-secure Access Control Register */
67
        /* unimplemented, fall through */
68
    default:
69
        return 0;
70
    }
71
}
72

    
73
static void a9_scu_write(void *opaque, target_phys_addr_t offset,
74
                         uint64_t value, unsigned size)
75
{
76
    a9mp_priv_state *s = (a9mp_priv_state *)opaque;
77
    uint32_t mask;
78
    uint32_t shift;
79
    switch (size) {
80
    case 1:
81
        mask = 0xff;
82
        break;
83
    case 2:
84
        mask = 0xffff;
85
        break;
86
    case 4:
87
        mask = 0xffffffff;
88
        break;
89
    default:
90
        fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n",
91
                size, offset);
92
        return;
93
    }
94

    
95
    switch (offset) {
96
    case 0x00: /* Control */
97
        s->scu_control = value & 1;
98
        break;
99
    case 0x4: /* Configuration: RO */
100
        break;
101
    case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */
102
        shift = (offset - 0x8) * 8;
103
        s->scu_status &= ~(mask << shift);
104
        s->scu_status |= ((value & mask) << shift);
105
        break;
106
    case 0x0c: /* Invalidate All Registers In Secure State */
107
        /* no-op as we do not implement caches */
108
        break;
109
    case 0x40: /* Filtering Start Address Register */
110
    case 0x44: /* Filtering End Address Register */
111
        /* RAZ/WI, like an implementation with only one AXI master */
112
        break;
113
    case 0x50: /* SCU Access Control Register */
114
    case 0x54: /* SCU Non-secure Access Control Register */
115
        /* unimplemented, fall through */
116
    default:
117
        break;
118
    }
119
}
120

    
121
static const MemoryRegionOps a9_scu_ops = {
122
    .read = a9_scu_read,
123
    .write = a9_scu_write,
124
    .endianness = DEVICE_NATIVE_ENDIAN,
125
};
126

    
127
static void a9mpcore_timer_irq_handler(void *opaque, int irq, int level)
128
{
129
    a9mp_priv_state *s = (a9mp_priv_state *)opaque;
130
    if (level && !s->old_timer_status[irq]) {
131
        gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
132
    }
133
    s->old_timer_status[irq] = level;
134
}
135

    
136
static void a9mp_priv_reset(DeviceState *dev)
137
{
138
    a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, sysbus_from_qdev(dev));
139
    int i;
140
    s->scu_control = 0;
141
    for (i = 0; i < ARRAY_SIZE(s->old_timer_status); i++) {
142
        s->old_timer_status[i] = 0;
143
    }
144
}
145

    
146
static int a9mp_priv_init(SysBusDevice *dev)
147
{
148
    a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, dev);
149
    SysBusDevice *busdev;
150
    int i;
151

    
152
    if (s->num_cpu > NCPU) {
153
        hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU);
154
    }
155

    
156
    gic_init(&s->gic, s->num_cpu, s->num_irq);
157

    
158
    s->mptimer = qdev_create(NULL, "arm_mptimer");
159
    qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
160
    qdev_init_nofail(s->mptimer);
161
    busdev = sysbus_from_qdev(s->mptimer);
162

    
163
    /* Memory map (addresses are offsets from PERIPHBASE):
164
     *  0x0000-0x00ff -- Snoop Control Unit
165
     *  0x0100-0x01ff -- GIC CPU interface
166
     *  0x0200-0x02ff -- Global Timer
167
     *  0x0300-0x05ff -- nothing
168
     *  0x0600-0x06ff -- private timers and watchdogs
169
     *  0x0700-0x0fff -- nothing
170
     *  0x1000-0x1fff -- GIC Distributor
171
     *
172
     * We should implement the global timer but don't currently do so.
173
     */
174
    memory_region_init(&s->container, "a9mp-priv-container", 0x2000);
175
    memory_region_init_io(&s->scu_iomem, &a9_scu_ops, s, "a9mp-scu", 0x100);
176
    memory_region_add_subregion(&s->container, 0, &s->scu_iomem);
177
    /* GIC CPU interface */
178
    memory_region_add_subregion(&s->container, 0x100, &s->gic.cpuiomem[0]);
179
    /* Note that the A9 exposes only the "timer/watchdog for this core"
180
     * memory region, not the "timer/watchdog for core X" ones 11MPcore has.
181
     */
182
    memory_region_add_subregion(&s->container, 0x600,
183
                                sysbus_mmio_get_region(busdev, 0));
184
    memory_region_add_subregion(&s->container, 0x620,
185
                                sysbus_mmio_get_region(busdev, 1));
186
    memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
187

    
188
    sysbus_init_mmio(dev, &s->container);
189

    
190
    /* Wire up the interrupt from each watchdog and timer. */
191
    s->timer_irq = qemu_allocate_irqs(a9mpcore_timer_irq_handler,
192
                                      s, (s->num_cpu + 1) * 2);
193
    for (i = 0; i < s->num_cpu * 2; i++) {
194
        sysbus_connect_irq(busdev, i, s->timer_irq[i]);
195
    }
196
    return 0;
197
}
198

    
199
static const VMStateDescription vmstate_a9mp_priv = {
200
    .name = "a9mpcore_priv",
201
    .version_id = 2,
202
    .minimum_version_id = 1,
203
    .fields = (VMStateField[]) {
204
        VMSTATE_UINT32(scu_control, a9mp_priv_state),
205
        VMSTATE_UINT32_ARRAY(old_timer_status, a9mp_priv_state, 8),
206
        VMSTATE_UINT32_V(scu_status, a9mp_priv_state, 2),
207
        VMSTATE_END_OF_LIST()
208
    }
209
};
210

    
211
static Property a9mp_priv_properties[] = {
212
    DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
213
    /* The Cortex-A9MP may have anything from 0 to 224 external interrupt
214
     * IRQ lines (with another 32 internal). We default to 64+32, which
215
     * is the number provided by the Cortex-A9MP test chip in the
216
     * Realview PBX-A9 and Versatile Express A9 development boards.
217
     * Other boards may differ and should set this property appropriately.
218
     */
219
    DEFINE_PROP_UINT32("num-irq", a9mp_priv_state, num_irq, 96),
220
    DEFINE_PROP_END_OF_LIST(),
221
};
222

    
223
static void a9mp_priv_class_init(ObjectClass *klass, void *data)
224
{
225
    DeviceClass *dc = DEVICE_CLASS(klass);
226
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
227

    
228
    k->init = a9mp_priv_init;
229
    dc->props = a9mp_priv_properties;
230
    dc->vmsd = &vmstate_a9mp_priv;
231
    dc->reset = a9mp_priv_reset;
232
}
233

    
234
static TypeInfo a9mp_priv_info = {
235
    .name          = "a9mpcore_priv",
236
    .parent        = TYPE_SYS_BUS_DEVICE,
237
    .instance_size = sizeof(a9mp_priv_state),
238
    .class_init    = a9mp_priv_class_init,
239
};
240

    
241
static void a9mp_register_devices(void)
242
{
243
    type_register_static(&a9mp_priv_info);
244
}
245

    
246
device_init(a9mp_register_devices)