RK3368 GPU: Rogue N Init.
[firefly-linux-kernel-4.4.55.git] / drivers / staging / imgtec / rogue / rgxfwimageutils.c
1 /*************************************************************************/ /*!
2 @File
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
7
8 The contents of this file are subject to the MIT license as set out below.
9
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:
16
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
19
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.
23
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.
31
32 This License is also included in this distribution in the file called
33 "MIT-COPYING".
34
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 */ /**************************************************************************/
43
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"
51
52
53 /************************************************************************
54 * FW Segments configuration
55 ************************************************************************/
56 typedef struct _RGX_FW_SEGMENT_
57 {
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;
63 } RGX_FW_SEGMENT;
64
65 typedef struct _RGX_FW_SEGMENT_LIST_
66 {
67         RGX_FW_SEGMENT *psRGXFWCodeSeg;
68         RGX_FW_SEGMENT *psRGXFWDataSeg;
69         IMG_UINT32 ui32CodeSegCount;
70         IMG_UINT32 ui32DataSegCount;
71 } RGX_FW_SEGMENT_LIST;
72
73
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 */
78 };
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"},
82 };
83 #define RGXFW_META_NUM_CODE_SEGMENTS  (sizeof(asRGXMetaFWCodeSegments)/sizeof(asRGXMetaFWCodeSegments[0]))
84 #define RGXFW_META_NUM_DATA_SEGMENTS  (sizeof(asRGXMetaFWDataSegments)/sizeof(asRGXMetaFWDataSegments[0]))
85 #endif
86
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"},
93 };
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"},
99 };
100
101 #define RGXFW_MIPS_NUM_CODE_SEGMENTS  (sizeof(asRGXMipsFWCodeSegments)/sizeof(asRGXMipsFWCodeSegments[0]))
102 #define RGXFW_MIPS_NUM_DATA_SEGMENTS  (sizeof(asRGXMipsFWDataSegments)/sizeof(asRGXMipsFWDataSegments[0]))
103 #endif
104
105 /*!
106 *******************************************************************************
107
108  @Function      FindMMUSegment
109
110  @Description   Given a 32 bit FW address attempt to find the corresponding
111                 pointer to FW allocation
112
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
117
118  @Return        PVRSRV_ERROR
119
120 ******************************************************************************/
121 static PVRSRV_ERROR FindMMUSegment(IMG_UINT32 ui32OffsetIn,
122                                    void *pvHostFWCodeAddr,
123                                    void *pvHostFWDataAddr,
124                                    void **uiHostAddrOut,
125                                    RGX_FW_SEGMENT_LIST *psRGXFWSegList)
126 {
127         RGX_FW_SEGMENT *psSegArr;
128         IMG_UINT32 i;
129
130         psSegArr = psRGXFWSegList->psRGXFWCodeSeg;
131         for (i = 0; i < psRGXFWSegList->ui32CodeSegCount; i++)
132         {
133                 if ((ui32OffsetIn >= psSegArr[i].ui32SegStartAddr) &&
134                     (ui32OffsetIn < (psSegArr[i].ui32SegStartAddr + psSegArr[i].ui32SegAllocSize)))
135                 {
136                         *uiHostAddrOut = pvHostFWCodeAddr;
137                         goto found;
138                 }
139         }
140
141         psSegArr = psRGXFWSegList->psRGXFWDataSeg;
142         for (i = 0; i < psRGXFWSegList->ui32DataSegCount; i++)
143         {
144                 if ((ui32OffsetIn >= psSegArr[i].ui32SegStartAddr) &&
145                    (ui32OffsetIn < (psSegArr[i].ui32SegStartAddr + psSegArr[i].ui32SegAllocSize)))
146                 {
147                         *uiHostAddrOut = pvHostFWDataAddr;
148                         goto found;
149                 }
150         }
151
152         return PVRSRV_ERROR_INIT_FAILURE;
153
154 found:
155         /* Direct Mem write to mapped memory */
156         ui32OffsetIn -= psSegArr[i].ui32SegStartAddr;
157         ui32OffsetIn += psSegArr[i].ui32FWMemOffset;
158
159         /* Add offset to pointer to FW allocation only if
160          * that allocation is available
161          */
162         if (*uiHostAddrOut)
163         {
164                 *(IMG_UINT8 **)uiHostAddrOut += ui32OffsetIn;
165         }
166
167         return PVRSRV_OK;
168 }
169
170 #if defined(RGX_FEATURE_META)  || defined(SUPPORT_KERNEL_SRVINIT)
171
172 /*!
173 *******************************************************************************
174
175  @Function      RGXFWConfigureSegID
176
177  @Description   Configures a single segment of the Segment MMU
178                 (base, limit and out_addr)
179
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
187
188  @Return        void
189
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)
198 {
199         IMG_UINT32 *pui32BootConf = *ppui32BootConf;
200         IMG_UINT32 ui32SegOutAddr0  = ui64SegOutAddr & 0x00000000FFFFFFFFUL;
201         IMG_UINT32 ui32SegOutAddr1  = (ui64SegOutAddr >> 32) & 0x00000000FFFFFFFFUL;
202
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 */
207         ui32LimitOff -= 1;
208
209         RGXCommentLogInit(hPrivate,
210                           "* FW %s - seg%d: meta_addr = 0x%08x, devv_addr = 0x%llx, limit = 0x%x",
211                           pszName, ui32SegID,
212                           ui32SegBase, (unsigned long long)ui64SegOutAddr,
213                           ui32LimitOff);
214
215         ui32SegBase |= RGXFW_SEGMMU_ALLTHRS_WRITEABLE;
216
217         *pui32BootConf++ = META_CR_MMCU_SEGMENTn_BASE(ui32SegID);
218         *pui32BootConf++ = ui32SegBase;
219
220         *pui32BootConf++ = META_CR_MMCU_SEGMENTn_LIMIT(ui32SegID);
221         *pui32BootConf++ = ui32LimitOff;
222
223         *pui32BootConf++ = META_CR_MMCU_SEGMENTn_OUTA0(ui32SegID);
224         *pui32BootConf++ = ui32SegOutAddr0;
225
226         *pui32BootConf++ = META_CR_MMCU_SEGMENTn_OUTA1(ui32SegID);
227         *pui32BootConf++ = ui32SegOutAddr1;
228
229         *ppui32BootConf = pui32BootConf;
230 }
231
232 /*!
233 *******************************************************************************
234
235  @Function      RGXFWConfigureSegMMU
236
237  @Description   Configures META's Segment MMU
238
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
243
244  @Return        void
245
246 ******************************************************************************/
247 static void RGXFWConfigureSegMMU(const void       *hPrivate,
248                                  IMG_DEV_VIRTADDR *psFWCodeDevVAddrBase,
249                                  IMG_DEV_VIRTADDR *psFWDataDevVAddrBase,
250                                  IMG_UINT32       **ppui32BootConf)
251 {
252         IMG_UINT64 ui64SegOutAddr;
253         IMG_UINT32 i;
254
255         PVR_UNREFERENCED_PARAMETER(psFWCodeDevVAddrBase);
256
257         /* Configure Segment MMU */
258         RGXCommentLogInit(hPrivate, "********** FW configure Segment MMU **********");
259
260         for (i = 0; i < RGXFW_META_NUM_DATA_SEGMENTS ; i++)
261         {
262                 ui64SegOutAddr = (psFWDataDevVAddrBase->uiAddr |
263                                   RGXFW_SEGMMU_OUTADDR_TOP(META_MMU_CONTEXT_MAPPING, RGXFW_SEGMMU_META_DM_ID)) +
264                                   asRGXMetaFWDataSegments[i].ui32FWMemOffset;
265
266                 RGXFWConfigureSegID(hPrivate,
267                                     ui64SegOutAddr,
268                                     asRGXMetaFWDataSegments[i].ui32SegStartAddr,
269                                     asRGXMetaFWDataSegments[i].ui32SegAllocSize,
270                                     asRGXMetaFWDataSegments[i].ui32SegId,
271                                     asRGXMetaFWDataSegments[i].pszSegName,
272                                     ppui32BootConf); /*write the sequence to the bootldr */
273         }
274 }
275
276 /*!
277 *******************************************************************************
278
279  @Function      RGXFWConfigureMetaCaches
280
281  @Description   Configure and enable the Meta instruction and data caches
282
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
288
289  @Return        void
290
291 ******************************************************************************/
292 static void RGXFWConfigureMetaCaches(const void *hPrivate,
293                                      IMG_UINT32 ui32NumThreads,
294                                      IMG_UINT32 ui32MainThreadID,
295                                      IMG_UINT32 **ppui32BootConf)
296 {
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;
302
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)
315
316         RGXCommentLogInit(hPrivate, "********** Meta caches configuration *********");
317
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;
322
323         if (ui32NumThreads == 1)
324         {
325                 if (ui32MainThreadID == 0)
326                 {
327                         ui32DCacheT0 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE;
328                         ui32ICacheT0 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE;
329                 }
330                 else
331                 {
332                         ui32DCacheT1 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE;
333                         ui32ICacheT1 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE;
334                 }
335         }
336         else
337         {
338                 ui32DCacheT0 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_HALF_CACHE;
339                 ui32ICacheT0 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_HALF_CACHE;
340
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;
345         }
346
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;
351
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);
355
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;
365
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);
374
375         /* Enable data cache hits */
376         *pui32BootConf++ = META_CR_MMCU_DCACHE_CTRL;
377         *pui32BootConf++ = META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN;
378
379         RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
380                           META_CR_MMCU_DCACHE_CTRL,
381                           META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN);
382
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;
392
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);
401
402         /* Enable instruction cache hits */
403         *pui32BootConf++ = META_CR_MMCU_ICACHE_CTRL;
404         *pui32BootConf++ = META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN;
405
406         RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
407                           META_CR_MMCU_ICACHE_CTRL,
408                           META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN);
409
410         *pui32BootConf++ = 0x040000C0;
411         *pui32BootConf++ = 0;
412
413         RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
414                           0x040000C0, 0);
415
416         *ppui32BootConf = pui32BootConf;
417 }
418
419 /*!
420 *******************************************************************************
421
422  @Function      ProcessLDRCommandStream
423
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
427
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
434
435  @Return        PVRSRV_ERROR
436
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)
444 {
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);
448
449         IMG_UINT32 *pui32BootConf  = *ppui32BootConf;
450         IMG_UINT32 ui32CorememSize = RGXGetFWCorememSize(hPrivate);
451         IMG_UINT32 ui32CorememCodeStartAddr = 0xFFFFFFFF;
452
453         RGXCommentLogInit(hPrivate, "**********************************************");
454         RGXCommentLogInit(hPrivate, "************** Begin LDR Parsing *************");
455         RGXCommentLogInit(hPrivate, "**********************************************");
456
457         while (psL1Data != NULL)
458         {
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;
464
465                 if (RGX_META_LDR_BLK_IS_COMMENT(psL1Data->ui16Cmd))
466                 {
467                         /* Don't process comment blocks */
468                         goto NextBlock;
469                 }
470
471                 switch (psL1Data->ui16Cmd & RGX_META_LDR_CMD_MASK)
472                 {
473                         case RGX_META_LDR_CMD_LOADMEM:
474                         {
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 */;
479                                 void *pvWriteAddr;
480                                 PVRSRV_ERROR eError;
481
482                                 if (RGX_META_IS_COREMEM_CODE(ui32Offset, ui32CorememSize))
483                                 {
484                                         if (ui32Offset < ui32CorememCodeStartAddr)
485                                         {
486                                                 if (ui32CorememCodeStartAddr == 0xFFFFFFFF)
487                                                 {
488                                                         /* Take the first coremem code address as the coremem code start address */
489                                                         ui32CorememCodeStartAddr = ui32Offset;
490
491                                                         /* Also check that there is a valid allocation for the coremem code */
492                                                         if (pvHostFWCorememAddr == NULL)
493                                                         {
494                                                                 RGXErrorLogInit(hPrivate,
495                                                                                 "ProcessLDRCommandStream: Coremem code found"
496                                                                                 "but no coremem allocation available!");
497
498                                                                 return PVRSRV_ERROR_INIT_FAILURE;
499                                                         }
500                                                 }
501                                                 else
502                                                 {
503                                                         /* The coremem addresses should be ordered in the LDR command stream */
504                                                         return PVRSRV_ERROR_INIT_FAILURE;
505                                                 }
506                                         }
507
508                                         /* Copy coremem data to buffer. The FW copies it to the actual coremem */
509                                         ui32Offset -= ui32CorememCodeStartAddr;
510
511                                         RGXMemCopy(hPrivate,
512                                                    (void*)((IMG_UINT8 *)pvHostFWCorememAddr + ui32Offset),
513                                                    psL2Block->aui32BlockData,
514                                                    ui32DataSize);
515                                 }
516                                 else
517                                 {
518                                         /* Global range is aliased to local range */
519                                         ui32Offset &= ~META_MEM_GLOBAL_RANGE_BIT;
520
521                                         eError = FindMMUSegment(ui32Offset,
522                                                                 pvHostFWCodeAddr,
523                                                                 pvHostFWDataAddr,
524                                                                 &pvWriteAddr,
525                                                                 &sRGXFWSegList);
526
527                                         if (eError != PVRSRV_OK)
528                                         {
529                                                 RGXErrorLogInit(hPrivate,
530                                                                 "ProcessLDRCommandStream: Addr 0x%x (size: %d) not found in any segment",
531                                                                 ui32Offset, ui32DataSize);
532                                                 return eError;
533                                         }
534
535                                         /* Write to FW allocation only if available */
536                                         if (pvWriteAddr)
537                                         {
538                                                 RGXMemCopy(hPrivate,
539                                                            pvWriteAddr,
540                                                            psL2Block->aui32BlockData,
541                                                            ui32DataSize);
542                                         }
543                                 }
544
545                                 break;
546                         }
547                         case RGX_META_LDR_CMD_LOADCORE:
548                         case RGX_META_LDR_CMD_LOADMMREG:
549                         {
550                                 return PVRSRV_ERROR_INIT_FAILURE;
551                         }
552                         case RGX_META_LDR_CMD_START_THREADS:
553                         {
554                                 /* Don't process this block */
555                                 break;
556                         }
557                         case RGX_META_LDR_CMD_ZEROMEM:
558                         {
559                                 IMG_UINT32 ui32Offset = psL1Data->aui32CmdData[0];
560                                 IMG_UINT32 ui32ByteCount = psL1Data->aui32CmdData[1];
561                                 void *pvWriteAddr;
562                                 PVRSRV_ERROR  eError;
563
564                                 if (RGX_META_IS_COREMEM_DATA(ui32Offset, ui32CorememSize))
565                                 {
566                                         /* cannot zero coremem directly */
567                                         break;
568                                 }
569
570                                 /* Global range is aliased to local range */
571                                 ui32Offset &= ~META_MEM_GLOBAL_RANGE_BIT;
572
573                                 eError = FindMMUSegment(ui32Offset,
574                                                         pvHostFWCodeAddr,
575                                                         pvHostFWDataAddr,
576                                                         &pvWriteAddr,
577                                                         &sRGXFWSegList);
578
579                                 if (eError != PVRSRV_OK)
580                                 {
581                                         RGXErrorLogInit(hPrivate,
582                                                         "ProcessLDRCommandStream: Addr 0x%x (size: %d) not found in any segment",
583                                                         ui32Offset, ui32ByteCount);
584                                         return eError;
585                                 }
586
587                                 /* Write to FW allocation only if available */
588                                 if (pvWriteAddr)
589                                 {
590                                         RGXMemSet(hPrivate, pvWriteAddr, 0, ui32ByteCount);
591                                 }
592
593                                 break;
594                         }
595                         case RGX_META_LDR_CMD_CONFIG:
596                         {
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;
602
603                                 while (ui32L2BlockSize)
604                                 {
605                                         switch (psConfigCommand->ui32Type)
606                                         {
607                                                 case RGX_META_LDR_CFG_PAUSE:
608                                                 case RGX_META_LDR_CFG_READ:
609                                                 {
610                                                         ui32CurrBlockSize = 8;
611                                                         return PVRSRV_ERROR_INIT_FAILURE;
612                                                 }
613                                                 case RGX_META_LDR_CFG_WRITE:
614                                                 {
615                                                         IMG_UINT32 ui32RegisterOffset = psConfigCommand->aui32BlockData[0];
616                                                         IMG_UINT32 ui32RegisterValue  = psConfigCommand->aui32BlockData[1];
617
618                                                         /* Only write to bootloader if we got a valid
619                                                          * pointer to the FW code allocation
620                                                          */
621                                                         if (pui32BootConf)
622                                                         {
623                                                                 /* Do register write */
624                                                                 *pui32BootConf++ = ui32RegisterOffset;
625                                                                 *pui32BootConf++ = ui32RegisterValue;
626                                                         }
627
628                                                         RGXCommentLogInit(hPrivate, "Meta SP: [0x%08x] = 0x%08x",
629                                                                           ui32RegisterOffset, ui32RegisterValue);
630
631                                                         ui32CurrBlockSize = 12;
632                                                         break;
633                                                 }
634                                                 case RGX_META_LDR_CFG_MEMSET:
635                                                 case RGX_META_LDR_CFG_MEMCHECK:
636                                                 {
637                                                         ui32CurrBlockSize = 20;
638                                                         return PVRSRV_ERROR_INIT_FAILURE;
639                                                 }
640                                                 default:
641                                                 {
642                                                         return PVRSRV_ERROR_INIT_FAILURE;
643                                                 }
644                                         }
645                                         ui32L2BlockSize -= ui32CurrBlockSize;
646                                         psConfigCommand = (RGX_META_LDR_CFG_BLK*) (((IMG_UINT8*) psConfigCommand) + ui32CurrBlockSize);
647                                 }
648
649                                 break;
650                         }
651                         default:
652                         {
653                                 return PVRSRV_ERROR_INIT_FAILURE;
654                         }
655                 }
656
657 NextBlock:
658
659                 if (psL1Data->ui32Next == 0xFFFFFFFF)
660                 {
661                         psL1Data = NULL;
662                 }
663                 else
664                 {
665                         psL1Data = (RGX_META_LDR_L1_DATA_BLK*) (((IMG_UINT8 *) pbLDR) + psL1Data->ui32Next);
666                 }
667         }
668
669         *ppui32BootConf = pui32BootConf;
670
671         RGXCommentLogInit(hPrivate, "**********************************************");
672         RGXCommentLogInit(hPrivate, "************** End Loader Parsing ************");
673         RGXCommentLogInit(hPrivate, "**********************************************");
674
675         return PVRSRV_OK;
676 }
677 #endif /* RGX_FEATURE_META */
678
679 #if defined(RGX_FEATURE_MIPS) || defined(SUPPORT_KERNEL_SRVINIT)
680 /*!
681 *******************************************************************************
682
683  @Function      ProcessELFCommandStream
684
685  @Description   Process the output of the Mips toolchain in the .ELF format
686                 copying code and data sections into their final location
687
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
692
693  @Return        PVRSRV_ERROR
694
695 ******************************************************************************/
696 static PVRSRV_ERROR ProcessELFCommandStream(const void *hPrivate,
697                                             const IMG_BYTE *pbELF,
698                                             void *pvHostFWCodeAddr,
699                                             void *pvHostFWDataAddr)
700 {
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);
705         PVRSRV_ERROR eError;
706
707         for (ui32Entry = 0; ui32Entry < psHeader->ui32Ephnum; ui32Entry++, psProgramHeader++)
708         {
709                 void *pvWriteAddr;
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;
715
716                 /* Only consider loadable entries in the ELF segment table */
717                 if (psProgramHeader->ui32Ptype != ELF_PT_LOAD) continue;
718
719                 eError = FindMMUSegment(psProgramHeader->ui32Pvaddr,
720                                         pvHostFWCodeAddr,
721                                         pvHostFWDataAddr,
722                                         &pvWriteAddr,
723                                         &sRGXFWSegList);
724
725                 if (eError != PVRSRV_OK)
726                 {
727                         RGXErrorLogInit(hPrivate,
728                                         "%s: Addr 0x%x (size: %d) not found in any segment",__func__,
729                                         psProgramHeader->ui32Pvaddr,
730                                         psProgramHeader->ui32Pfilesz);
731                         return eError;
732                 }
733
734                 /* Write to FW allocation only if available */
735                 if (pvWriteAddr)
736                 {
737                         RGXMemCopy(hPrivate,
738                                    pvWriteAddr,
739                                    (IMG_PBYTE)(pbELF + psProgramHeader->ui32Poffset),
740                                    psProgramHeader->ui32Pfilesz);
741
742                         RGXMemSet(hPrivate,
743                                   (IMG_PBYTE)pvWriteAddr + psProgramHeader->ui32Pfilesz,
744                                   0,
745                                   psProgramHeader->ui32Pmemsz - psProgramHeader->ui32Pfilesz);
746                 }
747         }
748
749         return PVRSRV_OK;
750 }
751 #endif /* RGX_FEATURE_MIPS */
752
753
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)
758 {
759         IMG_UINT32 i, ui32NumCodeSegments = 0, ui32NumDataSegments = 0;
760         RGX_FW_SEGMENT *pasRGXFWCodeSegments = NULL, *pasRGXFWDataSegments = NULL;
761
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;
766 #else
767         IMG_BOOL bMIPS = IMG_FALSE;
768 #endif
769
770 #if defined(RGX_FEATURE_META) || defined(SUPPORT_KERNEL_SRVINIT)
771         if (!bMIPS)
772         {
773                 pasRGXFWCodeSegments = asRGXMetaFWCodeSegments;
774                 pasRGXFWDataSegments = asRGXMetaFWDataSegments;
775                 ui32NumCodeSegments = RGXFW_META_NUM_CODE_SEGMENTS;
776                 ui32NumDataSegments = RGXFW_META_NUM_DATA_SEGMENTS;
777         }
778 #endif
779
780 #if defined(RGX_FEATURE_MIPS) || defined(SUPPORT_KERNEL_SRVINIT)
781         if (bMIPS)
782         {
783                 pasRGXFWCodeSegments = asRGXMipsFWCodeSegments;
784                 pasRGXFWDataSegments = asRGXMipsFWDataSegments;
785                 ui32NumCodeSegments = RGXFW_MIPS_NUM_CODE_SEGMENTS;
786                 ui32NumDataSegments = RGXFW_MIPS_NUM_DATA_SEGMENTS;
787         }
788 #endif
789
790         *puiFWCodeAllocSize = 0;
791         *puiFWDataAllocSize = 0;
792         *puiFWCorememAllocSize = 0;
793
794         /* Calculate how much memory the FW needs for its code and data segments */
795
796         for(i = 0; i < ui32NumCodeSegments; i++) {
797                 *puiFWCodeAllocSize += ((pasRGXFWCodeSegments + i)->ui32SegAllocSize);
798         }
799
800         for(i = 0; i < ui32NumDataSegments; i++) {
801                 *puiFWDataAllocSize += ((pasRGXFWDataSegments + i)->ui32SegAllocSize);
802         }
803
804         *puiFWCorememAllocSize = RGXGetFWCorememSize(hPrivate);
805
806         if (*puiFWCorememAllocSize != 0)
807         {
808                 *puiFWCorememAllocSize = *puiFWCorememAllocSize - RGX_META_COREMEM_DATA_SIZE;
809         }
810
811         if (bMIPS)
812         {
813                 if ((*puiFWCodeAllocSize % RGXMIPSFW_PAGE_SIZE) != 0)
814                 {
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;
819                 }
820
821                 if ((*puiFWDataAllocSize % RGXMIPSFW_PAGE_SIZE) != 0)
822                 {
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;
827                 }
828         }
829
830         return PVRSRV_OK;
831 }
832
833
834 PVRSRV_ERROR RGXProcessFWImage(const void           *hPrivate,
835                                const IMG_BYTE       *pbRGXFirmware,
836                                void                 *pvFWCode,
837                                void                 *pvFWData,
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)
846 {
847         PVRSRV_ERROR eError = PVRSRV_OK;
848
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;
853 #else
854         IMG_BOOL bMIPS = IMG_FALSE;
855 #endif
856
857 #if defined(RGX_FEATURE_META) || defined(SUPPORT_KERNEL_SRVINIT)
858         if (!bMIPS)
859         {
860                 IMG_UINT32 *pui32BootConf = NULL;
861                 /* Skip bootloader configuration if a pointer to the FW code
862                  * allocation is not available
863                  */
864                 if (pvFWCode)
865                 {
866                         /* This variable points to the bootloader code which is mostly
867                          * a sequence of <register address,register value> pairs
868                          */
869                         pui32BootConf = ((IMG_UINT32*) pvFWCode) + RGXFW_BOOTLDR_CONF_OFFSET;
870
871                         /* Slave port and JTAG accesses are privileged */
872                         *pui32BootConf++ = META_CR_SYSC_JTAG_THREAD;
873                         *pui32BootConf++ = META_CR_SYSC_JTAG_THREAD_PRIV_EN;
874
875                         RGXFWConfigureSegMMU(hPrivate,
876                                              psFWCodeDevVAddrBase,
877                                              psFWDataDevVAddrBase,
878                                              &pui32BootConf);
879                 }
880         
881                 /* Process FW image data stream */
882                 eError = ProcessLDRCommandStream(hPrivate,
883                                                  pbRGXFirmware,
884                                                  pvFWCode,
885                                                  pvFWData,
886                                                  pvFWCorememCode,
887                                                  &pui32BootConf);
888                 if (eError != PVRSRV_OK)
889                 {
890                         RGXErrorLogInit(hPrivate, "RGXProcessFWImage: Processing FW image failed (%d)", eError);
891                         return eError;
892                 }
893
894                 /* Skip bootloader configuration if a pointer to the FW code
895                  * allocation is not available
896                  */
897                 if (pvFWCode)
898                 {
899                         if ((ui32NumThreads == 0) || (ui32NumThreads > 2) || (ui32MainThreadID >= 2))
900                         {
901                                 RGXErrorLogInit(hPrivate,
902                                                 "ProcessFWImage: Wrong Meta threads configuration, using one thread only");
903
904                                 ui32NumThreads = 1;
905                                 ui32MainThreadID = 0;
906                         }
907
908                         RGXFWConfigureMetaCaches(hPrivate,
909                                                  ui32NumThreads,
910                                                  ui32MainThreadID,
911                                                  &pui32BootConf);
912
913                         /* Signal the end of the conf sequence */
914                         *pui32BootConf++ = 0x0;
915                         *pui32BootConf++ = 0x0;
916
917                         /* The FW main argv arguments start here */
918                         *pui32BootConf++ = psRGXFwInit->ui32Addr;
919
920                         if ((RGXGetFWCorememSize(hPrivate) != 0) && (psFWCorememFWAddr != NULL))
921                         {
922                                 *pui32BootConf++ = psFWCorememFWAddr->ui32Addr;
923                         }
924                         else
925                         {
926                                 *pui32BootConf++ = 0;
927                         }
928
929 #if defined(SUPPORT_KERNEL_SRVINIT)
930                         if (RGXDeviceHasFeatureInit(hPrivate, RGX_FEATURE_META_DMA_BIT_MASK))
931 #elif defined(RGX_FEATURE_META_DMA)
932                         if (IMG_TRUE)
933 #else
934                         if (IMG_FALSE)
935 #endif
936                         {
937                                 *pui32BootConf++ = (IMG_UINT32) (psFWCorememDevVAddrBase->uiAddr >> 32);
938                                 *pui32BootConf++ = (IMG_UINT32) psFWCorememDevVAddrBase->uiAddr;
939                         }
940                         else
941                         {
942                                 *pui32BootConf++ = 0;
943                                 *pui32BootConf++ = 0;
944                         }
945
946                 }
947         }
948 #endif
949
950 #if defined(RGX_FEATURE_MIPS) || defined(SUPPORT_KERNEL_SRVINIT)
951         if (bMIPS)
952         {
953                 /* Process FW image data stream */
954                 eError = ProcessELFCommandStream(hPrivate,
955                                                  pbRGXFirmware,
956                                                  pvFWCode,
957                                                  pvFWData);
958                 if (eError != PVRSRV_OK)
959                 {
960                         RGXErrorLogInit(hPrivate, "RGXProcessFWImage: Processing FW image failed (%d)", eError);
961                         return eError;
962                 }
963
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);
973         }
974 #endif
975
976         return eError;
977 }
978