tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / mali / common / mali_l2_cache.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 #include "mali_kernel_common.h"
11 #include "mali_osk.h"
12 #include "mali_l2_cache.h"
13 #include "mali_hw_core.h"
14 #include "mali_scheduler.h"
15
16 /**
17  * Size of the Mali L2 cache registers in bytes
18  */
19 #define MALI400_L2_CACHE_REGISTERS_SIZE 0x30
20
21 /**
22  * Mali L2 cache register numbers
23  * Used in the register read/write routines.
24  * See the hardware documentation for more information about each register
25  */
26 typedef enum mali_l2_cache_register {
27         MALI400_L2_CACHE_REGISTER_STATUS       = 0x0008,
28         /*unused                               = 0x000C */
29         MALI400_L2_CACHE_REGISTER_COMMAND      = 0x0010, /**< Misc cache commands, e.g. clear */
30         MALI400_L2_CACHE_REGISTER_CLEAR_PAGE   = 0x0014,
31         MALI400_L2_CACHE_REGISTER_MAX_READS    = 0x0018, /**< Limit of outstanding read requests */
32         MALI400_L2_CACHE_REGISTER_ENABLE       = 0x001C, /**< Enable misc cache features */
33         MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0 = 0x0020,
34         MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0 = 0x0024,
35         MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1 = 0x0028,
36         MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1 = 0x002C,
37 } mali_l2_cache_register;
38
39 /**
40  * Mali L2 cache commands
41  * These are the commands that can be sent to the Mali L2 cache unit
42  */
43 typedef enum mali_l2_cache_command
44 {
45         MALI400_L2_CACHE_COMMAND_CLEAR_ALL = 0x01, /**< Clear the entire cache */
46         /* Read HW TRM carefully before adding/using other commands than the clear above */
47 } mali_l2_cache_command;
48
49 /**
50  * Mali L2 cache commands
51  * These are the commands that can be sent to the Mali L2 cache unit
52  */
53 typedef enum mali_l2_cache_enable
54 {
55         MALI400_L2_CACHE_ENABLE_DEFAULT = 0x0, /**< Default state of enable register */
56         MALI400_L2_CACHE_ENABLE_ACCESS = 0x01, /**< Permit cacheable accesses */
57         MALI400_L2_CACHE_ENABLE_READ_ALLOCATE = 0x02, /**< Permit cache read allocate */
58 } mali_l2_cache_enable;
59
60 /**
61  * Mali L2 cache status bits
62  */
63 typedef enum mali_l2_cache_status
64 {
65         MALI400_L2_CACHE_STATUS_COMMAND_BUSY = 0x01, /**< Command handler of L2 cache is busy */
66         MALI400_L2_CACHE_STATUS_DATA_BUSY    = 0x02, /**< L2 cache is busy handling data requests */
67 } mali_l2_cache_status;
68
69 /**
70  * Definition of the L2 cache core struct
71  * Used to track a L2 cache unit in the system.
72  * Contains information about the mapping of the registers
73  */
74 struct mali_l2_cache_core
75 {
76         struct mali_hw_core  hw_core;      /**< Common for all HW cores */
77         u32                  core_id;      /**< Unique core ID */
78         _mali_osk_lock_t    *command_lock; /**< Serialize all L2 cache commands */
79         _mali_osk_lock_t    *counter_lock; /**< Synchronize L2 cache counter access */
80         u32                  counter_src0; /**< Performance counter 0, MALI_HW_CORE_NO_COUNTER for disabled */
81         u32                  counter_src1; /**< Performance counter 1, MALI_HW_CORE_NO_COUNTER for disabled */
82         u32                  last_invalidated_id;
83         mali_bool            power_is_enabled;
84 };
85
86 #define MALI400_L2_MAX_READS_DEFAULT 0x1C
87
88 static struct mali_l2_cache_core *mali_global_l2_cache_cores[MALI_MAX_NUMBER_OF_L2_CACHE_CORES];
89 static u32 mali_global_num_l2_cache_cores = 0;
90
91 int mali_l2_max_reads = MALI400_L2_MAX_READS_DEFAULT;
92
93 /* Local helper functions */
94 static _mali_osk_errcode_t mali_l2_cache_send_command(struct mali_l2_cache_core *cache, u32 reg, u32 val);
95
96
97 struct mali_l2_cache_core *mali_l2_cache_create(_mali_osk_resource_t *resource)
98 {
99         struct mali_l2_cache_core *cache = NULL;
100         _mali_osk_lock_flags_t lock_flags;
101
102 #if defined(MALI_UPPER_HALF_SCHEDULING)
103         lock_flags = _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE;
104 #else
105         lock_flags = _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE;
106 #endif
107
108         MALI_DEBUG_PRINT(2, ("Mali L2 cache: Creating Mali L2 cache: %s\n", resource->description));
109
110         if (mali_global_num_l2_cache_cores >= MALI_MAX_NUMBER_OF_L2_CACHE_CORES)
111         {
112                 MALI_PRINT_ERROR(("Mali L2 cache: Too many L2 cache core objects created\n"));
113                 return NULL;
114         }
115
116         cache = _mali_osk_malloc(sizeof(struct mali_l2_cache_core));
117         if (NULL != cache)
118         {
119                 cache->core_id =  mali_global_num_l2_cache_cores;
120                 cache->counter_src0 = MALI_HW_CORE_NO_COUNTER;
121                 cache->counter_src1 = MALI_HW_CORE_NO_COUNTER;
122                 if (_MALI_OSK_ERR_OK == mali_hw_core_create(&cache->hw_core, resource, MALI400_L2_CACHE_REGISTERS_SIZE))
123                 {
124                         cache->command_lock = _mali_osk_lock_init(lock_flags, 0, _MALI_OSK_LOCK_ORDER_L2_COMMAND);
125                         if (NULL != cache->command_lock)
126                         {
127                                 cache->counter_lock = _mali_osk_lock_init(lock_flags, 0, _MALI_OSK_LOCK_ORDER_L2_COUNTER);
128                                 if (NULL != cache->counter_lock)
129                                 {
130                                         mali_l2_cache_reset(cache);
131
132                                         cache->last_invalidated_id = 0;
133                                         cache->power_is_enabled = MALI_TRUE;
134
135                                         mali_global_l2_cache_cores[mali_global_num_l2_cache_cores] = cache;
136                                         mali_global_num_l2_cache_cores++;
137
138                                         return cache;
139                                 }
140                                 else
141                                 {
142                                         MALI_PRINT_ERROR(("Mali L2 cache: Failed to create counter lock for L2 cache core %s\n", cache->hw_core.description));
143                                 }
144
145                                 _mali_osk_lock_term(cache->command_lock);
146                         }
147                         else
148                         {
149                                 MALI_PRINT_ERROR(("Mali L2 cache: Failed to create command lock for L2 cache core %s\n", cache->hw_core.description));
150                         }
151
152                         mali_hw_core_delete(&cache->hw_core);
153                 }
154
155                 _mali_osk_free(cache);
156         }
157         else
158         {
159                 MALI_PRINT_ERROR(("Mali L2 cache: Failed to allocate memory for L2 cache core\n"));
160         }
161
162         return NULL;
163 }
164
165 void mali_l2_cache_delete(struct mali_l2_cache_core *cache)
166 {
167         u32 i;
168
169         /* reset to defaults */
170         mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)MALI400_L2_MAX_READS_DEFAULT);
171         mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_DEFAULT);
172
173         _mali_osk_lock_term(cache->counter_lock);
174         _mali_osk_lock_term(cache->command_lock);
175         mali_hw_core_delete(&cache->hw_core);
176
177         for (i = 0; i < MALI_MAX_NUMBER_OF_L2_CACHE_CORES; i++)
178         {
179                 if (mali_global_l2_cache_cores[i] == cache)
180                 {
181                         mali_global_l2_cache_cores[i] = NULL;
182                         mali_global_num_l2_cache_cores--;
183                 }
184         }
185
186         _mali_osk_free(cache);
187 }
188
189 void mali_l2_cache_power_is_enabled_set(struct mali_l2_cache_core * core, mali_bool power_is_enabled)
190 {
191        core->power_is_enabled = power_is_enabled;
192 }
193
194 mali_bool mali_l2_cache_power_is_enabled_get(struct mali_l2_cache_core * core)
195 {
196        return core->power_is_enabled;
197 }
198
199 u32 mali_l2_cache_get_id(struct mali_l2_cache_core *cache)
200 {
201         return cache->core_id;
202 }
203
204 mali_bool mali_l2_cache_core_set_counter_src0(struct mali_l2_cache_core *cache, u32 counter)
205 {
206         u32 value = 0; /* disabled src */
207         mali_bool core_is_on;
208
209         MALI_DEBUG_ASSERT_POINTER(cache);
210
211         core_is_on = mali_l2_cache_lock_power_state(cache);
212
213         _mali_osk_lock_wait(cache->counter_lock, _MALI_OSK_LOCKMODE_RW);
214
215         cache->counter_src0 = counter;
216
217         if (MALI_HW_CORE_NO_COUNTER != counter)
218         {
219                 value = counter;
220         }
221
222         if (MALI_TRUE == core_is_on)
223         {
224                 mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0, value);
225         }
226
227         _mali_osk_lock_signal(cache->counter_lock, _MALI_OSK_LOCKMODE_RW);
228
229         mali_l2_cache_unlock_power_state(cache);
230
231         return MALI_TRUE;
232 }
233
234 mali_bool mali_l2_cache_core_set_counter_src1(struct mali_l2_cache_core *cache, u32 counter)
235 {
236         u32 value = 0; /* disabled src */
237         mali_bool core_is_on;
238
239         MALI_DEBUG_ASSERT_POINTER(cache);
240
241         core_is_on = mali_l2_cache_lock_power_state(cache);
242
243         _mali_osk_lock_wait(cache->counter_lock, _MALI_OSK_LOCKMODE_RW);
244
245         cache->counter_src1 = counter;
246
247         if (MALI_HW_CORE_NO_COUNTER != counter)
248         {
249                 value = counter;
250         }
251
252         if (MALI_TRUE == core_is_on)
253         {
254                 mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1, value);
255         }
256
257         _mali_osk_lock_signal(cache->counter_lock, _MALI_OSK_LOCKMODE_RW);
258
259         mali_l2_cache_unlock_power_state(cache);
260
261         return MALI_TRUE;
262 }
263
264 u32 mali_l2_cache_core_get_counter_src0(struct mali_l2_cache_core *cache)
265 {
266         return cache->counter_src0;
267 }
268
269 u32 mali_l2_cache_core_get_counter_src1(struct mali_l2_cache_core *cache)
270 {
271         return cache->counter_src1;
272 }
273
274 void mali_l2_cache_core_get_counter_values(struct mali_l2_cache_core *cache, u32 *src0, u32 *value0, u32 *src1, u32 *value1)
275 {
276         MALI_DEBUG_ASSERT(NULL != src0);
277         MALI_DEBUG_ASSERT(NULL != value0);
278         MALI_DEBUG_ASSERT(NULL != src1);
279         MALI_DEBUG_ASSERT(NULL != value1);
280
281         /* Caller must hold the PM lock and know that we are powered on */
282
283         _mali_osk_lock_wait(cache->counter_lock, _MALI_OSK_LOCKMODE_RW);
284
285         *src0 = cache->counter_src0;
286         *src1 = cache->counter_src1;
287
288         if (cache->counter_src0 != MALI_HW_CORE_NO_COUNTER)
289         {
290                 *value0 = mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0);
291         }
292
293         if (cache->counter_src1 != MALI_HW_CORE_NO_COUNTER)
294         {
295                 *value1 = mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1);
296         }
297
298         _mali_osk_lock_signal(cache->counter_lock, _MALI_OSK_LOCKMODE_RW);
299 }
300
301 struct mali_l2_cache_core *mali_l2_cache_core_get_glob_l2_core(u32 index)
302 {
303         if (MALI_MAX_NUMBER_OF_L2_CACHE_CORES > index)
304         {
305                 return mali_global_l2_cache_cores[index];
306         }
307
308         return NULL;
309 }
310
311 u32 mali_l2_cache_core_get_glob_num_l2_cores(void)
312 {
313         return mali_global_num_l2_cache_cores;
314 }
315
316 void mali_l2_cache_reset(struct mali_l2_cache_core *cache)
317 {
318         /* Invalidate cache (just to keep it in a known state at startup) */
319         mali_l2_cache_invalidate_all(cache);
320
321         /* Enable cache */
322         mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_ACCESS | (u32)MALI400_L2_CACHE_ENABLE_READ_ALLOCATE);
323         mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)mali_l2_max_reads);
324
325         /* Restart any performance counters (if enabled) */
326         _mali_osk_lock_wait(cache->counter_lock, _MALI_OSK_LOCKMODE_RW);
327
328         if (cache->counter_src0 != MALI_HW_CORE_NO_COUNTER)
329         {
330                 mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0, cache->counter_src0);
331         }
332
333         if (cache->counter_src1 != MALI_HW_CORE_NO_COUNTER)
334         {
335                 mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1, cache->counter_src1);
336         }
337
338         _mali_osk_lock_signal(cache->counter_lock, _MALI_OSK_LOCKMODE_RW);
339 }
340
341 void mali_l2_cache_reset_all(void)
342 {
343         int i;
344         u32 num_cores = mali_l2_cache_core_get_glob_num_l2_cores();
345
346         for (i = 0; i < num_cores; i++)
347         {
348                 mali_l2_cache_reset(mali_l2_cache_core_get_glob_l2_core(i));
349         }
350 }
351
352 _mali_osk_errcode_t mali_l2_cache_invalidate_all(struct mali_l2_cache_core *cache)
353 {
354         return mali_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL);
355 }
356
357 mali_bool mali_l2_cache_invalidate_all_conditional(struct mali_l2_cache_core *cache, u32 id)
358 {
359        MALI_DEBUG_ASSERT_POINTER(cache);
360
361        if (NULL != cache)
362        {
363                /* If the last cache invalidation was done by a job with a higher id we
364                 * don't have to flush. Since user space will store jobs w/ their
365                 * corresponding memory in sequence (first job #0, then job #1, ...),
366                 * we don't have to flush for job n-1 if job n has already invalidated
367                 * the cache since we know for sure that job n-1's memory was already
368                 * written when job n was started. */
369                if (((s32)id) <= ((s32)cache->last_invalidated_id))
370                {
371                        return MALI_FALSE;
372                }
373                else
374                {
375                        cache->last_invalidated_id = mali_scheduler_get_new_id();
376                }
377
378                mali_l2_cache_invalidate_all(cache);
379        }
380        return MALI_TRUE;
381 }
382
383 void mali_l2_cache_invalidate_all_force(struct mali_l2_cache_core *cache)
384 {
385        MALI_DEBUG_ASSERT_POINTER(cache);
386
387        if (NULL != cache)
388        {
389                cache->last_invalidated_id = mali_scheduler_get_new_id();
390                mali_l2_cache_invalidate_all(cache);
391        }
392 }
393
394 _mali_osk_errcode_t mali_l2_cache_invalidate_pages(struct mali_l2_cache_core *cache, u32 *pages, u32 num_pages)
395 {
396         u32 i;
397         _mali_osk_errcode_t ret1, ret = _MALI_OSK_ERR_OK;
398
399         for (i = 0; i < num_pages; i++)
400         {
401                 ret1 = mali_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_CLEAR_PAGE, pages[i]);
402                 if (_MALI_OSK_ERR_OK != ret1)
403                 {
404                         ret = ret1;
405                 }
406         }
407
408         return ret;
409 }
410
411 void mali_l2_cache_invalidate_pages_conditional(u32 *pages, u32 num_pages)
412 {
413        u32 i;
414
415        for (i = 0; i < mali_global_num_l2_cache_cores; i++)
416        {
417                /*additional check*/
418                if (MALI_TRUE == mali_l2_cache_lock_power_state(mali_global_l2_cache_cores[i]))
419                {
420                        mali_l2_cache_invalidate_pages(mali_global_l2_cache_cores[i], pages, num_pages);
421                }
422                mali_l2_cache_unlock_power_state(mali_global_l2_cache_cores[i]);
423                /*check for failed power locking???*/
424        }
425 }
426
427 mali_bool mali_l2_cache_lock_power_state(struct mali_l2_cache_core *cache)
428 {
429         return _mali_osk_pm_dev_ref_add_no_power_on();
430 }
431
432 void mali_l2_cache_unlock_power_state(struct mali_l2_cache_core *cache)
433 {
434         _mali_osk_pm_dev_ref_dec_no_power_on();
435 }
436
437 /* -------- local helper functions below -------- */
438
439
440 static _mali_osk_errcode_t mali_l2_cache_send_command(struct mali_l2_cache_core *cache, u32 reg, u32 val)
441 {
442         int i = 0;
443         const int loop_count = 100000;
444
445         /*
446          * Grab lock in order to send commands to the L2 cache in a serialized fashion.
447          * The L2 cache will ignore commands if it is busy.
448          */
449         _mali_osk_lock_wait(cache->command_lock, _MALI_OSK_LOCKMODE_RW);
450
451         /* First, wait for L2 cache command handler to go idle */
452
453         for (i = 0; i < loop_count; i++)
454         {
455                 if (!(mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_STATUS) & (u32)MALI400_L2_CACHE_STATUS_COMMAND_BUSY))
456                 {
457                         break;
458                 }
459         }
460
461         if (i == loop_count)
462         {
463                 _mali_osk_lock_signal(cache->command_lock, _MALI_OSK_LOCKMODE_RW);
464                 MALI_DEBUG_PRINT(1, ( "Mali L2 cache: aborting wait for command interface to go idle\n"));
465                 MALI_ERROR( _MALI_OSK_ERR_FAULT );
466         }
467
468         /* then issue the command */
469         mali_hw_core_register_write(&cache->hw_core, reg, val);
470
471         _mali_osk_lock_signal(cache->command_lock, _MALI_OSK_LOCKMODE_RW);
472
473         MALI_SUCCESS;
474 }