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