tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / r4p0_rel0 / common / mali_mmu.c
1 /*
2  * Copyright (C) 2010-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_kernel_common.h"
12 #include "mali_osk.h"
13 #include "mali_osk_list.h"
14 #include "mali_ukk.h"
15
16 #include "mali_mmu.h"
17 #include "mali_hw_core.h"
18 #include "mali_group.h"
19 #include "mali_mmu_page_directory.h"
20
21 /**
22  * Size of the MMU registers in bytes
23  */
24 #define MALI_MMU_REGISTERS_SIZE 0x24
25
26 /**
27  * MMU commands
28  * These are the commands that can be sent
29  * to the MMU unit.
30  */
31 typedef enum mali_mmu_command {
32         MALI_MMU_COMMAND_ENABLE_PAGING = 0x00, /**< Enable paging (memory translation) */
33         MALI_MMU_COMMAND_DISABLE_PAGING = 0x01, /**< Disable paging (memory translation) */
34         MALI_MMU_COMMAND_ENABLE_STALL = 0x02, /**<  Enable stall on page fault */
35         MALI_MMU_COMMAND_DISABLE_STALL = 0x03, /**< Disable stall on page fault */
36         MALI_MMU_COMMAND_ZAP_CACHE = 0x04, /**< Zap the entire page table cache */
37         MALI_MMU_COMMAND_PAGE_FAULT_DONE = 0x05, /**< Page fault processed */
38         MALI_MMU_COMMAND_HARD_RESET = 0x06 /**< Reset the MMU back to power-on settings */
39 } mali_mmu_command;
40
41 static void mali_mmu_probe_trigger(void *data);
42 static _mali_osk_errcode_t mali_mmu_probe_ack(void *data);
43
44 MALI_STATIC_INLINE _mali_osk_errcode_t mali_mmu_raw_reset(struct mali_mmu_core *mmu);
45
46 /* page fault queue flush helper pages
47  * note that the mapping pointers are currently unused outside of the initialization functions */
48 static u32 mali_page_fault_flush_page_directory = MALI_INVALID_PAGE;
49 static mali_io_address mali_page_fault_flush_page_directory_mapping = NULL;
50 static u32 mali_page_fault_flush_page_table = MALI_INVALID_PAGE;
51 static mali_io_address mali_page_fault_flush_page_table_mapping = NULL;
52 static u32 mali_page_fault_flush_data_page = MALI_INVALID_PAGE;
53 static mali_io_address mali_page_fault_flush_data_page_mapping = NULL;
54
55 /* an empty page directory (no address valid) which is active on any MMU not currently marked as in use */
56 static u32 mali_empty_page_directory_phys   = MALI_INVALID_PAGE;
57 static mali_io_address mali_empty_page_directory_virt = NULL;
58
59
60 _mali_osk_errcode_t mali_mmu_initialize(void)
61 {
62         /* allocate the helper pages */
63         mali_empty_page_directory_phys = mali_allocate_empty_page(&mali_empty_page_directory_virt);
64         if(0 == mali_empty_page_directory_phys) {
65                 MALI_DEBUG_PRINT_ERROR(("Mali MMU: Could not allocate empty page directory.\n"));
66                 mali_empty_page_directory_phys = MALI_INVALID_PAGE;
67                 return _MALI_OSK_ERR_NOMEM;
68         }
69
70         if (_MALI_OSK_ERR_OK != mali_create_fault_flush_pages(&mali_page_fault_flush_page_directory,
71                 &mali_page_fault_flush_page_directory_mapping,
72                 &mali_page_fault_flush_page_table,
73                 &mali_page_fault_flush_page_table_mapping,
74                 &mali_page_fault_flush_data_page,
75                 &mali_page_fault_flush_data_page_mapping)) {
76                 MALI_DEBUG_PRINT_ERROR(("Mali MMU: Could not allocate fault flush pages\n"));
77                 mali_free_empty_page(mali_empty_page_directory_phys, mali_empty_page_directory_virt);
78                 mali_empty_page_directory_phys = MALI_INVALID_PAGE;
79                 mali_empty_page_directory_virt = NULL;
80                 return _MALI_OSK_ERR_NOMEM;
81         }
82
83         return _MALI_OSK_ERR_OK;
84 }
85
86 void mali_mmu_terminate(void)
87 {
88         MALI_DEBUG_PRINT(3, ("Mali MMU: terminating\n"));
89
90         /* Free global helper pages */
91         mali_free_empty_page(mali_empty_page_directory_phys, mali_empty_page_directory_virt);
92         mali_empty_page_directory_phys = MALI_INVALID_PAGE;
93         mali_empty_page_directory_virt = NULL;
94
95         /* Free the page fault flush pages */
96         mali_destroy_fault_flush_pages(&mali_page_fault_flush_page_directory, &mali_page_fault_flush_page_directory_mapping,
97                                        &mali_page_fault_flush_page_table, &mali_page_fault_flush_page_table_mapping,
98                                        &mali_page_fault_flush_data_page, &mali_page_fault_flush_data_page_mapping);
99 }
100
101 struct mali_mmu_core *mali_mmu_create(_mali_osk_resource_t *resource, struct mali_group *group, mali_bool is_virtual)
102 {
103         struct mali_mmu_core* mmu = NULL;
104
105         MALI_DEBUG_ASSERT_POINTER(resource);
106
107         MALI_DEBUG_PRINT(2, ("Mali MMU: Creating Mali MMU: %s\n", resource->description));
108
109         mmu = _mali_osk_calloc(1,sizeof(struct mali_mmu_core));
110         if (NULL != mmu) {
111                 if (_MALI_OSK_ERR_OK == mali_hw_core_create(&mmu->hw_core, resource, MALI_MMU_REGISTERS_SIZE)) {
112                         if (_MALI_OSK_ERR_OK == mali_group_add_mmu_core(group, mmu)) {
113                                 if (is_virtual) {
114                                         /* Skip reset and IRQ setup for virtual MMU */
115                                         return mmu;
116                                 }
117
118                                 if (_MALI_OSK_ERR_OK == mali_mmu_reset(mmu)) {
119                                         /* Setup IRQ handlers (which will do IRQ probing if needed) */
120                                         mmu->irq = _mali_osk_irq_init(resource->irq,
121                                                                       mali_group_upper_half_mmu,
122                                                                       group,
123                                                                       mali_mmu_probe_trigger,
124                                                                       mali_mmu_probe_ack,
125                                                                       mmu,
126                                                                       resource->description);
127                                         if (NULL != mmu->irq) {
128                                                 return mmu;
129                                         } else {
130                                                 MALI_PRINT_ERROR(("Mali MMU: Failed to setup interrupt handlers for MMU %s\n", mmu->hw_core.description));
131                                         }
132                                 }
133                                 mali_group_remove_mmu_core(group);
134                         } else {
135                                 MALI_PRINT_ERROR(("Mali MMU: Failed to add core %s to group\n", mmu->hw_core.description));
136                         }
137                         mali_hw_core_delete(&mmu->hw_core);
138                 }
139
140                 _mali_osk_free(mmu);
141         } else {
142                 MALI_PRINT_ERROR(("Failed to allocate memory for MMU\n"));
143         }
144
145         return NULL;
146 }
147
148 void mali_mmu_delete(struct mali_mmu_core *mmu)
149 {
150         if (NULL != mmu->irq) {
151                 _mali_osk_irq_term(mmu->irq);
152         }
153
154         mali_hw_core_delete(&mmu->hw_core);
155         _mali_osk_free(mmu);
156 }
157
158 static void mali_mmu_enable_paging(struct mali_mmu_core *mmu)
159 {
160         int i;
161
162         mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ENABLE_PAGING);
163
164         for (i = 0; i < MALI_REG_POLL_COUNT_FAST; ++i) {
165                 if (mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS) & MALI_MMU_STATUS_BIT_PAGING_ENABLED) {
166                         break;
167                 }
168         }
169         if (MALI_REG_POLL_COUNT_FAST == i) {
170                 MALI_PRINT_ERROR(("Enable paging request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS)));
171         }
172 }
173
174 /**
175  * Issues the enable stall command to the MMU and waits for HW to complete the request
176  * @param mmu The MMU to enable paging for
177  * @return MALI_TRUE if HW stall was successfully engaged, otherwise MALI_FALSE (req timed out)
178  */
179 static mali_bool mali_mmu_enable_stall(struct mali_mmu_core *mmu)
180 {
181         int i;
182         u32 mmu_status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS);
183
184         if ( 0 == (mmu_status & MALI_MMU_STATUS_BIT_PAGING_ENABLED) ) {
185                 MALI_DEBUG_PRINT(4, ("MMU stall is implicit when Paging is not enabled.\n"));
186                 return MALI_TRUE;
187         }
188
189         if ( mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE ) {
190                 MALI_DEBUG_PRINT(3, ("Aborting MMU stall request since it is in pagefault state.\n"));
191                 return MALI_FALSE;
192         }
193
194         mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ENABLE_STALL);
195
196         for (i = 0; i < MALI_REG_POLL_COUNT_FAST; ++i) {
197                 mmu_status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS);
198                 if (mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE) {
199                         break;
200                 }
201                 if ((mmu_status & MALI_MMU_STATUS_BIT_STALL_ACTIVE) && (0 == (mmu_status & MALI_MMU_STATUS_BIT_STALL_NOT_ACTIVE))) {
202                         break;
203                 }
204                 if (0 == (mmu_status & ( MALI_MMU_STATUS_BIT_PAGING_ENABLED ))) {
205                         break;
206                 }
207         }
208         if (MALI_REG_POLL_COUNT_FAST == i) {
209                 MALI_DEBUG_PRINT(2, ("Enable stall request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS)));
210                 return MALI_FALSE;
211         }
212
213         if ( mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE ) {
214                 MALI_DEBUG_PRINT(2, ("Aborting MMU stall request since it has a pagefault.\n"));
215                 return MALI_FALSE;
216         }
217
218         return MALI_TRUE;
219 }
220
221 /**
222  * Issues the disable stall command to the MMU and waits for HW to complete the request
223  * @param mmu The MMU to enable paging for
224  */
225 static void mali_mmu_disable_stall(struct mali_mmu_core *mmu)
226 {
227         int i;
228         u32 mmu_status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS);
229
230         if ( 0 == (mmu_status & MALI_MMU_STATUS_BIT_PAGING_ENABLED )) {
231                 MALI_DEBUG_PRINT(3, ("MMU disable skipped since it was not enabled.\n"));
232                 return;
233         }
234         if (mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE) {
235                 MALI_DEBUG_PRINT(2, ("Aborting MMU disable stall request since it is in pagefault state.\n"));
236                 return;
237         }
238
239         mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_DISABLE_STALL);
240
241         for (i = 0; i < MALI_REG_POLL_COUNT_FAST; ++i) {
242                 u32 status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS);
243                 if ( 0 == (status & MALI_MMU_STATUS_BIT_STALL_ACTIVE) ) {
244                         break;
245                 }
246                 if ( status &  MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE ) {
247                         break;
248                 }
249                 if ( 0 == (mmu_status & MALI_MMU_STATUS_BIT_PAGING_ENABLED )) {
250                         break;
251                 }
252         }
253         if (MALI_REG_POLL_COUNT_FAST == i) MALI_DEBUG_PRINT(1,("Disable stall request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS)));
254 }
255
256 void mali_mmu_page_fault_done(struct mali_mmu_core *mmu)
257 {
258         MALI_DEBUG_PRINT(4, ("Mali MMU: %s: Leaving page fault mode\n", mmu->hw_core.description));
259         mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_PAGE_FAULT_DONE);
260 }
261
262 MALI_STATIC_INLINE _mali_osk_errcode_t mali_mmu_raw_reset(struct mali_mmu_core *mmu)
263 {
264         int i;
265
266         mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR, 0xCAFEBABE);
267         MALI_DEBUG_ASSERT(0xCAFEB000 == mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR));
268         mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_HARD_RESET);
269
270         for (i = 0; i < MALI_REG_POLL_COUNT_FAST; ++i) {
271                 if (mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR) == 0) {
272                         break;
273                 }
274         }
275         if (MALI_REG_POLL_COUNT_FAST == i) {
276                 MALI_PRINT_ERROR(("Reset request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS)));
277                 return _MALI_OSK_ERR_FAULT;
278         }
279
280         return _MALI_OSK_ERR_OK;
281 }
282
283 _mali_osk_errcode_t mali_mmu_reset(struct mali_mmu_core *mmu)
284 {
285         _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT;
286         mali_bool stall_success;
287         MALI_DEBUG_ASSERT_POINTER(mmu);
288
289         stall_success = mali_mmu_enable_stall(mmu);
290         if (!stall_success) {
291                 err = _MALI_OSK_ERR_BUSY;
292         }
293
294         MALI_DEBUG_PRINT(3, ("Mali MMU: mali_kernel_mmu_reset: %s\n", mmu->hw_core.description));
295
296         if (_MALI_OSK_ERR_OK == mali_mmu_raw_reset(mmu)) {
297                 mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_MASK, MALI_MMU_INTERRUPT_PAGE_FAULT | MALI_MMU_INTERRUPT_READ_BUS_ERROR);
298                 /* no session is active, so just activate the empty page directory */
299                 mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR, mali_empty_page_directory_phys);
300                 mali_mmu_enable_paging(mmu);
301                 err = _MALI_OSK_ERR_OK;
302         }
303         mali_mmu_disable_stall(mmu);
304
305         return err;
306 }
307
308 mali_bool mali_mmu_zap_tlb(struct mali_mmu_core *mmu)
309 {
310         mali_bool stall_success = mali_mmu_enable_stall(mmu);
311
312         mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE);
313
314         if (MALI_FALSE == stall_success) {
315                 /* False means that it is in Pagefault state. Not possible to disable_stall then */
316                 return MALI_FALSE;
317         }
318
319         mali_mmu_disable_stall(mmu);
320         return MALI_TRUE;
321 }
322
323 void mali_mmu_zap_tlb_without_stall(struct mali_mmu_core *mmu)
324 {
325         mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE);
326 }
327
328
329 void mali_mmu_invalidate_page(struct mali_mmu_core *mmu, u32 mali_address)
330 {
331         mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_ZAP_ONE_LINE, MALI_MMU_PDE_ENTRY(mali_address));
332 }
333
334 static void mali_mmu_activate_address_space(struct mali_mmu_core *mmu, u32 page_directory)
335 {
336         /* The MMU must be in stalled or page fault mode, for this writing to work */
337         MALI_DEBUG_ASSERT( 0 != ( mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS)
338                                   & (MALI_MMU_STATUS_BIT_STALL_ACTIVE|MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE) ) );
339         mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR, page_directory);
340         mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE);
341
342 }
343
344 void mali_mmu_activate_page_directory(struct mali_mmu_core *mmu, struct mali_page_directory *pagedir)
345 {
346         mali_bool stall_success;
347         MALI_DEBUG_ASSERT_POINTER(mmu);
348
349         MALI_DEBUG_PRINT(5, ("Asked to activate page directory 0x%x on MMU %s\n", pagedir, mmu->hw_core.description));
350
351         stall_success = mali_mmu_enable_stall(mmu);
352         MALI_DEBUG_ASSERT(stall_success);
353         MALI_IGNORE(stall_success);
354         mali_mmu_activate_address_space(mmu, pagedir->page_directory);
355         mali_mmu_disable_stall(mmu);
356 }
357
358 void mali_mmu_activate_empty_page_directory(struct mali_mmu_core* mmu)
359 {
360         mali_bool stall_success;
361
362         MALI_DEBUG_ASSERT_POINTER(mmu);
363         MALI_DEBUG_PRINT(3, ("Activating the empty page directory on MMU %s\n", mmu->hw_core.description));
364
365         stall_success = mali_mmu_enable_stall(mmu);
366
367         /* This function can only be called when the core is idle, so it could not fail. */
368         MALI_DEBUG_ASSERT(stall_success);
369         MALI_IGNORE(stall_success);
370
371         mali_mmu_activate_address_space(mmu, mali_empty_page_directory_phys);
372         mali_mmu_disable_stall(mmu);
373 }
374
375 void mali_mmu_activate_fault_flush_page_directory(struct mali_mmu_core* mmu)
376 {
377         mali_bool stall_success;
378         MALI_DEBUG_ASSERT_POINTER(mmu);
379
380         MALI_DEBUG_PRINT(3, ("Activating the page fault flush page directory on MMU %s\n", mmu->hw_core.description));
381         stall_success = mali_mmu_enable_stall(mmu);
382         /* This function is expect to fail the stalling, since it might be in PageFault mode when it is called */
383         mali_mmu_activate_address_space(mmu, mali_page_fault_flush_page_directory);
384         if ( MALI_TRUE==stall_success ) mali_mmu_disable_stall(mmu);
385 }
386
387 /* Is called when we want the mmu to give an interrupt */
388 static void mali_mmu_probe_trigger(void *data)
389 {
390         struct mali_mmu_core *mmu = (struct mali_mmu_core *)data;
391         mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_RAWSTAT, MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR);
392 }
393
394 /* Is called when the irq probe wants the mmu to acknowledge an interrupt from the hw */
395 static _mali_osk_errcode_t mali_mmu_probe_ack(void *data)
396 {
397         struct mali_mmu_core *mmu = (struct mali_mmu_core *)data;
398         u32 int_stat;
399
400         int_stat = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_INT_STATUS);
401
402         MALI_DEBUG_PRINT(2, ("mali_mmu_probe_irq_acknowledge: intstat 0x%x\n", int_stat));
403         if (int_stat & MALI_MMU_INTERRUPT_PAGE_FAULT) {
404                 MALI_DEBUG_PRINT(2, ("Probe: Page fault detect: PASSED\n"));
405                 mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_PAGE_FAULT);
406         } else {
407                 MALI_DEBUG_PRINT(1, ("Probe: Page fault detect: FAILED\n"));
408         }
409
410         if (int_stat & MALI_MMU_INTERRUPT_READ_BUS_ERROR) {
411                 MALI_DEBUG_PRINT(2, ("Probe: Bus read error detect: PASSED\n"));
412                 mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_READ_BUS_ERROR);
413         } else {
414                 MALI_DEBUG_PRINT(1, ("Probe: Bus read error detect: FAILED\n"));
415         }
416
417         if ( (int_stat & (MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR)) ==
418              (MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR)) {
419                 return _MALI_OSK_ERR_OK;
420         }
421
422         return _MALI_OSK_ERR_FAULT;
423 }
424
425 #if 0
426 void mali_mmu_print_state(struct mali_mmu_core *mmu)
427 {
428         MALI_DEBUG_PRINT(2, ("MMU: State of %s is 0x%08x\n", mmu->hw_core.description, mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS)));
429 }
430 #endif