]> git.proxmox.com Git - mirror_qemu.git/blame - hw/mpcore.c
hw/mpcore: Clean up mpcore_priv_read/write as they are now SCU only
[mirror_qemu.git] / hw / mpcore.c
CommitLineData
9ee6e8bb 1/*
f7c70325 2 * ARM MPCore internal peripheral emulation (common code).
9ee6e8bb
PB
3 *
4 * Copyright (c) 2006-2007 CodeSourcery.
5 * Written by Paul Brook
6 *
8e31bf38 7 * This code is licensed under the GPL.
9ee6e8bb
PB
8 */
9
fe7e8758 10#include "sysbus.h"
87ecb68b 11#include "qemu-timer.h"
9ee6e8bb 12
9ee6e8bb 13#define NCPU 4
9ee6e8bb
PB
14
15static inline int
16gic_get_current_cpu(void)
17{
18 return cpu_single_env->cpu_index;
19}
20
21#include "arm_gic.c"
22
23/* MPCore private memory region. */
24
9ee6e8bb 25typedef struct mpcore_priv_state {
fe7e8758 26 gic_state gic;
9ee6e8bb 27 uint32_t scu_control;
fe7e8758 28 int iomemtype;
b9dc07d4 29 uint32_t old_timer_status[8];
c988bfad 30 uint32_t num_cpu;
b9dc07d4 31 qemu_irq *timer_irq;
755c0802
AK
32 MemoryRegion iomem;
33 MemoryRegion container;
b9dc07d4 34 DeviceState *mptimer;
9ee6e8bb
PB
35} mpcore_priv_state;
36
9ee6e8bb
PB
37/* Per-CPU private memory mapped IO. */
38
538ddf65
PM
39static uint64_t mpcore_scu_read(void *opaque, target_phys_addr_t offset,
40 unsigned size)
9ee6e8bb
PB
41{
42 mpcore_priv_state *s = (mpcore_priv_state *)opaque;
43 int id;
2206d2a6 44 offset &= 0xff;
538ddf65
PM
45 /* SCU */
46 switch (offset) {
47 case 0x00: /* Control. */
48 return s->scu_control;
49 case 0x04: /* Configuration. */
50 id = ((1 << s->num_cpu) - 1) << 4;
51 return id | (s->num_cpu - 1);
52 case 0x08: /* CPU status. */
53 return 0;
54 case 0x0c: /* Invalidate all. */
55 return 0;
56 default:
57 hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
9ee6e8bb 58 }
9ee6e8bb
PB
59}
60
538ddf65
PM
61static void mpcore_scu_write(void *opaque, target_phys_addr_t offset,
62 uint64_t value, unsigned size)
9ee6e8bb
PB
63{
64 mpcore_priv_state *s = (mpcore_priv_state *)opaque;
2206d2a6 65 offset &= 0xff;
538ddf65
PM
66 /* SCU */
67 switch (offset) {
68 case 0: /* Control register. */
69 s->scu_control = value & 1;
70 break;
71 case 0x0c: /* Invalidate all. */
72 /* This is a no-op as cache is not emulated. */
73 break;
74 default:
75 hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
9ee6e8bb 76 }
9ee6e8bb
PB
77}
78
538ddf65
PM
79static const MemoryRegionOps mpcore_scu_ops = {
80 .read = mpcore_scu_read,
81 .write = mpcore_scu_write,
755c0802 82 .endianness = DEVICE_NATIVE_ENDIAN,
9ee6e8bb
PB
83};
84
b9dc07d4
PM
85static void mpcore_timer_irq_handler(void *opaque, int irq, int level)
86{
87 mpcore_priv_state *s = (mpcore_priv_state *)opaque;
88 if (level && !s->old_timer_status[irq]) {
89 gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
90 }
91 s->old_timer_status[irq] = level;
92}
93
755c0802 94static void mpcore_priv_map_setup(mpcore_priv_state *s)
fe7e8758 95{
b9dc07d4
PM
96 int i;
97 SysBusDevice *busdev = sysbus_from_qdev(s->mptimer);
755c0802 98 memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
538ddf65 99 memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100);
755c0802 100 memory_region_add_subregion(&s->container, 0, &s->iomem);
2206d2a6
PM
101 /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs
102 * at 0x200, 0x300...
103 */
104 for (i = 0; i < (s->num_cpu + 1); i++) {
105 target_phys_addr_t offset = 0x100 + (i * 0x100);
106 memory_region_add_subregion(&s->container, offset, &s->gic.cpuiomem[i]);
107 }
b9dc07d4
PM
108 /* Add the regions for timer and watchdog for "current CPU" and
109 * for each specific CPU.
110 */
111 s->timer_irq = qemu_allocate_irqs(mpcore_timer_irq_handler,
112 s, (s->num_cpu + 1) * 2);
113 for (i = 0; i < (s->num_cpu + 1) * 2; i++) {
114 /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
115 target_phys_addr_t offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20;
116 memory_region_add_subregion(&s->container, offset,
117 sysbus_mmio_get_region(busdev, i));
118 }
755c0802 119 memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
b9dc07d4
PM
120 /* Wire up the interrupt from each watchdog and timer. */
121 for (i = 0; i < s->num_cpu * 2; i++) {
122 sysbus_connect_irq(busdev, i, s->timer_irq[i]);
123 }
fe7e8758 124}
9ee6e8bb 125
81a322d4 126static int mpcore_priv_init(SysBusDevice *dev)
9ee6e8bb 127{
fe7e8758 128 mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
9ee6e8bb 129
c988bfad 130 gic_init(&s->gic, s->num_cpu);
b9dc07d4
PM
131 s->mptimer = qdev_create(NULL, "arm_mptimer");
132 qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
133 qdev_init_nofail(s->mptimer);
755c0802 134 mpcore_priv_map_setup(s);
750ecd44 135 sysbus_init_mmio(dev, &s->container);
81a322d4 136 return 0;
9ee6e8bb 137}