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"
13 #include "qapi/error.h"
16 #include "hw/sysbus.h"
17 #include "sysemu/sysemu.h"
18 #include "hw/misc/mips_cmgcr.h"
19 #include "hw/misc/mips_cpc.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_cpc_base(MIPSGCRState
*gcr
, uint64_t val
)
34 if (is_cpc_connected(gcr
)) {
35 gcr
->cpc_base
= val
& GCR_CPC_BASE_MSK
;
36 memory_region_transaction_begin();
37 memory_region_set_address(gcr
->cpc_mr
,
38 gcr
->cpc_base
& GCR_CPC_BASE_CPCBASE_MSK
);
39 memory_region_set_enabled(gcr
->cpc_mr
,
40 gcr
->cpc_base
& GCR_CPC_BASE_CPCEN_MSK
);
41 memory_region_transaction_commit();
45 static inline void update_gic_base(MIPSGCRState
*gcr
, uint64_t val
)
47 if (is_gic_connected(gcr
)) {
48 gcr
->gic_base
= val
& GCR_GIC_BASE_MSK
;
49 memory_region_transaction_begin();
50 memory_region_set_address(gcr
->gic_mr
,
51 gcr
->gic_base
& GCR_GIC_BASE_GICBASE_MSK
);
52 memory_region_set_enabled(gcr
->gic_mr
,
53 gcr
->gic_base
& GCR_GIC_BASE_GICEN_MSK
);
54 memory_region_transaction_commit();
58 /* Read GCR registers */
59 static uint64_t gcr_read(void *opaque
, hwaddr addr
, unsigned size
)
61 MIPSGCRState
*gcr
= (MIPSGCRState
*) opaque
;
62 MIPSGCRVPState
*current_vps
= &gcr
->vps
[current_cpu
->cpu_index
];
63 MIPSGCRVPState
*other_vps
= &gcr
->vps
[current_vps
->other
];
66 /* Global Control Block Register */
74 case GCR_GIC_BASE_OFS
:
76 case GCR_CPC_BASE_OFS
:
78 case GCR_GIC_STATUS_OFS
:
79 return is_gic_connected(gcr
);
80 case GCR_CPC_STATUS_OFS
:
81 return is_cpc_connected(gcr
);
82 case GCR_L2_CONFIG_OFS
:
84 return GCR_L2_CONFIG_BYPASS_MSK
;
85 /* Core-Local and Core-Other Control Blocks */
86 case MIPS_CLCB_OFS
+ GCR_CL_CONFIG_OFS
:
87 case MIPS_COCB_OFS
+ GCR_CL_CONFIG_OFS
:
88 /* Set PVP to # of VPs - 1 */
89 return gcr
->num_vps
- 1;
90 case MIPS_CLCB_OFS
+ GCR_CL_RESETBASE_OFS
:
91 return current_vps
->reset_base
;
92 case MIPS_COCB_OFS
+ GCR_CL_RESETBASE_OFS
:
93 return other_vps
->reset_base
;
94 case MIPS_CLCB_OFS
+ GCR_CL_OTHER_OFS
:
95 return current_vps
->other
;
96 case MIPS_COCB_OFS
+ GCR_CL_OTHER_OFS
:
97 return other_vps
->other
;
99 qemu_log_mask(LOG_UNIMP
, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx
106 static inline target_ulong
get_exception_base(MIPSGCRVPState
*vps
)
108 /* TODO: BEV_BASE and SELECT_BEV */
109 return (int32_t)(vps
->reset_base
& GCR_CL_RESET_BASE_RESETBASE_MSK
);
112 /* Write GCR registers */
113 static void gcr_write(void *opaque
, hwaddr addr
, uint64_t data
, unsigned size
)
115 MIPSGCRState
*gcr
= (MIPSGCRState
*)opaque
;
116 MIPSGCRVPState
*current_vps
= &gcr
->vps
[current_cpu
->cpu_index
];
117 MIPSGCRVPState
*other_vps
= &gcr
->vps
[current_vps
->other
];
120 case GCR_GIC_BASE_OFS
:
121 update_gic_base(gcr
, data
);
123 case GCR_CPC_BASE_OFS
:
124 update_cpc_base(gcr
, data
);
126 case MIPS_CLCB_OFS
+ GCR_CL_RESETBASE_OFS
:
127 current_vps
->reset_base
= data
& GCR_CL_RESET_BASE_MSK
;
128 cpu_set_exception_base(current_cpu
->cpu_index
,
129 get_exception_base(current_vps
));
131 case MIPS_COCB_OFS
+ GCR_CL_RESETBASE_OFS
:
132 other_vps
->reset_base
= data
& GCR_CL_RESET_BASE_MSK
;
133 cpu_set_exception_base(current_vps
->other
,
134 get_exception_base(other_vps
));
136 case MIPS_CLCB_OFS
+ GCR_CL_OTHER_OFS
:
137 if ((data
& GCR_CL_OTHER_MSK
) < gcr
->num_vps
) {
138 current_vps
->other
= data
& GCR_CL_OTHER_MSK
;
141 case MIPS_COCB_OFS
+ GCR_CL_OTHER_OFS
:
142 if ((data
& GCR_CL_OTHER_MSK
) < gcr
->num_vps
) {
143 other_vps
->other
= data
& GCR_CL_OTHER_MSK
;
147 qemu_log_mask(LOG_UNIMP
, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx
148 " 0x%" PRIx64
"\n", size
, addr
, data
);
153 static const MemoryRegionOps gcr_ops
= {
156 .endianness
= DEVICE_NATIVE_ENDIAN
,
158 .max_access_size
= 8,
162 static void mips_gcr_init(Object
*obj
)
164 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
165 MIPSGCRState
*s
= MIPS_GCR(obj
);
167 object_property_add_link(obj
, "gic", TYPE_MEMORY_REGION
,
168 (Object
**)&s
->gic_mr
,
169 qdev_prop_allow_set_link_before_realize
,
170 OBJ_PROP_LINK_UNREF_ON_RELEASE
,
173 object_property_add_link(obj
, "cpc", TYPE_MEMORY_REGION
,
174 (Object
**)&s
->cpc_mr
,
175 qdev_prop_allow_set_link_before_realize
,
176 OBJ_PROP_LINK_UNREF_ON_RELEASE
,
179 memory_region_init_io(&s
->iomem
, OBJECT(s
), &gcr_ops
, s
,
180 "mips-gcr", GCR_ADDRSPACE_SZ
);
181 sysbus_init_mmio(sbd
, &s
->iomem
);
184 static void mips_gcr_reset(DeviceState
*dev
)
186 MIPSGCRState
*s
= MIPS_GCR(dev
);
189 update_gic_base(s
, 0);
190 update_cpc_base(s
, 0);
192 for (i
= 0; i
< s
->num_vps
; i
++) {
194 s
->vps
[i
].reset_base
= 0xBFC00000 & GCR_CL_RESET_BASE_MSK
;
195 cpu_set_exception_base(i
, get_exception_base(&s
->vps
[i
]));
199 static const VMStateDescription vmstate_mips_gcr
= {
202 .minimum_version_id
= 0,
203 .fields
= (VMStateField
[]) {
204 VMSTATE_UINT64(cpc_base
, MIPSGCRState
),
205 VMSTATE_END_OF_LIST()
209 static Property mips_gcr_properties
[] = {
210 DEFINE_PROP_INT32("num-vp", MIPSGCRState
, num_vps
, 1),
211 DEFINE_PROP_INT32("gcr-rev", MIPSGCRState
, gcr_rev
, 0x800),
212 DEFINE_PROP_UINT64("gcr-base", MIPSGCRState
, gcr_base
, GCR_BASE_ADDR
),
213 DEFINE_PROP_END_OF_LIST(),
216 static void mips_gcr_realize(DeviceState
*dev
, Error
**errp
)
218 MIPSGCRState
*s
= MIPS_GCR(dev
);
220 /* Create local set of registers for each VP */
221 s
->vps
= g_new(MIPSGCRVPState
, s
->num_vps
);
224 static void mips_gcr_class_init(ObjectClass
*klass
, void *data
)
226 DeviceClass
*dc
= DEVICE_CLASS(klass
);
227 dc
->props
= mips_gcr_properties
;
228 dc
->vmsd
= &vmstate_mips_gcr
;
229 dc
->reset
= mips_gcr_reset
;
230 dc
->realize
= mips_gcr_realize
;
233 static const TypeInfo mips_gcr_info
= {
234 .name
= TYPE_MIPS_GCR
,
235 .parent
= TYPE_SYS_BUS_DEVICE
,
236 .instance_size
= sizeof(MIPSGCRState
),
237 .instance_init
= mips_gcr_init
,
238 .class_init
= mips_gcr_class_init
,
241 static void mips_gcr_register_types(void)
243 type_register_static(&mips_gcr_info
);
246 type_init(mips_gcr_register_types
)