a918552162a80384e5ccdc86bc3a5a367a56bb87
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / common / mali_gp.c
1 /*
2  * Copyright (C) 2011-2015 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 "mali_osk_mali.h"
16 #include "regs/mali_gp_regs.h"
17 #include "mali_kernel_common.h"
18 #include "mali_kernel_core.h"
19 #if defined(CONFIG_MALI400_PROFILING)
20 #include "mali_osk_profiling.h"
21 #endif
22
23 static struct mali_gp_core *mali_global_gp_core = NULL;
24
25 /* Interrupt handlers */
26 static void mali_gp_irq_probe_trigger(void *data);
27 static _mali_osk_errcode_t mali_gp_irq_probe_ack(void *data);
28
29 struct mali_gp_core *mali_gp_create(const _mali_osk_resource_t *resource, struct mali_group *group)
30 {
31         struct mali_gp_core *core = NULL;
32
33         MALI_DEBUG_ASSERT(NULL == mali_global_gp_core);
34         MALI_DEBUG_PRINT(2, ("Mali GP: Creating Mali GP core: %s\n", resource->description));
35
36         core = _mali_osk_malloc(sizeof(struct mali_gp_core));
37         if (NULL != core) {
38                 if (_MALI_OSK_ERR_OK == mali_hw_core_create(&core->hw_core, resource, MALIGP2_REGISTER_ADDRESS_SPACE_SIZE)) {
39                         _mali_osk_errcode_t ret;
40
41                         ret = mali_gp_reset(core);
42
43                         if (_MALI_OSK_ERR_OK == ret) {
44                                 ret = mali_group_add_gp_core(group, core);
45                                 if (_MALI_OSK_ERR_OK == ret) {
46                                         /* Setup IRQ handlers (which will do IRQ probing if needed) */
47                                         core->irq = _mali_osk_irq_init(resource->irq,
48                                                                        mali_group_upper_half_gp,
49                                                                        group,
50                                                                        mali_gp_irq_probe_trigger,
51                                                                        mali_gp_irq_probe_ack,
52                                                                        core,
53                                                                        resource->description);
54                                         if (NULL != core->irq) {
55                                                 MALI_DEBUG_PRINT(4, ("Mali GP: set global gp core from 0x%08X to 0x%08X\n", mali_global_gp_core, core));
56                                                 mali_global_gp_core = core;
57
58                                                 return core;
59                                         } else {
60                                                 MALI_PRINT_ERROR(("Mali GP: Failed to setup interrupt handlers for GP core %s\n", core->hw_core.description));
61                                         }
62                                         mali_group_remove_gp_core(group);
63                                 } else {
64                                         MALI_PRINT_ERROR(("Mali GP: Failed to add core %s to group\n", core->hw_core.description));
65                                 }
66                         }
67                         mali_hw_core_delete(&core->hw_core);
68                 }
69
70                 _mali_osk_free(core);
71         } else {
72                 MALI_PRINT_ERROR(("Failed to allocate memory for GP core\n"));
73         }
74
75         return NULL;
76 }
77
78 void mali_gp_delete(struct mali_gp_core *core)
79 {
80         MALI_DEBUG_ASSERT_POINTER(core);
81
82         _mali_osk_irq_term(core->irq);
83         mali_hw_core_delete(&core->hw_core);
84         mali_global_gp_core = NULL;
85         _mali_osk_free(core);
86 }
87
88 void mali_gp_stop_bus(struct mali_gp_core *core)
89 {
90         MALI_DEBUG_ASSERT_POINTER(core);
91
92         mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_STOP_BUS);
93 }
94
95 _mali_osk_errcode_t mali_gp_stop_bus_wait(struct mali_gp_core *core)
96 {
97         int i;
98
99         MALI_DEBUG_ASSERT_POINTER(core);
100
101         /* Send the stop bus command. */
102         mali_gp_stop_bus(core);
103
104         /* Wait for bus to be stopped */
105         for (i = 0; i < MALI_REG_POLL_COUNT_SLOW; i++) {
106                 if (mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_STATUS) & MALIGP2_REG_VAL_STATUS_BUS_STOPPED) {
107                         break;
108                 }
109         }
110
111         if (MALI_REG_POLL_COUNT_SLOW == i) {
112                 MALI_PRINT_ERROR(("Mali GP: Failed to stop bus on %s\n", core->hw_core.description));
113                 return _MALI_OSK_ERR_FAULT;
114         }
115         return _MALI_OSK_ERR_OK;
116 }
117
118 void mali_gp_hard_reset(struct mali_gp_core *core)
119 {
120         const u32 reset_wait_target_register = MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_LIMIT;
121         const u32 reset_invalid_value = 0xC0FFE000;
122         const u32 reset_check_value = 0xC01A0000;
123         const u32 reset_default_value = 0;
124         int i;
125
126         MALI_DEBUG_ASSERT_POINTER(core);
127         MALI_DEBUG_PRINT(4, ("Mali GP: Hard reset of core %s\n", core->hw_core.description));
128
129         mali_hw_core_register_write(&core->hw_core, reset_wait_target_register, reset_invalid_value);
130
131         mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_RESET);
132
133         for (i = 0; i < MALI_REG_POLL_COUNT_FAST; i++) {
134                 mali_hw_core_register_write(&core->hw_core, reset_wait_target_register, reset_check_value);
135                 if (reset_check_value == mali_hw_core_register_read(&core->hw_core, reset_wait_target_register)) {
136                         break;
137                 }
138         }
139
140         if (MALI_REG_POLL_COUNT_FAST == i) {
141                 MALI_PRINT_ERROR(("Mali GP: The hard reset loop didn't work, unable to recover\n"));
142         }
143
144         mali_hw_core_register_write(&core->hw_core, reset_wait_target_register, reset_default_value); /* set it back to the default */
145         /* Re-enable interrupts */
146         mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL);
147         mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED);
148
149 }
150
151 void mali_gp_reset_async(struct mali_gp_core *core)
152 {
153         MALI_DEBUG_ASSERT_POINTER(core);
154
155         MALI_DEBUG_PRINT(4, ("Mali GP: Reset of core %s\n", core->hw_core.description));
156
157         mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, 0); /* disable the IRQs */
158         mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALI400GP_REG_VAL_IRQ_RESET_COMPLETED);
159         mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALI400GP_REG_VAL_CMD_SOFT_RESET);
160
161 }
162
163 _mali_osk_errcode_t mali_gp_reset_wait(struct mali_gp_core *core)
164 {
165         int i;
166         u32 rawstat = 0;
167
168         MALI_DEBUG_ASSERT_POINTER(core);
169
170         for (i = 0; i < MALI_REG_POLL_COUNT_FAST; i++) {
171                 rawstat = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT);
172                 if (rawstat & MALI400GP_REG_VAL_IRQ_RESET_COMPLETED) {
173                         break;
174                 }
175         }
176
177         if (i == MALI_REG_POLL_COUNT_FAST) {
178                 MALI_PRINT_ERROR(("Mali GP: Failed to reset core %s, rawstat: 0x%08x\n",
179                                   core->hw_core.description, rawstat));
180                 return _MALI_OSK_ERR_FAULT;
181         }
182
183         /* Re-enable interrupts */
184         mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL);
185         mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED);
186
187         return _MALI_OSK_ERR_OK;
188 }
189
190 _mali_osk_errcode_t mali_gp_reset(struct mali_gp_core *core)
191 {
192         mali_gp_reset_async(core);
193         return mali_gp_reset_wait(core);
194 }
195
196 void mali_gp_job_start(struct mali_gp_core *core, struct mali_gp_job *job)
197 {
198         u32 startcmd = 0;
199         u32 *frame_registers = mali_gp_job_get_frame_registers(job);
200         u32 counter_src0 = mali_gp_job_get_perf_counter_src0(job);
201         u32 counter_src1 = mali_gp_job_get_perf_counter_src1(job);
202
203         /* Disable gpu secure mode. */
204         if (MALI_TRUE == _mali_osk_gpu_secure_mode_is_enabled()) {
205                 _mali_osk_gpu_secure_mode_disable();
206         }
207
208         MALI_DEBUG_ASSERT_POINTER(core);
209
210         if (mali_gp_job_has_vs_job(job)) {
211                 startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_VS;
212         }
213
214         if (mali_gp_job_has_plbu_job(job)) {
215                 startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_PLBU;
216         }
217
218         MALI_DEBUG_ASSERT(0 != startcmd);
219
220         mali_hw_core_register_write_array_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR, frame_registers, MALIGP2_NUM_REGS_FRAME);
221
222         if (MALI_HW_CORE_NO_COUNTER != counter_src0) {
223                 mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC, counter_src0);
224                 mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, MALIGP2_REG_VAL_PERF_CNT_ENABLE);
225         }
226         if (MALI_HW_CORE_NO_COUNTER != counter_src1) {
227                 mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC, counter_src1);
228                 mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, MALIGP2_REG_VAL_PERF_CNT_ENABLE);
229         }
230
231         MALI_DEBUG_PRINT(3, ("Mali GP: Starting job (0x%08x) on core %s with command 0x%08X\n", job, core->hw_core.description, startcmd));
232
233         mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC);
234
235         /* Barrier to make sure the previous register write is finished */
236         _mali_osk_write_mem_barrier();
237
238         /* This is the command that starts the core.
239          *
240          * Don't actually run the job if PROFILING_SKIP_PP_JOBS are set, just
241          * force core to assert the completion interrupt.
242          */
243 #if !defined(PROFILING_SKIP_GP_JOBS)
244         mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, startcmd);
245 #else
246         {
247                 u32 bits = 0;
248
249                 if (mali_gp_job_has_vs_job(job))
250                         bits = MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST;
251                 if (mali_gp_job_has_plbu_job(job))
252                         bits |= MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST;
253
254                 mali_hw_core_register_write_relaxed(&core->hw_core,
255                                                     MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT, bits);
256         }
257 #endif
258
259         /* Barrier to make sure the previous register write is finished */
260         _mali_osk_write_mem_barrier();
261 }
262
263 void mali_gp_resume_with_new_heap(struct mali_gp_core *core, u32 start_addr, u32 end_addr)
264 {
265         u32 irq_readout;
266
267         MALI_DEBUG_ASSERT_POINTER(core);
268
269         irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT);
270
271         if (irq_readout & MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM) {
272                 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));
273                 mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); /* re-enable interrupts */
274                 mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR, start_addr);
275                 mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR, end_addr);
276
277                 MALI_DEBUG_PRINT(3, ("Mali GP: Resuming job\n"));
278
279                 mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC);
280                 _mali_osk_write_mem_barrier();
281         }
282         /*
283          * else: core has been reset between PLBU_OUT_OF_MEM interrupt and this new heap response.
284          * A timeout or a page fault on Mali-200 PP core can cause this behaviour.
285          */
286 }
287
288 u32 mali_gp_core_get_version(struct mali_gp_core *core)
289 {
290         MALI_DEBUG_ASSERT_POINTER(core);
291         return mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_VERSION);
292 }
293
294 struct mali_gp_core *mali_gp_get_global_gp_core(void)
295 {
296         return mali_global_gp_core;
297 }
298
299 /* ------------- interrupt handling below ------------------ */
300 static void mali_gp_irq_probe_trigger(void *data)
301 {
302         struct mali_gp_core *core = (struct mali_gp_core *)data;
303
304         mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED);
305         mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT, MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR);
306         _mali_osk_mem_barrier();
307 }
308
309 static _mali_osk_errcode_t mali_gp_irq_probe_ack(void *data)
310 {
311         struct mali_gp_core *core = (struct mali_gp_core *)data;
312         u32 irq_readout;
313
314         irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_STAT);
315         if (MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR & irq_readout) {
316                 mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR);
317                 _mali_osk_mem_barrier();
318                 return _MALI_OSK_ERR_OK;
319         }
320
321         return _MALI_OSK_ERR_FAULT;
322 }
323
324 /* ------ local helper functions below --------- */
325 #if MALI_STATE_TRACKING
326 u32 mali_gp_dump_state(struct mali_gp_core *core, char *buf, u32 size)
327 {
328         int n = 0;
329
330         n += _mali_osk_snprintf(buf + n, size - n, "\tGP: %s\n", core->hw_core.description);
331
332         return n;
333 }
334 #endif
335
336 void mali_gp_update_performance_counters(struct mali_gp_core *core, struct mali_gp_job *job)
337 {
338         u32 val0 = 0;
339         u32 val1 = 0;
340         u32 counter_src0 = mali_gp_job_get_perf_counter_src0(job);
341         u32 counter_src1 = mali_gp_job_get_perf_counter_src1(job);
342
343         if (MALI_HW_CORE_NO_COUNTER != counter_src0) {
344                 val0 = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE);
345                 mali_gp_job_set_perf_counter_value0(job, val0);
346
347 #if defined(CONFIG_MALI400_PROFILING)
348                 _mali_osk_profiling_report_hw_counter(COUNTER_VP_0_C0, val0);
349                 _mali_osk_profiling_record_global_counters(COUNTER_VP_0_C0, val0);
350 #endif
351
352         }
353
354         if (MALI_HW_CORE_NO_COUNTER != counter_src1) {
355                 val1 = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE);
356                 mali_gp_job_set_perf_counter_value1(job, val1);
357
358 #if defined(CONFIG_MALI400_PROFILING)
359                 _mali_osk_profiling_report_hw_counter(COUNTER_VP_0_C1, val1);
360                 _mali_osk_profiling_record_global_counters(COUNTER_VP_0_C1, val1);
361 #endif
362         }
363 }