xref: /OK3568_Linux_fs/kernel/drivers/gpu/arm/mali400/mali/common/mali_gp.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (C) 2011-2017 ARM Limited. All rights reserved.
3  *
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  *
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10 
11 #include "mali_gp.h"
12 #include "mali_hw_core.h"
13 #include "mali_group.h"
14 #include "mali_osk.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"
20 #endif
21 
22 static struct mali_gp_core *mali_global_gp_core = NULL;
23 
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);
27 
mali_gp_create(const _mali_osk_resource_t * resource,struct mali_group * group)28 struct mali_gp_core *mali_gp_create(const _mali_osk_resource_t *resource, struct mali_group *group)
29 {
30 	struct mali_gp_core *core = NULL;
31 
32 	MALI_DEBUG_ASSERT(NULL == mali_global_gp_core);
33 	MALI_DEBUG_PRINT(2, ("Mali GP: Creating Mali GP core: %s\n", resource->description));
34 
35 	core = _mali_osk_malloc(sizeof(struct mali_gp_core));
36 	if (NULL != 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;
39 
40 			ret = mali_gp_reset(core);
41 
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,
48 								       group,
49 								       mali_gp_irq_probe_trigger,
50 								       mali_gp_irq_probe_ack,
51 								       core,
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;
56 
57 						return core;
58 					} else {
59 						MALI_PRINT_ERROR(("Mali GP: Failed to setup interrupt handlers for GP core %s\n", core->hw_core.description));
60 					}
61 					mali_group_remove_gp_core(group);
62 				} else {
63 					MALI_PRINT_ERROR(("Mali GP: Failed to add core %s to group\n", core->hw_core.description));
64 				}
65 			}
66 			mali_hw_core_delete(&core->hw_core);
67 		}
68 
69 		_mali_osk_free(core);
70 	} else {
71 		MALI_PRINT_ERROR(("Failed to allocate memory for GP core\n"));
72 	}
73 
74 	return NULL;
75 }
76 
mali_gp_delete(struct mali_gp_core * core)77 void mali_gp_delete(struct mali_gp_core *core)
78 {
79 	MALI_DEBUG_ASSERT_POINTER(core);
80 
81 	_mali_osk_irq_term(core->irq);
82 	mali_hw_core_delete(&core->hw_core);
83 	mali_global_gp_core = NULL;
84 	_mali_osk_free(core);
85 }
86 
mali_gp_stop_bus(struct mali_gp_core * core)87 void mali_gp_stop_bus(struct mali_gp_core *core)
88 {
89 	MALI_DEBUG_ASSERT_POINTER(core);
90 
91 	mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_STOP_BUS);
92 }
93 
mali_gp_stop_bus_wait(struct mali_gp_core * core)94 _mali_osk_errcode_t mali_gp_stop_bus_wait(struct mali_gp_core *core)
95 {
96 	int i;
97 
98 	MALI_DEBUG_ASSERT_POINTER(core);
99 
100 	/* Send the stop bus command. */
101 	mali_gp_stop_bus(core);
102 
103 	/* Wait for bus to be stopped */
104 	for (i = 0; i < MALI_REG_POLL_COUNT_SLOW; i++) {
105 		if (mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_STATUS) & MALIGP2_REG_VAL_STATUS_BUS_STOPPED) {
106 			break;
107 		}
108 	}
109 
110 	if (MALI_REG_POLL_COUNT_SLOW == i) {
111 		MALI_PRINT_ERROR(("Mali GP: Failed to stop bus on %s\n", core->hw_core.description));
112 		return _MALI_OSK_ERR_FAULT;
113 	}
114 	return _MALI_OSK_ERR_OK;
115 }
116 
mali_gp_hard_reset(struct mali_gp_core * core)117 void mali_gp_hard_reset(struct mali_gp_core *core)
118 {
119 	const u32 reset_wait_target_register = MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_LIMIT;
120 	const u32 reset_invalid_value = 0xC0FFE000;
121 	const u32 reset_check_value = 0xC01A0000;
122 	const u32 reset_default_value = 0;
123 	int i;
124 
125 	MALI_DEBUG_ASSERT_POINTER(core);
126 	MALI_DEBUG_PRINT(4, ("Mali GP: Hard reset of core %s\n", core->hw_core.description));
127 
128 	mali_hw_core_register_write(&core->hw_core, reset_wait_target_register, reset_invalid_value);
129 
130 	mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_RESET);
131 
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)) {
135 			break;
136 		}
137 	}
138 
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"));
141 	}
142 
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);
147 
148 }
149 
mali_gp_reset_async(struct mali_gp_core * core)150 void mali_gp_reset_async(struct mali_gp_core *core)
151 {
152 	MALI_DEBUG_ASSERT_POINTER(core);
153 
154 	MALI_DEBUG_PRINT(4, ("Mali GP: Reset of core %s\n", core->hw_core.description));
155 
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);
159 
160 }
161 
mali_gp_reset_wait(struct mali_gp_core * core)162 _mali_osk_errcode_t mali_gp_reset_wait(struct mali_gp_core *core)
163 {
164 	int i;
165 	u32 rawstat = 0;
166 
167 	MALI_DEBUG_ASSERT_POINTER(core);
168 
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) {
172 			break;
173 		}
174 	}
175 
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;
180 	}
181 
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);
185 
186 	return _MALI_OSK_ERR_OK;
187 }
188 
mali_gp_reset(struct mali_gp_core * core)189 _mali_osk_errcode_t mali_gp_reset(struct mali_gp_core *core)
190 {
191 	mali_gp_reset_async(core);
192 	return mali_gp_reset_wait(core);
193 }
194 
mali_gp_job_start(struct mali_gp_core * core,struct mali_gp_job * job)195 void mali_gp_job_start(struct mali_gp_core *core, struct mali_gp_job *job)
196 {
197 	u32 startcmd = 0;
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);
201 
202 	MALI_DEBUG_ASSERT_POINTER(core);
203 
204 	if (mali_gp_job_has_vs_job(job)) {
205 		startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_VS;
206 	}
207 
208 	if (mali_gp_job_has_plbu_job(job)) {
209 		startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_PLBU;
210 	}
211 
212 	MALI_DEBUG_ASSERT(0 != startcmd);
213 
214 	mali_hw_core_register_write_array_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR, frame_registers, MALIGP2_NUM_REGS_FRAME);
215 
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);
219 	}
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);
223 	}
224 
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));
226 
227 	mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC);
228 
229 	/* Barrier to make sure the previous register write is finished */
230 	_mali_osk_write_mem_barrier();
231 
232 	/* This is the command that starts the core.
233 	 *
234 	 * Don't actually run the job if PROFILING_SKIP_PP_JOBS are set, just
235 	 * force core to assert the completion interrupt.
236 	 */
237 #if !defined(PROFILING_SKIP_GP_JOBS)
238 	mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, startcmd);
239 #else
240 	{
241 		u32 bits = 0;
242 
243 		if (mali_gp_job_has_vs_job(job))
244 			bits = MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST;
245 		if (mali_gp_job_has_plbu_job(job))
246 			bits |= MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST;
247 
248 		mali_hw_core_register_write_relaxed(&core->hw_core,
249 						    MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT, bits);
250 	}
251 #endif
252 
253 	/* Barrier to make sure the previous register write is finished */
254 	_mali_osk_write_mem_barrier();
255 }
256 
mali_gp_resume_with_new_heap(struct mali_gp_core * core,u32 start_addr,u32 end_addr)257 void mali_gp_resume_with_new_heap(struct mali_gp_core *core, u32 start_addr, u32 end_addr)
258 {
259 	u32 irq_readout;
260 
261 	MALI_DEBUG_ASSERT_POINTER(core);
262 
263 	irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT);
264 
265 	if (irq_readout & MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM) {
266 		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));
267 		mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); /* re-enable interrupts */
268 		mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR, start_addr);
269 		mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR, end_addr);
270 
271 		MALI_DEBUG_PRINT(3, ("Mali GP: Resuming job\n"));
272 
273 		mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC);
274 		_mali_osk_write_mem_barrier();
275 	}
276 	/*
277 	 * else: core has been reset between PLBU_OUT_OF_MEM interrupt and this new heap response.
278 	 * A timeout or a page fault on Mali-200 PP core can cause this behaviour.
279 	 */
280 }
281 
mali_gp_core_get_version(struct mali_gp_core * core)282 u32 mali_gp_core_get_version(struct mali_gp_core *core)
283 {
284 	MALI_DEBUG_ASSERT_POINTER(core);
285 	return mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_VERSION);
286 }
287 
mali_gp_get_global_gp_core(void)288 struct mali_gp_core *mali_gp_get_global_gp_core(void)
289 {
290 	return mali_global_gp_core;
291 }
292 
293 /* ------------- interrupt handling below ------------------ */
mali_gp_irq_probe_trigger(void * data)294 static void mali_gp_irq_probe_trigger(void *data)
295 {
296 	struct mali_gp_core *core = (struct mali_gp_core *)data;
297 
298 	mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED);
299 	mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT, MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR);
300 	_mali_osk_mem_barrier();
301 }
302 
mali_gp_irq_probe_ack(void * data)303 static _mali_osk_errcode_t mali_gp_irq_probe_ack(void *data)
304 {
305 	struct mali_gp_core *core = (struct mali_gp_core *)data;
306 	u32 irq_readout;
307 
308 	irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_STAT);
309 	if (MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR & irq_readout) {
310 		mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR);
311 		_mali_osk_mem_barrier();
312 		return _MALI_OSK_ERR_OK;
313 	}
314 
315 	return _MALI_OSK_ERR_FAULT;
316 }
317 
318 /* ------ local helper functions below --------- */
319 #if MALI_STATE_TRACKING
mali_gp_dump_state(struct mali_gp_core * core,char * buf,u32 size)320 u32 mali_gp_dump_state(struct mali_gp_core *core, char *buf, u32 size)
321 {
322 	int n = 0;
323 
324 	n += _mali_osk_snprintf(buf + n, size - n, "\tGP: %s\n", core->hw_core.description);
325 
326 	return n;
327 }
328 #endif
329 
mali_gp_update_performance_counters(struct mali_gp_core * core,struct mali_gp_job * job)330 void mali_gp_update_performance_counters(struct mali_gp_core *core, struct mali_gp_job *job)
331 {
332 	u32 val0 = 0;
333 	u32 val1 = 0;
334 	u32 counter_src0 = mali_gp_job_get_perf_counter_src0(job);
335 	u32 counter_src1 = mali_gp_job_get_perf_counter_src1(job);
336 
337 	if (MALI_HW_CORE_NO_COUNTER != counter_src0) {
338 		val0 = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE);
339 		mali_gp_job_set_perf_counter_value0(job, val0);
340 
341 #if defined(CONFIG_MALI400_PROFILING)
342 		_mali_osk_profiling_report_hw_counter(COUNTER_VP_0_C0, val0);
343 		_mali_osk_profiling_record_global_counters(COUNTER_VP_0_C0, val0);
344 #endif
345 
346 	}
347 
348 	if (MALI_HW_CORE_NO_COUNTER != counter_src1) {
349 		val1 = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE);
350 		mali_gp_job_set_perf_counter_value1(job, val1);
351 
352 #if defined(CONFIG_MALI400_PROFILING)
353 		_mali_osk_profiling_report_hw_counter(COUNTER_VP_0_C1, val1);
354 		_mali_osk_profiling_record_global_counters(COUNTER_VP_0_C1, val1);
355 #endif
356 	}
357 }
358