1 /****************************************************************************
3 * Copyright (C) 2005 - 2013 by Vivante Corp.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the license, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *****************************************************************************/
22 #include "gc_hal_kernel_precomp.h"
24 #define _GC_OBJ_ZONE gcvZONE_POWER
26 /******************************************************************************\
27 ************************ Dynamic Voltage Frequency Setting *********************
28 \******************************************************************************/
37 return Dvfs->loads[Index];
47 if (Dvfs->currentScale < 32)
49 *Scale = Dvfs->currentScale + 8;
53 *Scale = Dvfs->currentScale + 8;
54 *Scale = gcmMIN(64, *Scale);
59 _RecordFrequencyHistory(
66 struct _FrequencyHistory *history = Dvfs->frequencyHistory;
68 for (i = 0; i < 16; i++)
70 if (history->frequency == Frequency)
75 if (history->frequency == 0)
77 history->frequency = Frequency;
98 struct _FrequencyHistory * history = Dvfs->frequencyHistory;
100 for (i = 0; i < 16; i++)
102 if (history->frequency == Frequency)
112 return history->count;
125 gctUINT8 load[4], nextLoad;
128 /* Last 4 history. */
129 load[0] = (Load & 0xFF);
130 load[1] = (Load & 0xFF00) >> 8;
131 load[2] = (Load & 0xFF0000) >> 16;
132 load[3] = (Load & 0xFF000000) >> 24;
134 /* Determine target scale. */
137 _IncreaseScale(Dvfs, Load, &scale);
141 nextLoad = (load[0] + load[1] + load[2] + load[3])/4;
143 scale = Dvfs->currentScale * (nextLoad) / 54;
145 scale = gcmMAX(1, scale);
146 scale = gcmMIN(64, scale);
151 Dvfs->loads[(load[0]-1)/8]++;
156 if (Dvfs->totalConfig % 100 == 0)
158 gcmkPRINT("=======================================================");
159 gcmkPRINT("GPU Load: %-8d %-8d %-8d %-8d %-8d %-8d %-8d %-8d",
160 8, 16, 24, 32, 40, 48, 56, 64);
161 gcmkPRINT(" %-8d %-8d %-8d %-8d %-8d %-8d %-8d %-8d",
162 _GetLoadHistory(Dvfs,2, 0),
163 _GetLoadHistory(Dvfs,2, 1),
164 _GetLoadHistory(Dvfs,2, 2),
165 _GetLoadHistory(Dvfs,2, 3),
166 _GetLoadHistory(Dvfs,2, 4),
167 _GetLoadHistory(Dvfs,2, 5),
168 _GetLoadHistory(Dvfs,2, 6),
169 _GetLoadHistory(Dvfs,2, 7)
172 gcmkPRINT("Frequency(MHz) %-8d %-8d %-8d %-8d %-8d",
173 58, 120, 240, 360, 480);
174 gcmkPRINT(" %-8d %-8d %-8d %-8d %-8d",
175 _GetFrequencyHistory(Dvfs, 58),
176 _GetFrequencyHistory(Dvfs,120),
177 _GetFrequencyHistory(Dvfs,240),
178 _GetFrequencyHistory(Dvfs,360),
179 _GetFrequencyHistory(Dvfs,480)
190 gckDVFS dvfs = (gckDVFS) Data;
191 gckHARDWARE hardware = dvfs->hardware;
195 gctUINT32 t1, t2, consumed;
199 gcmkONERROR(gckHARDWARE_QueryLoad(hardware, &value));
201 /* determine target sacle. */
202 _Policy(dvfs, value, &scale);
204 /* Set frequency and voltage. */
205 gcmkONERROR(gckOS_SetGPUFrequency(hardware->os, hardware->core, scale));
207 /* Query real frequency. */
209 gckOS_QueryGPUFrequency(hardware->os,
212 &dvfs->currentScale));
214 _RecordFrequencyHistory(dvfs, frequency);
216 gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_POWER,
217 "Current frequency = %d",
221 gcmkONERROR(gckHARDWARE_SetDVFSPeroid(hardware, frequency));
224 /* Determine next querying time. */
227 consumed = gcmMIN(((long)t2 - (long)t1), 5);
229 if (dvfs->stop == gcvFALSE)
231 gcmkVERIFY_OK(gckOS_StartTimer(hardware->os,
233 dvfs->pollingTime - consumed));
241 IN gckHARDWARE Hardware,
247 gckDVFS dvfs = gcvNULL;
248 gckOS os = Hardware->os;
250 gcmkHEADER_ARG("Hardware=0x%X", Hardware);
252 gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
253 gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL);
255 /* Allocate a gckDVFS manager. */
256 gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckDVFS), &pointer));
258 gckOS_ZeroMemory(pointer, gcmSIZEOF(struct _gckDVFS));
262 /* Initialization. */
263 dvfs->hardware = Hardware;
264 dvfs->pollingTime = gcdDVFS_POLLING_TIME;
265 dvfs->os = Hardware->os;
266 dvfs->currentScale = 64;
268 /* Create a polling timer. */
269 gcmkONERROR(gckOS_CreateTimer(os, _TimerFunction, pointer, &dvfs->timer));
271 /* Initialize frequency and voltage adjustment helper. */
272 gcmkONERROR(gckOS_PrepareGPUFrequency(os, Hardware->core));
286 gcmkVERIFY_OK(gckOS_DestroyTimer(os, dvfs->timer));
289 gcmkOS_SAFE_FREE(os, dvfs);
301 gcmkHEADER_ARG("Dvfs=0x%X", Dvfs);
302 gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL);
304 /* Deinitialize helper fuunction. */
305 gcmkVERIFY_OK(gckOS_FinishGPUFrequency(Dvfs->os, Dvfs->hardware->core));
308 gcmkVERIFY_OK(gckOS_DestroyTimer(Dvfs->os, Dvfs->timer));
310 gcmkOS_SAFE_FREE(Dvfs->os, Dvfs);
321 gcmkHEADER_ARG("Dvfs=0x%X", Dvfs);
322 gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL);
324 gckHARDWARE_InitDVFS(Dvfs->hardware);
326 Dvfs->stop = gcvFALSE;
328 gckOS_StartTimer(Dvfs->os, Dvfs->timer, Dvfs->pollingTime);
339 gcmkHEADER_ARG("Dvfs=0x%X", Dvfs);
340 gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL);
342 Dvfs->stop = gcvTRUE;