2 * This confidential and proprietary software may be used only as
3 * authorised by a licensing agreement from ARM Limited
4 * (C) COPYRIGHT 2011-2013 ARM Limited
6 * The entire notice above must be reproduced on all authorised
7 * copies and copies may only be made to the extent permitted
8 * by a licensing agreement from ARM Limited.
12 #include "mali_hw_core.h"
13 #include "mali_group.h"
15 #include "regs/mali_gp_regs.h"
16 #include "mali_kernel_common.h"
17 #include "mali_kernel_core.h"
18 #if defined(CONFIG_MALI400_PROFILING)
19 #include "mali_osk_profiling.h"
22 static struct mali_gp_core
*mali_global_gp_core
= NULL
;
24 /* Interrupt handlers */
25 static void mali_gp_irq_probe_trigger(void *data
);
26 static _mali_osk_errcode_t
mali_gp_irq_probe_ack(void *data
);
28 struct mali_gp_core
*mali_gp_create(const _mali_osk_resource_t
* resource
, struct mali_group
*group
)
30 struct mali_gp_core
* core
= NULL
;
32 MALI_DEBUG_ASSERT(NULL
== mali_global_gp_core
);
33 MALI_DEBUG_PRINT(2, ("Mali GP: Creating Mali GP core: %s\n", resource
->description
));
35 core
= _mali_osk_malloc(sizeof(struct mali_gp_core
));
37 if (_MALI_OSK_ERR_OK
== mali_hw_core_create(&core
->hw_core
, resource
, MALIGP2_REGISTER_ADDRESS_SPACE_SIZE
)) {
38 _mali_osk_errcode_t ret
;
40 ret
= mali_gp_reset(core
);
42 if (_MALI_OSK_ERR_OK
== ret
) {
43 ret
= mali_group_add_gp_core(group
, core
);
44 if (_MALI_OSK_ERR_OK
== ret
) {
45 /* Setup IRQ handlers (which will do IRQ probing if needed) */
46 core
->irq
= _mali_osk_irq_init(resource
->irq
,
47 mali_group_upper_half_gp
,
49 mali_gp_irq_probe_trigger
,
50 mali_gp_irq_probe_ack
,
52 resource
->description
);
53 if (NULL
!= core
->irq
) {
54 MALI_DEBUG_PRINT(4, ("Mali GP: set global gp core from 0x%08X to 0x%08X\n", mali_global_gp_core
, core
));
55 mali_global_gp_core
= core
;
59 MALI_PRINT_ERROR(("Mali GP: Failed to setup interrupt handlers for GP core %s\n", core
->hw_core
.description
));
61 mali_group_remove_gp_core(group
);
63 MALI_PRINT_ERROR(("Mali GP: Failed to add core %s to group\n", core
->hw_core
.description
));
66 mali_hw_core_delete(&core
->hw_core
);
71 MALI_PRINT_ERROR(("Failed to allocate memory for GP core\n"));
77 void mali_gp_delete(struct mali_gp_core
*core
)
79 MALI_DEBUG_ASSERT_POINTER(core
);
81 _mali_osk_irq_term(core
->irq
);
82 mali_hw_core_delete(&core
->hw_core
);
83 mali_global_gp_core
= NULL
;
87 void mali_gp_stop_bus(struct mali_gp_core
*core
)
89 MALI_DEBUG_ASSERT_POINTER(core
);
91 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_CMD
, MALIGP2_REG_VAL_CMD_STOP_BUS
);
94 _mali_osk_errcode_t
mali_gp_stop_bus_wait(struct mali_gp_core
*core
)
98 MALI_DEBUG_ASSERT_POINTER(core
);
100 /* Send the stop bus command. */
101 mali_gp_stop_bus(core
);
103 /* Wait for bus to be stopped */
104 for (i
= 0; i
< MALI_REG_POLL_COUNT_FAST
; i
++) {
105 if (mali_hw_core_register_read(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_STATUS
) & MALIGP2_REG_VAL_STATUS_BUS_STOPPED
) {
110 if (MALI_REG_POLL_COUNT_FAST
== i
) {
111 MALI_PRINT_ERROR(("Mali GP: Failed to stop bus on %s\n", core
->hw_core
.description
));
112 return _MALI_OSK_ERR_FAULT
;
114 return _MALI_OSK_ERR_OK
;
117 void mali_gp_hard_reset(struct mali_gp_core
*core
)
119 const u32 reset_wait_target_register
= MALIGP2_REG_ADDR_MGMT_WRITE_BOUND_LOW
;
120 const u32 reset_invalid_value
= 0xC0FFE000;
121 const u32 reset_check_value
= 0xC01A0000;
122 const u32 reset_default_value
= 0;
125 MALI_DEBUG_ASSERT_POINTER(core
);
126 MALI_DEBUG_PRINT(4, ("Mali GP: Hard reset of core %s\n", core
->hw_core
.description
));
128 mali_hw_core_register_write(&core
->hw_core
, reset_wait_target_register
, reset_invalid_value
);
130 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_CMD
, MALIGP2_REG_VAL_CMD_RESET
);
132 for (i
= 0; i
< MALI_REG_POLL_COUNT_FAST
; i
++) {
133 mali_hw_core_register_write(&core
->hw_core
, reset_wait_target_register
, reset_check_value
);
134 if (reset_check_value
== mali_hw_core_register_read(&core
->hw_core
, reset_wait_target_register
)) {
139 if (MALI_REG_POLL_COUNT_FAST
== i
) {
140 MALI_PRINT_ERROR(("Mali GP: The hard reset loop didn't work, unable to recover\n"));
143 mali_hw_core_register_write(&core
->hw_core
, reset_wait_target_register
, reset_default_value
); /* set it back to the default */
144 /* Re-enable interrupts */
145 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_CLEAR
, MALIGP2_REG_VAL_IRQ_MASK_ALL
);
146 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_MASK
, MALIGP2_REG_VAL_IRQ_MASK_USED
);
150 void mali_gp_reset_async(struct mali_gp_core
*core
)
152 MALI_DEBUG_ASSERT_POINTER(core
);
154 MALI_DEBUG_PRINT(4, ("Mali GP: Reset of core %s\n", core
->hw_core
.description
));
156 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_MASK
, 0); /* disable the IRQs */
157 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_CLEAR
, MALI400GP_REG_VAL_IRQ_RESET_COMPLETED
);
158 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_CMD
, MALI400GP_REG_VAL_CMD_SOFT_RESET
);
162 _mali_osk_errcode_t
mali_gp_reset_wait(struct mali_gp_core
*core
)
167 MALI_DEBUG_ASSERT_POINTER(core
);
169 for (i
= 0; i
< MALI_REG_POLL_COUNT_FAST
; i
++) {
170 rawstat
= mali_hw_core_register_read(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT
);
171 if (rawstat
& MALI400GP_REG_VAL_IRQ_RESET_COMPLETED
) {
176 if (i
== MALI_REG_POLL_COUNT_FAST
) {
177 MALI_PRINT_ERROR(("Mali GP: Failed to reset core %s, rawstat: 0x%08x\n",
178 core
->hw_core
.description
, rawstat
));
179 return _MALI_OSK_ERR_FAULT
;
182 /* Re-enable interrupts */
183 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_CLEAR
, MALIGP2_REG_VAL_IRQ_MASK_ALL
);
184 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_MASK
, MALIGP2_REG_VAL_IRQ_MASK_USED
);
186 return _MALI_OSK_ERR_OK
;
189 _mali_osk_errcode_t
mali_gp_reset(struct mali_gp_core
*core
)
191 mali_gp_reset_async(core
);
192 return mali_gp_reset_wait(core
);
195 void mali_gp_job_start(struct mali_gp_core
*core
, struct mali_gp_job
*job
)
198 u32
*frame_registers
= mali_gp_job_get_frame_registers(job
);
199 u32 counter_src0
= mali_gp_job_get_perf_counter_src0(job
);
200 u32 counter_src1
= mali_gp_job_get_perf_counter_src1(job
);
202 MALI_DEBUG_ASSERT_POINTER(core
);
204 if (mali_gp_job_has_vs_job(job
)) {
205 startcmd
|= (u32
) MALIGP2_REG_VAL_CMD_START_VS
;
208 if (mali_gp_job_has_plbu_job(job
)) {
209 startcmd
|= (u32
) MALIGP2_REG_VAL_CMD_START_PLBU
;
212 MALI_DEBUG_ASSERT(0 != startcmd
);
214 mali_hw_core_register_write_array_relaxed(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR
, frame_registers
, MALIGP2_NUM_REGS_FRAME
);
216 if (MALI_HW_CORE_NO_COUNTER
!= counter_src0
) {
217 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC
, counter_src0
);
218 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_ENABLE
, MALIGP2_REG_VAL_PERF_CNT_ENABLE
);
220 if (MALI_HW_CORE_NO_COUNTER
!= counter_src1
) {
221 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC
, counter_src1
);
222 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE
, MALIGP2_REG_VAL_PERF_CNT_ENABLE
);
225 MALI_DEBUG_PRINT(3, ("Mali GP: Starting job (0x%08x) on core %s with command 0x%08X\n", job
, core
->hw_core
.description
, startcmd
));
227 mali_hw_core_register_write_relaxed(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_CMD
, MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC
);
229 /* Barrier to make sure the previous register write is finished */
230 _mali_osk_write_mem_barrier();
232 /* This is the command that starts the core. */
233 mali_hw_core_register_write_relaxed(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_CMD
, startcmd
);
235 /* Barrier to make sure the previous register write is finished */
236 _mali_osk_write_mem_barrier();
239 void mali_gp_resume_with_new_heap(struct mali_gp_core
*core
, u32 start_addr
, u32 end_addr
)
243 MALI_DEBUG_ASSERT_POINTER(core
);
245 irq_readout
= mali_hw_core_register_read(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT
);
247 if (irq_readout
& MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM
) {
248 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_CLEAR
, (MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM
| MALIGP2_REG_VAL_IRQ_HANG
));
249 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_MASK
, MALIGP2_REG_VAL_IRQ_MASK_USED
); /* re-enable interrupts */
250 mali_hw_core_register_write_relaxed(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR
, start_addr
);
251 mali_hw_core_register_write_relaxed(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR
, end_addr
);
253 MALI_DEBUG_PRINT(3, ("Mali GP: Resuming job\n"));
255 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_CMD
, MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC
);
256 _mali_osk_write_mem_barrier();
259 * else: core has been reset between PLBU_OUT_OF_MEM interrupt and this new heap response.
260 * A timeout or a page fault on Mali-200 PP core can cause this behaviour.
264 u32
mali_gp_core_get_version(struct mali_gp_core
*core
)
266 MALI_DEBUG_ASSERT_POINTER(core
);
267 return mali_hw_core_register_read(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_VERSION
);
270 struct mali_gp_core
*mali_gp_get_global_gp_core(void)
272 return mali_global_gp_core
;
275 /* ------------- interrupt handling below ------------------ */
276 static void mali_gp_irq_probe_trigger(void *data
)
278 struct mali_gp_core
*core
= (struct mali_gp_core
*)data
;
280 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_MASK
, MALIGP2_REG_VAL_IRQ_MASK_USED
);
281 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT
, MALIGP2_REG_VAL_CMD_FORCE_HANG
);
282 _mali_osk_mem_barrier();
285 static _mali_osk_errcode_t
mali_gp_irq_probe_ack(void *data
)
287 struct mali_gp_core
*core
= (struct mali_gp_core
*)data
;
290 irq_readout
= mali_hw_core_register_read(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_STAT
);
291 if (MALIGP2_REG_VAL_IRQ_FORCE_HANG
& irq_readout
) {
292 mali_hw_core_register_write(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_INT_CLEAR
, MALIGP2_REG_VAL_IRQ_FORCE_HANG
);
293 _mali_osk_mem_barrier();
294 return _MALI_OSK_ERR_OK
;
297 return _MALI_OSK_ERR_FAULT
;
300 /* ------ local helper functions below --------- */
301 #if MALI_STATE_TRACKING
302 u32
mali_gp_dump_state(struct mali_gp_core
*core
, char *buf
, u32 size
)
306 n
+= _mali_osk_snprintf(buf
+ n
, size
- n
, "\tGP: %s\n", core
->hw_core
.description
);
312 void mali_gp_update_performance_counters(struct mali_gp_core
*core
, struct mali_gp_job
*job
, mali_bool suspend
)
316 u32 counter_src0
= mali_gp_job_get_perf_counter_src0(job
);
317 u32 counter_src1
= mali_gp_job_get_perf_counter_src1(job
);
319 if (MALI_HW_CORE_NO_COUNTER
!= counter_src0
) {
320 val0
= mali_hw_core_register_read(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE
);
321 mali_gp_job_set_perf_counter_value0(job
, val0
);
323 #if defined(CONFIG_MALI400_PROFILING)
324 _mali_osk_profiling_report_hw_counter(COUNTER_VP_0_C0
, val0
);
329 if (MALI_HW_CORE_NO_COUNTER
!= counter_src1
) {
330 val1
= mali_hw_core_register_read(&core
->hw_core
, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE
);
331 mali_gp_job_set_perf_counter_value1(job
, val1
);
333 #if defined(CONFIG_MALI400_PROFILING)
334 _mali_osk_profiling_report_hw_counter(COUNTER_VP_0_C1
, val1
);