quic/qbox
Loading...
Searching...
No Matches
arm-gicv2.h
1/*
2 * This file is part of libqbox
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
4 * Author: GreenSocs 2021
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9#ifndef _LIBQBOX_COMPONENTS_IRQ_CTRL_ARM_GICV2_H
10#define _LIBQBOX_COMPONENTS_IRQ_CTRL_ARM_GICV2_H
11
12#include <systemc>
13#include <cci_configuration>
14
15#include <scp/report.h>
16
17#include <module_factory_registery.h>
18
19#include <device.h>
20#include <ports/target.h>
21#include <ports/qemu-initiator-signal-socket.h>
22#include <ports/qemu-target-signal-socket.h>
23
24class arm_gicv2m : public QemuDevice
25{
26protected:
27 cci::cci_param<unsigned int> p_base_spi;
28 cci::cci_param<unsigned int> p_num_spis;
29
30public:
31 /*
32 * Output interrupt lines. Vector are sized with the number of SPIs
33 * These cannot be plugged anywhere on the gic: it depends on the
34 * base-spi/num-spis parameter.
35 */
36 sc_core::sc_vector<QemuInitiatorSignalSocket> spi_out;
37
39
40 arm_gicv2m(const sc_core::sc_module_name& name, QemuInstance& inst)
41 : QemuDevice(name, inst, "arm-gicv2m")
42 , p_base_spi("base_spi", 0, "Start index of gic's spis")
43 , p_num_spis("num_spis", 0, "Number of gic's spis")
44 , spi_out("spi_out", p_num_spis)
45 , iface("iface", inst)
46 {
47 }
48
49 unsigned int get_base_spi() { return p_base_spi; }
50
51 unsigned int get_num_spis() { return p_num_spis; }
52
53 void before_end_of_elaboration()
54 {
55 QemuDevice::before_end_of_elaboration();
56
57 m_dev.set_prop_int("base-spi", p_base_spi);
58 m_dev.set_prop_int("num-spi", p_num_spis);
59 }
60
61 void end_of_elaboration()
62 {
63 QemuDevice::end_of_elaboration();
64
66
67 iface.init(sbd, 0);
68
69 /* IRQs out */
70 for (int i = 0; i < p_num_spis; i++) {
71 spi_out[i].init_sbd(sbd, i);
72 }
73 }
74};
75
76class arm_gicv2 : public QemuDevice
77{
78public:
79 static const uint32_t NUM_PPI = 32;
80
81protected:
82 cci::cci_param<unsigned int> p_num_cpu;
83 cci::cci_param<unsigned int> p_num_spi;
84 cci::cci_param<unsigned int> p_revision;
85 cci::cci_param<bool> p_has_virt_extensions;
86 cci::cci_param<bool> p_has_security_extensions;
87 cci::cci_param<unsigned int> p_num_prio_bits;
88 cci::cci_param<bool> p_has_msi_support;
89
90public:
91 arm_gicv2m* m_gicv2m;
92
93 QemuTargetSocket<> dist_iface;
94 QemuTargetSocket<> cpu_iface;
95 QemuTargetSocket<> virt_iface;
96 QemuTargetSocket<> vcpu_iface;
97 QemuTargetSocket<>::TlmTargetSocket v2m_iface;
98
99 /* Shared peripheral interrupts: sized with the p_num_spi parameter */
100 sc_core::sc_vector<QemuTargetSignalSocket> spi_in;
101
102 /*
103 * Private peripheral interrupts: 32 per CPUs, the outer vector is sized with the
104 * number of CPUs.
105 */
106 sc_core::sc_vector<sc_core::sc_vector<QemuTargetSignalSocket> > ppi_in;
107
108 /* Output interrupt lines. Vector are sized with the number of CPUs */
109 sc_core::sc_vector<QemuInitiatorSignalSocket> irq_out;
110 sc_core::sc_vector<QemuInitiatorSignalSocket> fiq_out;
111 sc_core::sc_vector<QemuInitiatorSignalSocket> virq_out;
112 sc_core::sc_vector<QemuInitiatorSignalSocket> vfiq_out;
113 sc_core::sc_vector<QemuInitiatorSignalSocket> maintenance_out;
114
115 arm_gicv2(const sc_core::sc_module_name& name, sc_core::sc_object* o)
116 : arm_gicv2(name, *(dynamic_cast<QemuInstance*>(o)))
117 {
118 }
119 arm_gicv2(const sc_core::sc_module_name& name, QemuInstance& inst)
120 : QemuDevice(name, inst, "arm_gic")
121 , p_num_cpu("num_cpu", 0, "Number of CPU interfaces")
122 , p_num_spi("num_spi", 0, "Number of shared peripheral interrupts")
123 , p_revision("revision", 2, "Revision of the GIC (1 -> v1, 2 -> v2, 0 -> 11MPCore)")
124 , p_has_virt_extensions("has_virt_extensions", false,
125 "Enable virtualization extensions "
126 "(v2 only)")
127 , p_has_security_extensions("has_security_extensions", false,
128 "Enable security extensions "
129 "(v1 and v2 only)")
130 , p_num_prio_bits("num_prio_bits", 8, "Number of priority bits implemented by this GIC")
131 , p_has_msi_support("has_msi_support", false, "Enable gicv2m extension to support MSI")
132 , m_gicv2m(NULL)
133 , dist_iface("dist_iface", inst)
134 , cpu_iface("cpu_iface", inst)
135 , virt_iface("virt_iface", inst)
136 , vcpu_iface("vcpu_iface", inst)
137 , v2m_iface("v2m_iface")
138 , spi_in("spi_in", p_num_spi)
139 , ppi_in("ppi_in_cpu", p_num_cpu,
140 [](const char* n, size_t i) { return new sc_core::sc_vector<QemuTargetSignalSocket>(n, NUM_PPI); })
141 , irq_out("irq_out", p_num_cpu)
142 , fiq_out("fiq_out", p_num_cpu)
143 , virq_out("virq_out", p_num_cpu)
144 , vfiq_out("vfiq_out", p_num_cpu)
145 , maintenance_out("maintenance_out", p_num_cpu)
146 {
147 if (p_has_msi_support) {
148 m_gicv2m = new arm_gicv2m("v2m", inst);
149
150 // Hierarchical bind our v2m_iface to our child interface
151 v2m_iface.bind(m_gicv2m->iface);
152
153 // Connect spis
154 unsigned int v2m_num_spis = m_gicv2m->get_num_spis();
155 unsigned int v2m_base_spi = m_gicv2m->get_base_spi();
156 if (v2m_num_spis + v2m_base_spi > p_num_spi) {
157 SCP_FATAL(SCMOD) << "Gicv2 does not have enough spis for v2m config";
158 }
159 for (unsigned int i = 0; i < v2m_num_spis; i++) {
160 m_gicv2m->spi_out[i].bind(spi_in[i + v2m_base_spi]);
161 }
162 }
163 }
164
165 ~arm_gicv2()
166 {
167 if (m_gicv2m) {
168 delete m_gicv2m;
169 }
170 }
171
172 void before_end_of_elaboration()
173 {
174 QemuDevice::before_end_of_elaboration();
175
176 m_dev.set_prop_int("num-cpu", p_num_cpu);
177 m_dev.set_prop_int("num-irq", p_num_spi + NUM_PPI);
178 m_dev.set_prop_int("revision", p_revision);
179 m_dev.set_prop_bool("has-virtualization-extensions", p_has_virt_extensions);
180 m_dev.set_prop_bool("has-security-extensions", p_has_security_extensions);
181 m_dev.set_prop_int("num-priority-bits", p_num_prio_bits);
182 }
183
184 void end_of_elaboration()
185 {
186 QemuDevice::set_sysbus_as_parent_bus();
187 QemuDevice::end_of_elaboration();
188
189 qemu::SysBusDevice sbd(m_dev);
190 int cpu, i;
191
192 dist_iface.init(sbd, 0);
193 cpu_iface.init(sbd, 1);
194
195 if (p_has_virt_extensions) {
196 virt_iface.init(sbd, 2);
197 vcpu_iface.init(sbd, 3);
198 }
199
200 /* SPIs in */
201 for (i = 0; i < p_num_spi; i++) {
202 spi_in[i].init(m_dev, i);
203 }
204
205 /* PPIs in */
206 for (cpu = 0; cpu < p_num_cpu; cpu++) {
207 for (i = 0; i < NUM_PPI; i++) {
208 int ppi_idx = p_num_spi + cpu * NUM_PPI + i;
209 ppi_in[cpu][i].init(m_dev, ppi_idx);
210 }
211 }
212
213 /* Output lines */
214 for (cpu = 0; cpu < p_num_cpu; cpu++) {
215 irq_out[cpu].init_sbd(sbd, p_num_cpu * 0 + cpu);
216 fiq_out[cpu].init_sbd(sbd, p_num_cpu * 1 + cpu);
217 virq_out[cpu].init_sbd(sbd, p_num_cpu * 2 + cpu);
218 vfiq_out[cpu].init_sbd(sbd, p_num_cpu * 3 + cpu);
219
220 if (p_has_virt_extensions) {
221 maintenance_out[cpu].init_sbd(sbd, p_num_cpu * 4 + cpu);
222 }
223 }
224 }
225};
226
227extern "C" void module_register();
228
229#endif
QEMU device abstraction as a SystemC module.
Definition device.h:37
This class encapsulates a libqemu-cxx qemu::LibQemu instance. It handles QEMU parameters and instance...
Definition qemu-instance.h:89
Definition target.h:160
Definition arm-gicv2.h:77
Definition arm-gicv2.h:25
Definition libqemu-cxx.h:638