]>
Commit | Line | Data |
---|---|---|
3994215d YK |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
6 | * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. | |
7 | * Authors: Sanjay Lal <sanjayl@kymasys.com> | |
8 | * | |
9 | * Copyright (C) 2015 Imagination Technologies | |
10 | */ | |
11 | ||
12 | #include "qemu/osdep.h" | |
03dd024f | 13 | #include "qemu/log.h" |
3994215d YK |
14 | #include "hw/hw.h" |
15 | #include "hw/sysbus.h" | |
16 | #include "sysemu/sysemu.h" | |
17 | #include "hw/misc/mips_cmgcr.h" | |
2edd5261 | 18 | #include "hw/misc/mips_cpc.h" |
19494f81 | 19 | #include "hw/intc/mips_gic.h" |
2edd5261 LA |
20 | |
21 | static inline bool is_cpc_connected(MIPSGCRState *s) | |
22 | { | |
23 | return s->cpc_mr != NULL; | |
24 | } | |
25 | ||
19494f81 LA |
26 | static inline bool is_gic_connected(MIPSGCRState *s) |
27 | { | |
28 | return s->gic_mr != NULL; | |
29 | } | |
30 | ||
08944be1 PB |
31 | static inline void update_gcr_base(MIPSGCRState *gcr, uint64_t val) |
32 | { | |
33 | CPUState *cpu; | |
34 | MIPSCPU *mips_cpu; | |
35 | ||
36 | gcr->gcr_base = val & GCR_BASE_GCRBASE_MSK; | |
37 | memory_region_set_address(&gcr->iomem, gcr->gcr_base); | |
38 | ||
39 | CPU_FOREACH(cpu) { | |
40 | mips_cpu = MIPS_CPU(cpu); | |
41 | mips_cpu->env.CP0_CMGCRBase = gcr->gcr_base >> 4; | |
42 | } | |
43 | } | |
44 | ||
2edd5261 LA |
45 | static inline void update_cpc_base(MIPSGCRState *gcr, uint64_t val) |
46 | { | |
47 | if (is_cpc_connected(gcr)) { | |
48 | gcr->cpc_base = val & GCR_CPC_BASE_MSK; | |
49 | memory_region_transaction_begin(); | |
50 | memory_region_set_address(gcr->cpc_mr, | |
51 | gcr->cpc_base & GCR_CPC_BASE_CPCBASE_MSK); | |
52 | memory_region_set_enabled(gcr->cpc_mr, | |
53 | gcr->cpc_base & GCR_CPC_BASE_CPCEN_MSK); | |
54 | memory_region_transaction_commit(); | |
55 | } | |
56 | } | |
3994215d | 57 | |
19494f81 LA |
58 | static inline void update_gic_base(MIPSGCRState *gcr, uint64_t val) |
59 | { | |
60 | if (is_gic_connected(gcr)) { | |
61 | gcr->gic_base = val & GCR_GIC_BASE_MSK; | |
62 | memory_region_transaction_begin(); | |
63 | memory_region_set_address(gcr->gic_mr, | |
64 | gcr->gic_base & GCR_GIC_BASE_GICBASE_MSK); | |
65 | memory_region_set_enabled(gcr->gic_mr, | |
66 | gcr->gic_base & GCR_GIC_BASE_GICEN_MSK); | |
67 | memory_region_transaction_commit(); | |
68 | } | |
69 | } | |
70 | ||
3994215d YK |
71 | /* Read GCR registers */ |
72 | static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size) | |
73 | { | |
74 | MIPSGCRState *gcr = (MIPSGCRState *) opaque; | |
c09199fe LA |
75 | MIPSGCRVPState *current_vps = &gcr->vps[current_cpu->cpu_index]; |
76 | MIPSGCRVPState *other_vps = &gcr->vps[current_vps->other]; | |
3994215d YK |
77 | |
78 | switch (addr) { | |
79 | /* Global Control Block Register */ | |
80 | case GCR_CONFIG_OFS: | |
81 | /* Set PCORES to 0 */ | |
82 | return 0; | |
83 | case GCR_BASE_OFS: | |
84 | return gcr->gcr_base; | |
85 | case GCR_REV_OFS: | |
86 | return gcr->gcr_rev; | |
19494f81 LA |
87 | case GCR_GIC_BASE_OFS: |
88 | return gcr->gic_base; | |
2edd5261 LA |
89 | case GCR_CPC_BASE_OFS: |
90 | return gcr->cpc_base; | |
19494f81 LA |
91 | case GCR_GIC_STATUS_OFS: |
92 | return is_gic_connected(gcr); | |
2edd5261 LA |
93 | case GCR_CPC_STATUS_OFS: |
94 | return is_cpc_connected(gcr); | |
3994215d YK |
95 | case GCR_L2_CONFIG_OFS: |
96 | /* L2 BYPASS */ | |
97 | return GCR_L2_CONFIG_BYPASS_MSK; | |
98 | /* Core-Local and Core-Other Control Blocks */ | |
99 | case MIPS_CLCB_OFS + GCR_CL_CONFIG_OFS: | |
100 | case MIPS_COCB_OFS + GCR_CL_CONFIG_OFS: | |
101 | /* Set PVP to # of VPs - 1 */ | |
102 | return gcr->num_vps - 1; | |
c09199fe LA |
103 | case MIPS_CLCB_OFS + GCR_CL_RESETBASE_OFS: |
104 | return current_vps->reset_base; | |
105 | case MIPS_COCB_OFS + GCR_CL_RESETBASE_OFS: | |
106 | return other_vps->reset_base; | |
3994215d | 107 | case MIPS_CLCB_OFS + GCR_CL_OTHER_OFS: |
c09199fe LA |
108 | return current_vps->other; |
109 | case MIPS_COCB_OFS + GCR_CL_OTHER_OFS: | |
110 | return other_vps->other; | |
3994215d YK |
111 | default: |
112 | qemu_log_mask(LOG_UNIMP, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx | |
113 | "\n", size, addr); | |
114 | return 0; | |
115 | } | |
116 | return 0; | |
117 | } | |
118 | ||
c09199fe LA |
119 | static inline target_ulong get_exception_base(MIPSGCRVPState *vps) |
120 | { | |
121 | /* TODO: BEV_BASE and SELECT_BEV */ | |
122 | return (int32_t)(vps->reset_base & GCR_CL_RESET_BASE_RESETBASE_MSK); | |
123 | } | |
124 | ||
3994215d YK |
125 | /* Write GCR registers */ |
126 | static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) | |
127 | { | |
2edd5261 | 128 | MIPSGCRState *gcr = (MIPSGCRState *)opaque; |
c09199fe LA |
129 | MIPSGCRVPState *current_vps = &gcr->vps[current_cpu->cpu_index]; |
130 | MIPSGCRVPState *other_vps = &gcr->vps[current_vps->other]; | |
2edd5261 | 131 | |
3994215d | 132 | switch (addr) { |
08944be1 PB |
133 | case GCR_BASE_OFS: |
134 | update_gcr_base(gcr, data); | |
135 | break; | |
19494f81 LA |
136 | case GCR_GIC_BASE_OFS: |
137 | update_gic_base(gcr, data); | |
138 | break; | |
2edd5261 LA |
139 | case GCR_CPC_BASE_OFS: |
140 | update_cpc_base(gcr, data); | |
141 | break; | |
c09199fe LA |
142 | case MIPS_CLCB_OFS + GCR_CL_RESETBASE_OFS: |
143 | current_vps->reset_base = data & GCR_CL_RESET_BASE_MSK; | |
144 | cpu_set_exception_base(current_cpu->cpu_index, | |
145 | get_exception_base(current_vps)); | |
146 | break; | |
147 | case MIPS_COCB_OFS + GCR_CL_RESETBASE_OFS: | |
148 | other_vps->reset_base = data & GCR_CL_RESET_BASE_MSK; | |
149 | cpu_set_exception_base(current_vps->other, | |
150 | get_exception_base(other_vps)); | |
151 | break; | |
152 | case MIPS_CLCB_OFS + GCR_CL_OTHER_OFS: | |
153 | if ((data & GCR_CL_OTHER_MSK) < gcr->num_vps) { | |
154 | current_vps->other = data & GCR_CL_OTHER_MSK; | |
155 | } | |
156 | break; | |
157 | case MIPS_COCB_OFS + GCR_CL_OTHER_OFS: | |
158 | if ((data & GCR_CL_OTHER_MSK) < gcr->num_vps) { | |
159 | other_vps->other = data & GCR_CL_OTHER_MSK; | |
160 | } | |
161 | break; | |
3994215d YK |
162 | default: |
163 | qemu_log_mask(LOG_UNIMP, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx | |
164 | " 0x%" PRIx64 "\n", size, addr, data); | |
165 | break; | |
166 | } | |
167 | } | |
168 | ||
169 | static const MemoryRegionOps gcr_ops = { | |
170 | .read = gcr_read, | |
171 | .write = gcr_write, | |
172 | .endianness = DEVICE_NATIVE_ENDIAN, | |
173 | .impl = { | |
174 | .max_access_size = 8, | |
175 | }, | |
176 | }; | |
177 | ||
178 | static void mips_gcr_init(Object *obj) | |
179 | { | |
180 | SysBusDevice *sbd = SYS_BUS_DEVICE(obj); | |
181 | MIPSGCRState *s = MIPS_GCR(obj); | |
182 | ||
183 | memory_region_init_io(&s->iomem, OBJECT(s), &gcr_ops, s, | |
184 | "mips-gcr", GCR_ADDRSPACE_SZ); | |
185 | sysbus_init_mmio(sbd, &s->iomem); | |
186 | } | |
187 | ||
2edd5261 LA |
188 | static void mips_gcr_reset(DeviceState *dev) |
189 | { | |
190 | MIPSGCRState *s = MIPS_GCR(dev); | |
c09199fe | 191 | int i; |
2edd5261 | 192 | |
19494f81 | 193 | update_gic_base(s, 0); |
2edd5261 | 194 | update_cpc_base(s, 0); |
c09199fe LA |
195 | |
196 | for (i = 0; i < s->num_vps; i++) { | |
197 | s->vps[i].other = 0; | |
198 | s->vps[i].reset_base = 0xBFC00000 & GCR_CL_RESET_BASE_MSK; | |
199 | cpu_set_exception_base(i, get_exception_base(&s->vps[i])); | |
200 | } | |
2edd5261 LA |
201 | } |
202 | ||
203 | static const VMStateDescription vmstate_mips_gcr = { | |
204 | .name = "mips-gcr", | |
205 | .version_id = 0, | |
206 | .minimum_version_id = 0, | |
207 | .fields = (VMStateField[]) { | |
208 | VMSTATE_UINT64(cpc_base, MIPSGCRState), | |
209 | VMSTATE_END_OF_LIST() | |
210 | }, | |
211 | }; | |
212 | ||
3994215d YK |
213 | static Property mips_gcr_properties[] = { |
214 | DEFINE_PROP_INT32("num-vp", MIPSGCRState, num_vps, 1), | |
215 | DEFINE_PROP_INT32("gcr-rev", MIPSGCRState, gcr_rev, 0x800), | |
216 | DEFINE_PROP_UINT64("gcr-base", MIPSGCRState, gcr_base, GCR_BASE_ADDR), | |
e4934bb3 FZ |
217 | DEFINE_PROP_LINK("gic", MIPSGCRState, gic_mr, TYPE_MEMORY_REGION, |
218 | MemoryRegion *), | |
219 | DEFINE_PROP_LINK("cpc", MIPSGCRState, cpc_mr, TYPE_MEMORY_REGION, | |
220 | MemoryRegion *), | |
3994215d YK |
221 | DEFINE_PROP_END_OF_LIST(), |
222 | }; | |
223 | ||
c09199fe LA |
224 | static void mips_gcr_realize(DeviceState *dev, Error **errp) |
225 | { | |
226 | MIPSGCRState *s = MIPS_GCR(dev); | |
227 | ||
228 | /* Create local set of registers for each VP */ | |
229 | s->vps = g_new(MIPSGCRVPState, s->num_vps); | |
230 | } | |
231 | ||
3994215d YK |
232 | static void mips_gcr_class_init(ObjectClass *klass, void *data) |
233 | { | |
234 | DeviceClass *dc = DEVICE_CLASS(klass); | |
235 | dc->props = mips_gcr_properties; | |
2edd5261 LA |
236 | dc->vmsd = &vmstate_mips_gcr; |
237 | dc->reset = mips_gcr_reset; | |
c09199fe | 238 | dc->realize = mips_gcr_realize; |
3994215d YK |
239 | } |
240 | ||
241 | static const TypeInfo mips_gcr_info = { | |
242 | .name = TYPE_MIPS_GCR, | |
243 | .parent = TYPE_SYS_BUS_DEVICE, | |
244 | .instance_size = sizeof(MIPSGCRState), | |
245 | .instance_init = mips_gcr_init, | |
246 | .class_init = mips_gcr_class_init, | |
247 | }; | |
248 | ||
249 | static void mips_gcr_register_types(void) | |
250 | { | |
251 | type_register_static(&mips_gcr_info); | |
252 | } | |
253 | ||
254 | type_init(mips_gcr_register_types) |