1 /*************************************************************************/ /*!
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
8 The contents of this file are subject to the MIT license as set out below.
10 Permission is hereby granted, free of charge, to any person obtaining a copy
11 of this software and associated documentation files (the "Software"), to deal
12 in the Software without restriction, including without limitation the rights
13 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 copies of the Software, and to permit persons to whom the Software is
15 furnished to do so, subject to the following conditions:
17 The above copyright notice and this permission notice shall be included in
18 all copies or substantial portions of the Software.
20 Alternatively, the contents of this file may be used under the terms of
21 the GNU General Public License Version 2 ("GPL") in which case the provisions
22 of GPL are applicable instead of those above.
24 If you wish to allow use of your version of this file only under the terms of
25 GPL, and not to allow others to use your version of this file under the terms
26 of the MIT license, indicate your decision by deleting the provisions above
27 and replace them with the notice and other provisions required by GPL as set
28 out in the file called "GPL-COPYING" included in this distribution. If you do
29 not delete the provisions above, a recipient may use your version of this file
30 under the terms of either the MIT license or GPL.
32 This License is also included in this distribution in the file called
35 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
36 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
37 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
38 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
39 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
40 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
41 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 */ /**************************************************************************/
47 #include "rgx_fwif_km.h"
48 #include "rgxfwutils.h"
50 #include "pvr_debug.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"
62 #if defined(PVRSRV_ENABLE_PROCESS_STATS)
63 #include "process_stats.h"
66 #include "pvr_dvfs_device.h"
69 static PVRSRV_ERROR RGXFWNotifyHostTimeout(PVRSRV_RGXDEV_INFO *psDevInfo)
72 RGXFWIF_KCCB_CMD sCmd;
73 RGXFWIF_RUNTIME_CFG *psRuntimeCfg = psDevInfo->psRGXFWIfRuntimeCfg;
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;
83 /* Ensure the new APM latency is written to memory before requesting the FW to read it */
86 eError = RGXSendCommand(psDevInfo,
95 static void _RGXUpdateGPUUtilStats(PVRSRV_RGXDEV_INFO *psDevInfo)
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;
104 psUtilFWCb = psDevInfo->psRGXFWIfGpuUtilFWCb;
105 paui64StatsCounters = &psUtilFWCb->aui64StatsCounters[0];
107 OSLockAcquire(psDevInfo->hGPUUtilLock);
109 ui64TimeNow = RGXFWIF_GPU_UTIL_GET_TIME(OSClockns64());
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;
117 /* Update state and time of the latest update */
118 psUtilFWCb->ui64LastWord = RGXFWIF_GPU_UTIL_MAKE_WORD(ui64TimeNow, ui64LastState);
120 OSLockRelease(psDevInfo->hGPUUtilLock);
124 static INLINE PVRSRV_ERROR RGXDoStop(PVRSRV_DEVICE_NODE *psDeviceNode)
128 #if defined(SUPPORT_TRUSTED_DEVICE) && !defined(NO_HARDWARE)
129 PVRSRV_DEVICE_CONFIG *psDevConfig = psDeviceNode->psDevConfig;
131 if (psDevConfig->pfnTDRGXStop == NULL)
133 PVR_DPF((PVR_DBG_ERROR, "RGXPrePowerState: TDRGXStop not implemented!"));
134 return PVRSRV_ERROR_NOT_IMPLEMENTED;
137 eError = psDevConfig->pfnTDRGXStop(psDevConfig->hSysData);
139 PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
141 eError = RGXStop(&psDevInfo->sPowerParams);
150 PVRSRV_ERROR RGXPrePowerState (IMG_HANDLE hDevHandle,
151 PVRSRV_DEV_POWER_STATE eNewPowerState,
152 PVRSRV_DEV_POWER_STATE eCurrentPowerState,
155 PVRSRV_ERROR eError = PVRSRV_OK;
157 if ((eNewPowerState != eCurrentPowerState) &&
158 (eNewPowerState != PVRSRV_DEV_POWER_STATE_ON))
160 PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
161 PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
162 RGXFWIF_KCCB_CMD sPowCmd;
163 RGXFWIF_TRACEBUF *psFWTraceBuf = psDevInfo->psRGXFWIfTraceBuf;
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;
170 eError = SyncPrimSet(psDevInfo->psPowSyncPrim, 0);
171 if (eError != PVRSRV_OK)
173 PVR_DPF((PVR_DBG_ERROR,"%s: Failed to set Power sync prim",
178 eError = RGXSendCommand(psDevInfo,
183 if (eError != PVRSRV_OK)
185 PVR_DPF((PVR_DBG_ERROR,"RGXPrePowerState: Failed to send Power off request"));
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);
193 /* Check the Power state after the answer */
194 if (eError == PVRSRV_OK)
196 /* Finally, de-initialise some registers. */
197 if (psFWTraceBuf->ePowState == RGXFWIF_POW_OFF)
199 #if !defined(NO_HARDWARE)
201 for (ui32TID = 0; ui32TID < RGXFW_THREAD_NUM; ui32TID++)
203 /* Wait for the pending META/MIPS to host interrupts to come back. */
204 eError = PVRSRVPollForValueKM(&psDevInfo->aui32SampleIRQCount[ui32TID],
205 psFWTraceBuf->aui32InterruptCount[ui32TID],
208 if (eError != PVRSRV_OK)
210 PVR_DPF((PVR_DBG_ERROR, \
211 "RGXPrePowerState: Wait for pending interrupts failed. Thread %u: Host:%u, FW: %u", \
213 psDevInfo->aui32SampleIRQCount[ui32TID], \
214 psFWTraceBuf->aui32InterruptCount[ui32TID]));
216 RGX_WaitForInterruptsTimeout(psDevInfo);
220 #endif /* NO_HARDWARE */
222 /* Update GPU frequency and timer correlation related data */
223 RGXGPUFreqCalibratePrePowerOff(psDeviceNode);
225 /* Update GPU state counters */
226 _RGXUpdateGPUUtilStats(psDevInfo);
228 #if defined(PVR_DVFS)
229 eError = SuspendDVFS();
230 if (eError != PVRSRV_OK)
232 PVR_DPF((PVR_DBG_ERROR,"RGXPrePowerState: Failed to suspend DVFS"));
237 psDevInfo->bRGXPowered = IMG_FALSE;
239 eError = RGXDoStop(psDeviceNode);
240 if (eError != PVRSRV_OK)
242 PVR_DPF((PVR_DBG_ERROR, "RGXPrePowerState: RGXDoStop failed (%s)",
243 PVRSRVGetErrorStringKM(eError)));
244 eError = PVRSRV_ERROR_DEVICE_POWER_CHANGE_FAILURE;
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;
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));
258 else if (eError == PVRSRV_ERROR_TIMEOUT)
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"));
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;
275 static INLINE PVRSRV_ERROR RGXDoStart(PVRSRV_DEVICE_NODE *psDeviceNode)
279 #if defined(SUPPORT_TRUSTED_DEVICE) && !defined(NO_HARDWARE)
280 PVRSRV_DEVICE_CONFIG *psDevConfig = psDeviceNode->psDevConfig;
282 if (psDevConfig->pfnTDRGXStart == NULL)
284 PVR_DPF((PVR_DBG_ERROR, "RGXPostPowerState: TDRGXStart not implemented!"));
285 return PVRSRV_ERROR_NOT_IMPLEMENTED;
288 eError = psDevConfig->pfnTDRGXStart(psDevConfig->hSysData);
290 PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
292 eError = RGXStart(&psDevInfo->sPowerParams);
301 PVRSRV_ERROR RGXPostPowerState (IMG_HANDLE hDevHandle,
302 PVRSRV_DEV_POWER_STATE eNewPowerState,
303 PVRSRV_DEV_POWER_STATE eCurrentPowerState,
306 if ((eNewPowerState != eCurrentPowerState) &&
307 (eCurrentPowerState != PVRSRV_DEV_POWER_STATE_ON))
310 PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
311 PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
312 RGXFWIF_INIT *psRGXFWInit;
314 if (eCurrentPowerState == PVRSRV_DEV_POWER_STATE_OFF)
316 /* Update GPU frequency and timer correlation related data */
317 RGXGPUFreqCalibratePostPowerOn(psDeviceNode);
319 /* Update GPU state counters */
320 _RGXUpdateGPUUtilStats(psDevInfo);
322 eError = RGXDoStart(psDeviceNode);
323 if (eError != PVRSRV_OK)
325 PVR_DPF((PVR_DBG_ERROR,"RGXPostPowerState: RGXDoStart failed"));
331 #if defined(SUPPORT_EXTRA_METASP_DEBUG)
332 eError = ValidateFWImageWithSP(psDevInfo);
333 if (eError != PVRSRV_OK) return eError;
336 eError = DevmemAcquireCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc,
337 (void **)&psRGXFWInit);
338 if (eError != PVRSRV_OK)
340 PVR_DPF((PVR_DBG_ERROR,
341 "RGXPostPowerState: Failed to acquire kernel fw if ctl (%u)",
347 * Check whether the FW has started by polling on bFirmwareStarted flag
349 if (PVRSRVPollForValueKM((IMG_UINT32 *)&psRGXFWInit->bFirmwareStarted,
351 0xFFFFFFFF) != PVRSRV_OK)
353 PVR_DPF((PVR_DBG_ERROR, "RGXPostPowerState: Polling for 'FW started' flag failed."));
354 eError = PVRSRV_ERROR_TIMEOUT;
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.
363 PVRSRV_POWER_DEV *psPowerDev = psDeviceNode->psPowerDev;
367 PVRSRV_DEV_POWER_STATE eOldPowerState = psPowerDev->eCurrentPowerState;
369 PVRSRVPowerUnlock(psDeviceNode);
370 psPowerDev->eCurrentPowerState = PVRSRV_DEV_POWER_STATE_ON;
371 RGXDumpDebugInfo(NULL, psDeviceNode->pvDevice);
372 psPowerDev->eCurrentPowerState = eOldPowerState;
373 PVRSRVPowerLock(psDeviceNode);
377 DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc);
382 PDUMPCOMMENTWITHFLAGS(PDUMP_FLAGS_CONTINUOUS, "Wait for the Firmware to start.");
383 eError = DevmemPDumpDevmemPol32(psDevInfo->psRGXFWIfInitMemDesc,
384 offsetof(RGXFWIF_INIT, bFirmwareStarted),
387 PDUMP_POLL_OPERATOR_EQUAL,
388 PDUMP_FLAGS_CONTINUOUS);
390 if (eError != PVRSRV_OK)
392 PVR_DPF((PVR_DBG_ERROR,
393 "RGXPostPowerState: problem pdumping POL for psRGXFWIfInitMemDesc (%d)",
395 DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc);
400 #if defined(PVRSRV_ENABLE_PROCESS_STATS)
401 SetFirmwareStartTime(psRGXFWInit->ui32FirmwareStartedTimeStamp);
404 HTBSyncPartitionMarker(psRGXFWInit->ui32MarkerVal);
406 DevmemReleaseCpuVirtAddr(psDevInfo->psRGXFWIfInitMemDesc);
408 psDevInfo->bRGXPowered = IMG_TRUE;
410 #if defined(PVR_DVFS)
411 eError = ResumeDVFS();
412 if (eError != PVRSRV_OK)
414 PVR_DPF((PVR_DBG_ERROR,"RGXPostPowerState: Failed to resume DVFS"));
421 PDUMPCOMMENT("RGXPostPowerState: Current state: %d, New state: %d", eCurrentPowerState, eNewPowerState);
428 RGXPreClockSpeedChange
430 PVRSRV_ERROR RGXPreClockSpeedChange (IMG_HANDLE hDevHandle,
431 PVRSRV_DEV_POWER_STATE eCurrentPowerState)
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;
439 PVR_UNREFERENCED_PARAMETER(psRGXData);
441 PVR_DPF((PVR_DBG_MESSAGE,"RGXPreClockSpeedChange: RGX clock speed was %uHz",
442 psRGXData->psRGXTimingInfo->ui32CoreClockSpeed));
444 if ((eCurrentPowerState != PVRSRV_DEV_POWER_STATE_OFF)
445 && (psFWTraceBuf->ePowState != RGXFWIF_POW_OFF))
447 /* Update GPU frequency and timer correlation related data */
448 RGXGPUFreqCalibratePreClockSpeedChange(psDeviceNode);
456 RGXPostClockSpeedChange
458 PVRSRV_ERROR RGXPostClockSpeedChange (IMG_HANDLE hDevHandle,
459 PVRSRV_DEV_POWER_STATE eCurrentPowerState)
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;
468 /* Update runtime configuration with the new value */
469 psDevInfo->psRGXFWIfRuntimeCfg->ui32CoreClockSpeed = ui32NewClockSpeed;
471 if ((eCurrentPowerState != PVRSRV_DEV_POWER_STATE_OFF)
472 && (psFWTraceBuf->ePowState != RGXFWIF_POW_OFF))
474 RGXFWIF_KCCB_CMD sCOREClkSpeedChangeCmd;
476 RGXGPUFreqCalibratePostClockSpeedChange(psDeviceNode, ui32NewClockSpeed);
478 sCOREClkSpeedChangeCmd.eCmdType = RGXFWIF_KCCB_CMD_CORECLKSPEEDCHANGE;
479 sCOREClkSpeedChangeCmd.uCmdData.sCORECLKSPEEDCHANGEData.ui32NewClockSpeed = ui32NewClockSpeed;
481 /* Ensure the new clock speed is written to memory before requesting the FW to read it */
484 PDUMPCOMMENT("Scheduling CORE clock speed change command");
487 eError = RGXSendCommand(psDeviceNode->pvDevice,
489 &sCOREClkSpeedChangeCmd,
490 sizeof(sCOREClkSpeedChangeCmd),
494 if (eError != PVRSRV_OK)
496 PDUMPCOMMENT("Scheduling CORE clock speed change command failed");
497 PVR_DPF((PVR_DBG_ERROR, "RGXPostClockSpeedChange: Scheduling KCCB command failed. Error:%u", eError));
501 PVR_DPF((PVR_DBG_MESSAGE,"RGXPostClockSpeedChange: RGX clock speed changed to %uHz",
502 psRGXData->psRGXTimingInfo->ui32CoreClockSpeed));
510 ******************************************************************************
512 @Function RGXDustCountChange
516 Does change of number of DUSTs
518 @Input hDevHandle : RGX Device Node
519 @Input ui32NumberOfDusts : Number of DUSTs to make transition to
521 @Return PVRSRV_ERROR :
523 ******************************************************************************/
524 PVRSRV_ERROR RGXDustCountChange(IMG_HANDLE hDevHandle,
525 IMG_UINT32 ui32NumberOfDusts)
528 PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
529 PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
531 RGXFWIF_KCCB_CMD sDustCountChange;
532 IMG_UINT32 ui32MaxAvailableDusts = MAX(1, (psDevInfo->sDevFeatureCfg.ui32NumClusters/2));
533 RGXFWIF_RUNTIME_CFG *psRuntimeCfg = psDevInfo->psRGXFWIfRuntimeCfg;
535 if (ui32NumberOfDusts > ui32MaxAvailableDusts)
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",
541 ui32MaxAvailableDusts,
546 #if defined(FIX_HW_BRN_59042)
547 if (ui32NumberOfDusts < ui32MaxAvailableDusts && (ui32NumberOfDusts & 0x1))
549 PVR_DPF((PVR_DBG_ERROR,
550 "RGXDustCountChange: Invalid number of DUSTs (%u) due to HW restriction. Allowed values are :-",
552 switch (ui32MaxAvailableDusts)
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;
561 return PVRSRV_ERROR_INVALID_PARAMS;
565 psRuntimeCfg->ui32DefaultDustsNumInit = ui32NumberOfDusts;
567 #if !defined(NO_HARDWARE)
569 RGXFWIF_TRACEBUF *psFWTraceBuf = psDevInfo->psRGXFWIfTraceBuf;
571 if (psFWTraceBuf->ePowState == RGXFWIF_POW_OFF)
576 if (psFWTraceBuf->ePowState != RGXFWIF_POW_FORCED_IDLE)
578 eError = PVRSRV_ERROR_DEVICE_POWER_CHANGE_DENIED;
579 PVR_DPF((PVR_DBG_ERROR,"RGXDustCountChange: Attempt to change dust count when not IDLE"));
585 eError = SyncPrimSet(psDevInfo->psPowSyncPrim, 0);
586 if (eError != PVRSRV_OK)
588 PVR_DPF((PVR_DBG_ERROR,"%s: Failed to set Power sync prim",
593 sDustCountChange.eCmdType = RGXFWIF_KCCB_CMD_POW;
594 sDustCountChange.uCmdData.sPowData.ePowType = RGXFWIF_POW_NUMDUST_CHANGE;
595 sDustCountChange.uCmdData.sPowData.uPoweReqData.ui32NumOfDusts = ui32NumberOfDusts;
597 PDUMPCOMMENT("Scheduling command to change Dust Count to %u", ui32NumberOfDusts);
598 eError = RGXSendCommand(psDeviceNode->pvDevice,
601 sizeof(sDustCountChange),
604 if (eError != PVRSRV_OK)
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));
611 /* Wait for the firmware to answer. */
612 eError = PVRSRVPollForValueKM(psDevInfo->psPowSyncPrim->pui32LinAddr, 0x1, 0xFFFFFFFF);
614 if (eError != PVRSRV_OK)
616 PVR_DPF((PVR_DBG_ERROR,"RGXDustCountChange: Timeout waiting for idle request"));
621 PDUMPCOMMENT("RGXDustCountChange: Poll for Kernel SyncPrim [0x%p] on DM %d ", psDevInfo->psPowSyncPrim->pui32LinAddr, RGXFWIF_DM_GP);
623 SyncPrimPDumpPol(psDevInfo->psPowSyncPrim,
626 PDUMP_POLL_OPERATOR_EQUAL,
633 @Function RGXAPMLatencyChange
635 PVRSRV_ERROR RGXAPMLatencyChange(IMG_HANDLE hDevHandle,
636 IMG_UINT32 ui32ActivePMLatencyms,
637 IMG_BOOL bActivePMLatencyPersistant)
640 PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
641 PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
643 RGXFWIF_RUNTIME_CFG *psRuntimeCfg = psDevInfo->psRGXFWIfRuntimeCfg;
644 PVRSRV_DEV_POWER_STATE ePowerState;
646 eError = PVRSRVPowerLock(psDeviceNode);
647 if (eError != PVRSRV_OK)
649 PVR_DPF((PVR_DBG_ERROR,"RGXAPMLatencyChange: Failed to acquire power lock"));
653 /* Update runtime configuration with the new values */
654 psRuntimeCfg->ui32ActivePMLatencyms = ui32ActivePMLatencyms;
655 psRuntimeCfg->bActivePMLatencyPersistant = bActivePMLatencyPersistant;
657 eError = PVRSRVGetDevicePowerState(psDeviceNode, &ePowerState);
659 if ((eError == PVRSRV_OK) && (ePowerState != PVRSRV_DEV_POWER_STATE_OFF))
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;
667 /* Ensure the new APM latency is written to memory before requesting the FW to read it */
670 PDUMPCOMMENT("Scheduling command to change APM latency to %u", ui32ActivePMLatencyms);
671 eError = RGXSendCommand(psDeviceNode->pvDevice,
673 &sActivePMLatencyChange,
674 sizeof(sActivePMLatencyChange),
677 if (eError != PVRSRV_OK)
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));
685 PVRSRVPowerUnlock(psDeviceNode);
691 RGXActivePowerRequest
693 PVRSRV_ERROR RGXActivePowerRequest(IMG_HANDLE hDevHandle)
695 PVRSRV_ERROR eError = PVRSRV_OK;
696 PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
698 PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
699 RGXFWIF_TRACEBUF *psFWTraceBuf = psDevInfo->psRGXFWIfTraceBuf;
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. */
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)
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;
717 /* Check again for IDLE once we have the power lock */
718 if (psFWTraceBuf->ePowState == RGXFWIF_POW_IDLE)
721 psDevInfo->ui32ActivePMReqTotal++;
723 #if defined(PVRSRV_ENABLE_PROCESS_STATS)
724 SetFirmwareHandshakeIdleTime(RGXReadHWTimerReg(psDevInfo)-psFWTraceBuf->ui64StartIdleTime);
728 eError = PVRSRVSetDevicePowerStateKM(psDeviceNode,
729 PVRSRV_DEV_POWER_STATE_OFF,
730 IMG_FALSE); /* forced */
733 if (eError == PVRSRV_OK)
735 psDevInfo->ui32ActivePMReqOk++;
737 else if (eError == PVRSRV_ERROR_DEVICE_POWER_CHANGE_DENIED)
739 psDevInfo->ui32ActivePMReqDenied++;
744 PVRSRVPowerUnlock(psDeviceNode);
746 _RGXActivePowerRequest_PowerLock_failed:
747 OSReleaseBridgeLock();
756 #define RGX_FORCED_IDLE_RETRY_COUNT 10
758 PVRSRV_ERROR RGXForcedIdleRequest(IMG_HANDLE hDevHandle, IMG_BOOL bDeviceOffPermitted)
760 PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
761 PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
762 RGXFWIF_KCCB_CMD sPowCmd;
764 IMG_UINT32 ui32RetryCount = 0;
766 #if !defined(NO_HARDWARE)
767 RGXFWIF_TRACEBUF *psFWTraceBuf = psDevInfo->psRGXFWIfTraceBuf;
769 /* Firmware already forced idle */
770 if (psFWTraceBuf->ePowState == RGXFWIF_POW_FORCED_IDLE)
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)
778 return (bDeviceOffPermitted) ? PVRSRV_OK : PVRSRV_ERROR_DEVICE_IDLE_REQUEST_DENIED;
782 eError = SyncPrimSet(psDevInfo->psPowSyncPrim, 0);
783 if (eError != PVRSRV_OK)
785 PVR_DPF((PVR_DBG_ERROR,"%s: Failed to set Power sync prim",
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;
793 PDUMPCOMMENT("RGXForcedIdleRequest: Sending forced idle command");
795 /* Send one forced IDLE command to GP */
796 eError = RGXSendCommand(psDevInfo,
802 if (eError != PVRSRV_OK)
804 PVR_DPF((PVR_DBG_ERROR,"RGXForcedIdleRequest: Failed to send idle request"));
808 /* Wait for GPU to finish current workload */
810 eError = PVRSRVPollForValueKM(psDevInfo->psPowSyncPrim->pui32LinAddr, 0x1, 0xFFFFFFFF);
811 if ((eError == PVRSRV_OK) || (ui32RetryCount == RGX_FORCED_IDLE_RETRY_COUNT))
816 PVR_DPF((PVR_DBG_WARNING,"RGXForcedIdleRequest: Request timeout. Retry %d of %d", ui32RetryCount, RGX_FORCED_IDLE_RETRY_COUNT));
819 if (eError != PVRSRV_OK)
821 RGXFWNotifyHostTimeout(psDevInfo);
822 PVR_DPF((PVR_DBG_ERROR,"RGXForcedIdleRequest: Idle request failed. Firmware potentially left in forced idle state"));
827 PDUMPCOMMENT("RGXForcedIdleRequest: Poll for Kernel SyncPrim [0x%p] on DM %d ", psDevInfo->psPowSyncPrim->pui32LinAddr, RGXFWIF_DM_GP);
829 SyncPrimPDumpPol(psDevInfo->psPowSyncPrim,
832 PDUMP_POLL_OPERATOR_EQUAL,
836 #if !defined(NO_HARDWARE)
837 /* Check the firmware state for idleness */
838 if (psFWTraceBuf->ePowState != RGXFWIF_POW_FORCED_IDLE)
840 PVR_DPF((PVR_DBG_ERROR,"RGXForcedIdleRequest: Failed to force IDLE"));
842 return PVRSRV_ERROR_DEVICE_IDLE_REQUEST_DENIED;
850 RGXCancelForcedIdleRequest
852 PVRSRV_ERROR RGXCancelForcedIdleRequest(IMG_HANDLE hDevHandle)
854 PVRSRV_DEVICE_NODE *psDeviceNode = hDevHandle;
855 PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
856 RGXFWIF_KCCB_CMD sPowCmd;
857 PVRSRV_ERROR eError = PVRSRV_OK;
859 eError = SyncPrimSet(psDevInfo->psPowSyncPrim, 0);
860 if (eError != PVRSRV_OK)
862 PVR_DPF((PVR_DBG_ERROR,"%s: Failed to set Power sync prim",
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;
872 PDUMPCOMMENT("RGXForcedIdleRequest: Sending cancel forced idle command");
874 /* Send cancel forced IDLE command to GP */
875 eError = RGXSendCommand(psDevInfo,
881 if (eError != PVRSRV_OK)
883 PDUMPCOMMENT("RGXCancelForcedIdleRequest: Failed to send cancel IDLE request for DM%d", RGXFWIF_DM_GP);
887 /* Wait for the firmware to answer. */
888 eError = PVRSRVPollForValueKM(psDevInfo->psPowSyncPrim->pui32LinAddr, 1, 0xFFFFFFFF);
890 if (eError != PVRSRV_OK)
892 PVR_DPF((PVR_DBG_ERROR,"RGXCancelForcedIdleRequest: Timeout waiting for cancel idle request"));
897 PDUMPCOMMENT("RGXCancelForcedIdleRequest: Poll for Kernel SyncPrim [0x%p] on DM %d ", psDevInfo->psPowSyncPrim->pui32LinAddr, RGXFWIF_DM_GP);
899 SyncPrimPDumpPol(psDevInfo->psPowSyncPrim,
902 PDUMP_POLL_OPERATOR_EQUAL,
909 PVR_DPF((PVR_DBG_ERROR,"RGXCancelForcedIdleRequest: Firmware potentially left in forced idle state"));
914 ******************************************************************************
916 @Function PVRSRVGetNextDustCount
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.
925 0->1, 0<-1, 0->2, 0<-2, (0->1)
926 1->1, 1->2, 1<-2, (1->2)
930 Redundant transitions in brackets.
932 @Input psDustReqState : Counter state used to calculate next dust count
933 @Input ui32DustCount : Number of dusts in the core
937 ******************************************************************************/
938 IMG_UINT32 RGXGetNextDustCount(RGX_DUST_STATE *psDustReqState, IMG_UINT32 ui32DustCount)
940 if (psDustReqState->bToggle)
942 psDustReqState->ui32DustCount2++;
945 if (psDustReqState->ui32DustCount2 > ui32DustCount)
947 psDustReqState->ui32DustCount1++;
948 psDustReqState->ui32DustCount2 = psDustReqState->ui32DustCount1;
951 if (psDustReqState->ui32DustCount1 > ui32DustCount)
953 psDustReqState->ui32DustCount1 = 0;
954 psDustReqState->ui32DustCount2 = 0;
957 psDustReqState->bToggle = !psDustReqState->bToggle;
959 return (psDustReqState->bToggle) ? psDustReqState->ui32DustCount1 : psDustReqState->ui32DustCount2;
962 /******************************************************************************
963 End of file (rgxpower.c)
964 ******************************************************************************/