Initial commit
[kernel/linux-3.0.git] / drivers / media / video / samsung / mali / common / mali_kernel_l2_cache.c
1 /*
2  * Copyright (C) 2010 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_osk_list.h"
13
14 #include "mali_kernel_core.h"
15 #include "mali_kernel_pp.h"
16 #include "mali_kernel_subsystem.h"
17 #include "regs/mali_200_regs.h"
18 #include "mali_kernel_rendercore.h"
19 #include "mali_kernel_l2_cache.h"
20
21 /**
22  * Size of the Mali L2 cache registers in bytes
23  */
24 #define MALI400_L2_CACHE_REGISTERS_SIZE 0x30
25
26 /**
27  * Mali L2 cache register numbers
28  * Used in the register read/write routines.
29  * See the hardware documentation for more information about each register
30  */
31 typedef enum mali_l2_cache_register {
32         MALI400_L2_CACHE_REGISTER_STATUS       = 0x0002,
33         /*unused                               = 0x0003 */
34         MALI400_L2_CACHE_REGISTER_COMMAND      = 0x0004, /**< Misc cache commands, e.g. clear */
35         MALI400_L2_CACHE_REGISTER_CLEAR_PAGE   = 0x0005,
36         MALI400_L2_CACHE_REGISTER_MAX_READS    = 0x0006, /**< Limit of outstanding read requests */
37         MALI400_L2_CACHE_REGISTER_ENABLE       = 0x0007, /**< Enable misc cache features */
38         MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0 = 0x0008,
39         MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0 = 0x0009,
40         MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1 = 0x000A,
41         MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1 = 0x000B,
42 } mali_l2_cache_register;
43
44
45 /**
46  * Mali L2 cache commands
47  * These are the commands that can be sent to the Mali L2 cache unit
48  */
49 typedef enum mali_l2_cache_command
50 {
51         MALI400_L2_CACHE_COMMAND_CLEAR_ALL = 0x01, /**< Clear the entire cache */
52         /* Read HW TRM carefully before adding/using other commands than the clear above */
53 } mali_l2_cache_command;
54
55 /**
56  * Mali L2 cache commands
57  * These are the commands that can be sent to the Mali L2 cache unit
58  */
59 typedef enum mali_l2_cache_enable
60 {
61         MALI400_L2_CACHE_ENABLE_DEFAULT = 0x0, /**< Default state of enable register */
62         MALI400_L2_CACHE_ENABLE_ACCESS = 0x01, /**< Permit cacheable accesses */
63         MALI400_L2_CACHE_ENABLE_READ_ALLOCATE = 0x02, /**< Permit cache read allocate */
64 } mali_l2_cache_enable;
65
66 /**
67  * Mali L2 cache status bits
68  */
69 typedef enum mali_l2_cache_status
70 {
71         MALI400_L2_CACHE_STATUS_COMMAND_BUSY = 0x01, /**< Command handler of L2 cache is busy */
72         MALI400_L2_CACHE_STATUS_DATA_BUSY    = 0x02, /**< L2 cache is busy handling data requests */
73 } mali_l2_cache_status;
74
75
76 /**
77  * Definition of the L2 cache core struct
78  * Used to track a L2 cache unit in the system.
79  * Contains information about the mapping of the registers
80  */
81 typedef struct mali_kernel_l2_cache_core
82 {
83         unsigned long base; /**< Physical address of the registers */
84         mali_io_address mapped_registers; /**< Virtual mapping of the registers */
85         u32 mapping_size; /**< Size of registers in bytes */
86         _mali_osk_list_t list; /**< Used to link multiple cache cores into a list */
87         _mali_osk_lock_t *lock; /**< Serialize all L2 cache commands */
88 } mali_kernel_l2_cache_core;
89
90
91 #define MALI400_L2_MAX_READS_DEFAULT 0x1C
92
93 int mali_l2_max_reads = MALI400_L2_MAX_READS_DEFAULT;
94
95
96 /**
97  * Mali L2 cache subsystem startup function
98  * Called by the driver core when the driver is loaded.
99  *
100  * @param id Identifier assigned by the core to the L2 cache subsystem
101  * @return 0 on success, negative on error
102  */
103 static _mali_osk_errcode_t mali_l2_cache_initialize(mali_kernel_subsystem_identifier id);
104
105 /**
106  * Mali L2 cache subsystem shutdown function
107  * Called by the driver core when the driver is unloaded.
108  * Cleans up
109  * @param id Identifier assigned by the core to the L2 cache subsystem
110  */
111 static void mali_l2_cache_terminate(mali_kernel_subsystem_identifier id);
112
113 /**
114  * L2 cache subsystem complete notification function.
115  * Called by the driver core when all drivers have loaded and all resources has been registered
116  * @param id Identifier assigned by the core to the L2 cache subsystem
117  * @return 0 on success, negative on error
118  */
119 static _mali_osk_errcode_t mali_l2_cache_load_complete(mali_kernel_subsystem_identifier id);
120
121 /**
122  * Mali L2 cache subsystem's notification handler for a Mali L2 cache resource instances.
123  * Registered with the core during startup.
124  * Called by the core for each Mali L2 cache described in the active architecture's config.h file.
125  * @param resource The resource to handle (type MALI400L2)
126  * @return 0 if the Mali L2 cache was found and initialized, negative on error
127  */
128 static _mali_osk_errcode_t mali_l2_cache_core_create(_mali_osk_resource_t * resource);
129
130 /**
131  * Write to a L2 cache register
132  * Writes the given value to the specified register
133  * @param unit The L2 cache to write to
134  * @param reg The register to write to
135  * @param val The value to write to the register
136  */
137 static void mali_l2_cache_register_write(mali_kernel_l2_cache_core * unit, mali_l2_cache_register reg, u32 val);
138
139
140
141 /**
142  * Invalidate specified L2 cache
143  * @param cache The L2 cache to invalidate
144  * @return 0 if Mali L2 cache was successfully invalidated, otherwise error
145  */
146 static _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all_cache(mali_kernel_l2_cache_core *cache);
147
148
149 /*
150         The fixed Mali L2 cache system's mali subsystem interface implementation.
151         We currently handle module and session life-time management.
152 */
153 struct mali_kernel_subsystem mali_subsystem_l2_cache =
154 {
155         mali_l2_cache_initialize,    /**< startup */
156         NULL, /*mali_l2_cache_terminate,*/     /**< shutdown */
157         mali_l2_cache_load_complete, /**< load_complete */
158         NULL,                        /**< system_info_fill */
159         NULL,                        /**< session_begin */
160         NULL,                        /**< session_end */
161         NULL,                        /**< broadcast_notification */
162 #if MALI_STATE_TRACKING
163         NULL,                        /**< dump_state */
164 #endif
165 };
166
167
168
169 static _MALI_OSK_LIST_HEAD(caches_head);
170
171
172
173
174 /* called during module init */
175 static _mali_osk_errcode_t mali_l2_cache_initialize(mali_kernel_subsystem_identifier id)
176 {
177         _mali_osk_errcode_t err;
178
179         MALI_IGNORE( id );
180
181         MALI_DEBUG_PRINT(2, ( "Mali L2 cache system initializing\n"));
182
183         _MALI_OSK_INIT_LIST_HEAD(&caches_head);
184
185         /* This will register the function for adding Mali L2 cache cores to the subsystem */
186         err = _mali_kernel_core_register_resource_handler(MALI400L2, mali_l2_cache_core_create);
187
188         MALI_ERROR(err);
189 }
190
191
192
193 /* called if/when our module is unloaded */
194 static void mali_l2_cache_terminate(mali_kernel_subsystem_identifier id)
195 {
196         mali_kernel_l2_cache_core * cache, *temp_cache;
197
198         MALI_DEBUG_PRINT(2, ( "Mali L2 cache system terminating\n"));
199
200         /* loop over all L2 cache units and shut them down */
201         _MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list )
202         {
203                 /* reset to defaults */
204                 mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)MALI400_L2_MAX_READS_DEFAULT);
205                 mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_DEFAULT);
206
207                 /* remove from the list of cacges on the system */
208                 _mali_osk_list_del( &cache->list );
209
210                 /* release resources */
211                 _mali_osk_mem_unmapioregion( cache->base, cache->mapping_size, cache->mapped_registers );
212                 _mali_osk_mem_unreqregion( cache->base, cache->mapping_size );
213                 _mali_osk_lock_term( cache->lock );
214                 _mali_osk_free( cache );
215
216                 #if USING_MALI_PMM
217                         /* Unregister the L2 cache with the PMM */
218                         malipmm_core_unregister( MALI_PMM_CORE_L2 );
219                 #endif
220         }
221 }
222
223 static _mali_osk_errcode_t mali_l2_cache_core_create(_mali_osk_resource_t * resource)
224 {
225         _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT ;
226         mali_kernel_l2_cache_core * cache = NULL;
227
228         MALI_DEBUG_PRINT(2, ( "Creating Mali L2 cache: %s\n", resource->description));
229
230 #if USING_MALI_PMM
231         /* Register the L2 cache with the PMM */
232         err = malipmm_core_register( MALI_PMM_CORE_L2 );
233         if( _MALI_OSK_ERR_OK != err )
234         {
235                 MALI_DEBUG_PRINT(1, ( "Failed to register L2 cache unit with PMM"));
236                 return err;
237         }
238 #endif
239
240         err = _mali_osk_mem_reqregion( resource->base, MALI400_L2_CACHE_REGISTERS_SIZE, resource->description);
241
242         MALI_CHECK_GOTO( _MALI_OSK_ERR_OK == err, err_cleanup_requestmem_failed);
243
244         /* Reset error that might be passed out */
245         err = _MALI_OSK_ERR_FAULT;
246
247         cache = _mali_osk_malloc(sizeof(mali_kernel_l2_cache_core));
248
249         MALI_CHECK_GOTO( NULL != cache, err_cleanup);
250
251         cache->lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 104 );
252
253         MALI_CHECK_GOTO( NULL != cache->lock, err_cleanup);
254
255         /* basic setup */
256         _MALI_OSK_INIT_LIST_HEAD(&cache->list);
257
258         cache->base = resource->base;
259         cache->mapping_size = MALI400_L2_CACHE_REGISTERS_SIZE;
260
261         /* map the registers */
262         cache->mapped_registers = _mali_osk_mem_mapioregion( cache->base, cache->mapping_size, resource->description );
263
264         MALI_CHECK_GOTO( NULL != cache->mapped_registers, err_cleanup);
265
266         /* Invalidate cache (just to keep it in a known state at startup) */
267         err = mali_kernel_l2_cache_invalidate_all_cache(cache);
268
269         MALI_CHECK_GOTO( _MALI_OSK_ERR_OK == err, err_cleanup);
270
271         /* add to our list of L2 caches */
272         _mali_osk_list_add( &cache->list, &caches_head );
273
274         MALI_SUCCESS;
275
276 err_cleanup:
277         /* This cleanup used when resources have been requested successfully */
278
279         if ( NULL != cache )
280         {
281                 if (NULL != cache->mapped_registers)
282                 {
283                         _mali_osk_mem_unmapioregion( cache->base, cache->mapping_size, cache->mapped_registers);
284                 }
285                 else
286                 {
287                         MALI_DEBUG_PRINT(1, ( "Failed to map Mali L2 cache registers at 0x%08lX\n", cache->base));
288                 }
289
290                 if( NULL != cache->lock )
291                 {
292                         _mali_osk_lock_term( cache->lock );
293                 }
294                 else
295                 {
296                         MALI_DEBUG_PRINT(1, ( "Failed to allocate a lock for handling a L2 cache unit"));
297                 }
298
299                 _mali_osk_free( cache );
300         }
301         else
302         {
303                 MALI_DEBUG_PRINT(1, ( "Failed to allocate memory for handling a L2 cache unit"));
304         }
305
306         /* A call is to request region, so this must always be reversed */
307         _mali_osk_mem_unreqregion( resource->base, MALI400_L2_CACHE_REGISTERS_SIZE);
308 #if USING_MALI_PMM
309         malipmm_core_unregister( MALI_PMM_CORE_L2 );
310 #endif
311         return err;
312
313 err_cleanup_requestmem_failed:
314         MALI_DEBUG_PRINT(1, ("Failed to request Mali L2 cache '%s' register address space at (0x%08X - 0x%08X)\n",
315                                                  resource->description, resource->base, resource->base + MALI400_L2_CACHE_REGISTERS_SIZE - 1) );
316 #if USING_MALI_PMM
317         malipmm_core_unregister( MALI_PMM_CORE_L2 );
318 #endif
319         return err;
320
321 }
322
323
324 static void mali_l2_cache_register_write(mali_kernel_l2_cache_core * unit, mali_l2_cache_register reg, u32 val)
325 {
326         _mali_osk_mem_iowrite32(unit->mapped_registers, (u32)reg * sizeof(u32), val);
327 }
328
329
330 static u32 mali_l2_cache_register_read(mali_kernel_l2_cache_core * unit, mali_l2_cache_register reg)
331 {
332         return _mali_osk_mem_ioread32(unit->mapped_registers, (u32)reg * sizeof(u32));
333 }
334
335 void mali_kernel_l2_cache_do_enable(void)
336 {
337         mali_kernel_l2_cache_core * cache, *temp_cache;
338
339         /* loop over all L2 cache units and enable them*/
340         _MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list)
341         {
342                 mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_ACCESS | (u32)MALI400_L2_CACHE_ENABLE_READ_ALLOCATE);
343                 mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)mali_l2_max_reads);
344         }
345 }
346
347
348 static _mali_osk_errcode_t mali_l2_cache_load_complete(mali_kernel_subsystem_identifier id)
349 {
350         mali_kernel_l2_cache_do_enable();
351         MALI_DEBUG_PRINT(2, ( "Mali L2 cache system load complete\n"));
352
353         MALI_SUCCESS;
354 }
355
356 static _mali_osk_errcode_t mali_kernel_l2_cache_send_command(mali_kernel_l2_cache_core *cache, u32 reg, u32 val)
357 {
358         int i = 0;
359         const int loop_count = 100000;
360
361         /*
362          * Grab lock in order to send commands to the L2 cache in a serialized fashion.
363          * The L2 cache will ignore commands if it is busy.
364          */
365         _mali_osk_lock_wait(cache->lock, _MALI_OSK_LOCKMODE_RW);
366
367         /* First, wait for L2 cache command handler to go idle */
368
369         for (i = 0; i < loop_count; i++)
370         {
371                 if (!(_mali_osk_mem_ioread32(cache->mapped_registers , (u32)MALI400_L2_CACHE_REGISTER_STATUS * sizeof(u32)) & (u32)MALI400_L2_CACHE_STATUS_COMMAND_BUSY))
372                 {
373                         break;
374                 }
375         }
376
377         if (i == loop_count)
378         {
379                 _mali_osk_lock_signal(cache->lock, _MALI_OSK_LOCKMODE_RW);
380                 MALI_DEBUG_PRINT(1, ( "Mali L2 cache: aborting wait for command interface to go idle\n"));
381                 MALI_ERROR( _MALI_OSK_ERR_FAULT );
382         }
383
384         /* then issue the command */
385         mali_l2_cache_register_write(cache, reg, val);
386
387         _mali_osk_lock_signal(cache->lock, _MALI_OSK_LOCKMODE_RW);
388         MALI_SUCCESS;
389 }
390
391
392 static _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all_cache(mali_kernel_l2_cache_core *cache)
393 {
394         return mali_kernel_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL);
395 }
396
397 _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all(void)
398 {
399         mali_kernel_l2_cache_core * cache, *temp_cache;
400
401         /* loop over all L2 cache units and invalidate them */
402
403         _MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list)
404         {
405                 MALI_CHECK_NO_ERROR( mali_kernel_l2_cache_invalidate_all_cache(cache) );
406         }
407
408         MALI_SUCCESS;
409 }
410
411
412 static _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_page_cache(mali_kernel_l2_cache_core *cache, u32 page)
413 {
414         return mali_kernel_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_CLEAR_PAGE, page);
415 }
416
417 _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_page(u32 page)
418 {
419         mali_kernel_l2_cache_core * cache, *temp_cache;
420
421         /* loop over all L2 cache units and invalidate them */
422
423         _MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list)
424         {
425                 MALI_CHECK_NO_ERROR( mali_kernel_l2_cache_invalidate_page_cache(cache, page) );
426         }
427
428         MALI_SUCCESS;
429 }
430
431
432 void mali_kernel_l2_cache_set_perf_counters(u32 src0, u32 src1, int force_reset)
433 {
434         mali_kernel_l2_cache_core * cache, *temp_cache;
435         int reset0 = force_reset;
436         int reset1 = force_reset;
437         MALI_DEBUG_CODE(
438                 int changed0 = 0;
439                 int changed1 = 0;
440         )
441
442         /* loop over all L2 cache units and activate the counters on them */
443         _MALI_OSK_LIST_FOREACHENTRY(cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list)
444         {
445                 u32 cur_src0 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0);
446                 u32 cur_src1 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1);
447
448                 if (src0 != cur_src0)
449                 {
450                         mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0, src0);
451                         MALI_DEBUG_CODE(changed0 = 1;)
452                         reset0 = 1;
453                 }
454
455                 if (src1 != cur_src1)
456                 {
457                         mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1, src1);
458                         MALI_DEBUG_CODE(changed1 = 1;)
459                         reset1 = 1;
460                 }
461
462                 if (reset0)
463                 {
464                         mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0, 0);
465                 }
466
467                 if (reset1)
468                 {
469                         mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1, 0);
470                 }
471
472                 MALI_DEBUG_PRINT(5, ("L2 cache counters set: SRC0=%u, CHANGED0=%d, RESET0=%d, SRC1=%u, CHANGED1=%d, RESET1=%d\n",
473                         src0, changed0, reset0,
474                         src1, changed1, reset1));
475         }
476 }
477
478
479 void mali_kernel_l2_cache_get_perf_counters(u32 *src0, u32 *val0, u32 *src1, u32 *val1)
480 {
481         mali_kernel_l2_cache_core * cache, *temp_cache;
482         int first_time = 1;
483         *src0 = 0;
484         *src1 = 0;
485         *val0 = 0;
486         *val1 = 0;
487
488         /* loop over all L2 cache units and read the counters */
489         _MALI_OSK_LIST_FOREACHENTRY(cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list)
490         {
491                 u32 cur_src0 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0);
492                 u32 cur_src1 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1);
493                 u32 cur_val0 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0);
494                 u32 cur_val1 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1);
495
496                 MALI_DEBUG_PRINT(5, ("L2 cache counters get: SRC0=%u, VAL0=%u, SRC1=%u, VAL1=%u\n", cur_src0, cur_val0, cur_src1, cur_val1));
497
498                 /* Only update the counter source once, with the value from the first L2 cache unit. */
499                 if (first_time)
500                 {
501                         *src0 = cur_src0;
502                         *src1 = cur_src1;
503                         first_time = 0;
504                 }
505
506                 /* Bail out if the L2 cache units have different counters set. */
507                 if (*src0 == cur_src0 && *src1 == cur_src1)
508                 {
509                         *val0 += cur_val0;
510                         *val1 += cur_val1;
511                 }
512                 else
513                 {
514                         MALI_DEBUG_PRINT(1, ("Warning: Mali L2 caches has different performance counters set, not retrieving data\n"));
515                 }
516         }
517 }