2 * Samsung exynos4210 GIC implementation. Based on hw/arm_gic.c
4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
7 * Evgeny Voevodin <e.voevodin@samsung.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 * See the GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, see <http://www.gnu.org/licenses/>.
23 #include "qemu/osdep.h"
24 #include "hw/sysbus.h"
25 #include "migration/vmstate.h"
26 #include "qapi/error.h"
27 #include "qemu/module.h"
29 #include "hw/qdev-properties.h"
30 #include "hw/intc/exynos4210_gic.h"
31 #include "hw/arm/exynos4210.h"
32 #include "qom/object.h"
34 #define EXYNOS4210_GIC_NIRQ 160
36 #define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE 0x10000
37 #define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE 0x10000
39 #define EXYNOS4210_EXT_GIC_PER_CPU_OFFSET 0x8000
40 #define EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(n) \
41 ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
42 #define EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(n) \
43 ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
45 #define EXYNOS4210_GIC_CPU_REGION_SIZE 0x100
46 #define EXYNOS4210_GIC_DIST_REGION_SIZE 0x1000
48 static void exynos4210_gic_set_irq(void *opaque
, int irq
, int level
)
50 Exynos4210GicState
*s
= (Exynos4210GicState
*)opaque
;
51 qemu_set_irq(qdev_get_gpio_in(s
->gic
, irq
), level
);
54 static void exynos4210_gic_realize(DeviceState
*dev
, Error
**errp
)
56 Object
*obj
= OBJECT(dev
);
57 Exynos4210GicState
*s
= EXYNOS4210_GIC(obj
);
58 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
59 SysBusDevice
*gicbusdev
;
60 uint32_t n
= s
->num_cpu
;
63 s
->gic
= qdev_new("arm_gic");
64 qdev_prop_set_uint32(s
->gic
, "num-cpu", s
->num_cpu
);
65 qdev_prop_set_uint32(s
->gic
, "num-irq", EXYNOS4210_GIC_NIRQ
);
66 gicbusdev
= SYS_BUS_DEVICE(s
->gic
);
67 sysbus_realize_and_unref(gicbusdev
, &error_fatal
);
69 /* Pass through outbound IRQ lines from the GIC */
70 sysbus_pass_irq(sbd
, gicbusdev
);
72 /* Pass through inbound GPIO lines to the GIC */
73 qdev_init_gpio_in(dev
, exynos4210_gic_set_irq
,
74 EXYNOS4210_GIC_NIRQ
- 32);
76 memory_region_init(&s
->cpu_container
, obj
, "exynos4210-cpu-container",
77 EXYNOS4210_EXT_GIC_CPU_REGION_SIZE
);
78 memory_region_init(&s
->dist_container
, obj
, "exynos4210-dist-container",
79 EXYNOS4210_EXT_GIC_DIST_REGION_SIZE
);
82 * This clues in gcc that our on-stack buffers do, in fact have
83 * enough room for the cpu numbers. gcc 9.2.1 on 32-bit x86
84 * doesn't figure this out, otherwise and gives spurious warnings.
86 assert(n
<= EXYNOS4210_GIC_NCPUS
);
87 for (i
= 0; i
< n
; i
++) {
88 g_autofree
char *cpu_alias_name
= g_strdup_printf("exynos4210-gic-alias_cpu%u", i
);
89 g_autofree
char *dist_alias_name
= g_strdup_printf("exynos4210-gic-alias_dist%u", i
);
91 /* Map CPU interface per SMP Core */
92 memory_region_init_alias(&s
->cpu_alias
[i
], obj
,
94 sysbus_mmio_get_region(gicbusdev
, 1),
96 EXYNOS4210_GIC_CPU_REGION_SIZE
);
97 memory_region_add_subregion(&s
->cpu_container
,
98 EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(i
), &s
->cpu_alias
[i
]);
100 /* Map Distributor per SMP Core */
101 memory_region_init_alias(&s
->dist_alias
[i
], obj
,
103 sysbus_mmio_get_region(gicbusdev
, 0),
105 EXYNOS4210_GIC_DIST_REGION_SIZE
);
106 memory_region_add_subregion(&s
->dist_container
,
107 EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(i
), &s
->dist_alias
[i
]);
110 sysbus_init_mmio(sbd
, &s
->cpu_container
);
111 sysbus_init_mmio(sbd
, &s
->dist_container
);
114 static Property exynos4210_gic_properties
[] = {
115 DEFINE_PROP_UINT32("num-cpu", Exynos4210GicState
, num_cpu
, 1),
116 DEFINE_PROP_END_OF_LIST(),
119 static void exynos4210_gic_class_init(ObjectClass
*klass
, void *data
)
121 DeviceClass
*dc
= DEVICE_CLASS(klass
);
123 device_class_set_props(dc
, exynos4210_gic_properties
);
124 dc
->realize
= exynos4210_gic_realize
;
127 static const TypeInfo exynos4210_gic_info
= {
128 .name
= TYPE_EXYNOS4210_GIC
,
129 .parent
= TYPE_SYS_BUS_DEVICE
,
130 .instance_size
= sizeof(Exynos4210GicState
),
131 .class_init
= exynos4210_gic_class_init
,
134 static void exynos4210_gic_register_types(void)
136 type_register_static(&exynos4210_gic_info
);
139 type_init(exynos4210_gic_register_types
)