aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/pvr/omap4/sysutils_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/pvr/omap4/sysutils_linux.c')
-rw-r--r--drivers/gpu/pvr/omap4/sysutils_linux.c537
1 files changed, 537 insertions, 0 deletions
diff --git a/drivers/gpu/pvr/omap4/sysutils_linux.c b/drivers/gpu/pvr/omap4/sysutils_linux.c
new file mode 100644
index 00000000000..40b2cc35ccc
--- /dev/null
+++ b/drivers/gpu/pvr/omap4/sysutils_linux.c
@@ -0,0 +1,537 @@
1/**********************************************************************
2 *
3 * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful but, except
10 * as otherwise stated in writing, without any warranty; without even the
11 * implied warranty of merchantability or fitness for a particular purpose.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * The full GNU General Public License is included in this distribution in
19 * the file called "COPYING".
20 *
21 * Contact Information:
22 * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23 * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
24 *
25 ******************************************************************************/
26
27#include <linux/version.h>
28#include <linux/clk.h>
29#include <linux/err.h>
30#include <linux/hardirq.h>
31#include <linux/mutex.h>
32
33#include "sgxdefs.h"
34#include "services_headers.h"
35#include "sysinfo.h"
36#include "sgxapi_km.h"
37#include "sysconfig.h"
38#include "sgxinfokm.h"
39#include "syslocal.h"
40
41#include <linux/platform_device.h>
42#include <linux/pm_runtime.h>
43
44#if !defined(PVR_LINUX_USING_WORKQUEUES)
45#error "PVR_LINUX_USING_WORKQUEUES must be defined"
46#endif
47
48#if ((defined(DEBUG) || defined(TIMING)) && \
49 (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))) && \
50 !defined(PVR_NO_OMAP_TIMER)
51#define PVR_OMAP4_TIMING_PRCM
52#endif
53
54#define ONE_MHZ 1000000
55#define HZ_TO_MHZ(m) ((m) / ONE_MHZ)
56
57#if defined(SUPPORT_OMAP3430_SGXFCLK_96M)
58#define SGX_PARENT_CLOCK "cm_96m_fck"
59#else
60#define SGX_PARENT_CLOCK "core_ck"
61#endif
62
63#if defined(LDM_PLATFORM) && !defined(SUPPORT_DRI_DRM)
64extern struct platform_device *gpsPVRLDMDev;
65#endif
66
67static IMG_VOID PowerLockWrap(SYS_SPECIFIC_DATA *psSysSpecData)
68{
69 if (!in_interrupt())
70 {
71 mutex_lock(&psSysSpecData->sPowerLock);
72
73 }
74}
75
76static IMG_VOID PowerLockUnwrap(SYS_SPECIFIC_DATA *psSysSpecData)
77{
78 if (!in_interrupt())
79 {
80 mutex_unlock(&psSysSpecData->sPowerLock);
81 }
82}
83
84PVRSRV_ERROR SysPowerLockWrap(IMG_VOID)
85{
86 SYS_DATA *psSysData;
87
88 SysAcquireData(&psSysData);
89
90 PowerLockWrap(psSysData->pvSysSpecificData);
91
92 return PVRSRV_OK;
93}
94
95IMG_VOID SysPowerLockUnwrap(IMG_VOID)
96{
97 SYS_DATA *psSysData;
98
99 SysAcquireData(&psSysData);
100
101 PowerLockUnwrap(psSysData->pvSysSpecificData);
102}
103
104IMG_BOOL WrapSystemPowerChange(SYS_SPECIFIC_DATA *psSysSpecData)
105{
106 return IMG_TRUE;
107}
108
109IMG_VOID UnwrapSystemPowerChange(SYS_SPECIFIC_DATA *psSysSpecData)
110{
111}
112
113static inline IMG_UINT32 scale_by_rate(IMG_UINT32 val, IMG_UINT32 rate1, IMG_UINT32 rate2)
114{
115 if (rate1 >= rate2)
116 {
117 return val * (rate1 / rate2);
118 }
119
120 return val / (rate2 / rate1);
121}
122
123static inline IMG_UINT32 scale_prop_to_SGX_clock(IMG_UINT32 val, IMG_UINT32 rate)
124{
125 return scale_by_rate(val, rate, SYS_SGX_CLOCK_SPEED);
126}
127
128static inline IMG_UINT32 scale_inv_prop_to_SGX_clock(IMG_UINT32 val, IMG_UINT32 rate)
129{
130 return scale_by_rate(val, SYS_SGX_CLOCK_SPEED, rate);
131}
132
133IMG_VOID SysGetSGXTimingInformation(SGX_TIMING_INFORMATION *psTimingInfo)
134{
135 IMG_UINT32 rate;
136
137#if defined(NO_HARDWARE)
138 rate = SYS_SGX_CLOCK_SPEED;
139#else
140 PVR_ASSERT(atomic_read(&gpsSysSpecificData->sSGXClocksEnabled) != 0);
141
142#if defined(OMAP4_PRCM_ENABLE)
143 rate = clk_get_rate(gpsSysSpecificData->psSGX_FCK);
144#else
145 rate = SYS_SGX_CLOCK_SPEED;
146#endif
147 PVR_ASSERT(rate != 0);
148#endif
149 psTimingInfo->ui32CoreClockSpeed = rate;
150 psTimingInfo->ui32HWRecoveryFreq = scale_prop_to_SGX_clock(SYS_SGX_HWRECOVERY_TIMEOUT_FREQ, rate);
151 psTimingInfo->ui32uKernelFreq = scale_prop_to_SGX_clock(SYS_SGX_PDS_TIMER_FREQ, rate);
152#if defined(SUPPORT_ACTIVE_POWER_MANAGEMENT)
153 psTimingInfo->bEnableActivePM = IMG_TRUE;
154#else
155 psTimingInfo->bEnableActivePM = IMG_FALSE;
156#endif
157 psTimingInfo->ui32ActivePowManLatencyms = SYS_SGX_ACTIVE_POWER_LATENCY_MS;
158}
159
160PVRSRV_ERROR EnableSGXClocks(SYS_DATA *psSysData)
161{
162#if !defined(NO_HARDWARE)
163 SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
164#if defined(OMAP4_PRCM_ENABLE)
165 long lNewRate;
166 long lRate;
167 IMG_INT res;
168#endif
169
170
171 if (atomic_read(&psSysSpecData->sSGXClocksEnabled) != 0)
172 {
173 return PVRSRV_OK;
174 }
175
176 PVR_DPF((PVR_DBG_MESSAGE, "EnableSGXClocks: Enabling SGX Clocks"));
177
178#if defined(LDM_PLATFORM) && !defined(SUPPORT_DRI_DRM)
179 pm_runtime_get_sync(&gpsPVRLDMDev->dev);
180#endif
181
182#if defined(OMAP4_PRCM_ENABLE)
183
184#if defined(DEBUG)
185 {
186 IMG_UINT32 rate = clk_get_rate(psSysSpecData->psMPU_CK);
187 PVR_DPF((PVR_DBG_MESSAGE, "EnableSGXClocks: CPU Clock is %dMhz", HZ_TO_MHZ(rate)));
188 }
189#endif
190
191 res = clk_enable(psSysSpecData->psSGX_FCK);
192 if (res < 0)
193 {
194 PVR_DPF((PVR_DBG_ERROR, "EnableSGXClocks: Couldn't enable SGX functional clock (%d)", res));
195 return PVRSRV_ERROR_UNABLE_TO_ENABLE_CLOCK;
196 }
197
198 res = clk_enable(psSysSpecData->psSGX_ICK);
199 if (res < 0)
200 {
201 PVR_DPF((PVR_DBG_ERROR, "EnableSGXClocks: Couldn't enable SGX interface clock (%d)", res));
202
203 clk_disable(psSysSpecData->psSGX_FCK);
204 return PVRSRV_ERROR_UNABLE_TO_ENABLE_CLOCK;
205 }
206
207 lNewRate = clk_round_rate(psSysSpecData->psSGX_FCK, SYS_SGX_CLOCK_SPEED + ONE_MHZ);
208 if (lNewRate <= 0)
209 {
210 PVR_DPF((PVR_DBG_ERROR, "EnableSGXClocks: Couldn't round SGX functional clock rate"));
211 return PVRSRV_ERROR_UNABLE_TO_ROUND_CLOCK_RATE;
212 }
213
214
215 lRate = clk_get_rate(psSysSpecData->psSGX_FCK);
216 if (lRate != lNewRate)
217 {
218 res = clk_set_rate(psSysSpecData->psSGX_FCK, lNewRate);
219 if (res < 0)
220 {
221 PVR_DPF((PVR_DBG_WARNING, "EnableSGXClocks: Couldn't set SGX functional clock rate (%d)", res));
222 }
223 }
224
225#if defined(DEBUG)
226 {
227 IMG_UINT32 rate = clk_get_rate(psSysSpecData->psSGX_FCK);
228 PVR_DPF((PVR_DBG_MESSAGE, "EnableSGXClocks: SGX Functional Clock is %dMhz", HZ_TO_MHZ(rate)));
229 }
230#endif
231
232#endif
233
234
235 atomic_set(&psSysSpecData->sSGXClocksEnabled, 1);
236
237#else
238 PVR_UNREFERENCED_PARAMETER(psSysData);
239#endif
240 return PVRSRV_OK;
241}
242
243
244IMG_VOID DisableSGXClocks(SYS_DATA *psSysData)
245{
246#if !defined(NO_HARDWARE)
247 SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
248
249
250 if (atomic_read(&psSysSpecData->sSGXClocksEnabled) == 0)
251 {
252 return;
253 }
254
255 PVR_DPF((PVR_DBG_MESSAGE, "DisableSGXClocks: Disabling SGX Clocks"));
256
257#if defined(LDM_PLATFORM) && !defined(SUPPORT_DRI_DRM)
258 pm_runtime_put_sync(&gpsPVRLDMDev->dev);
259#endif
260
261#if defined(OMAP4_PRCM_ENABLE)
262 if (psSysSpecData->psSGX_ICK)
263 {
264 clk_disable(psSysSpecData->psSGX_ICK);
265 }
266
267 if (psSysSpecData->psSGX_FCK)
268 {
269 clk_disable(psSysSpecData->psSGX_FCK);
270 }
271#endif
272
273
274 atomic_set(&psSysSpecData->sSGXClocksEnabled, 0);
275
276#else
277 PVR_UNREFERENCED_PARAMETER(psSysData);
278#endif
279}
280
281PVRSRV_ERROR EnableSystemClocks(SYS_DATA *psSysData)
282{
283 SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
284#if (defined(OMAP4_PRCM_ENABLE) || defined(PVR_OMAP4_TIMING_PRCM))
285 struct clk *psCLK;
286 IMG_INT res;
287#endif
288#if defined(PVR_OMAP4_TIMING_PRCM)
289 struct clk *sys_ck;
290 IMG_INT rate;
291#endif
292 PVRSRV_ERROR eError;
293
294#if (defined(DEBUG) || defined(TIMING)) && !defined(PVR_NO_OMAP_TIMER)
295 IMG_CPU_PHYADDR TimerRegPhysBase;
296 IMG_HANDLE hTimerEnable;
297 IMG_UINT32 *pui32TimerEnable;
298#endif
299
300 PVR_TRACE(("EnableSystemClocks: Enabling System Clocks"));
301
302 if (!psSysSpecData->bSysClocksOneTimeInit)
303 {
304 mutex_init(&psSysSpecData->sPowerLock);
305
306 atomic_set(&psSysSpecData->sSGXClocksEnabled, 0);
307
308#if defined(OMAP4_PRCM_ENABLE)
309 psCLK = clk_get(NULL, SGX_PARENT_CLOCK);
310 if (IS_ERR(psCLK))
311 {
312 PVR_DPF((PVR_DBG_ERROR, "EnableSsystemClocks: Couldn't get Core Clock"));
313 goto ExitError;
314 }
315 psSysSpecData->psCORE_CK = psCLK;
316
317 psCLK = clk_get(NULL, "sgx_fck");
318 if (IS_ERR(psCLK))
319 {
320 PVR_DPF((PVR_DBG_ERROR, "EnableSsystemClocks: Couldn't get SGX Functional Clock"));
321 goto ExitError;
322 }
323 psSysSpecData->psSGX_FCK = psCLK;
324
325 psCLK = clk_get(NULL, "sgx_ick");
326 if (IS_ERR(psCLK))
327 {
328 PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get SGX Interface Clock"));
329 goto ExitError;
330 }
331 psSysSpecData->psSGX_ICK = psCLK;
332
333#if defined(DEBUG)
334 psCLK = clk_get(NULL, "mpu_ck");
335 if (IS_ERR(psCLK))
336 {
337 PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get MPU Clock"));
338 goto ExitError;
339 }
340 psSysSpecData->psMPU_CK = psCLK;
341#endif
342 res = clk_set_parent(psSysSpecData->psSGX_FCK, psSysSpecData->psCORE_CK);
343 if (res < 0)
344 {
345 PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't set SGX parent clock (%d)", res));
346 goto ExitError;
347 }
348#endif
349
350 psSysSpecData->bSysClocksOneTimeInit = IMG_TRUE;
351 }
352
353#if (defined(DEBUG) || defined(TIMING)) && !defined(PVR_NO_OMAP_TIMER)
354#if defined(PVR_OMAP4_TIMING_PRCM)
355
356 psCLK = clk_get(NULL, "gpt11_fck");
357 if (IS_ERR(psCLK))
358 {
359 PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get GPTIMER11 functional clock"));
360 goto ExitUnRegisterConstraintNotifications;
361 }
362 psSysSpecData->psGPT11_FCK = psCLK;
363
364 psCLK = clk_get(NULL, "gpt11_ick");
365 if (IS_ERR(psCLK))
366 {
367 PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get GPTIMER11 interface clock"));
368 goto ExitUnRegisterConstraintNotifications;
369 }
370 psSysSpecData->psGPT11_ICK = psCLK;
371
372 sys_ck = clk_get(NULL, "sys_clkin_ck");
373 if (IS_ERR(sys_ck))
374 {
375 PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't get System clock"));
376 goto ExitUnRegisterConstraintNotifications;
377 }
378
379 if(clk_get_parent(psSysSpecData->psGPT11_FCK) != sys_ck)
380 {
381 PVR_TRACE(("Setting GPTIMER11 parent to System Clock"));
382 res = clk_set_parent(psSysSpecData->psGPT11_FCK, sys_ck);
383 if (res < 0)
384 {
385 PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't set GPTIMER11 parent clock (%d)", res));
386 goto ExitUnRegisterConstraintNotifications;
387 }
388 }
389
390 rate = clk_get_rate(psSysSpecData->psGPT11_FCK);
391 PVR_TRACE(("GPTIMER11 clock is %dMHz", HZ_TO_MHZ(rate)));
392
393 res = clk_enable(psSysSpecData->psGPT11_FCK);
394 if (res < 0)
395 {
396 PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't enable GPTIMER11 functional clock (%d)", res));
397 goto ExitUnRegisterConstraintNotifications;
398 }
399
400 res = clk_enable(psSysSpecData->psGPT11_ICK);
401 if (res < 0)
402 {
403 PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: Couldn't enable GPTIMER11 interface clock (%d)", res));
404 goto ExitDisableGPT11FCK;
405 }
406#endif
407
408
409 TimerRegPhysBase.uiAddr = SYS_OMAP4430_GP11TIMER_TSICR_SYS_PHYS_BASE;
410 pui32TimerEnable = OSMapPhysToLin(TimerRegPhysBase,
411 4,
412 PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
413 &hTimerEnable);
414
415 if (pui32TimerEnable == IMG_NULL)
416 {
417 PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: OSMapPhysToLin failed"));
418 goto ExitDisableGPT11ICK;
419 }
420
421 if(!(*pui32TimerEnable & 4))
422 {
423 PVR_TRACE(("Setting GPTIMER11 mode to posted (currently is non-posted)"));
424
425
426 *pui32TimerEnable |= 4;
427 }
428
429 OSUnMapPhysToLin(pui32TimerEnable,
430 4,
431 PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
432 hTimerEnable);
433
434
435 TimerRegPhysBase.uiAddr = SYS_OMAP4430_GP11TIMER_ENABLE_SYS_PHYS_BASE;
436 pui32TimerEnable = OSMapPhysToLin(TimerRegPhysBase,
437 4,
438 PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
439 &hTimerEnable);
440
441 if (pui32TimerEnable == IMG_NULL)
442 {
443 PVR_DPF((PVR_DBG_ERROR, "EnableSystemClocks: OSMapPhysToLin failed"));
444 goto ExitDisableGPT11ICK;
445 }
446
447
448 *pui32TimerEnable = 3;
449
450 OSUnMapPhysToLin(pui32TimerEnable,
451 4,
452 PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
453 hTimerEnable);
454
455#endif
456
457 eError = PVRSRV_OK;
458 goto Exit;
459
460#if (defined(DEBUG) || defined(TIMING)) && !defined(PVR_NO_OMAP_TIMER)
461ExitDisableGPT11ICK:
462#if defined(PVR_OMAP4_TIMING_PRCM)
463 clk_disable(psSysSpecData->psGPT11_ICK);
464ExitDisableGPT11FCK:
465 clk_disable(psSysSpecData->psGPT11_FCK);
466ExitUnRegisterConstraintNotifications:
467#endif
468#endif
469#if defined(OMAP4_PRCM_ENABLE)
470ExitError:
471#endif
472 eError = PVRSRV_ERROR_DISABLE_CLOCK_FAILURE;
473Exit:
474 return eError;
475}
476
477IMG_VOID DisableSystemClocks(SYS_DATA *psSysData)
478{
479#if (defined(DEBUG) || defined(TIMING)) && !defined(PVR_NO_OMAP_TIMER)
480#if defined(PVR_OMAP4_TIMING_PRCM)
481 SYS_SPECIFIC_DATA *psSysSpecData = (SYS_SPECIFIC_DATA *) psSysData->pvSysSpecificData;
482#endif
483 IMG_CPU_PHYADDR TimerRegPhysBase;
484 IMG_HANDLE hTimerDisable;
485 IMG_UINT32 *pui32TimerDisable;
486#endif
487
488 PVR_TRACE(("DisableSystemClocks: Disabling System Clocks"));
489
490
491 DisableSGXClocks(psSysData);
492
493#if (defined(DEBUG) || defined(TIMING)) && !defined(PVR_NO_OMAP_TIMER)
494
495 TimerRegPhysBase.uiAddr = SYS_OMAP4430_GP11TIMER_ENABLE_SYS_PHYS_BASE;
496 pui32TimerDisable = OSMapPhysToLin(TimerRegPhysBase,
497 4,
498 PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
499 &hTimerDisable);
500
501 if (pui32TimerDisable == IMG_NULL)
502 {
503 PVR_DPF((PVR_DBG_ERROR, "DisableSystemClocks: OSMapPhysToLin failed"));
504 }
505 else
506 {
507 *pui32TimerDisable = 0;
508
509 OSUnMapPhysToLin(pui32TimerDisable,
510 4,
511 PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
512 hTimerDisable);
513 }
514
515#if defined(PVR_OMAP4_TIMING_PRCM)
516 clk_disable(psSysSpecData->psGPT11_ICK);
517
518 clk_disable(psSysSpecData->psGPT11_FCK);
519#endif
520#endif
521}
522
523PVRSRV_ERROR SysPMRuntimeRegister(void)
524{
525#if defined(LDM_PLATFORM) && !defined(SUPPORT_DRI_DRM)
526 pm_runtime_enable(&gpsPVRLDMDev->dev);
527#endif
528 return PVRSRV_OK;
529}
530
531PVRSRV_ERROR SysPMRuntimeUnregister(void)
532{
533#if defined(LDM_PLATFORM) && !defined(SUPPORT_DRI_DRM)
534 pm_runtime_disable(&gpsPVRLDMDev->dev);
535#endif
536 return PVRSRV_OK;
537}