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
6 * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
7 * Authors: Sanjay Lal <sanjayl@kymasys.com>
9 * Copyright (C) 2015 Imagination Technologies
12 #include "qemu/osdep.h"
15 #include "hw/sysbus.h"
16 #include "sysemu/sysemu.h"
17 #include "hw/misc/mips_cmgcr.h"
18 #include "hw/misc/mips_cpc.h"
19 #include "hw/intc/mips_gic.h"
21 static inline bool is_cpc_connected(MIPSGCRState
*s
)
23 return s
->cpc_mr
!= NULL
;
26 static inline bool is_gic_connected(MIPSGCRState
*s
)
28 return s
->gic_mr
!= NULL
;
31 static inline void update_gcr_base(MIPSGCRState
*gcr
, uint64_t val
)
36 gcr
->gcr_base
= val
& GCR_BASE_GCRBASE_MSK
;
37 memory_region_set_address(&gcr
->iomem
, gcr
->gcr_base
);
40 mips_cpu
= MIPS_CPU(cpu
);
41 mips_cpu
->env
.CP0_CMGCRBase
= gcr
->gcr_base
>> 4;
45 static inline void update_cpc_base(MIPSGCRState
*gcr
, uint64_t val
)
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();
58 static inline void update_gic_base(MIPSGCRState
*gcr
, uint64_t val
)
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();
71 /* Read GCR registers */
72 static uint64_t gcr_read(void *opaque
, hwaddr addr
, unsigned size
)
74 MIPSGCRState
*gcr
= (MIPSGCRState
*) opaque
;
75 MIPSGCRVPState
*current_vps
= &gcr
->vps
[current_cpu
->cpu_index
];
76 MIPSGCRVPState
*other_vps
= &gcr
->vps
[current_vps
->other
];
79 /* Global Control Block Register */
87 case GCR_GIC_BASE_OFS
:
89 case GCR_CPC_BASE_OFS
:
91 case GCR_GIC_STATUS_OFS
:
92 return is_gic_connected(gcr
);
93 case GCR_CPC_STATUS_OFS
:
94 return is_cpc_connected(gcr
);
95 case GCR_L2_CONFIG_OFS
:
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;
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
;
107 case MIPS_CLCB_OFS
+ GCR_CL_OTHER_OFS
:
108 return current_vps
->other
;
109 case MIPS_COCB_OFS
+ GCR_CL_OTHER_OFS
:
110 return other_vps
->other
;
112 qemu_log_mask(LOG_UNIMP
, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx
119 static inline target_ulong
get_exception_base(MIPSGCRVPState
*vps
)
121 /* TODO: BEV_BASE and SELECT_BEV */
122 return (int32_t)(vps
->reset_base
& GCR_CL_RESET_BASE_RESETBASE_MSK
);
125 /* Write GCR registers */
126 static void gcr_write(void *opaque
, hwaddr addr
, uint64_t data
, unsigned size
)
128 MIPSGCRState
*gcr
= (MIPSGCRState
*)opaque
;
129 MIPSGCRVPState
*current_vps
= &gcr
->vps
[current_cpu
->cpu_index
];
130 MIPSGCRVPState
*other_vps
= &gcr
->vps
[current_vps
->other
];
134 update_gcr_base(gcr
, data
);
136 case GCR_GIC_BASE_OFS
:
137 update_gic_base(gcr
, data
);
139 case GCR_CPC_BASE_OFS
:
140 update_cpc_base(gcr
, data
);
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
));
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
));
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
;
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
;
163 qemu_log_mask(LOG_UNIMP
, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx
164 " 0x%" PRIx64
"\n", size
, addr
, data
);
169 static const MemoryRegionOps gcr_ops
= {
172 .endianness
= DEVICE_NATIVE_ENDIAN
,
174 .max_access_size
= 8,
178 static void mips_gcr_init(Object
*obj
)
180 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
181 MIPSGCRState
*s
= MIPS_GCR(obj
);
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
);
188 static void mips_gcr_reset(DeviceState
*dev
)
190 MIPSGCRState
*s
= MIPS_GCR(dev
);
193 update_gic_base(s
, 0);
194 update_cpc_base(s
, 0);
196 for (i
= 0; i
< s
->num_vps
; i
++) {
198 s
->vps
[i
].reset_base
= 0xBFC00000 & GCR_CL_RESET_BASE_MSK
;
199 cpu_set_exception_base(i
, get_exception_base(&s
->vps
[i
]));
203 static const VMStateDescription vmstate_mips_gcr
= {
206 .minimum_version_id
= 0,
207 .fields
= (VMStateField
[]) {
208 VMSTATE_UINT64(cpc_base
, MIPSGCRState
),
209 VMSTATE_END_OF_LIST()
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
),
217 DEFINE_PROP_LINK("gic", MIPSGCRState
, gic_mr
, TYPE_MEMORY_REGION
,
219 DEFINE_PROP_LINK("cpc", MIPSGCRState
, cpc_mr
, TYPE_MEMORY_REGION
,
221 DEFINE_PROP_END_OF_LIST(),
224 static void mips_gcr_realize(DeviceState
*dev
, Error
**errp
)
226 MIPSGCRState
*s
= MIPS_GCR(dev
);
228 /* Create local set of registers for each VP */
229 s
->vps
= g_new(MIPSGCRVPState
, s
->num_vps
);
232 static void mips_gcr_class_init(ObjectClass
*klass
, void *data
)
234 DeviceClass
*dc
= DEVICE_CLASS(klass
);
235 dc
->props
= mips_gcr_properties
;
236 dc
->vmsd
= &vmstate_mips_gcr
;
237 dc
->reset
= mips_gcr_reset
;
238 dc
->realize
= mips_gcr_realize
;
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
,
249 static void mips_gcr_register_types(void)
251 type_register_static(&mips_gcr_info
);
254 type_init(mips_gcr_register_types
)