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"
14 #include "qemu/module.h"
15 #include "hw/sysbus.h"
16 #include "migration/vmstate.h"
17 #include "hw/misc/mips_cmgcr.h"
18 #include "hw/misc/mips_cpc.h"
19 #include "hw/qdev-properties.h"
20 #include "hw/intc/mips_gic.h"
22 static inline bool is_cpc_connected(MIPSGCRState
*s
)
24 return s
->cpc_mr
!= NULL
;
27 static inline bool is_gic_connected(MIPSGCRState
*s
)
29 return s
->gic_mr
!= NULL
;
32 static inline void update_gcr_base(MIPSGCRState
*gcr
, uint64_t val
)
37 gcr
->gcr_base
= val
& GCR_BASE_GCRBASE_MSK
;
38 memory_region_set_address(&gcr
->iomem
, gcr
->gcr_base
);
41 mips_cpu
= MIPS_CPU(cpu
);
42 mips_cpu
->env
.CP0_CMGCRBase
= gcr
->gcr_base
>> 4;
46 static inline void update_cpc_base(MIPSGCRState
*gcr
, uint64_t val
)
48 if (is_cpc_connected(gcr
)) {
49 gcr
->cpc_base
= val
& GCR_CPC_BASE_MSK
;
50 memory_region_transaction_begin();
51 memory_region_set_address(gcr
->cpc_mr
,
52 gcr
->cpc_base
& GCR_CPC_BASE_CPCBASE_MSK
);
53 memory_region_set_enabled(gcr
->cpc_mr
,
54 gcr
->cpc_base
& GCR_CPC_BASE_CPCEN_MSK
);
55 memory_region_transaction_commit();
59 static inline void update_gic_base(MIPSGCRState
*gcr
, uint64_t val
)
61 if (is_gic_connected(gcr
)) {
62 gcr
->gic_base
= val
& GCR_GIC_BASE_MSK
;
63 memory_region_transaction_begin();
64 memory_region_set_address(gcr
->gic_mr
,
65 gcr
->gic_base
& GCR_GIC_BASE_GICBASE_MSK
);
66 memory_region_set_enabled(gcr
->gic_mr
,
67 gcr
->gic_base
& GCR_GIC_BASE_GICEN_MSK
);
68 memory_region_transaction_commit();
72 /* Read GCR registers */
73 static uint64_t gcr_read(void *opaque
, hwaddr addr
, unsigned size
)
75 MIPSGCRState
*gcr
= (MIPSGCRState
*) opaque
;
76 MIPSGCRVPState
*current_vps
= &gcr
->vps
[current_cpu
->cpu_index
];
77 MIPSGCRVPState
*other_vps
= &gcr
->vps
[current_vps
->other
];
80 /* Global Control Block Register */
88 case GCR_GIC_BASE_OFS
:
90 case GCR_CPC_BASE_OFS
:
92 case GCR_GIC_STATUS_OFS
:
93 return is_gic_connected(gcr
);
94 case GCR_CPC_STATUS_OFS
:
95 return is_cpc_connected(gcr
);
96 case GCR_L2_CONFIG_OFS
:
98 return GCR_L2_CONFIG_BYPASS_MSK
;
99 /* Core-Local and Core-Other Control Blocks */
100 case MIPS_CLCB_OFS
+ GCR_CL_CONFIG_OFS
:
101 case MIPS_COCB_OFS
+ GCR_CL_CONFIG_OFS
:
102 /* Set PVP to # of VPs - 1 */
103 return gcr
->num_vps
- 1;
104 case MIPS_CLCB_OFS
+ GCR_CL_RESETBASE_OFS
:
105 return current_vps
->reset_base
;
106 case MIPS_COCB_OFS
+ GCR_CL_RESETBASE_OFS
:
107 return other_vps
->reset_base
;
108 case MIPS_CLCB_OFS
+ GCR_CL_OTHER_OFS
:
109 return current_vps
->other
;
110 case MIPS_COCB_OFS
+ GCR_CL_OTHER_OFS
:
111 return other_vps
->other
;
113 qemu_log_mask(LOG_UNIMP
, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx
120 static inline target_ulong
get_exception_base(MIPSGCRVPState
*vps
)
122 /* TODO: BEV_BASE and SELECT_BEV */
123 return (int32_t)(vps
->reset_base
& GCR_CL_RESET_BASE_RESETBASE_MSK
);
126 /* Write GCR registers */
127 static void gcr_write(void *opaque
, hwaddr addr
, uint64_t data
, unsigned size
)
129 MIPSGCRState
*gcr
= (MIPSGCRState
*)opaque
;
130 MIPSGCRVPState
*current_vps
= &gcr
->vps
[current_cpu
->cpu_index
];
131 MIPSGCRVPState
*other_vps
= &gcr
->vps
[current_vps
->other
];
135 update_gcr_base(gcr
, data
);
137 case GCR_GIC_BASE_OFS
:
138 update_gic_base(gcr
, data
);
140 case GCR_CPC_BASE_OFS
:
141 update_cpc_base(gcr
, data
);
143 case MIPS_CLCB_OFS
+ GCR_CL_RESETBASE_OFS
:
144 current_vps
->reset_base
= data
& GCR_CL_RESET_BASE_MSK
;
145 cpu_set_exception_base(current_cpu
->cpu_index
,
146 get_exception_base(current_vps
));
148 case MIPS_COCB_OFS
+ GCR_CL_RESETBASE_OFS
:
149 other_vps
->reset_base
= data
& GCR_CL_RESET_BASE_MSK
;
150 cpu_set_exception_base(current_vps
->other
,
151 get_exception_base(other_vps
));
153 case MIPS_CLCB_OFS
+ GCR_CL_OTHER_OFS
:
154 if ((data
& GCR_CL_OTHER_MSK
) < gcr
->num_vps
) {
155 current_vps
->other
= data
& GCR_CL_OTHER_MSK
;
158 case MIPS_COCB_OFS
+ GCR_CL_OTHER_OFS
:
159 if ((data
& GCR_CL_OTHER_MSK
) < gcr
->num_vps
) {
160 other_vps
->other
= data
& GCR_CL_OTHER_MSK
;
164 qemu_log_mask(LOG_UNIMP
, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx
165 " 0x%" PRIx64
"\n", size
, addr
, data
);
170 static const MemoryRegionOps gcr_ops
= {
173 .endianness
= DEVICE_NATIVE_ENDIAN
,
175 .max_access_size
= 8,
179 static void mips_gcr_init(Object
*obj
)
181 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
182 MIPSGCRState
*s
= MIPS_GCR(obj
);
184 memory_region_init_io(&s
->iomem
, OBJECT(s
), &gcr_ops
, s
,
185 "mips-gcr", GCR_ADDRSPACE_SZ
);
186 sysbus_init_mmio(sbd
, &s
->iomem
);
189 static void mips_gcr_reset(DeviceState
*dev
)
191 MIPSGCRState
*s
= MIPS_GCR(dev
);
194 update_gic_base(s
, 0);
195 update_cpc_base(s
, 0);
197 for (i
= 0; i
< s
->num_vps
; i
++) {
199 s
->vps
[i
].reset_base
= 0xBFC00000 & GCR_CL_RESET_BASE_MSK
;
200 cpu_set_exception_base(i
, get_exception_base(&s
->vps
[i
]));
204 static const VMStateDescription vmstate_mips_gcr
= {
207 .minimum_version_id
= 0,
208 .fields
= (const VMStateField
[]) {
209 VMSTATE_UINT64(cpc_base
, MIPSGCRState
),
210 VMSTATE_END_OF_LIST()
214 static Property mips_gcr_properties
[] = {
215 DEFINE_PROP_UINT32("num-vp", MIPSGCRState
, num_vps
, 1),
216 DEFINE_PROP_INT32("gcr-rev", MIPSGCRState
, gcr_rev
, 0x800),
217 DEFINE_PROP_UINT64("gcr-base", MIPSGCRState
, gcr_base
, GCR_BASE_ADDR
),
218 DEFINE_PROP_LINK("gic", MIPSGCRState
, gic_mr
, TYPE_MEMORY_REGION
,
220 DEFINE_PROP_LINK("cpc", MIPSGCRState
, cpc_mr
, TYPE_MEMORY_REGION
,
222 DEFINE_PROP_END_OF_LIST(),
225 static void mips_gcr_realize(DeviceState
*dev
, Error
**errp
)
227 MIPSGCRState
*s
= MIPS_GCR(dev
);
229 /* Create local set of registers for each VP */
230 s
->vps
= g_new(MIPSGCRVPState
, s
->num_vps
);
233 static void mips_gcr_class_init(ObjectClass
*klass
, void *data
)
235 DeviceClass
*dc
= DEVICE_CLASS(klass
);
236 device_class_set_props(dc
, mips_gcr_properties
);
237 dc
->vmsd
= &vmstate_mips_gcr
;
238 dc
->reset
= mips_gcr_reset
;
239 dc
->realize
= mips_gcr_realize
;
242 static const TypeInfo mips_gcr_info
= {
243 .name
= TYPE_MIPS_GCR
,
244 .parent
= TYPE_SYS_BUS_DEVICE
,
245 .instance_size
= sizeof(MIPSGCRState
),
246 .instance_init
= mips_gcr_init
,
247 .class_init
= mips_gcr_class_init
,
250 static void mips_gcr_register_types(void)
252 type_register_static(&mips_gcr_info
);
255 type_init(mips_gcr_register_types
)