tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / r4p0_rel0 / 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                 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
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
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
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_FAST; 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_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;
113         }
114         return _MALI_OSK_ERR_OK;
115 }
116
117 void mali_gp_hard_reset(struct mali_gp_core *core)
118 {
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;
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
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
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
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
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         mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, startcmd);
234
235         /* Barrier to make sure the previous register write is finished */
236         _mali_osk_write_mem_barrier();
237 }
238
239 void mali_gp_resume_with_new_heap(struct mali_gp_core *core, u32 start_addr, u32 end_addr)
240 {
241         u32 irq_readout;
242
243         MALI_DEBUG_ASSERT_POINTER(core);
244
245         irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT);
246
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);
252
253                 MALI_DEBUG_PRINT(3, ("Mali GP: Resuming job\n"));
254
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();
257         }
258         /*
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.
261          */
262 }
263
264 u32 mali_gp_core_get_version(struct mali_gp_core *core)
265 {
266         MALI_DEBUG_ASSERT_POINTER(core);
267         return mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_VERSION);
268 }
269
270 struct mali_gp_core *mali_gp_get_global_gp_core(void)
271 {
272         return mali_global_gp_core;
273 }
274
275 /* ------------- interrupt handling below ------------------ */
276 static void mali_gp_irq_probe_trigger(void *data)
277 {
278         struct mali_gp_core *core = (struct mali_gp_core *)data;
279
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();
283 }
284
285 static _mali_osk_errcode_t mali_gp_irq_probe_ack(void *data)
286 {
287         struct mali_gp_core *core = (struct mali_gp_core *)data;
288         u32 irq_readout;
289
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;
295         }
296
297         return _MALI_OSK_ERR_FAULT;
298 }
299
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)
303 {
304         int n = 0;
305
306         n += _mali_osk_snprintf(buf + n, size - n, "\tGP: %s\n", core->hw_core.description);
307
308         return n;
309 }
310 #endif
311
312 void mali_gp_update_performance_counters(struct mali_gp_core *core, struct mali_gp_job *job, mali_bool suspend)
313 {
314         u32 val0 = 0;
315         u32 val1 = 0;
316         u32 counter_src0 = mali_gp_job_get_perf_counter_src0(job);
317         u32 counter_src1 = mali_gp_job_get_perf_counter_src1(job);
318
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);
322
323 #if defined(CONFIG_MALI400_PROFILING)
324                 _mali_osk_profiling_report_hw_counter(COUNTER_VP_0_C0, val0);
325 #endif
326
327         }
328
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);
332
333 #if defined(CONFIG_MALI400_PROFILING)
334                 _mali_osk_profiling_report_hw_counter(COUNTER_VP_0_C1, val1);
335 #endif
336         }
337 }