RK3368 GPU: Rogue N Init.
[firefly-linux-kernel-4.4.55.git] / drivers / staging / imgtec / rogue / rgxpower.c
1 /*************************************************************************/ /*!
2 @File
3 @Title          Device specific power routines
4 @Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @Description    Device specific functions
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 #include <stddef.h>
45 #include "rgxpower.h"
46 #include "rgxinit.h"
47 #include "rgx_fwif_km.h"
48 #include "rgxfwutils.h"
49 #include "pdump_km.h"
50 #include "pvr_debug.h"
51 #include "osfunc.h"
52 #include "rgxdebug.h"
53 #include "devicemem.h"
54 #include "devicemem_pdump.h"
55 #include "rgxtimecorr.h"
56 #include "devicemem_utils.h"
57 #include "htbserver.h"
58 #include "rgxstartstop.h"
59 #include "sync.h"
60 #include "lists.h"
61
62 #if defined(PVRSRV_ENABLE_PROCESS_STATS)
63 #include "process_stats.h"
64 #endif
65 #if defined(PVR_DVFS)
66 #include "pvr_dvfs_device.h"
67 #endif
68
69 static PVRSRV_ERROR RGXFWNotifyHostTimeout(PVRSRV_RGXDEV_INFO *psDevInfo)
70 {
71         PVRSRV_ERROR     eError;
72         RGXFWIF_KCCB_CMD sCmd;
73         RGXFWIF_RUNTIME_CFG     *psRuntimeCfg = psDevInfo->psRGXFWIfRuntimeCfg;
74
75         /* Send the Timeout notification to the FW */
76         /* Extending the APM Latency Change command structure with the notification boolean for 
77            backwards compatibility reasons */
78         sCmd.eCmdType = RGXFWIF_KCCB_CMD_POW;
79         sCmd.uCmdData.sPowData.ePowType = RGXFWIF_POW_APM_LATENCY_CHANGE;
80         sCmd.uCmdData.sPowData.uPoweReqData.ui32ActivePMLatencyms = psRuntimeCfg->ui32ActivePMLatencyms;
81         sCmd.uCmdData.sPowData.bNotifyTimeout = IMG_TRUE;
82
83         /* Ensure the new APM latency is written to memory before requesting the FW to read it */
84         OSMemoryBarrier();
85
86         eError = RGXSendCommand(psDevInfo,
87                                 RGXFWIF_DM_GP,
88                                 &sCmd,
89                                 sizeof(sCmd),
90                                 PDUMP_FLAGS_NONE);
91
92         return eError;
93 }
94
95 static void _RGXUpdateGPUUtilStats(PVRSRV_RGXDEV_INFO *psDevInfo)
96 {
97         RGXFWIF_GPU_UTIL_FWCB *psUtilFWCb;
98         IMG_UINT64 *paui64StatsCounters;
99         IMG_UINT64 ui64LastPeriod;
100         IMG_UINT64 ui64LastState;
101         IMG_UINT64 ui64LastTime;
102         IMG_UINT64 ui64TimeNow;
103
104         psUtilFWCb = psDevInfo->psRGXFWIfGpuUtilFWCb;
105         paui64StatsCounters = &psUtilFWCb->aui64StatsCounters[0];
106
107         OSLockAcquire(psDevInfo->hGPUUtilLock);
108
109         ui64TimeNow = RGXFWIF_GPU_UTIL_GET_TIME(OSClockns64());
110
111         /* Update counters to account for the time since the last update */
112         ui64LastState  = RGXFWIF_GPU_UTIL_GET_STATE(psUtilFWCb->ui64LastWord);
113         ui64LastTime   = RGXFWIF_GPU_UTIL_GET_TIME(psUtilFWCb->ui64LastWord);
114         ui64LastPeriod = RGXFWIF_GPU_UTIL_GET_PERIOD(ui64TimeNow, ui64LastTime);
115         paui64StatsCounters[ui64LastState] += ui64LastPeriod;
116
117         /* Update state and time of the latest update */
118         psUtilFWCb->ui64LastWord = RGXFWIF_GPU_UTIL_MAKE_WORD(ui64TimeNow, ui64LastState);
119
120         OSLockRelease(psDevInfo->hGPUUtilLock);
121 }
122
123
124 static INLINE PVRSRV_ERROR RGXDoStop(PVRSRV_DEVICE_NODE *psDeviceNode)
125 {
126         PVRSRV_ERROR eError;
127
128 #if defined(SUPPORT_TRUSTED_DEVICE) && !defined(NO_HARDWARE)
129         PVRSRV_DEVICE_CONFIG *psDevConfig = psDeviceNode->psDevConfig;
130
131         if (psDevConfig->pfnTDRGXStop == NULL)
132         {
133                 PVR_DPF((PVR_DBG_ERROR, "RGXPrePowerState: TDRGXStop not implemented!"));
134                 return PVRSRV_ERROR_NOT_IMPLEMENTED;
135         }
136
137         eError = psDevConfig->pfnTDRGXStop(psDevConfig->hSysData);
138 #else
139         PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
140
141         eError = RGXStop(&psDevInfo->sPowerParams);
142 #endif
143
144         return eError;
145 }
146
147 /*
148         RGXPrePowerState
149 */
150 PVRSRV_ERROR RGXPrePowerState (IMG_HANDLE                               hDevHandle,
151                                                            PVRSRV_DEV_POWER_STATE       eNewPowerState,
152                                                            PVRSRV_DEV_POWER_STATE       eCurrentPowerState,
153                                                            IMG_BOOL                                     bForced)
154 {
155         PVRSRV_ERROR eError = PVRSRV_OK;
156
157         if ((eNewPowerState != eCurrentPowerState) &&
158                 (eNewPowerState != PVRSRV_DEV_POWER_STATE_ON))
159         {
160                 PVRSRV_DEVICE_NODE      *psDeviceNode = hDevHandle;
161                 PVRSRV_RGXDEV_INFO      *psDevInfo = psDeviceNode->pvDevice;
162                 RGXFWIF_KCCB_CMD        sPowCmd;
163                 RGXFWIF_TRACEBUF        *psFWTraceBuf = psDevInfo->psRGXFWIfTraceBuf;
164
165                 /* Send the Power off request to the FW */
166                 sPowCmd.eCmdType = RGXFWIF_KCCB_CMD_POW;
167                 sPowCmd.uCmdData.sPowData.ePowType = RGXFWIF_POW_OFF_REQ;
168                 sPowCmd.uCmdData.sPowData.uPoweReqData.bForced = bForced;
169
170                 eError = SyncPrimSet(psDevInfo->psPowSyncPrim, 0);
171                 if (eError != PVRSRV_OK)
172                 {
173                         PVR_DPF((PVR_DBG_ERROR,"%s: Failed to set Power sync prim",
174                                 __FUNCTION__));
175                         return eError;
176                 }
177
178                 eError = RGXSendCommand(psDevInfo,
179                                         RGXFWIF_DM_GP,
180                                         &sPowCmd,
181                                         sizeof(sPowCmd),
182                                         PDUMP_FLAGS_NONE);
183                 if (eError != PVRSRV_OK)
184                 {
185                         PVR_DPF((PVR_DBG_ERROR,"RGXPrePowerState: Failed to send Power off request"));
186                         return eError;
187                 }
188
189                 /* Wait for the firmware to complete processing. It cannot use PVRSRVWaitForValueKM as it relies 
190                    on the EventObject which is signalled in this MISR */
191                 eError = PVRSRVPollForValueKM(psDevInfo->psPowSyncPrim->pui32LinAddr, 0x1, 0xFFFFFFFF);
192
193                 /* Check the Power state after the answer */
194                 if (eError == PVRSRV_OK)        
195                 {
196                         /* Finally, de-initialise some registers. */
197                         if (psFWTraceBuf->ePowState == RGXFWIF_POW_OFF)
198                         {
199 #if !defined(NO_HARDWARE)
200                                 IMG_UINT32 ui32TID;
201                                 for (ui32TID = 0; ui32TID < RGXFW_THREAD_NUM; ui32TID++)
202                                 {
203                                         /* Wait for the pending META/MIPS to host interrupts to come back. */
204                                         eError = PVRSRVPollForValueKM(&psDevInfo->aui32SampleIRQCount[ui32TID],
205                                                                                           psFWTraceBuf->aui32InterruptCount[ui32TID],
206                                                                                           0xffffffff);
207
208                                         if (eError != PVRSRV_OK)
209                                         {
210                                                 PVR_DPF((PVR_DBG_ERROR, \
211                                                                 "RGXPrePowerState: Wait for pending interrupts failed. Thread %u: Host:%u, FW: %u", \
212                                                                 ui32TID, \
213                                                                 psDevInfo->aui32SampleIRQCount[ui32TID], \
214                                                                 psFWTraceBuf->aui32InterruptCount[ui32TID]));
215
216                                                 RGX_WaitForInterruptsTimeout(psDevInfo);
217                                                 break;
218                                         }
219                                 }
220 #endif /* NO_HARDWARE */
221
222                                 /* Update GPU frequency and timer correlation related data */
223                                 RGXGPUFreqCalibratePrePowerOff(psDeviceNode);
224
225                                 /* Update GPU state counters */
226                                 _RGXUpdateGPUUtilStats(psDevInfo);
227
228 #if defined(PVR_DVFS)
229                                 eError = SuspendDVFS();
230                                 if (eError != PVRSRV_OK)
231                                 {
232                                         PVR_DPF((PVR_DBG_ERROR,"RGXPrePowerState: Failed to suspend DVFS"));
233                                         return eError;
234                                 }
235 #endif
236
237                                 psDevInfo->bRGXPowered = IMG_FALSE;
238
239                                 eError = RGXDoStop(psDeviceNode);
240                                 if (eError != PVRSRV_OK)
241                                 {
242                                         PVR_DPF((PVR_DBG_ERROR, "RGXPrePowerState: RGXDoStop failed (%s)",
243                                                  PVRSRVGetErrorStringKM(eError)));
244                                         eError = PVRSRV_ERROR_DEVICE_POWER_CHANGE_FAILURE;
245                                 }
246                         }
247                         else
248                         {
249                                 /* the sync was updated bu the pow state isn't off -> the FW denied the transition */
250                                 eError = PVRSRV_ERROR_DEVICE_POWER_CHANGE_DENIED;
251
252                                 if (bForced)
253                                 {       /* It is an error for a forced request to be denied */
254                                         PVR_DPF((PVR_DBG_ERROR,"RGXPrePowerState: Failure to power off during a forced power off. FW: %d", psFWTraceBuf->ePowState));
255                                 }
256                         }
257                 }
258                 else if (eError == PVRSRV_ERROR_TIMEOUT)
259                 {
260                         /* timeout waiting for the FW to ack the request: return timeout */
261                         PVR_DPF((PVR_DBG_WARNING,"RGXPrePowerState: Timeout waiting for powoff ack from the FW"));
262                 }
263                 else
264                 {
265                         PVR_DPF((PVR_DBG_ERROR,"RGXPrePowerState: Error waiting for powoff ack from the FW (%s)", PVRSRVGetErrorStringKM(eError)));
266                         eError = PVRSRV_ERROR_DEVICE_POWER_CHANGE_FAILURE;
267                 }
268
269         }
270
271         return eError;
272 }
273
274
275 static INLINE PVRSRV_ERROR RGXDoStart(PVRSRV_DEVICE_NODE *psDeviceNode)
276 {
277         PVRSRV_ERROR eError;
278
279 #if defined(SUPPORT_TRUSTED_DEVICE) && !defined(NO_HARDWARE)
280         PVRSRV_DEVICE_CONFIG *psDevConfig = psDeviceNode->psDevConfig;
281
282         if (psDevConfig->pfnTDRGXStart == NULL)
283         {
284                 PVR_DPF((PVR_DBG_ERROR, "RGXPostPowerState: TDRGXStart not implemented!"));
285                 return PVRSRV_ERROR_NOT_IMPLEMENTED;
286         }
287
288         eError = psDevConfig->pfnTDRGXStart(psDevConfig->hSysData);
289 #else
290         PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
291
292         eError = RGXStart(&psDevInfo->sPowerParams);
293 #endif
294
295         return eError;
296 }
297
298 /*
299         RGXPostPowerState
300 */
301 PVRSRV_ERROR RGXPostPowerState (IMG_HANDLE                              hDevHandle,
302                                                                 PVRSRV_DEV_POWER_STATE  eNewPowerState,
303                                                                 PVRSRV_DEV_POWER_STATE  eCurrentPowerState,
304                                                                 IMG_BOOL                                bForced)
305 {
306         if ((eNewPowerState != eCurrentPowerState) &&
307                 (eCurrentPowerState != PVRSRV_DEV_POWER_STATE_ON))
308         {
309                 PVRSRV_ERROR             eError;
310                 PVRSRV_DEVICE_NODE       *psDeviceNode = hDevHandle;
311                 PVRSRV_RGXDEV_INFO       *psDevInfo = psDeviceNode->pvDevice;
312                 RGXFWIF_INIT *psRGXFWInit;
313
314                 if (eCurrentPowerState == PVRSRV_DEV_POWER_STATE_OFF)
315                 {
316                         /* Update GPU frequency and timer correlation related data */
317                         RGXGPUFreqCalibratePostPowerOn(psDeviceNode);
318
319                         /* Update GPU state counters */
320                         _RGXUpdateGPUUtilStats(psDevInfo);
321
322                         eError = RGXDoStart(psDeviceNode);
323                         if (eError != PVRSRV_OK)
324                         {
325                                 PVR_DPF((PVR_DBG_ERROR,"RGXPostPowerState: RGXDoStart failed"));
326                                 return eError;
327                         }
328
329                         OSMemoryBarrier();
330
331 #if defined(SUPPORT_EXTRA_METASP_DEBUG)
332                         eError = ValidateFWImageWithSP(psDevInfo);
333                         if (eError != PVRSRV_OK) return eError;
334 #endif
335
336                         eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc,
337                                                           (void **)&psRGXFWInit);
338                         if (eError != PVRSRV_OK)
339                         {
340                                 PVR_DPF((PVR_DBG_ERROR,
341                                          "RGXPostPowerState: Failed to acquire kernel fw if ctl (%u)",
342                                          eError));
343                                 return eError;
344                         }
345
346                         /*
347                          * Check whether the FW has started by polling on bFirmwareStarted flag
348                          */
349                         if (PVRSRVPollForValueKM((IMG_UINT32 *)&psRGXFWInit->bFirmwareStarted,
350                                                  IMG_TRUE,
351                                                  0xFFFFFFFF) != PVRSRV_OK)
352                         {
353                                 PVR_DPF((PVR_DBG_ERROR, "RGXPostPowerState: Polling for 'FW started' flag failed."));
354                                 eError = PVRSRV_ERROR_TIMEOUT;
355
356                                 /*
357                                  * When bFirmwareStarted fails some info maybe gained by doing the following
358                                  * debug dump but unfortunately it could lockup some cores or cause other power
359                                  * lock issues. The code is placed here to provide a possible example approach
360                                  * when all other ideas have been tried.
361                                  */
362                                 /*{
363                                         PVRSRV_POWER_DEV *psPowerDev = psDeviceNode->psPowerDev;
364                                 
365                                         if (psPowerDev)
366                                         {
367                                                 PVRSRV_DEV_POWER_STATE  eOldPowerState = psPowerDev->eCurrentPowerState;
368
369                                                 PVRSRVPowerUnlock(psDeviceNode);
370                                                 psPowerDev->eCurrentPowerState = PVRSRV_DEV_POWER_STATE_ON;
371                                                 RGXDumpDebugInfo(NULL, psDeviceNode->pvDevice);
372                                                 psPowerDev->eCurrentPowerState = eOldPowerState;
373                                                 PVRSRVPowerLock(psDeviceNode);
374                                         }
375                                 }*/
376                                 
377                                 DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc);
378                                 return eError;
379                         }
380
381 #if defined(PDUMP)
382                         PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "Wait for the Firmware to start.");
383                         eError = DevmemPDumpDevmemPol32(psDevInfo->psRGXFWIfInitMemDesc,
384                                                         offsetof(RGXFWIF_INIT, bFirmwareStarted),
385                                                         IMG_TRUE,
386                                                         0xFFFFFFFFU,
387                                                         PDUMP_POLL_OPERATOR_EQUAL,
388                                                         PDUMP_FLAGS_CONTINUOUS);
389
390                         if (eError != PVRSRV_OK)
391                         {
392                                 PVR_DPF((PVR_DBG_ERROR,
393                                          "RGXPostPowerState: problem pdumping POL for psRGXFWIfInitMemDesc (%d)",
394                                          eError));
395                                 DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc);
396                                 return eError;
397                         }
398 #endif
399
400 #if defined(PVRSRV_ENABLE_PROCESS_STATS)
401                         SetFirmwareStartTime(psRGXFWInit->ui32FirmwareStartedTimeStamp);
402 #endif
403
404                         HTBSyncPartitionMarker(psRGXFWInit->ui32MarkerVal);
405
406                         DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc);
407
408                         psDevInfo->bRGXPowered = IMG_TRUE;
409
410 #if defined(PVR_DVFS)
411                         eError = ResumeDVFS();
412                         if (eError != PVRSRV_OK)
413                         {
414                                 PVR_DPF((PVR_DBG_ERROR,"RGXPostPowerState: Failed to resume DVFS"));
415                                 return eError;
416                         }
417 #endif
418                 }
419         }
420
421         PDUMPCOMMENT("RGXPostPowerState: Current state: %d, New state: %d", eCurrentPowerState, eNewPowerState);
422
423         return PVRSRV_OK;
424 }
425
426
427 /*
428         RGXPreClockSpeedChange
429 */
430 PVRSRV_ERROR RGXPreClockSpeedChange (IMG_HANDLE                         hDevHandle,
431                                                                          PVRSRV_DEV_POWER_STATE eCurrentPowerState)
432 {
433         PVRSRV_ERROR            eError = PVRSRV_OK;
434         PVRSRV_DEVICE_NODE      *psDeviceNode = hDevHandle;
435         PVRSRV_RGXDEV_INFO      *psDevInfo = psDeviceNode->pvDevice;
436         RGX_DATA                        *psRGXData = (RGX_DATA*)psDeviceNode->psDevConfig->hDevData;
437         RGXFWIF_TRACEBUF        *psFWTraceBuf = psDevInfo->psRGXFWIfTraceBuf;
438
439         PVR_UNREFERENCED_PARAMETER(psRGXData);
440
441         PVR_DPF((PVR_DBG_MESSAGE,"RGXPreClockSpeedChange: RGX clock speed was %uHz",
442                         psRGXData->psRGXTimingInfo->ui32CoreClockSpeed));
443
444     if ((eCurrentPowerState != PVRSRV_DEV_POWER_STATE_OFF)
445                 && (psFWTraceBuf->ePowState != RGXFWIF_POW_OFF))
446         {
447                 /* Update GPU frequency and timer correlation related data */
448                 RGXGPUFreqCalibratePreClockSpeedChange(psDeviceNode);
449         }
450
451         return eError;
452 }
453
454
455 /*
456         RGXPostClockSpeedChange
457 */
458 PVRSRV_ERROR RGXPostClockSpeedChange (IMG_HANDLE                                hDevHandle,
459                                                                           PVRSRV_DEV_POWER_STATE        eCurrentPowerState)
460 {
461         PVRSRV_DEVICE_NODE      *psDeviceNode = hDevHandle;
462         PVRSRV_RGXDEV_INFO      *psDevInfo = psDeviceNode->pvDevice;
463         RGX_DATA                        *psRGXData = (RGX_DATA*)psDeviceNode->psDevConfig->hDevData;
464         PVRSRV_ERROR            eError = PVRSRV_OK;
465         RGXFWIF_TRACEBUF        *psFWTraceBuf = psDevInfo->psRGXFWIfTraceBuf;
466         IMG_UINT32              ui32NewClockSpeed = psRGXData->psRGXTimingInfo->ui32CoreClockSpeed;
467
468         /* Update runtime configuration with the new value */
469         psDevInfo->psRGXFWIfRuntimeCfg->ui32CoreClockSpeed = ui32NewClockSpeed;
470
471     if ((eCurrentPowerState != PVRSRV_DEV_POWER_STATE_OFF) 
472                 && (psFWTraceBuf->ePowState != RGXFWIF_POW_OFF))
473         {
474                 RGXFWIF_KCCB_CMD        sCOREClkSpeedChangeCmd;
475
476                 RGXGPUFreqCalibratePostClockSpeedChange(psDeviceNode, ui32NewClockSpeed);
477
478                 sCOREClkSpeedChangeCmd.eCmdType = RGXFWIF_KCCB_CMD_CORECLKSPEEDCHANGE;
479                 sCOREClkSpeedChangeCmd.uCmdData.sCORECLKSPEEDCHANGEData.ui32NewClockSpeed = ui32NewClockSpeed;
480
481                 /* Ensure the new clock speed is written to memory before requesting the FW to read it */
482                 OSMemoryBarrier();
483
484                 PDUMPCOMMENT("Scheduling CORE clock speed change command");
485
486                 PDUMPPOWCMDSTART();
487                 eError = RGXSendCommand(psDeviceNode->pvDevice,
488                                            RGXFWIF_DM_GP,
489                                            &sCOREClkSpeedChangeCmd,
490                                            sizeof(sCOREClkSpeedChangeCmd),
491                                            PDUMP_FLAGS_NONE);
492                 PDUMPPOWCMDEND();
493
494                 if (eError != PVRSRV_OK)
495                 {
496                         PDUMPCOMMENT("Scheduling CORE clock speed change command failed");
497                         PVR_DPF((PVR_DBG_ERROR, "RGXPostClockSpeedChange: Scheduling KCCB command failed. Error:%u", eError));
498                         return eError;
499                 }
500  
501                 PVR_DPF((PVR_DBG_MESSAGE,"RGXPostClockSpeedChange: RGX clock speed changed to %uHz",
502                                 psRGXData->psRGXTimingInfo->ui32CoreClockSpeed));
503         }
504
505         return eError;
506 }
507
508
509 /*!
510 ******************************************************************************
511
512  @Function      RGXDustCountChange
513
514  @Description
515
516         Does change of number of DUSTs
517
518  @Input    hDevHandle : RGX Device Node
519  @Input    ui32NumberOfDusts : Number of DUSTs to make transition to
520
521  @Return   PVRSRV_ERROR :
522
523 ******************************************************************************/
524 PVRSRV_ERROR RGXDustCountChange(IMG_HANDLE                              hDevHandle,
525                                                                 IMG_UINT32                              ui32NumberOfDusts)
526 {
527
528         PVRSRV_DEVICE_NODE      *psDeviceNode = hDevHandle;
529         PVRSRV_RGXDEV_INFO      *psDevInfo = psDeviceNode->pvDevice;
530         PVRSRV_ERROR            eError;
531         RGXFWIF_KCCB_CMD        sDustCountChange;
532         IMG_UINT32                      ui32MaxAvailableDusts = MAX(1, (psDevInfo->sDevFeatureCfg.ui32NumClusters/2));
533         RGXFWIF_RUNTIME_CFG *psRuntimeCfg = psDevInfo->psRGXFWIfRuntimeCfg;
534
535         if (ui32NumberOfDusts > ui32MaxAvailableDusts)
536         {
537                 eError = PVRSRV_ERROR_INVALID_PARAMS;
538                 PVR_DPF((PVR_DBG_ERROR,
539                                 "RGXDustCountChange: Invalid number of DUSTs (%u) while expecting value within <0,%u>. Error:%u",
540                                 ui32NumberOfDusts,
541                                 ui32MaxAvailableDusts,
542                                 eError));
543                 return eError;
544         }
545
546         #if defined(FIX_HW_BRN_59042)
547         if (ui32NumberOfDusts < ui32MaxAvailableDusts && (ui32NumberOfDusts & 0x1))
548         {
549                 PVR_DPF((PVR_DBG_ERROR,
550                                 "RGXDustCountChange: Invalid number of DUSTs (%u) due to HW restriction. Allowed values are :-",
551                                 ui32NumberOfDusts));
552                 switch (ui32MaxAvailableDusts)
553                 {
554                         case 2: PVR_DPF((PVR_DBG_ERROR, "0, 2")); break;
555                         case 3: PVR_DPF((PVR_DBG_ERROR, "0, 2, 3")); break;
556                         case 4: PVR_DPF((PVR_DBG_ERROR, "0, 2, 4")); break;
557                         case 5: PVR_DPF((PVR_DBG_ERROR, "0, 2, 4, 5")); break;
558                         case 6: PVR_DPF((PVR_DBG_ERROR, "0, 2, 4, 6")); break;
559                         default: break;
560                 }
561                 return PVRSRV_ERROR_INVALID_PARAMS;
562         }
563         #endif
564
565         psRuntimeCfg->ui32DefaultDustsNumInit = ui32NumberOfDusts;
566
567         #if !defined(NO_HARDWARE)
568         {
569                 RGXFWIF_TRACEBUF        *psFWTraceBuf = psDevInfo->psRGXFWIfTraceBuf;
570
571                 if (psFWTraceBuf->ePowState == RGXFWIF_POW_OFF)
572                 {
573                         return PVRSRV_OK;
574                 }
575
576                 if (psFWTraceBuf->ePowState != RGXFWIF_POW_FORCED_IDLE)
577                 {
578                         eError = PVRSRV_ERROR_DEVICE_POWER_CHANGE_DENIED;
579                         PVR_DPF((PVR_DBG_ERROR,"RGXDustCountChange: Attempt to change dust count when not IDLE"));
580                         return eError;
581                 }
582         }
583         #endif
584
585         eError = SyncPrimSet(psDevInfo->psPowSyncPrim, 0);
586         if (eError != PVRSRV_OK)
587         {
588                 PVR_DPF((PVR_DBG_ERROR,"%s: Failed to set Power sync prim",
589                         __FUNCTION__));
590                 return eError;
591         }
592
593         sDustCountChange.eCmdType = RGXFWIF_KCCB_CMD_POW;
594         sDustCountChange.uCmdData.sPowData.ePowType = RGXFWIF_POW_NUMDUST_CHANGE;
595         sDustCountChange.uCmdData.sPowData.uPoweReqData.ui32NumOfDusts = ui32NumberOfDusts;
596
597         PDUMPCOMMENT("Scheduling command to change Dust Count to %u", ui32NumberOfDusts);
598         eError = RGXSendCommand(psDeviceNode->pvDevice,
599                                 RGXFWIF_DM_GP,
600                                 &sDustCountChange,
601                                 sizeof(sDustCountChange),
602                                 PDUMP_FLAGS_NONE);
603
604         if (eError != PVRSRV_OK)
605         {
606                 PDUMPCOMMENT("Scheduling command to change Dust Count failed. Error:%u", eError);
607                 PVR_DPF((PVR_DBG_ERROR, "RGXDustCountChange: Scheduling KCCB to change Dust Count failed. Error:%u", eError));
608                 return eError;
609         }
610
611         /* Wait for the firmware to answer. */
612         eError = PVRSRVPollForValueKM(psDevInfo->psPowSyncPrim->pui32LinAddr, 0x1, 0xFFFFFFFF);
613
614         if (eError != PVRSRV_OK)
615         {
616                 PVR_DPF((PVR_DBG_ERROR,"RGXDustCountChange: Timeout waiting for idle request"));
617                 return eError;
618         }
619
620 #if defined(PDUMP)
621         PDUMPCOMMENT("RGXDustCountChange: Poll for Kernel SyncPrim [0x%p] on DM %d ", psDevInfo->psPowSyncPrim->pui32LinAddr, RGXFWIF_DM_GP);
622
623         SyncPrimPDumpPol(psDevInfo->psPowSyncPrim,
624                                         1,
625                                         0xffffffff,
626                                         PDUMP_POLL_OPERATOR_EQUAL,
627                                         0);
628 #endif
629
630         return PVRSRV_OK;
631 }
632 /*
633  @Function      RGXAPMLatencyChange
634 */
635 PVRSRV_ERROR RGXAPMLatencyChange(IMG_HANDLE                             hDevHandle,
636                                 IMG_UINT32                              ui32ActivePMLatencyms,
637                                 IMG_BOOL                                bActivePMLatencyPersistant)
638 {
639
640         PVRSRV_DEVICE_NODE      *psDeviceNode = hDevHandle;
641         PVRSRV_RGXDEV_INFO      *psDevInfo = psDeviceNode->pvDevice;
642         PVRSRV_ERROR            eError;
643         RGXFWIF_RUNTIME_CFG     *psRuntimeCfg = psDevInfo->psRGXFWIfRuntimeCfg;
644         PVRSRV_DEV_POWER_STATE  ePowerState;
645
646         eError = PVRSRVPowerLock(psDeviceNode);
647         if (eError != PVRSRV_OK)
648         {
649                 PVR_DPF((PVR_DBG_ERROR,"RGXAPMLatencyChange: Failed to acquire power lock"));
650                 return eError;
651         }
652
653         /* Update runtime configuration with the new values */
654         psRuntimeCfg->ui32ActivePMLatencyms = ui32ActivePMLatencyms;
655         psRuntimeCfg->bActivePMLatencyPersistant = bActivePMLatencyPersistant;
656
657         eError = PVRSRVGetDevicePowerState(psDeviceNode, &ePowerState);
658
659         if ((eError == PVRSRV_OK) && (ePowerState != PVRSRV_DEV_POWER_STATE_OFF))
660         {
661                 RGXFWIF_KCCB_CMD        sActivePMLatencyChange;
662                 sActivePMLatencyChange.eCmdType = RGXFWIF_KCCB_CMD_POW;
663                 sActivePMLatencyChange.uCmdData.sPowData.bNotifyTimeout = IMG_FALSE;
664                 sActivePMLatencyChange.uCmdData.sPowData.ePowType = RGXFWIF_POW_APM_LATENCY_CHANGE;
665                 sActivePMLatencyChange.uCmdData.sPowData.uPoweReqData.ui32ActivePMLatencyms = ui32ActivePMLatencyms;
666
667                 /* Ensure the new APM latency is written to memory before requesting the FW to read it */
668                 OSMemoryBarrier();
669
670                 PDUMPCOMMENT("Scheduling command to change APM latency to %u", ui32ActivePMLatencyms);
671                 eError = RGXSendCommand(psDeviceNode->pvDevice,
672                                         RGXFWIF_DM_GP,
673                                         &sActivePMLatencyChange,
674                                         sizeof(sActivePMLatencyChange),
675                                         PDUMP_FLAGS_NONE);
676
677                 if (eError != PVRSRV_OK)
678                 {
679                         PDUMPCOMMENT("Scheduling command to change APM latency failed. Error:%u", eError);
680                         PVR_DPF((PVR_DBG_ERROR, "RGXAPMLatencyChange: Scheduling KCCB to change APM latency failed. Error:%u", eError));
681                         return eError;
682                 }
683         }
684
685         PVRSRVPowerUnlock(psDeviceNode);
686
687         return PVRSRV_OK;
688 }
689
690 /*
691         RGXActivePowerRequest
692 */
693 PVRSRV_ERROR RGXActivePowerRequest(IMG_HANDLE hDevHandle)
694 {
695         PVRSRV_ERROR eError = PVRSRV_OK;
696         PVRSRV_DEVICE_NODE      *psDeviceNode = hDevHandle;
697
698         PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
699         RGXFWIF_TRACEBUF *psFWTraceBuf = psDevInfo->psRGXFWIfTraceBuf;
700
701         OSAcquireBridgeLock();
702         /* NOTE: If this function were to wait for event object attempt should be
703            made to prevent releasing bridge lock during sleep. Bridge lock should
704            be held during sleep. */
705
706         /* Powerlock to avoid further requests from racing with the FW hand-shake from now on
707            (previous kicks to this point are detected by the FW) */
708         eError = PVRSRVPowerLock(psDeviceNode);
709         if(eError != PVRSRV_OK)
710         {
711                 PVR_DPF((PVR_DBG_ERROR,
712                                  "%s: Failed to acquire PowerLock (device: %p, error: %s)",
713                                  __func__, psDeviceNode, PVRSRVGetErrorStringKM(eError)));
714                 goto _RGXActivePowerRequest_PowerLock_failed;
715         }
716
717         /* Check again for IDLE once we have the power lock */
718         if (psFWTraceBuf->ePowState == RGXFWIF_POW_IDLE)
719         {
720
721                 psDevInfo->ui32ActivePMReqTotal++;
722
723 #if defined(PVRSRV_ENABLE_PROCESS_STATS)
724         SetFirmwareHandshakeIdleTime(RGXReadHWTimerReg(psDevInfo)-psFWTraceBuf->ui64StartIdleTime);
725 #endif
726
727                 PDUMPPOWCMDSTART();
728                 eError = PVRSRVSetDevicePowerStateKM(psDeviceNode,
729                                                                                          PVRSRV_DEV_POWER_STATE_OFF,
730                                                                                          IMG_FALSE); /* forced */
731                 PDUMPPOWCMDEND();
732
733                 if (eError == PVRSRV_OK)
734                 {
735                         psDevInfo->ui32ActivePMReqOk++;
736                 }
737                 else if (eError == PVRSRV_ERROR_DEVICE_POWER_CHANGE_DENIED)
738                 {
739                         psDevInfo->ui32ActivePMReqDenied++;
740                 }
741
742         }
743
744         PVRSRVPowerUnlock(psDeviceNode);
745
746 _RGXActivePowerRequest_PowerLock_failed:
747         OSReleaseBridgeLock();
748
749         return eError;
750
751 }
752 /*
753         RGXForcedIdleRequest
754 */
755
756 #define RGX_FORCED_IDLE_RETRY_COUNT 10
757
758 PVRSRV_ERROR RGXForcedIdleRequest(IMG_HANDLE hDevHandle, IMG_BOOL bDeviceOffPermitted)
759 {
760         PVRSRV_DEVICE_NODE      *psDeviceNode = hDevHandle;
761         PVRSRV_RGXDEV_INFO      *psDevInfo = psDeviceNode->pvDevice;
762         RGXFWIF_KCCB_CMD        sPowCmd;
763         PVRSRV_ERROR            eError;
764         IMG_UINT32              ui32RetryCount = 0;
765
766 #if !defined(NO_HARDWARE)
767         RGXFWIF_TRACEBUF        *psFWTraceBuf = psDevInfo->psRGXFWIfTraceBuf;
768
769         /* Firmware already forced idle */
770         if (psFWTraceBuf->ePowState == RGXFWIF_POW_FORCED_IDLE)
771         {
772                 return PVRSRV_OK;
773         }
774
775         /* Firmware is not powered. Sometimes this is permitted, for instance we were forcing idle to power down. */
776         if (psFWTraceBuf->ePowState == RGXFWIF_POW_OFF)
777         {
778                 return (bDeviceOffPermitted) ? PVRSRV_OK : PVRSRV_ERROR_DEVICE_IDLE_REQUEST_DENIED;
779         }
780 #endif
781
782         eError = SyncPrimSet(psDevInfo->psPowSyncPrim, 0);
783         if (eError != PVRSRV_OK)
784         {
785                 PVR_DPF((PVR_DBG_ERROR,"%s: Failed to set Power sync prim",
786                         __FUNCTION__));
787                 return eError;
788         }
789         sPowCmd.eCmdType = RGXFWIF_KCCB_CMD_POW;
790         sPowCmd.uCmdData.sPowData.ePowType = RGXFWIF_POW_FORCED_IDLE_REQ;
791         sPowCmd.uCmdData.sPowData.uPoweReqData.bCancelForcedIdle = IMG_FALSE;
792
793         PDUMPCOMMENT("RGXForcedIdleRequest: Sending forced idle command");
794
795         /* Send one forced IDLE command to GP */
796         eError = RGXSendCommand(psDevInfo,
797                         RGXFWIF_DM_GP,
798                         &sPowCmd,
799                         sizeof(sPowCmd),
800                         PDUMP_FLAGS_NONE);
801
802         if (eError != PVRSRV_OK)
803         {
804                 PVR_DPF((PVR_DBG_ERROR,"RGXForcedIdleRequest: Failed to send idle request"));
805                 return eError;
806         }
807
808         /* Wait for GPU to finish current workload */
809         do {
810                 eError = PVRSRVPollForValueKM(psDevInfo->psPowSyncPrim->pui32LinAddr, 0x1, 0xFFFFFFFF);
811                 if ((eError == PVRSRV_OK) || (ui32RetryCount == RGX_FORCED_IDLE_RETRY_COUNT))
812                 {
813                         break;
814                 }
815                 ui32RetryCount++;
816                 PVR_DPF((PVR_DBG_WARNING,"RGXForcedIdleRequest: Request timeout. Retry %d of %d", ui32RetryCount, RGX_FORCED_IDLE_RETRY_COUNT));
817         } while (IMG_TRUE);
818
819         if (eError != PVRSRV_OK)
820         {
821                 RGXFWNotifyHostTimeout(psDevInfo);
822                 PVR_DPF((PVR_DBG_ERROR,"RGXForcedIdleRequest: Idle request failed. Firmware potentially left in forced idle state"));
823                 return eError;
824         }
825
826 #if defined(PDUMP)
827         PDUMPCOMMENT("RGXForcedIdleRequest: Poll for Kernel SyncPrim [0x%p] on DM %d ", psDevInfo->psPowSyncPrim->pui32LinAddr, RGXFWIF_DM_GP);
828
829         SyncPrimPDumpPol(psDevInfo->psPowSyncPrim,
830                                         1,
831                                         0xffffffff,
832                                         PDUMP_POLL_OPERATOR_EQUAL,
833                                         0);
834 #endif
835
836 #if !defined(NO_HARDWARE)
837         /* Check the firmware state for idleness */
838         if (psFWTraceBuf->ePowState != RGXFWIF_POW_FORCED_IDLE)
839         {
840                 PVR_DPF((PVR_DBG_ERROR,"RGXForcedIdleRequest: Failed to force IDLE"));
841
842                 return PVRSRV_ERROR_DEVICE_IDLE_REQUEST_DENIED;
843         }
844 #endif
845
846         return PVRSRV_OK;
847 }
848
849 /*
850         RGXCancelForcedIdleRequest
851 */
852 PVRSRV_ERROR RGXCancelForcedIdleRequest(IMG_HANDLE hDevHandle)
853 {
854         PVRSRV_DEVICE_NODE      *psDeviceNode = hDevHandle;
855         PVRSRV_RGXDEV_INFO      *psDevInfo = psDeviceNode->pvDevice;
856         RGXFWIF_KCCB_CMD        sPowCmd;
857         PVRSRV_ERROR            eError = PVRSRV_OK;
858
859         eError = SyncPrimSet(psDevInfo->psPowSyncPrim, 0);
860         if (eError != PVRSRV_OK)
861         {
862                 PVR_DPF((PVR_DBG_ERROR,"%s: Failed to set Power sync prim",
863                         __FUNCTION__));
864                 goto ErrorExit;
865         }
866
867         /* Send the IDLE request to the FW */
868         sPowCmd.eCmdType = RGXFWIF_KCCB_CMD_POW;
869         sPowCmd.uCmdData.sPowData.ePowType = RGXFWIF_POW_FORCED_IDLE_REQ;
870         sPowCmd.uCmdData.sPowData.uPoweReqData.bCancelForcedIdle = IMG_TRUE;
871
872         PDUMPCOMMENT("RGXForcedIdleRequest: Sending cancel forced idle command");
873
874         /* Send cancel forced IDLE command to GP */
875         eError = RGXSendCommand(psDevInfo,
876                         RGXFWIF_DM_GP,
877                         &sPowCmd,
878                         sizeof(sPowCmd),
879                         PDUMP_FLAGS_NONE);
880
881         if (eError != PVRSRV_OK)
882         {
883                 PDUMPCOMMENT("RGXCancelForcedIdleRequest: Failed to send cancel IDLE request for DM%d", RGXFWIF_DM_GP);
884                 goto ErrorExit;
885         }
886
887         /* Wait for the firmware to answer. */
888         eError = PVRSRVPollForValueKM(psDevInfo->psPowSyncPrim->pui32LinAddr, 1, 0xFFFFFFFF);
889
890         if (eError != PVRSRV_OK)
891         {
892                 PVR_DPF((PVR_DBG_ERROR,"RGXCancelForcedIdleRequest: Timeout waiting for cancel idle request"));
893                 goto ErrorExit;
894         }
895
896 #if defined(PDUMP)
897         PDUMPCOMMENT("RGXCancelForcedIdleRequest: Poll for Kernel SyncPrim [0x%p] on DM %d ", psDevInfo->psPowSyncPrim->pui32LinAddr, RGXFWIF_DM_GP);
898
899         SyncPrimPDumpPol(psDevInfo->psPowSyncPrim,
900                                         1,
901                                         0xffffffff,
902                                         PDUMP_POLL_OPERATOR_EQUAL,
903                                         0);
904 #endif
905
906         return eError;
907
908 ErrorExit:
909         PVR_DPF((PVR_DBG_ERROR,"RGXCancelForcedIdleRequest: Firmware potentially left in forced idle state"));
910         return eError;
911 }
912
913 /*!
914 ******************************************************************************
915
916  @Function      PVRSRVGetNextDustCount
917
918  @Description
919
920         Calculate a sequence of dust counts to achieve full transition coverage.
921         We increment two counts of dusts and switch up and down between them.
922         It does contain a few redundant transitions. If two dust exist, the
923         output transitions should be as follows.
924
925         0->1, 0<-1, 0->2, 0<-2, (0->1)
926         1->1, 1->2, 1<-2, (1->2)
927         2->2, (2->0),
928         0->0. Repeat.
929
930         Redundant transitions in brackets.
931
932  @Input         psDustReqState : Counter state used to calculate next dust count
933  @Input         ui32DustCount : Number of dusts in the core
934
935  @Return        PVRSRV_ERROR
936
937 ******************************************************************************/
938 IMG_UINT32 RGXGetNextDustCount(RGX_DUST_STATE *psDustReqState, IMG_UINT32 ui32DustCount)
939 {
940         if (psDustReqState->bToggle)
941         {
942                 psDustReqState->ui32DustCount2++;
943         }
944
945         if (psDustReqState->ui32DustCount2 > ui32DustCount)
946         {
947                 psDustReqState->ui32DustCount1++;
948                 psDustReqState->ui32DustCount2 = psDustReqState->ui32DustCount1;
949         }
950
951         if (psDustReqState->ui32DustCount1 > ui32DustCount)
952         {
953                 psDustReqState->ui32DustCount1 = 0;
954                 psDustReqState->ui32DustCount2 = 0;
955         }
956
957         psDustReqState->bToggle = !psDustReqState->bToggle;
958
959         return (psDustReqState->bToggle) ? psDustReqState->ui32DustCount1 : psDustReqState->ui32DustCount2;
960 }
961
962 /******************************************************************************
963  End of file (rgxpower.c)
964 ******************************************************************************/