RK3368 GPU version Rogue M 1.28
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / rogue_m / services / server / devices / rgx / rgxtimecorr.c
1 /*************************************************************************/ /*!
2 @File
3 @Title          Device specific time correlation and calibration routines
4 @Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved
5 @Description    Device specific time correlation and calibration routines
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 "rgxtimecorr.h"
45 #include "rgxfwutils.h"
46
47 /******************************************************************************
48  *
49  * - A calibration period is started on power-on and after a DVFS transition,
50  *   and it's closed before a power-off and before a DVFS transition
51  *   (so power-on -> dfvs -> dvfs -> power-off , power on -> dvfs -> dvfs...,
52  *   where each arrow is a calibration period)
53  *
54  * - The timers on the Host and on the FW are correlated at the beginning of
55  *   each period together with the (possibly calibrated) current GPU frequency
56  *
57  * - If the frequency has not changed since the last power-off/on sequence or
58  *   before/after a DVFS transition (-> the transition didn't really happen)
59  *   then multiple consecutive periods are merged (the higher the numbers the
60  *   better the accuracy in the computed clock speed)
61  *
62  * - Correlation and calibration are also done more or less periodically
63  *   (using a best effort approach)
64  *
65  *****************************************************************************/
66
67 static IMG_VOID _RGXMakeTimeCorrData(PVRSRV_DEVICE_NODE *psDeviceNode)
68 {
69         PVRSRV_RGXDEV_INFO    *psDevInfo     = psDeviceNode->pvDevice;
70         RGXFWIF_GPU_UTIL_FWCB *psGpuUtilFWCB = psDevInfo->psRGXFWIfGpuUtilFWCb;
71         RGX_GPU_DVFS_TABLE    *psGpuDVFSTable = psDevInfo->psGpuDVFSTable;
72         RGXFWIF_TIME_CORR     *psTimeCorr;
73         IMG_UINT32            ui32NewSeqCount;
74         IMG_UINT32            ui32CoreClockSpeed;
75         IMG_UINT32            ui32Remainder;
76
77         ui32CoreClockSpeed = psGpuDVFSTable->aui32DVFSClock[psGpuDVFSTable->ui32CurrentDVFSId];
78
79         ui32NewSeqCount = psGpuUtilFWCB->ui32TimeCorrSeqCount + 1;
80         psTimeCorr = &psGpuUtilFWCB->sTimeCorr[RGXFWIF_TIME_CORR_CURR_INDEX(ui32NewSeqCount)];
81
82         psTimeCorr->ui64CRTimeStamp    = RGXReadHWTimerReg(psDevInfo);
83         psTimeCorr->ui64OSTimeStamp    = OSClockns64();
84         psTimeCorr->ui32CoreClockSpeed = ui32CoreClockSpeed;
85         psTimeCorr->ui32CRDeltaToOSDeltaKNs =
86             RGXFWIF_GET_CRDELTA_TO_OSDELTA_K_NS(ui32CoreClockSpeed, ui32Remainder);
87
88         /* Make sure the values are written to memory before updating the index of the current entry */
89         OSWriteMemoryBarrier();
90
91         /* Update the index of the current entry in the timer correlation array */
92         psGpuUtilFWCB->ui32TimeCorrSeqCount = ui32NewSeqCount;
93
94         PVR_DPF((PVR_DBG_MESSAGE,"RGXMakeTimeCorrData: Correlated OS timestamp %llu (ns) with CR timestamp %llu, GPU clock speed %uHz",
95                  psTimeCorr->ui64OSTimeStamp, psTimeCorr->ui64CRTimeStamp, psTimeCorr->ui32CoreClockSpeed));
96 }
97
98
99 static IMG_VOID _RGXGPUFreqCalibrationPeriodStart(PVRSRV_DEVICE_NODE *psDeviceNode, RGX_GPU_DVFS_TABLE *psGpuDVFSTable)
100 {
101         PVRSRV_RGXDEV_INFO *psDevInfo         = psDeviceNode->pvDevice;
102         RGX_DATA           *psRGXData         = (RGX_DATA*)psDeviceNode->psDevConfig->hDevData;
103         IMG_UINT32         ui32CoreClockSpeed = psRGXData->psRGXTimingInfo->ui32CoreClockSpeed;
104         IMG_UINT32         ui32Index          = RGX_GPU_DVFS_GET_INDEX(ui32CoreClockSpeed);
105
106         IMG_UINT64 ui64CRTimestamp = RGXReadHWTimerReg(psDevInfo);
107         IMG_UINT64 ui64OSTimestamp = OSClockus64();
108
109         psGpuDVFSTable->ui64CalibrationCRTimestamp = ui64CRTimestamp;
110         psGpuDVFSTable->ui64CalibrationOSTimestamp = ui64OSTimestamp;
111
112         /* Set the time needed to (re)calibrate the GPU frequency */
113         if((psGpuDVFSTable->aui32DVFSClock[ui32Index] == 0) ||                /* We never met this frequency */
114            (psGpuDVFSTable->aui32DVFSClock[ui32Index] == ui32CoreClockSpeed)) /* We weren't able to calibrate this frequency previously */
115         {
116                 psGpuDVFSTable->aui32DVFSClock[ui32Index] = ui32CoreClockSpeed;
117                 psGpuDVFSTable->ui32CalibrationPeriod     = RGX_GPU_DVFS_FIRST_CALIBRATION_TIME_US;
118
119                 PVR_DPF((PVR_DBG_MESSAGE, "RGXGPUFreqCalibrationStart: using uncalibrated GPU frequency %u", ui32CoreClockSpeed));
120         }
121         else if(psGpuDVFSTable->ui32CalibrationPeriod == RGX_GPU_DVFS_FIRST_CALIBRATION_TIME_US)
122         {
123                 psGpuDVFSTable->ui32CalibrationPeriod = RGX_GPU_DVFS_TRANSITION_CALIBRATION_TIME_US;
124         }
125         else
126         {
127                 psGpuDVFSTable->ui32CalibrationPeriod = RGX_GPU_DVFS_PERIODIC_CALIBRATION_TIME_US;
128         }
129
130         /* Update the index to the DVFS table */
131         psGpuDVFSTable->ui32CurrentDVFSId = ui32Index;
132 }
133
134
135 static IMG_VOID _RGXGPUFreqCalibrationPeriodStop(PVRSRV_DEVICE_NODE *psDeviceNode, RGX_GPU_DVFS_TABLE *psGpuDVFSTable)
136 {
137         PVRSRV_RGXDEV_INFO *psDevInfo = psDeviceNode->pvDevice;
138
139         IMG_UINT64 ui64CRTimestamp = RGXReadHWTimerReg(psDevInfo);
140         IMG_UINT64 ui64OSTimestamp = OSClockus64();
141
142         if(!psGpuDVFSTable->bAccumulatePeriod)
143         {
144                 psGpuDVFSTable->ui64CalibrationCRTimediff = 0;
145                 psGpuDVFSTable->ui64CalibrationOSTimediff = 0;
146         }
147
148         psGpuDVFSTable->ui64CalibrationCRTimediff += ui64CRTimestamp - psGpuDVFSTable->ui64CalibrationCRTimestamp;
149         psGpuDVFSTable->ui64CalibrationOSTimediff += ui64OSTimestamp - psGpuDVFSTable->ui64CalibrationOSTimestamp;
150 }
151
152
153 static IMG_UINT32 _RGXGPUFreqCalibrationCalculate(PVRSRV_DEVICE_NODE *psDeviceNode, RGX_GPU_DVFS_TABLE *psGpuDVFSTable)
154 {
155         IMG_UINT32 ui32CalibratedClockSpeed;
156         IMG_UINT32 ui32Remainder;
157
158         ui32CalibratedClockSpeed =
159             RGXFWIF_GET_GPU_CLOCK_FREQUENCY_HZ(psGpuDVFSTable->ui64CalibrationCRTimediff, psGpuDVFSTable->ui64CalibrationOSTimediff, ui32Remainder);
160
161         PVR_DPF((PVR_DBG_MESSAGE, "GPU frequency calibration: %u -> %u done over %llu us",
162                  psGpuDVFSTable->aui32DVFSClock[psGpuDVFSTable->ui32CurrentDVFSId],
163                  ui32CalibratedClockSpeed,
164                  psGpuDVFSTable->ui64CalibrationOSTimediff));
165
166         psGpuDVFSTable->aui32DVFSClock[psGpuDVFSTable->ui32CurrentDVFSId] = ui32CalibratedClockSpeed;
167
168         return ui32CalibratedClockSpeed;
169 }
170
171
172 /*
173         RGXGPUFreqCalibratePrePowerState
174 */
175 IMG_VOID RGXGPUFreqCalibratePrePowerState(IMG_HANDLE hDevHandle)
176 {
177         PVRSRV_DEVICE_NODE  *psDeviceNode   = hDevHandle;
178         PVRSRV_RGXDEV_INFO  *psDevInfo      = psDeviceNode->pvDevice;
179         RGX_GPU_DVFS_TABLE  *psGpuDVFSTable = psDevInfo->psGpuDVFSTable;
180
181         _RGXGPUFreqCalibrationPeriodStop(psDeviceNode, psGpuDVFSTable);
182
183         if(psGpuDVFSTable->ui64CalibrationOSTimediff >= psGpuDVFSTable->ui32CalibrationPeriod)
184         {
185                 _RGXGPUFreqCalibrationCalculate(psDeviceNode, psGpuDVFSTable);
186         }
187 }
188
189
190 /*
191         RGXGPUFreqCalibratePostPowerState
192 */
193 IMG_VOID RGXGPUFreqCalibratePostPowerState(IMG_HANDLE hDevHandle)
194 {
195         PVRSRV_DEVICE_NODE  *psDeviceNode      = hDevHandle;
196         PVRSRV_RGXDEV_INFO  *psDevInfo         = psDeviceNode->pvDevice;
197         RGX_GPU_DVFS_TABLE  *psGpuDVFSTable    = psDevInfo->psGpuDVFSTable;
198         RGX_DATA            *psRGXData         = (RGX_DATA*)psDeviceNode->psDevConfig->hDevData;
199         IMG_UINT32          ui32CoreClockSpeed = psRGXData->psRGXTimingInfo->ui32CoreClockSpeed;
200
201         /* If the frequency hasn't changed then accumulate the time diffs to get a better result */
202         psGpuDVFSTable->bAccumulatePeriod = (RGX_GPU_DVFS_GET_INDEX(ui32CoreClockSpeed) == psGpuDVFSTable->ui32CurrentDVFSId);
203
204         _RGXGPUFreqCalibrationPeriodStart(psDeviceNode, psGpuDVFSTable);
205
206         /* Update the timer correlation data */
207         _RGXMakeTimeCorrData(psDeviceNode);
208 }
209
210
211 /*
212         RGXGPUFreqCalibratePreClockSpeedChange
213 */
214 IMG_VOID RGXGPUFreqCalibratePreClockSpeedChange(IMG_HANDLE hDevHandle)
215 {
216         PVRSRV_DEVICE_NODE  *psDeviceNode   = hDevHandle;
217         PVRSRV_RGXDEV_INFO  *psDevInfo      = psDeviceNode->pvDevice;
218         RGX_GPU_DVFS_TABLE  *psGpuDVFSTable = psDevInfo->psGpuDVFSTable;
219
220         _RGXGPUFreqCalibrationPeriodStop(psDeviceNode, psGpuDVFSTable);
221
222         /* Wait until RGXPostClockSpeedChange() to do anything as the GPU frequency may be left
223          * unchanged (in that case we delay calibration/correlation to get a better result later) */
224 }
225
226
227 /*
228         RGXGPUFreqCalibratePostClockSpeedChange
229 */
230 IMG_UINT32 RGXGPUFreqCalibratePostClockSpeedChange(IMG_HANDLE hDevHandle, IMG_UINT32 ui32NewClockSpeed)
231 {
232         PVRSRV_DEVICE_NODE  *psDeviceNode          = hDevHandle;
233         PVRSRV_RGXDEV_INFO  *psDevInfo             = psDeviceNode->pvDevice;
234         RGX_GPU_DVFS_TABLE  *psGpuDVFSTable        = psDevInfo->psGpuDVFSTable;
235         IMG_UINT32          ui32ReturnedClockSpeed = ui32NewClockSpeed;
236
237         if(RGX_GPU_DVFS_GET_INDEX(ui32NewClockSpeed) != psGpuDVFSTable->ui32CurrentDVFSId)
238         {
239                 /* Only calibrate if the last period was long enough */
240                 if(psGpuDVFSTable->ui64CalibrationOSTimediff >= RGX_GPU_DVFS_TRANSITION_CALIBRATION_TIME_US)
241                 {
242                         ui32ReturnedClockSpeed = _RGXGPUFreqCalibrationCalculate(psDeviceNode, psGpuDVFSTable);
243                 }
244
245                 _RGXGPUFreqCalibrationPeriodStart(psDeviceNode, psGpuDVFSTable);
246
247                 /* Update the timer correlation data */
248                 _RGXMakeTimeCorrData(psDeviceNode);
249
250                 psGpuDVFSTable->bAccumulatePeriod = IMG_FALSE;
251         }
252         else
253         {
254                 psGpuDVFSTable->bAccumulatePeriod = IMG_TRUE;
255         }
256
257         return ui32ReturnedClockSpeed;
258 }
259
260
261 /*
262         RGXGPUFreqCalibrateCorrelatePeriodic
263 */
264 IMG_VOID RGXGPUFreqCalibrateCorrelatePeriodic(IMG_HANDLE hDevHandle)
265 {
266         PVRSRV_DEVICE_NODE     *psDeviceNode   = hDevHandle;
267         PVRSRV_RGXDEV_INFO     *psDevInfo      = psDeviceNode->pvDevice;
268         RGX_GPU_DVFS_TABLE     *psGpuDVFSTable = psDevInfo->psGpuDVFSTable;
269         PVRSRV_DATA            *psPVRSRVData;
270         IMG_UINT64             ui64TimeNow     = OSClockus64();
271         PVRSRV_DEV_POWER_STATE ePowerState;
272
273         /* Check if it's the right time to recalibrate the GPU clock frequency */
274         if((ui64TimeNow - psGpuDVFSTable->ui64CalibrationOSTimestamp) < psGpuDVFSTable->ui32CalibrationPeriod) return;
275
276         /* Try to acquire the powerlock, if not possible then don't wait */
277         psPVRSRVData     = PVRSRVGetPVRSRVData();
278         if (OSLockIsLocked(psPVRSRVData->hPowerLock)) return; /* Better to not wait here if possible */
279         /* There's a chance that the powerlock could be taken here, it's not that bad even if not desirable
280            (TODO use OSTryLockAcquire, currently implemented under Linux only) */
281         if (PVRSRVPowerLock() != PVRSRV_OK) return;
282
283         /* If the GPU is off then we can't do anything */
284         PVRSRVGetDevicePowerState(psDeviceNode->sDevId.ui32DeviceIndex, &ePowerState);
285         if (ePowerState != PVRSRV_DEV_POWER_STATE_ON)
286         {
287                 PVRSRVPowerUnlock();
288                 return;
289         }
290
291         /* All checks passed, we can calibrate and correlate */
292         _RGXGPUFreqCalibrationPeriodStop(psDeviceNode, psGpuDVFSTable);
293         _RGXGPUFreqCalibrationCalculate(psDeviceNode, psGpuDVFSTable);
294         _RGXGPUFreqCalibrationPeriodStart(psDeviceNode, psGpuDVFSTable);
295         _RGXMakeTimeCorrData(psDeviceNode);
296
297         /* Force Accumulate Period to false to not trigger a periodic calibration over and over again */
298         psGpuDVFSTable->bAccumulatePeriod = IMG_FALSE;
299
300         PVRSRVPowerUnlock();
301 }
302
303
304 /******************************************************************************
305  End of file (rgxtimecorr.c)
306 ******************************************************************************/