ENGR00156850 gpu-viv: add gpu-viv driver source
[wandboard.git] / drivers / mxc / gpu-viv / hal / kernel / gc_hal_kernel_mmu_vg.c
blobe3206277d891af60094ae637e7684d4b95b45f7b
1 /****************************************************************************
3 * Copyright (C) 2005 - 2011 by Vivante Corp.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the license, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *****************************************************************************/
24 #include "gc_hal_kernel_precomp.h"
26 #if gcdENABLE_VG
28 #define _GC_OBJ_ZONE gcvZONE_MMU
30 /*******************************************************************************
32 ** gckVGMMU_Construct
34 ** Construct a new gckVGMMU object.
36 ** INPUT:
38 ** gckVGKERNEL Kernel
39 ** Pointer to an gckVGKERNEL object.
41 ** gctSIZE_T MmuSize
42 ** Number of bytes for the page table.
44 ** OUTPUT:
46 ** gckVGMMU * Mmu
47 ** Pointer to a variable that receives the gckVGMMU object pointer.
49 gceSTATUS gckVGMMU_Construct(
50 IN gckVGKERNEL Kernel,
51 IN gctSIZE_T MmuSize,
52 OUT gckVGMMU * Mmu
55 gckOS os;
56 gckVGHARDWARE hardware;
57 gceSTATUS status;
58 gckVGMMU mmu;
59 gctUINT32 * pageTable;
60 gctUINT32 i;
62 gcmkHEADER_ARG("Kernel=0x%x MmuSize=0x%x Mmu=0x%x", Kernel, MmuSize, Mmu);
64 /* Verify the arguments. */
65 gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
66 gcmkVERIFY_ARGUMENT(MmuSize > 0);
67 gcmkVERIFY_ARGUMENT(Mmu != gcvNULL);
69 /* Extract the gckOS object pointer. */
70 os = Kernel->os;
71 gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
73 /* Extract the gckVGHARDWARE object pointer. */
74 hardware = Kernel->hardware;
75 gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
77 /* Allocate memory for the gckVGMMU object. */
78 status = gckOS_Allocate(os, sizeof(struct _gckVGMMU), (gctPOINTER *) &mmu);
80 if (status < 0)
82 /* Error. */
83 gcmkFATAL(
84 "%s(%d): could not allocate gckVGMMU object.",
85 __FUNCTION__, __LINE__
88 return status;
91 /* Initialize the gckVGMMU object. */
92 mmu->object.type = gcvOBJ_MMU;
93 mmu->os = os;
94 mmu->hardware = hardware;
96 /* Create the mutex. */
97 status = gckOS_CreateMutex(os, &mmu->mutex);
99 if (status < 0)
101 /* Roll back. */
102 mmu->object.type = gcvOBJ_UNKNOWN;
103 gcmkVERIFY_OK(gckOS_Free(os, mmu));
105 /* Error. */
106 return status;
109 /* Allocate the page table. */
110 mmu->pageTableSize = MmuSize;
111 status = gckOS_AllocateContiguous(os,
112 gcvFALSE,
113 &mmu->pageTableSize,
114 &mmu->pageTablePhysical,
115 &mmu->pageTableLogical);
117 if (status < 0)
119 /* Roll back. */
120 gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex));
122 mmu->object.type = gcvOBJ_UNKNOWN;
123 gcmkVERIFY_OK(gckOS_Free(os, mmu));
125 /* Error. */
126 gcmkFATAL(
127 "%s(%d): could not allocate page table.",
128 __FUNCTION__, __LINE__
131 return status;
134 /* Compute number of entries in page table. */
135 mmu->entryCount = mmu->pageTableSize / sizeof(gctUINT32);
136 mmu->entry = 0;
138 /* Mark the entire page table as available. */
139 pageTable = (gctUINT32 *) mmu->pageTableLogical;
140 for (i = 0; i < mmu->entryCount; i++)
142 pageTable[i] = (gctUINT32)~0;
145 /* Set page table address. */
146 status = gckVGHARDWARE_SetMMU(hardware, mmu->pageTableLogical);
148 if (status < 0)
150 /* Free the page table. */
151 gcmkVERIFY_OK(gckOS_FreeContiguous(mmu->os,
152 mmu->pageTablePhysical,
153 mmu->pageTableLogical,
154 mmu->pageTableSize));
156 /* Roll back. */
157 gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex));
159 mmu->object.type = gcvOBJ_UNKNOWN;
160 gcmkVERIFY_OK(gckOS_Free(os, mmu));
162 /* Error. */
163 gcmkFATAL(
164 "%s(%d): could not program page table.",
165 __FUNCTION__, __LINE__
168 return status;
171 /* Return the gckVGMMU object pointer. */
172 *Mmu = mmu;
174 gcmkTRACE_ZONE(
175 gcvLEVEL_INFO, gcvZONE_MMU,
176 "%s(%d): %u entries at %p.(0x%08X)\n",
177 __FUNCTION__, __LINE__,
178 mmu->entryCount,
179 mmu->pageTableLogical,
180 mmu->pageTablePhysical
183 gcmkFOOTER_NO();
184 /* Success. */
185 return gcvSTATUS_OK;
188 /*******************************************************************************
190 ** gckVGMMU_Destroy
192 ** Destroy a nAQMMU object.
194 ** INPUT:
196 ** gckVGMMU Mmu
197 ** Pointer to an gckVGMMU object.
199 ** OUTPUT:
201 ** Nothing.
203 gceSTATUS gckVGMMU_Destroy(
204 IN gckVGMMU Mmu
207 gcmkHEADER_ARG("Mmu=0x%x", Mmu);
209 /* Verify the arguments. */
210 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
212 /* Free the page table. */
213 gcmkVERIFY_OK(gckOS_FreeContiguous(Mmu->os,
214 Mmu->pageTablePhysical,
215 Mmu->pageTableLogical,
216 Mmu->pageTableSize));
218 /* Roll back. */
219 gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->mutex));
221 /* Mark the gckVGMMU object as unknown. */
222 Mmu->object.type = gcvOBJ_UNKNOWN;
224 /* Free the gckVGMMU object. */
225 gcmkVERIFY_OK(gckOS_Free(Mmu->os, Mmu));
227 gcmkFOOTER_NO();
228 /* Success. */
229 return gcvSTATUS_OK;
232 /*******************************************************************************
234 ** gckVGMMU_AllocatePages
236 ** Allocate pages inside the page table.
238 ** INPUT:
240 ** gckVGMMU Mmu
241 ** Pointer to an gckVGMMU object.
243 ** gctSIZE_T PageCount
244 ** Number of pages to allocate.
246 ** OUTPUT:
248 ** gctPOINTER * PageTable
249 ** Pointer to a variable that receives the base address of the page
250 ** table.
252 ** gctUINT32 * Address
253 ** Pointer to a variable that receives the hardware specific address.
255 gceSTATUS gckVGMMU_AllocatePages(
256 IN gckVGMMU Mmu,
257 IN gctSIZE_T PageCount,
258 OUT gctPOINTER * PageTable,
259 OUT gctUINT32 * Address
262 gceSTATUS status;
263 gctUINT32 tail, index, i;
264 gctUINT32 * table;
265 gctBOOL allocated = gcvFALSE;
267 gcmkHEADER_ARG("Mmu=0x%x PageCount=0x%x PageTable=0x%x Address=0x%x",
268 Mmu, PageCount, PageTable, Address);
270 /* Verify the arguments. */
271 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
272 gcmkVERIFY_ARGUMENT(PageCount > 0);
273 gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
274 gcmkVERIFY_ARGUMENT(Address != gcvNULL);
276 gcmkTRACE_ZONE(
277 gcvLEVEL_INFO, gcvZONE_MMU,
278 "%s(%d): %u pages.\n",
279 __FUNCTION__, __LINE__,
280 PageCount
283 if (PageCount > Mmu->entryCount)
285 gcmkTRACE_ZONE(
286 gcvLEVEL_ERROR, gcvZONE_MMU,
287 "%s(%d): page table too small for %u pages.\n",
288 __FUNCTION__, __LINE__,
289 PageCount
292 /* Not enough pages avaiable. */
293 return gcvSTATUS_OUT_OF_RESOURCES;
296 /* Grab the mutex. */
297 status = gckOS_AcquireMutex(Mmu->os, Mmu->mutex, gcvINFINITE);
299 if (status < 0)
301 gcmkTRACE_ZONE(
302 gcvLEVEL_ERROR, gcvZONE_MMU,
303 "%s(%d): could not acquire mutex.\n"
304 ,__FUNCTION__, __LINE__
307 /* Error. */
308 return status;
311 /* Compute the tail for this allocation. */
312 tail = Mmu->entryCount - PageCount;
314 /* Walk all entries until we find enough slots. */
315 for (index = Mmu->entry; index <= tail;)
317 /* Access page table. */
318 table = (gctUINT32 *) Mmu->pageTableLogical + index;
320 /* See if all slots are available. */
321 for (i = 0; i < PageCount; i++, table++)
323 if (*table != ~0)
325 /* Start from next slot. */
326 index += i + 1;
327 break;
331 if (i == PageCount)
333 /* Bail out if we have enough page entries. */
334 allocated = gcvTRUE;
335 break;
339 if (!allocated)
341 /* Flush the MMU. */
342 status = gckVGHARDWARE_FlushMMU(Mmu->hardware);
344 if (status >= 0)
346 /* Walk all entries until we find enough slots. */
347 for (index = 0; index <= tail;)
349 /* Access page table. */
350 table = (gctUINT32 *) Mmu->pageTableLogical + index;
352 /* See if all slots are available. */
353 for (i = 0; i < PageCount; i++, table++)
355 if (*table != ~0)
357 /* Start from next slot. */
358 index += i + 1;
359 break;
363 if (i == PageCount)
365 /* Bail out if we have enough page entries. */
366 allocated = gcvTRUE;
367 break;
373 if (!allocated && (status >= 0))
375 gcmkTRACE_ZONE(
376 gcvLEVEL_ERROR, gcvZONE_MMU,
377 "%s(%d): not enough free pages for %u pages.\n",
378 __FUNCTION__, __LINE__,
379 PageCount
382 /* Not enough empty slots available. */
383 status = gcvSTATUS_OUT_OF_RESOURCES;
386 if (status >= 0)
388 /* Build virtual address. */
389 status = gckVGHARDWARE_BuildVirtualAddress(Mmu->hardware,
390 index,
392 Address);
394 if (status >= 0)
396 /* Update current entry into page table. */
397 Mmu->entry = index + PageCount;
399 /* Return pointer to page table. */
400 *PageTable = (gctUINT32 *) Mmu->pageTableLogical + index;
402 gcmkTRACE_ZONE(
403 gcvLEVEL_INFO, gcvZONE_MMU,
404 "%s(%d): allocated %u pages at index %u (0x%08X) @ %p.\n",
405 __FUNCTION__, __LINE__,
406 PageCount,
407 index,
408 *Address,
409 *PageTable
414 /* Release the mutex. */
415 gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->mutex));
416 gcmkFOOTER();
418 /* Return status. */
419 return status;
422 /*******************************************************************************
424 ** gckVGMMU_FreePages
426 ** Free pages inside the page table.
428 ** INPUT:
430 ** gckVGMMU Mmu
431 ** Pointer to an gckVGMMU object.
433 ** gctPOINTER PageTable
434 ** Base address of the page table to free.
436 ** gctSIZE_T PageCount
437 ** Number of pages to free.
439 ** OUTPUT:
441 ** Nothing.
443 gceSTATUS gckVGMMU_FreePages(
444 IN gckVGMMU Mmu,
445 IN gctPOINTER PageTable,
446 IN gctSIZE_T PageCount
449 gctUINT32 * table;
451 gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=0x%x",
452 Mmu, PageTable, PageCount);
454 /* Verify the arguments. */
455 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
456 gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
457 gcmkVERIFY_ARGUMENT(PageCount > 0);
459 gcmkTRACE_ZONE(
460 gcvLEVEL_INFO, gcvZONE_MMU,
461 "%s(%d): freeing %u pages at index %u @ %p.\n",
462 __FUNCTION__, __LINE__,
463 PageCount,
464 ((gctUINT32 *) PageTable - (gctUINT32 *) Mmu->pageTableLogical),
465 PageTable
468 /* Convert pointer. */
469 table = (gctUINT32 *) PageTable;
471 /* Mark the page table entries as available. */
472 while (PageCount-- > 0)
474 *table++ = (gctUINT32)~0;
477 gcmkFOOTER_NO();
478 /* Success. */
479 return gcvSTATUS_OK;
482 gceSTATUS
483 gckVGMMU_SetPage(
484 IN gckVGMMU Mmu,
485 IN gctUINT32 PageAddress,
486 IN gctUINT32 *PageEntry
489 gcmkHEADER_ARG("Mmu=0x%x", Mmu);
491 /* Verify the arguments. */
492 gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
493 gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL);
494 gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF));
496 *PageEntry = PageAddress;
498 /* Success. */
499 gcmkFOOTER_NO();
500 return gcvSTATUS_OK;
503 #endif /* gcdENABLE_VG */