1 /*************************************************************************/ /*!
3 @Title Services Firmware image utilities used at init time
4 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @Description Services Firmware image utilities used at init time
6 @License Dual MIT/GPLv2
8 The contents of this file are subject to the MIT license as set out below.
10 Permission is hereby granted, free of charge, to any person obtaining a copy
11 of this software and associated documentation files (the "Software"), to deal
12 in the Software without restriction, including without limitation the rights
13 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 copies of the Software, and to permit persons to whom the Software is
15 furnished to do so, subject to the following conditions:
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
20 Alternatively, the contents of this file may be used under the terms of
21 the GNU General Public License Version 2 ("GPL") in which case the provisions
22 of GPL are applicable instead of those above.
24 If you wish to allow use of your version of this file only under the terms of
25 GPL, and not to allow others to use your version of this file under the terms
26 of the MIT license, indicate your decision by deleting the provisions above
27 and replace them with the notice and other provisions required by GPL as set
28 out in the file called "GPL-COPYING" included in this distribution. If you do
29 not delete the provisions above, a recipient may use your version of this file
30 under the terms of either the MIT license or GPL.
32 This License is also included in this distribution in the file called
35 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
36 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
37 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
38 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
39 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
40 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
41 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 */ /**************************************************************************/
44 /* The routines implemented here are built on top of an abstraction layer to
45 * hide DDK/OS-specific details in case they are used outside of the DDK
46 * (e.g. when trusted device is enabled).
47 * Any new dependency should be added to rgxlayer.h.
48 * Any new code should be built on top of the existing abstraction layer,
49 * which should be extended when necessary. */
50 #include "rgxfwimageutils.h"
53 /************************************************************************
54 * FW Segments configuration
55 ************************************************************************/
56 typedef struct _RGX_FW_SEGMENT_
58 IMG_UINT32 ui32SegId; /*!< Segment Id */
59 IMG_UINT32 ui32SegStartAddr; /*!< Segment Start Addr */
60 IMG_UINT32 ui32SegAllocSize; /*!< Amount of memory to allocate for that segment */
61 IMG_UINT32 ui32FWMemOffset; /*!< Offset of this segment in the collated FW mem allocation */
62 const IMG_CHAR *pszSegName;
65 typedef struct _RGX_FW_SEGMENT_LIST_
67 RGX_FW_SEGMENT *psRGXFWCodeSeg;
68 RGX_FW_SEGMENT *psRGXFWDataSeg;
69 IMG_UINT32 ui32CodeSegCount;
70 IMG_UINT32 ui32DataSegCount;
71 } RGX_FW_SEGMENT_LIST;
74 #if defined(RGX_FEATURE_META) || defined(SUPPORT_KERNEL_SRVINIT)
75 static RGX_FW_SEGMENT asRGXMetaFWCodeSegments[] = {
76 /* Seg ID Seg Start Addr Alloc size FWMem offset Name */
77 {RGXFW_SEGMMU_TEXT_ID, RGXFW_BOOTLDR_META_ADDR, 0x31000, 0, "Bootldr and Code"}, /* Has to be the first one to get the proper DevV addr */
79 static RGX_FW_SEGMENT asRGXMetaFWDataSegments[] = {
80 /* Seg ID Seg Start Addr Alloc size FWMem offset Name */
81 {RGXFW_SEGMMU_DATA_ID, 0x38880000, 0x17000, 0, "Local Shared and Data"},
83 #define RGXFW_META_NUM_CODE_SEGMENTS (sizeof(asRGXMetaFWCodeSegments)/sizeof(asRGXMetaFWCodeSegments[0]))
84 #define RGXFW_META_NUM_DATA_SEGMENTS (sizeof(asRGXMetaFWDataSegments)/sizeof(asRGXMetaFWDataSegments[0]))
87 #if defined(RGX_FEATURE_MIPS) || defined(SUPPORT_KERNEL_SRVINIT)
88 static RGX_FW_SEGMENT asRGXMipsFWCodeSegments[] = {
89 /* Seg ID Seg Start Addr Alloc size FWMem offset Name */
90 { 0, RGXMIPSFW_BOOT_NMI_CODE_VIRTUAL_BASE, RGXMIPSFW_BOOT_NMI_CODE_SIZE, RGXMIPSFW_BOOT_NMI_CODE_OFFSET, "Bootldr and NMI code"},
91 { 1, RGXMIPSFW_EXCEPTIONS_VIRTUAL_BASE, RGXMIPSFW_EXCEPTIONSVECTORS_SIZE, RGXMIPSFW_EXCEPTIONSVECTORS_OFFSET, "Exception vectors"},
92 { 2, RGXMIPSFW_CODE_VIRTUAL_BASE, RGXMIPSFW_CODE_SIZE, RGXMIPSFW_CODE_OFFSET, "Text"},
94 static RGX_FW_SEGMENT asRGXMipsFWDataSegments[] = {
95 /* Seg ID Seg Start Addr Alloc size FWMem offset Name */
96 { 3, RGXMIPSFW_BOOT_NMI_DATA_VIRTUAL_BASE, RGXMIPSFW_BOOT_NMI_DATA_SIZE, RGXMIPSFW_BOOT_NMI_DATA_OFFSET, "Bootldr and NMI data"},
97 { 4, RGXMIPSFW_DATA_VIRTUAL_BASE, RGXMIPSFW_DATA_SIZE, RGXMIPSFW_DATA_OFFSET, "Local Data"},
98 { 5, RGXMIPSFW_STACK_VIRTUAL_BASE, RGXMIPSFW_STACK_SIZE, RGXMIPSFW_DATA_SIZE, "Stack"},
101 #define RGXFW_MIPS_NUM_CODE_SEGMENTS (sizeof(asRGXMipsFWCodeSegments)/sizeof(asRGXMipsFWCodeSegments[0]))
102 #define RGXFW_MIPS_NUM_DATA_SEGMENTS (sizeof(asRGXMipsFWDataSegments)/sizeof(asRGXMipsFWDataSegments[0]))
106 *******************************************************************************
108 @Function FindMMUSegment
110 @Description Given a 32 bit FW address attempt to find the corresponding
111 pointer to FW allocation
113 @Input ui32OffsetIn : 32 bit FW address
114 @Input pvHostFWCodeAddr : Pointer to FW code
115 @Input pvHostFWDataAddr : Pointer to FW data
116 @Input uiHostAddrOut : CPU pointer equivalent to ui32OffsetIn
120 ******************************************************************************/
121 static PVRSRV_ERROR FindMMUSegment(IMG_UINT32 ui32OffsetIn,
122 void *pvHostFWCodeAddr,
123 void *pvHostFWDataAddr,
124 void **uiHostAddrOut,
125 RGX_FW_SEGMENT_LIST *psRGXFWSegList)
127 RGX_FW_SEGMENT *psSegArr;
130 psSegArr = psRGXFWSegList->psRGXFWCodeSeg;
131 for (i = 0; i < psRGXFWSegList->ui32CodeSegCount; i++)
133 if ((ui32OffsetIn >= psSegArr[i].ui32SegStartAddr) &&
134 (ui32OffsetIn < (psSegArr[i].ui32SegStartAddr + psSegArr[i].ui32SegAllocSize)))
136 *uiHostAddrOut = pvHostFWCodeAddr;
141 psSegArr = psRGXFWSegList->psRGXFWDataSeg;
142 for (i = 0; i < psRGXFWSegList->ui32DataSegCount; i++)
144 if ((ui32OffsetIn >= psSegArr[i].ui32SegStartAddr) &&
145 (ui32OffsetIn < (psSegArr[i].ui32SegStartAddr + psSegArr[i].ui32SegAllocSize)))
147 *uiHostAddrOut = pvHostFWDataAddr;
152 return PVRSRV_ERROR_INIT_FAILURE;
155 /* Direct Mem write to mapped memory */
156 ui32OffsetIn -= psSegArr[i].ui32SegStartAddr;
157 ui32OffsetIn += psSegArr[i].ui32FWMemOffset;
159 /* Add offset to pointer to FW allocation only if
160 * that allocation is available
164 *(IMG_UINT8 **)uiHostAddrOut += ui32OffsetIn;
170 #if defined(RGX_FEATURE_META) || defined(SUPPORT_KERNEL_SRVINIT)
173 *******************************************************************************
175 @Function RGXFWConfigureSegID
177 @Description Configures a single segment of the Segment MMU
178 (base, limit and out_addr)
180 @Input hPrivate : Implementation specific data
181 @Input ui64SegOutAddr : Segment output base address (40 bit devVaddr)
182 @Input ui32SegBase : Segment input base address (32 bit FW address)
183 @Input ui32SegLimit : Segment size
184 @Input ui32SegID : Segment ID
185 @Input pszName : Segment name
186 @Input ppui32BootConf : Pointer to bootloader data
190 ******************************************************************************/
191 static void RGXFWConfigureSegID(const void *hPrivate,
192 IMG_UINT64 ui64SegOutAddr,
193 IMG_UINT32 ui32SegBase,
194 IMG_UINT32 ui32SegLimit,
195 IMG_UINT32 ui32SegID,
196 const IMG_CHAR *pszName,
197 IMG_UINT32 **ppui32BootConf)
199 IMG_UINT32 *pui32BootConf = *ppui32BootConf;
200 IMG_UINT32 ui32SegOutAddr0 = ui64SegOutAddr & 0x00000000FFFFFFFFUL;
201 IMG_UINT32 ui32SegOutAddr1 = (ui64SegOutAddr >> 32) & 0x00000000FFFFFFFFUL;
203 /* META segments have a minimum size */
204 IMG_UINT32 ui32LimitOff = (ui32SegLimit < RGXFW_SEGMMU_ALIGN) ?
205 RGXFW_SEGMMU_ALIGN : ui32SegLimit;
206 /* the limit is an offset, therefore off = size - 1 */
209 RGXCommentLogInit(hPrivate,
210 "* FW %s - seg%d: meta_addr = 0x%08x, devv_addr = 0x%llx, limit = 0x%x",
212 ui32SegBase, (unsigned long long)ui64SegOutAddr,
215 ui32SegBase |= RGXFW_SEGMMU_ALLTHRS_WRITEABLE;
217 *pui32BootConf++ = META_CR_MMCU_SEGMENTn_BASE(ui32SegID);
218 *pui32BootConf++ = ui32SegBase;
220 *pui32BootConf++ = META_CR_MMCU_SEGMENTn_LIMIT(ui32SegID);
221 *pui32BootConf++ = ui32LimitOff;
223 *pui32BootConf++ = META_CR_MMCU_SEGMENTn_OUTA0(ui32SegID);
224 *pui32BootConf++ = ui32SegOutAddr0;
226 *pui32BootConf++ = META_CR_MMCU_SEGMENTn_OUTA1(ui32SegID);
227 *pui32BootConf++ = ui32SegOutAddr1;
229 *ppui32BootConf = pui32BootConf;
233 *******************************************************************************
235 @Function RGXFWConfigureSegMMU
237 @Description Configures META's Segment MMU
239 @Input hPrivate : Implementation specific data
240 @Input psFWCodeDevVAddrBase : FW code base device virtual address
241 @Input psFWDataDevVAddrBase : FW data base device virtual address
242 @Input ppui32BootConf : Pointer to bootloader data
246 ******************************************************************************/
247 static void RGXFWConfigureSegMMU(const void *hPrivate,
248 IMG_DEV_VIRTADDR *psFWCodeDevVAddrBase,
249 IMG_DEV_VIRTADDR *psFWDataDevVAddrBase,
250 IMG_UINT32 **ppui32BootConf)
252 IMG_UINT64 ui64SegOutAddr;
255 PVR_UNREFERENCED_PARAMETER(psFWCodeDevVAddrBase);
257 /* Configure Segment MMU */
258 RGXCommentLogInit(hPrivate, "********** FW configure Segment MMU **********");
260 for (i = 0; i < RGXFW_META_NUM_DATA_SEGMENTS ; i++)
262 ui64SegOutAddr = (psFWDataDevVAddrBase->uiAddr |
263 RGXFW_SEGMMU_OUTADDR_TOP(META_MMU_CONTEXT_MAPPING, RGXFW_SEGMMU_META_DM_ID)) +
264 asRGXMetaFWDataSegments[i].ui32FWMemOffset;
266 RGXFWConfigureSegID(hPrivate,
268 asRGXMetaFWDataSegments[i].ui32SegStartAddr,
269 asRGXMetaFWDataSegments[i].ui32SegAllocSize,
270 asRGXMetaFWDataSegments[i].ui32SegId,
271 asRGXMetaFWDataSegments[i].pszSegName,
272 ppui32BootConf); /*write the sequence to the bootldr */
277 *******************************************************************************
279 @Function RGXFWConfigureMetaCaches
281 @Description Configure and enable the Meta instruction and data caches
283 @Input hPrivate : Implementation specific data
284 @Input ui32NumThreads : Number of FW threads in use
285 @Input ui32MainThreadID : ID of the FW thread in use
286 (only meaningful if ui32NumThreads == 1)
287 @Input ppui32BootConf : Pointer to bootloader data
291 ******************************************************************************/
292 static void RGXFWConfigureMetaCaches(const void *hPrivate,
293 IMG_UINT32 ui32NumThreads,
294 IMG_UINT32 ui32MainThreadID,
295 IMG_UINT32 **ppui32BootConf)
297 IMG_UINT32 *pui32BootConf = *ppui32BootConf;
298 IMG_UINT32 ui32DCacheT0, ui32ICacheT0;
299 IMG_UINT32 ui32DCacheT1, ui32ICacheT1;
300 IMG_UINT32 ui32DCacheT2, ui32ICacheT2;
301 IMG_UINT32 ui32DCacheT3, ui32ICacheT3;
303 #define META_CR_MMCU_LOCAL_EBCTRL (0x04830600)
304 #define META_CR_MMCU_LOCAL_EBCTRL_ICWIN (0x3 << 14)
305 #define META_CR_MMCU_LOCAL_EBCTRL_DCWIN (0x3 << 6)
306 #define META_CR_SYSC_DCPART(n) (0x04830200 + (n)*0x8)
307 #define META_CR_SYSC_DCPARTX_CACHED_WRITE_ENABLE (0x1 << 31)
308 #define META_CR_SYSC_ICPART(n) (0x04830220 + (n)*0x8)
309 #define META_CR_SYSC_XCPARTX_LOCAL_ADDR_OFFSET_TOP_HALF (0x8 << 16)
310 #define META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE (0xF)
311 #define META_CR_SYSC_XCPARTX_LOCAL_ADDR_HALF_CACHE (0x7)
312 #define META_CR_MMCU_DCACHE_CTRL (0x04830018)
313 #define META_CR_MMCU_ICACHE_CTRL (0x04830020)
314 #define META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN (0x1)
316 RGXCommentLogInit(hPrivate, "********** Meta caches configuration *********");
318 /* Initialise I/Dcache settings */
319 ui32DCacheT0 = ui32DCacheT1 = META_CR_SYSC_DCPARTX_CACHED_WRITE_ENABLE;
320 ui32DCacheT2 = ui32DCacheT3 = META_CR_SYSC_DCPARTX_CACHED_WRITE_ENABLE;
321 ui32ICacheT0 = ui32ICacheT1 = ui32ICacheT2 = ui32ICacheT3 = 0;
323 if (ui32NumThreads == 1)
325 if (ui32MainThreadID == 0)
327 ui32DCacheT0 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE;
328 ui32ICacheT0 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE;
332 ui32DCacheT1 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE;
333 ui32ICacheT1 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE;
338 ui32DCacheT0 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_HALF_CACHE;
339 ui32ICacheT0 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_HALF_CACHE;
341 ui32DCacheT1 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_HALF_CACHE |
342 META_CR_SYSC_XCPARTX_LOCAL_ADDR_OFFSET_TOP_HALF;
343 ui32ICacheT1 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_HALF_CACHE |
344 META_CR_SYSC_XCPARTX_LOCAL_ADDR_OFFSET_TOP_HALF;
347 /* Local region MMU enhanced bypass: WIN-3 mode for code and data caches */
348 *pui32BootConf++ = META_CR_MMCU_LOCAL_EBCTRL;
349 *pui32BootConf++ = META_CR_MMCU_LOCAL_EBCTRL_ICWIN |
350 META_CR_MMCU_LOCAL_EBCTRL_DCWIN;
352 RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
353 META_CR_MMCU_LOCAL_EBCTRL,
354 META_CR_MMCU_LOCAL_EBCTRL_ICWIN | META_CR_MMCU_LOCAL_EBCTRL_DCWIN);
356 /* Data cache partitioning thread 0 to 3 */
357 *pui32BootConf++ = META_CR_SYSC_DCPART(0);
358 *pui32BootConf++ = ui32DCacheT0;
359 *pui32BootConf++ = META_CR_SYSC_DCPART(1);
360 *pui32BootConf++ = ui32DCacheT1;
361 *pui32BootConf++ = META_CR_SYSC_DCPART(2);
362 *pui32BootConf++ = ui32DCacheT2;
363 *pui32BootConf++ = META_CR_SYSC_DCPART(3);
364 *pui32BootConf++ = ui32DCacheT3;
366 RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
367 META_CR_SYSC_DCPART(0), ui32DCacheT0);
368 RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
369 META_CR_SYSC_DCPART(1), ui32DCacheT1);
370 RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
371 META_CR_SYSC_DCPART(2), ui32DCacheT2);
372 RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
373 META_CR_SYSC_DCPART(3), ui32DCacheT3);
375 /* Enable data cache hits */
376 *pui32BootConf++ = META_CR_MMCU_DCACHE_CTRL;
377 *pui32BootConf++ = META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN;
379 RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
380 META_CR_MMCU_DCACHE_CTRL,
381 META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN);
383 /* Instruction cache partitioning thread 0 to 3 */
384 *pui32BootConf++ = META_CR_SYSC_ICPART(0);
385 *pui32BootConf++ = ui32ICacheT0;
386 *pui32BootConf++ = META_CR_SYSC_ICPART(1);
387 *pui32BootConf++ = ui32ICacheT1;
388 *pui32BootConf++ = META_CR_SYSC_ICPART(2);
389 *pui32BootConf++ = ui32ICacheT2;
390 *pui32BootConf++ = META_CR_SYSC_ICPART(3);
391 *pui32BootConf++ = ui32ICacheT3;
393 RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
394 META_CR_SYSC_ICPART(0), ui32ICacheT0);
395 RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
396 META_CR_SYSC_ICPART(1), ui32ICacheT1);
397 RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
398 META_CR_SYSC_ICPART(2), ui32ICacheT2);
399 RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
400 META_CR_SYSC_ICPART(3), ui32ICacheT3);
402 /* Enable instruction cache hits */
403 *pui32BootConf++ = META_CR_MMCU_ICACHE_CTRL;
404 *pui32BootConf++ = META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN;
406 RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
407 META_CR_MMCU_ICACHE_CTRL,
408 META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN);
410 *pui32BootConf++ = 0x040000C0;
411 *pui32BootConf++ = 0;
413 RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
416 *ppui32BootConf = pui32BootConf;
420 *******************************************************************************
422 @Function ProcessLDRCommandStream
424 @Description Process the output of the Meta toolchain in the .LDR format
425 copying code and data sections into their final location and
426 passing some information to the Meta bootloader
428 @Input hPrivate : Implementation specific data
429 @Input pbLDR : Pointer to FW blob
430 @Input pvHostFWCodeAddr : Pointer to FW code
431 @Input pvHostFWDataAddr : Pointer to FW data
432 @Input pvHostFWCorememAddr : Pointer to FW coremem code
433 @Input ppui32BootConf : Pointer to bootloader data
437 ******************************************************************************/
438 static PVRSRV_ERROR ProcessLDRCommandStream(const void *hPrivate,
439 const IMG_BYTE* pbLDR,
440 void* pvHostFWCodeAddr,
441 void* pvHostFWDataAddr,
442 void* pvHostFWCorememAddr,
443 IMG_UINT32 **ppui32BootConf)
445 RGX_META_LDR_BLOCK_HDR *psHeader = (RGX_META_LDR_BLOCK_HDR *) pbLDR;
446 RGX_META_LDR_L1_DATA_BLK *psL1Data =
447 (RGX_META_LDR_L1_DATA_BLK*) ((IMG_UINT8 *) pbLDR + psHeader->ui32SLData);
449 IMG_UINT32 *pui32BootConf = *ppui32BootConf;
450 IMG_UINT32 ui32CorememSize = RGXGetFWCorememSize(hPrivate);
451 IMG_UINT32 ui32CorememCodeStartAddr = 0xFFFFFFFF;
453 RGXCommentLogInit(hPrivate, "**********************************************");
454 RGXCommentLogInit(hPrivate, "************** Begin LDR Parsing *************");
455 RGXCommentLogInit(hPrivate, "**********************************************");
457 while (psL1Data != NULL)
459 RGX_FW_SEGMENT_LIST sRGXFWSegList;
460 sRGXFWSegList.psRGXFWCodeSeg = asRGXMetaFWCodeSegments;
461 sRGXFWSegList.psRGXFWDataSeg = asRGXMetaFWDataSegments;
462 sRGXFWSegList.ui32CodeSegCount = RGXFW_META_NUM_CODE_SEGMENTS;
463 sRGXFWSegList.ui32DataSegCount = RGXFW_META_NUM_DATA_SEGMENTS;
465 if (RGX_META_LDR_BLK_IS_COMMENT(psL1Data->ui16Cmd))
467 /* Don't process comment blocks */
471 switch (psL1Data->ui16Cmd & RGX_META_LDR_CMD_MASK)
473 case RGX_META_LDR_CMD_LOADMEM:
475 RGX_META_LDR_L2_DATA_BLK *psL2Block =
476 (RGX_META_LDR_L2_DATA_BLK*) (((IMG_UINT8 *) pbLDR) + psL1Data->aui32CmdData[1]);
477 IMG_UINT32 ui32Offset = psL1Data->aui32CmdData[0];
478 IMG_UINT32 ui32DataSize = psL2Block->ui16Length - 6 /* L2 Tag length and checksum */;
482 if (RGX_META_IS_COREMEM_CODE(ui32Offset, ui32CorememSize))
484 if (ui32Offset < ui32CorememCodeStartAddr)
486 if (ui32CorememCodeStartAddr == 0xFFFFFFFF)
488 /* Take the first coremem code address as the coremem code start address */
489 ui32CorememCodeStartAddr = ui32Offset;
491 /* Also check that there is a valid allocation for the coremem code */
492 if (pvHostFWCorememAddr == NULL)
494 RGXErrorLogInit(hPrivate,
495 "ProcessLDRCommandStream: Coremem code found"
496 "but no coremem allocation available!");
498 return PVRSRV_ERROR_INIT_FAILURE;
503 /* The coremem addresses should be ordered in the LDR command stream */
504 return PVRSRV_ERROR_INIT_FAILURE;
508 /* Copy coremem data to buffer. The FW copies it to the actual coremem */
509 ui32Offset -= ui32CorememCodeStartAddr;
512 (void*)((IMG_UINT8 *)pvHostFWCorememAddr + ui32Offset),
513 psL2Block->aui32BlockData,
518 /* Global range is aliased to local range */
519 ui32Offset &= ~META_MEM_GLOBAL_RANGE_BIT;
521 eError = FindMMUSegment(ui32Offset,
527 if (eError != PVRSRV_OK)
529 RGXErrorLogInit(hPrivate,
530 "ProcessLDRCommandStream: Addr 0x%x (size: %d) not found in any segment",
531 ui32Offset, ui32DataSize);
535 /* Write to FW allocation only if available */
540 psL2Block->aui32BlockData,
547 case RGX_META_LDR_CMD_LOADCORE:
548 case RGX_META_LDR_CMD_LOADMMREG:
550 return PVRSRV_ERROR_INIT_FAILURE;
552 case RGX_META_LDR_CMD_START_THREADS:
554 /* Don't process this block */
557 case RGX_META_LDR_CMD_ZEROMEM:
559 IMG_UINT32 ui32Offset = psL1Data->aui32CmdData[0];
560 IMG_UINT32 ui32ByteCount = psL1Data->aui32CmdData[1];
564 if (RGX_META_IS_COREMEM_DATA(ui32Offset, ui32CorememSize))
566 /* cannot zero coremem directly */
570 /* Global range is aliased to local range */
571 ui32Offset &= ~META_MEM_GLOBAL_RANGE_BIT;
573 eError = FindMMUSegment(ui32Offset,
579 if (eError != PVRSRV_OK)
581 RGXErrorLogInit(hPrivate,
582 "ProcessLDRCommandStream: Addr 0x%x (size: %d) not found in any segment",
583 ui32Offset, ui32ByteCount);
587 /* Write to FW allocation only if available */
590 RGXMemSet(hPrivate, pvWriteAddr, 0, ui32ByteCount);
595 case RGX_META_LDR_CMD_CONFIG:
597 RGX_META_LDR_L2_DATA_BLK *psL2Block =
598 (RGX_META_LDR_L2_DATA_BLK*) (((IMG_UINT8 *) pbLDR) + psL1Data->aui32CmdData[0]);
599 RGX_META_LDR_CFG_BLK *psConfigCommand = (RGX_META_LDR_CFG_BLK*) psL2Block->aui32BlockData;
600 IMG_UINT32 ui32L2BlockSize = psL2Block->ui16Length - 6 /* L2 Tag length and checksum */;
601 IMG_UINT32 ui32CurrBlockSize = 0;
603 while (ui32L2BlockSize)
605 switch (psConfigCommand->ui32Type)
607 case RGX_META_LDR_CFG_PAUSE:
608 case RGX_META_LDR_CFG_READ:
610 ui32CurrBlockSize = 8;
611 return PVRSRV_ERROR_INIT_FAILURE;
613 case RGX_META_LDR_CFG_WRITE:
615 IMG_UINT32 ui32RegisterOffset = psConfigCommand->aui32BlockData[0];
616 IMG_UINT32 ui32RegisterValue = psConfigCommand->aui32BlockData[1];
618 /* Only write to bootloader if we got a valid
619 * pointer to the FW code allocation
623 /* Do register write */
624 *pui32BootConf++ = ui32RegisterOffset;
625 *pui32BootConf++ = ui32RegisterValue;
628 RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
629 ui32RegisterOffset, ui32RegisterValue);
631 ui32CurrBlockSize = 12;
634 case RGX_META_LDR_CFG_MEMSET:
635 case RGX_META_LDR_CFG_MEMCHECK:
637 ui32CurrBlockSize = 20;
638 return PVRSRV_ERROR_INIT_FAILURE;
642 return PVRSRV_ERROR_INIT_FAILURE;
645 ui32L2BlockSize -= ui32CurrBlockSize;
646 psConfigCommand = (RGX_META_LDR_CFG_BLK*) (((IMG_UINT8*) psConfigCommand) + ui32CurrBlockSize);
653 return PVRSRV_ERROR_INIT_FAILURE;
659 if (psL1Data->ui32Next == 0xFFFFFFFF)
665 psL1Data = (RGX_META_LDR_L1_DATA_BLK*) (((IMG_UINT8 *) pbLDR) + psL1Data->ui32Next);
669 *ppui32BootConf = pui32BootConf;
671 RGXCommentLogInit(hPrivate, "**********************************************");
672 RGXCommentLogInit(hPrivate, "************** End Loader Parsing ************");
673 RGXCommentLogInit(hPrivate, "**********************************************");
677 #endif /* RGX_FEATURE_META */
679 #if defined(RGX_FEATURE_MIPS) || defined(SUPPORT_KERNEL_SRVINIT)
681 *******************************************************************************
683 @Function ProcessELFCommandStream
685 @Description Process the output of the Mips toolchain in the .ELF format
686 copying code and data sections into their final location
688 @Input hPrivate : Implementation specific data
689 @Input pbELF : Pointer to FW blob
690 @Input pvHostFWCodeAddr : Pointer to FW code
691 @Input pvHostFWDataAddr : Pointer to FW data
695 ******************************************************************************/
696 static PVRSRV_ERROR ProcessELFCommandStream(const void *hPrivate,
697 const IMG_BYTE *pbELF,
698 void *pvHostFWCodeAddr,
699 void *pvHostFWDataAddr)
701 IMG_UINT32 ui32Entry;
702 RGX_MIPS_ELF_HDR *psHeader = (RGX_MIPS_ELF_HDR *)pbELF;
703 RGX_MIPS_ELF_PROGRAM_HDR *psProgramHeader =
704 (RGX_MIPS_ELF_PROGRAM_HDR *)(pbELF + psHeader->ui32Ephoff);
707 for (ui32Entry = 0; ui32Entry < psHeader->ui32Ephnum; ui32Entry++, psProgramHeader++)
710 RGX_FW_SEGMENT_LIST sRGXFWSegList;
711 sRGXFWSegList.psRGXFWCodeSeg = asRGXMipsFWCodeSegments;
712 sRGXFWSegList.psRGXFWDataSeg = asRGXMipsFWDataSegments;
713 sRGXFWSegList.ui32CodeSegCount = RGXFW_MIPS_NUM_CODE_SEGMENTS;
714 sRGXFWSegList.ui32DataSegCount = RGXFW_MIPS_NUM_DATA_SEGMENTS;
716 /* Only consider loadable entries in the ELF segment table */
717 if (psProgramHeader->ui32Ptype != ELF_PT_LOAD) continue;
719 eError = FindMMUSegment(psProgramHeader->ui32Pvaddr,
725 if (eError != PVRSRV_OK)
727 RGXErrorLogInit(hPrivate,
728 "%s: Addr 0x%x (size: %d) not found in any segment",__func__,
729 psProgramHeader->ui32Pvaddr,
730 psProgramHeader->ui32Pfilesz);
734 /* Write to FW allocation only if available */
739 (IMG_PBYTE)(pbELF + psProgramHeader->ui32Poffset),
740 psProgramHeader->ui32Pfilesz);
743 (IMG_PBYTE)pvWriteAddr + psProgramHeader->ui32Pfilesz,
745 psProgramHeader->ui32Pmemsz - psProgramHeader->ui32Pfilesz);
751 #endif /* RGX_FEATURE_MIPS */
754 PVRSRV_ERROR RGXGetFWImageAllocSize(const void *hPrivate,
755 IMG_DEVMEM_SIZE_T *puiFWCodeAllocSize,
756 IMG_DEVMEM_SIZE_T *puiFWDataAllocSize,
757 IMG_DEVMEM_SIZE_T *puiFWCorememAllocSize)
759 IMG_UINT32 i, ui32NumCodeSegments = 0, ui32NumDataSegments = 0;
760 RGX_FW_SEGMENT *pasRGXFWCodeSegments = NULL, *pasRGXFWDataSegments = NULL;
762 #if defined(SUPPORT_KERNEL_SRVINIT)
763 IMG_BOOL bMIPS = RGXDeviceHasFeatureInit(hPrivate, RGX_FEATURE_MIPS_BIT_MASK);
764 #elif defined(RGX_FEATURE_MIPS)
765 IMG_BOOL bMIPS = IMG_TRUE;
767 IMG_BOOL bMIPS = IMG_FALSE;
770 #if defined(RGX_FEATURE_META) || defined(SUPPORT_KERNEL_SRVINIT)
773 pasRGXFWCodeSegments = asRGXMetaFWCodeSegments;
774 pasRGXFWDataSegments = asRGXMetaFWDataSegments;
775 ui32NumCodeSegments = RGXFW_META_NUM_CODE_SEGMENTS;
776 ui32NumDataSegments = RGXFW_META_NUM_DATA_SEGMENTS;
780 #if defined(RGX_FEATURE_MIPS) || defined(SUPPORT_KERNEL_SRVINIT)
783 pasRGXFWCodeSegments = asRGXMipsFWCodeSegments;
784 pasRGXFWDataSegments = asRGXMipsFWDataSegments;
785 ui32NumCodeSegments = RGXFW_MIPS_NUM_CODE_SEGMENTS;
786 ui32NumDataSegments = RGXFW_MIPS_NUM_DATA_SEGMENTS;
790 *puiFWCodeAllocSize = 0;
791 *puiFWDataAllocSize = 0;
792 *puiFWCorememAllocSize = 0;
794 /* Calculate how much memory the FW needs for its code and data segments */
796 for(i = 0; i < ui32NumCodeSegments; i++) {
797 *puiFWCodeAllocSize += ((pasRGXFWCodeSegments + i)->ui32SegAllocSize);
800 for(i = 0; i < ui32NumDataSegments; i++) {
801 *puiFWDataAllocSize += ((pasRGXFWDataSegments + i)->ui32SegAllocSize);
804 *puiFWCorememAllocSize = RGXGetFWCorememSize(hPrivate);
806 if (*puiFWCorememAllocSize != 0)
808 *puiFWCorememAllocSize = *puiFWCorememAllocSize - RGX_META_COREMEM_DATA_SIZE;
813 if ((*puiFWCodeAllocSize % RGXMIPSFW_PAGE_SIZE) != 0)
815 RGXErrorLogInit(hPrivate,
816 "%s: The MIPS FW code allocation is not"
817 " a multiple of the page size!", __func__);
818 return PVRSRV_ERROR_INIT_FAILURE;
821 if ((*puiFWDataAllocSize % RGXMIPSFW_PAGE_SIZE) != 0)
823 RGXErrorLogInit(hPrivate,
824 "%s: The MIPS FW data allocation is not"
825 " a multiple of the page size!", __func__);
826 return PVRSRV_ERROR_INIT_FAILURE;
834 PVRSRV_ERROR RGXProcessFWImage(const void *hPrivate,
835 const IMG_BYTE *pbRGXFirmware,
838 void *pvFWCorememCode,
839 IMG_DEV_VIRTADDR *psFWCodeDevVAddrBase,
840 IMG_DEV_VIRTADDR *psFWDataDevVAddrBase,
841 IMG_DEV_VIRTADDR *psFWCorememDevVAddrBase,
842 RGXFWIF_DEV_VIRTADDR *psFWCorememFWAddr,
843 RGXFWIF_DEV_VIRTADDR *psRGXFwInit,
844 IMG_UINT32 ui32NumThreads,
845 IMG_UINT32 ui32MainThreadID)
847 PVRSRV_ERROR eError = PVRSRV_OK;
849 #if defined(SUPPORT_KERNEL_SRVINIT)
850 IMG_BOOL bMIPS = RGXDeviceHasFeatureInit(hPrivate, RGX_FEATURE_MIPS_BIT_MASK);
851 #elif defined(RGX_FEATURE_MIPS)
852 IMG_BOOL bMIPS = IMG_TRUE;
854 IMG_BOOL bMIPS = IMG_FALSE;
857 #if defined(RGX_FEATURE_META) || defined(SUPPORT_KERNEL_SRVINIT)
860 IMG_UINT32 *pui32BootConf = NULL;
861 /* Skip bootloader configuration if a pointer to the FW code
862 * allocation is not available
866 /* This variable points to the bootloader code which is mostly
867 * a sequence of <register address,register value> pairs
869 pui32BootConf = ((IMG_UINT32*) pvFWCode) + RGXFW_BOOTLDR_CONF_OFFSET;
871 /* Slave port and JTAG accesses are privileged */
872 *pui32BootConf++ = META_CR_SYSC_JTAG_THREAD;
873 *pui32BootConf++ = META_CR_SYSC_JTAG_THREAD_PRIV_EN;
875 RGXFWConfigureSegMMU(hPrivate,
876 psFWCodeDevVAddrBase,
877 psFWDataDevVAddrBase,
881 /* Process FW image data stream */
882 eError = ProcessLDRCommandStream(hPrivate,
888 if (eError != PVRSRV_OK)
890 RGXErrorLogInit(hPrivate, "RGXProcessFWImage: Processing FW image failed (%d)", eError);
894 /* Skip bootloader configuration if a pointer to the FW code
895 * allocation is not available
899 if ((ui32NumThreads == 0) || (ui32NumThreads > 2) || (ui32MainThreadID >= 2))
901 RGXErrorLogInit(hPrivate,
902 "ProcessFWImage: Wrong Meta threads configuration, using one thread only");
905 ui32MainThreadID = 0;
908 RGXFWConfigureMetaCaches(hPrivate,
913 /* Signal the end of the conf sequence */
914 *pui32BootConf++ = 0x0;
915 *pui32BootConf++ = 0x0;
917 /* The FW main argv arguments start here */
918 *pui32BootConf++ = psRGXFwInit->ui32Addr;
920 if ((RGXGetFWCorememSize(hPrivate) != 0) && (psFWCorememFWAddr != NULL))
922 *pui32BootConf++ = psFWCorememFWAddr->ui32Addr;
926 *pui32BootConf++ = 0;
929 #if defined(SUPPORT_KERNEL_SRVINIT)
930 if (RGXDeviceHasFeatureInit(hPrivate, RGX_FEATURE_META_DMA_BIT_MASK))
931 #elif defined(RGX_FEATURE_META_DMA)
937 *pui32BootConf++ = (IMG_UINT32) (psFWCorememDevVAddrBase->uiAddr >> 32);
938 *pui32BootConf++ = (IMG_UINT32) psFWCorememDevVAddrBase->uiAddr;
942 *pui32BootConf++ = 0;
943 *pui32BootConf++ = 0;
950 #if defined(RGX_FEATURE_MIPS) || defined(SUPPORT_KERNEL_SRVINIT)
953 /* Process FW image data stream */
954 eError = ProcessELFCommandStream(hPrivate,
958 if (eError != PVRSRV_OK)
960 RGXErrorLogInit(hPrivate, "RGXProcessFWImage: Processing FW image failed (%d)", eError);
964 PVR_UNREFERENCED_PARAMETER(pvFWData); /* No need to touch the data segment in MIPS */
965 PVR_UNREFERENCED_PARAMETER(pvFWCorememCode); /* Coremem N/A in MIPS */
966 PVR_UNREFERENCED_PARAMETER(psFWCodeDevVAddrBase);
967 PVR_UNREFERENCED_PARAMETER(psFWDataDevVAddrBase);
968 PVR_UNREFERENCED_PARAMETER(psFWCorememDevVAddrBase);
969 PVR_UNREFERENCED_PARAMETER(psFWCorememFWAddr);
970 PVR_UNREFERENCED_PARAMETER(psRGXFwInit);
971 PVR_UNREFERENCED_PARAMETER(ui32NumThreads);
972 PVR_UNREFERENCED_PARAMETER(ui32MainThreadID);