gpu: pvr: pdumpfs: add stream_frames debugfs entry
[sgx.git] / pvr / sysutils.c
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 <plat/omap-pm.h>
32 #include <linux/bug.h>
33 #include <plat/clock.h>
34 #include <plat/cpu.h>
35 #include "sgxdefs.h"
36 #include "services_headers.h"
37 #include "sysinfo.h"
38 #include "sgxapi_km.h"
39 #include "sysconfig.h"
40 #include "sgxinfokm.h"
41 #include "syslocal.h"
42 #include "env_data.h"
43 #include "ocpdefs.h"
44 #include "pvr_bridge_km.h"
45
46 #define HZ_TO_MHZ(m) ((m) / 1000000)
47
48 static inline unsigned long scale_by_rate(unsigned long val,
49                                           unsigned long rate1,
50                                           unsigned long rate2)
51 {
52         if (rate1 >= rate2)
53                 return val * (rate1 / rate2);
54
55         return val / (rate2 / rate1);
56 }
57
58 static inline unsigned long scale_prop_to_SGX_clock(unsigned long val,
59                                                     unsigned long rate)
60 {
61         return scale_by_rate(val, rate, sgx_get_max_freq());
62 }
63
64 void SysGetSGXTimingInformation(struct SGX_TIMING_INFORMATION *psTimingInfo)
65 {
66         unsigned long rate;
67
68 #if defined(NO_HARDWARE)
69         rate = SYS_SGX_MAX_FREQ_NO_HW;
70 #else
71         rate = clk_get_rate(gpsSysSpecificData->psSGX_FCK);
72         PVR_ASSERT(rate != 0);
73 #endif
74         psTimingInfo->ui32CoreClockSpeed = rate;
75         psTimingInfo->ui32HWRecoveryFreq =
76             scale_prop_to_SGX_clock(SYS_SGX_HWRECOVERY_TIMEOUT_FREQ, rate);
77         psTimingInfo->ui32uKernelFreq =
78             scale_prop_to_SGX_clock(SYS_SGX_PDS_TIMER_FREQ, rate);
79         psTimingInfo->ui32ActivePowManLatencyms =
80             SYS_SGX_ACTIVE_POWER_LATENCY_MS;
81 }
82
83 static int vdd2_post_func(struct notifier_block *n, unsigned long event,
84                           void *ptr)
85 {
86         PVR_UNREFERENCED_PARAMETER(n);
87         PVR_UNREFERENCED_PARAMETER(event);
88         PVR_UNREFERENCED_PARAMETER(ptr);
89
90         if (atomic_read(&gpsSysSpecificData->sSGXClocksEnabled) != 0 &&
91             gpsSysSpecificData->bSGXInitComplete) {
92 #if defined(CONFIG_PVR_DEBUG_EXTRA)
93                 unsigned long rate;
94
95                 rate = clk_get_rate(gpsSysSpecificData->psSGX_FCK);
96
97                 PVR_ASSERT(rate != 0);
98
99                 PVR_TRACE("%s: SGX clock rate: %dMHz", __func__,
100                            HZ_TO_MHZ(rate));
101 #endif
102                 PVRSRVDevicePostClockSpeedChange(gpsSysSpecificData->
103                                                  psSGXDevNode->sDevId.
104                                                  ui32DeviceIndex, IMG_TRUE,
105                                                  NULL);
106         }
107         return 0;
108 }
109
110 static int vdd2_pre_func(struct notifier_block *n, unsigned long event,
111                          void *ptr)
112 {
113         PVR_UNREFERENCED_PARAMETER(n);
114         PVR_UNREFERENCED_PARAMETER(event);
115         PVR_UNREFERENCED_PARAMETER(ptr);
116
117         if (atomic_read(&gpsSysSpecificData->sSGXClocksEnabled) != 0 &&
118             gpsSysSpecificData->bSGXInitComplete) {
119                 BUG_ON(gpsSysData->eCurrentPowerState > PVRSRV_POWER_STATE_D1);
120                 PVRSRVDevicePreClockSpeedChange(gpsSysSpecificData->
121                                                 psSGXDevNode->sDevId.
122                                                 ui32DeviceIndex, IMG_TRUE,
123                                                 NULL);
124         }
125
126         return 0;
127 }
128
129 static int vdd2_pre_post_func(struct notifier_block *n, unsigned long event,
130                               void *ptr)
131 {
132         struct clk_notifier_data *cnd;
133
134         PVR_UNREFERENCED_PARAMETER(n);
135
136         cnd = (struct clk_notifier_data *)ptr;
137
138         PVR_TRACE("vdd2_pre_post_func: %s clock rate = %lu",
139                   (CLK_PRE_RATE_CHANGE == event) ? "old" :
140                   (CLK_POST_RATE_CHANGE == event) ? "new" :
141                   "???",
142                   cnd->rate);
143
144         if (CLK_PRE_RATE_CHANGE == event) {
145                 pvr_dev_lock();
146                 PVR_TRACE("vdd2_pre_post_func: CLK_PRE_RATE_CHANGE event");
147                 vdd2_pre_func(n, event, ptr);
148         } else if (CLK_POST_RATE_CHANGE == event) {
149                 PVR_TRACE("vdd2_pre_post_func: CLK_POST_RATE_CHANGE event");
150                 vdd2_post_func(n, event, ptr);
151                 pvr_dev_unlock();
152         } else if (CLK_ABORT_RATE_CHANGE == event) {
153                 PVR_TRACE("vdd2_pre_post_func: CLK_ABORT_RATE_CHANGE event");
154                 pvr_dev_unlock();
155         } else {
156                 printk(KERN_ERR "vdd2_pre_post_func: unexpected event (%lu)\n",
157                         event);
158                 PVR_DPF(PVR_DBG_ERROR,
159                          "vdd2_pre_post_func: unexpected event (%lu)", event);
160         }
161         PVR_TRACE("vdd2_pre_post_func end.");
162         return 0;
163 }
164
165 static struct notifier_block vdd2_pre_post = {
166         vdd2_pre_post_func,
167         NULL
168 };
169
170 static void RegisterConstraintNotifications(struct SYS_SPECIFIC_DATA
171                                             *psSysSpecData)
172 {
173         PVR_TRACE("Registering constraint notifications");
174
175         clk_notifier_register(psSysSpecData->psSGX_FCK, &vdd2_pre_post);
176         PVR_TRACE("VDD2 constraint notifications registered");
177 }
178
179 static void UnRegisterConstraintNotifications(struct SYS_SPECIFIC_DATA
180                                               *psSysSpecData)
181 {
182         PVR_TRACE("Unregistering constraint notifications");
183
184         clk_notifier_unregister(psSysSpecData->psSGX_FCK, &vdd2_pre_post);
185 }
186
187 static struct device sgx_dev;
188 static int sgx_clock_enabled;
189
190 /* return value: current sgx load
191  * 0 - not busy
192  * 100 - busy
193  */
194 static unsigned int sgx_current_load(void)
195 {
196         enum PVRSRV_ERROR eError;
197         struct SYS_DATA *psSysData;
198         struct SYS_SPECIFIC_DATA *psSysSpecData;
199         struct PVRSRV_DEVICE_NODE *psDeviceNode;
200         static unsigned int kicks_prev;
201         static long time_prev;
202
203         eError = SysAcquireData(&psSysData);
204         if (eError != PVRSRV_OK)
205                 return 0;
206         psSysSpecData =
207             (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
208         if (!psSysSpecData ||
209             atomic_read(&psSysSpecData->sSGXClocksEnabled) == 0)
210                 return 0;
211         psDeviceNode = psSysData->psDeviceNodeList;
212         while (psDeviceNode) {
213                 if ((psDeviceNode->sDevId.eDeviceType ==
214                             PVRSRV_DEVICE_TYPE_SGX) &&
215                     psDeviceNode->pvDevice) {
216                         struct PVRSRV_SGXDEV_INFO *psDevInfo =
217                             (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice;
218                         unsigned int kicks = psDevInfo->ui32KickTACounter;
219                         unsigned int load;
220                         long time_elapsed;
221
222                         time_elapsed = jiffies - time_prev;
223                         if (likely(time_elapsed))
224                                 load =
225                                     1000 * (kicks - kicks_prev) / time_elapsed;
226                         else
227                                 load = 0;
228                         kicks_prev = kicks;
229                         time_prev += time_elapsed;
230                         /*
231                          * if the period between calls to this function was
232                          * too long, then load stats are invalid
233                          */
234                         if (time_elapsed > 5 * HZ)
235                                 return 0;
236                         /*pr_err("SGX load %u\n", load); */
237
238                         /*
239                          * 'load' shows how many times sgx was kicked
240                          * per 1000 jiffies
241                          * 150 is arbitrarily chosen threshold.
242                          * If the number of kicks is below threshold
243                          * then sgx is doing
244                          * some small jobs and we can keep the clock freq low.
245                          */
246                         if (load < 150)
247                                 return 0;
248                         else
249                                 return 100;
250                 }
251                 psDeviceNode = psDeviceNode->psNext;
252         }
253         return 0;
254 }
255
256 static void sgx_lock_perf(struct work_struct *work)
257 {
258         int vdd1, vdd2;
259         static int bHigh;
260         int high;
261         unsigned int load;
262         struct delayed_work *d_work =
263             container_of(work, struct delayed_work, work);
264         struct ENV_DATA *psEnvData =
265             container_of(d_work, struct ENV_DATA, sPerfWork);
266
267         pvr_lock();
268
269         if (pvr_is_disabled()) {
270                 pvr_unlock();
271                 return;
272         }
273
274         load = sgx_current_load();
275
276         pvr_unlock();
277
278         if (load) {
279                 vdd1 = 500000000;
280                 vdd2 = 400000;
281                 high = 1;
282         } else {
283                 vdd1 = 0;
284                 vdd2 = 0;
285                 high = 0;
286         }
287         if (high != bHigh) {
288                 omap_pm_set_min_bus_tput(&sgx_dev, OCP_INITIATOR_AGENT, vdd2);
289                 bHigh = high;
290         }
291
292         if (sgx_clock_enabled || load)
293                 queue_delayed_work(psEnvData->psPerfWorkqueue,
294                                    &psEnvData->sPerfWork, HZ / 5);
295 }
296
297 static void sgx_need_perf(struct SYS_DATA *psSysData, int ena)
298 {
299         struct ENV_DATA *psEnvData =
300             (struct ENV_DATA *)psSysData->pvEnvSpecificData;
301
302         sgx_clock_enabled = ena;
303         cancel_delayed_work(&psEnvData->sPerfWork);
304         queue_delayed_work(psEnvData->psPerfWorkqueue, &psEnvData->sPerfWork,
305                            0);
306 }
307
308 enum PVRSRV_ERROR OSInitPerf(void *pvSysData)
309 {
310         struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData;
311         struct ENV_DATA *psEnvData =
312             (struct ENV_DATA *)psSysData->pvEnvSpecificData;
313
314         if (psEnvData->psPerfWorkqueue) {
315                 PVR_DPF(PVR_DBG_ERROR, "OSInitPerf: already inited");
316                 return PVRSRV_ERROR_GENERIC;
317         }
318
319         PVR_TRACE("Initing DVFS %x", pvSysData);
320
321         psEnvData->psPerfWorkqueue = create_singlethread_workqueue("sgx_perf");
322         INIT_DELAYED_WORK(&psEnvData->sPerfWork, sgx_lock_perf);
323
324         return PVRSRV_OK;
325 }
326
327 enum PVRSRV_ERROR OSCleanupPerf(void *pvSysData)
328 {
329         struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData;
330         struct ENV_DATA *psEnvData =
331             (struct ENV_DATA *)psSysData->pvEnvSpecificData;
332
333         if (!psEnvData->psPerfWorkqueue) {
334                 PVR_DPF(PVR_DBG_ERROR, "OSCleanupPerf: not inited");
335                 return PVRSRV_ERROR_GENERIC;
336         }
337
338         PVR_TRACE("Cleaning up DVFS");
339
340         sgx_clock_enabled = 0;
341         flush_workqueue(psEnvData->psPerfWorkqueue);
342         destroy_workqueue(psEnvData->psPerfWorkqueue);
343
344         return PVRSRV_OK;
345 }
346
347 static inline void setup_int_bypass(void)
348 {
349         if (cpu_is_omap3630())
350                 sgx_ocp_write_reg(EUR_CR_OCP_DEBUG_CONFIG,
351                               EUR_CR_OCP_DEBUG_CONFIG_THALIA_INT_BYPASS_MASK);
352 }
353
354 #ifndef NO_HARDWARE
355
356 static enum PVRSRV_ERROR sgx_force_enable_clocks(struct SYS_DATA *psSysData)
357 {
358         struct SYS_SPECIFIC_DATA *psSysSpecData =
359             (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
360         int res;
361
362         res = clk_enable(psSysSpecData->psSGX_FCK);
363         if (res < 0) {
364                 PVR_DPF(PVR_DBG_ERROR, "%s: "
365                                 "Couldn't enable SGX functional clock (%d)",
366                          __func__, res);
367                 return PVRSRV_ERROR_GENERIC;
368         }
369
370         res = clk_enable(psSysSpecData->psSGX_ICK);
371         if (res < 0) {
372                 PVR_DPF(PVR_DBG_ERROR, "%s: "
373                                 "Couldn't enable SGX interface clock (%d)",
374                          __func__, res);
375
376                 clk_disable(psSysSpecData->psSGX_FCK);
377                 return PVRSRV_ERROR_GENERIC;
378         }
379
380         setup_int_bypass();
381
382         return PVRSRV_OK;
383 }
384
385 static void sgx_force_disable_clocks(struct SYS_DATA *psSysData)
386 {
387         struct SYS_SPECIFIC_DATA *psSysSpecData =
388             (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
389
390         if (psSysSpecData->psSGX_ICK)
391                 clk_disable(psSysSpecData->psSGX_ICK);
392
393         if (psSysSpecData->psSGX_FCK)
394                 clk_disable(psSysSpecData->psSGX_FCK);
395 }
396
397 #else           /* NO_HARDWARE */
398
399 static enum PVRSRV_ERROR sgx_force_enable_clocks(struct SYS_DATA *psSYsData)
400 {
401         return PVRSRV_OK;
402 }
403
404 static void sgx_force_disable_clocks(struct SYS_DATA *psSYsData)
405 {
406 }
407
408 #endif          /* NO_HARDWARE */
409
410 static bool force_clocks_on(void)
411 {
412 #ifdef CONFIG_PVR_FORCE_CLOCKS_ON
413         return true;
414 #else
415         return false;
416 #endif
417 }
418
419 enum PVRSRV_ERROR EnableSGXClocks(struct SYS_DATA *psSysData)
420 {
421         struct SYS_SPECIFIC_DATA *psSysSpecData =
422             (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
423         enum PVRSRV_ERROR res = PVRSRV_OK;
424
425         if (atomic_xchg(&psSysSpecData->sSGXClocksEnabled, 1))
426                 return PVRSRV_OK;
427
428         /*
429          * In case of force clocks on we have already enabled the clocks
430          * at init time.
431          */
432         if (!force_clocks_on())
433                 res = sgx_force_enable_clocks(psSysData);
434
435         if (res == PVRSRV_OK) {
436                 BUG_ON(!atomic_read(&psSysSpecData->sSGXClocksEnabled));
437                 sgx_need_perf(psSysData, 1);
438         } else {
439                 atomic_set(&psSysSpecData->sSGXClocksEnabled, 0);
440         }
441
442         return res;
443 }
444
445 void DisableSGXClocks(struct SYS_DATA *psSysData)
446 {
447         struct SYS_SPECIFIC_DATA *psSysSpecData =
448             (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
449
450         if (!atomic_xchg(&psSysSpecData->sSGXClocksEnabled, 0))
451                 return;
452
453         if (!force_clocks_on())
454                 sgx_force_disable_clocks(psSysData);
455
456         BUG_ON(atomic_read(&psSysSpecData->sSGXClocksEnabled));
457
458         sgx_need_perf(psSysData, 0);
459 }
460
461 static enum PVRSRV_ERROR InitSgxClocks(struct SYS_DATA *psSysData)
462 {
463         struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
464         struct clk *psCLK;
465         struct clk *core_ck = NULL;
466         unsigned long rate;
467         int r;
468
469         psCLK = clk_get(NULL, "sgx_fck");
470         if (IS_ERR(psCLK))
471                 goto err0;
472         psSysSpecData->psSGX_FCK = psCLK;
473
474         psCLK = clk_get(NULL, "sgx_ick");
475         if (IS_ERR(psCLK))
476                 goto err1;
477         psSysSpecData->psSGX_ICK = psCLK;
478
479         core_ck = clk_get(NULL, "core_ck");
480         if (IS_ERR(core_ck))
481                 goto err2;
482         if (clk_set_parent(psSysSpecData->psSGX_FCK, core_ck) < 0) {
483                 clk_put(core_ck);
484                 goto err2;
485         }
486         clk_put(core_ck);
487
488         /* +1 to account for rounding errors */
489         rate = clk_round_rate(psSysSpecData->psSGX_FCK, sgx_get_max_freq() + 1);
490         r = clk_set_rate(psSysSpecData->psSGX_FCK, rate);
491         if (r < 0) {
492                 unsigned long current_rate;
493
494                 current_rate = clk_get_rate(psSysSpecData->psSGX_FCK);
495                 pr_warning("error %d when setting SGX fclk to %lu Hz, "
496                            "falling back to %lu Hz\n", r, rate, current_rate);
497         } else {
498                 pr_info("SGX clock rate %lu MHz\n", rate / 1000000);
499         };
500
501         RegisterConstraintNotifications(psSysSpecData);
502         return PVRSRV_OK;
503
504 err2:
505         clk_put(psSysSpecData->psSGX_ICK);
506 err1:
507         clk_put(psSysSpecData->psSGX_FCK);
508 err0:
509         PVR_DPF(PVR_DBG_ERROR,
510                  "%s: couldn't init clocks fck %p ick %p core %p", __func__,
511                  psSysSpecData->psSGX_FCK, psSysSpecData->psSGX_ICK, core_ck);
512         psSysSpecData->psSGX_FCK = NULL;
513         psSysSpecData->psSGX_ICK = NULL;
514
515         return PVRSRV_ERROR_GENERIC;
516 }
517
518 static void CleanupSgxClocks(struct SYS_DATA *psSysData)
519 {
520         struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
521         UnRegisterConstraintNotifications(psSysSpecData);
522
523         if (psSysSpecData->psSGX_ICK) {
524                 clk_put(psSysSpecData->psSGX_ICK);
525                 psSysSpecData->psSGX_ICK = NULL;
526         }
527
528         if (psSysSpecData->psSGX_FCK) {
529                 clk_put(psSysSpecData->psSGX_FCK);
530                 psSysSpecData->psSGX_FCK = NULL;
531         }
532 }
533
534 #if defined(CONFIG_PVR_DEBUG_EXTRA) || defined(TIMING)
535 static inline u32 gpt_read_reg(struct SYS_DATA *psSysData, u32 reg)
536 {
537         struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
538
539         return __raw_readl(psSysSpecData->gpt_base + reg);
540 }
541
542 static inline void gpt_write_reg(struct SYS_DATA *psSysData, u32 reg, u32 val)
543 {
544         struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
545
546         __raw_writel(val, psSysSpecData->gpt_base + reg);
547 }
548
549 static enum PVRSRV_ERROR InitDebugClocks(struct SYS_DATA *psSysData)
550 {
551         struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
552         struct clk *psCLK;
553         struct clk *sys_ck = NULL;
554         u32 rate;
555
556         psCLK = clk_get(NULL, "mpu_ck");
557         if (IS_ERR(psCLK))
558                 goto err0;
559         psSysSpecData->psMPU_CK = psCLK;
560
561         psCLK = clk_get(NULL, "gpt11_fck");
562         if (IS_ERR(psCLK))
563                 goto err1;
564         psSysSpecData->psGPT11_FCK = psCLK;
565
566         psCLK = clk_get(NULL, "gpt11_ick");
567         if (IS_ERR(psCLK))
568                 goto err2;
569         psSysSpecData->psGPT11_ICK = psCLK;
570
571         sys_ck = clk_get(NULL, "sys_ck");
572         if (IS_ERR(sys_ck))
573                 goto err3;
574         if (clk_get_parent(psSysSpecData->psGPT11_FCK) != sys_ck)
575                 if (clk_set_parent(psSysSpecData->psGPT11_FCK, sys_ck) < 0) {
576                         clk_put(sys_ck);
577                         goto err3;
578                 }
579         clk_put(sys_ck);
580
581         PVR_TRACE("GPTIMER11 clock is %dMHz",
582                    HZ_TO_MHZ(clk_get_rate(psSysSpecData->psGPT11_FCK)));
583
584         psSysSpecData->gpt_base = ioremap(SYS_OMAP3430_GP11TIMER_PHYS_BASE,
585                                           SYS_OMAP3430_GPTIMER_SIZE);
586         if (!psSysSpecData->gpt_base)
587                 goto err3;
588
589         clk_enable(psSysSpecData->psGPT11_ICK);
590         clk_enable(psSysSpecData->psGPT11_FCK);
591
592         rate = gpt_read_reg(psSysData, SYS_OMAP3430_GPTIMER_TSICR);
593         if (!(rate & 4)) {
594                 PVR_TRACE("Setting GPTIMER11 mode to posted "
595                           "(currently is non-posted)");
596                 gpt_write_reg(psSysData, SYS_OMAP3430_GPTIMER_TSICR, rate | 4);
597         }
598
599         clk_disable(psSysSpecData->psGPT11_FCK);
600         clk_disable(psSysSpecData->psGPT11_ICK);
601
602         return PVRSRV_OK;
603
604 err3:
605         clk_put(psSysSpecData->psGPT11_ICK);
606 err2:
607         clk_put(psSysSpecData->psGPT11_FCK);
608 err1:
609         clk_put(psSysSpecData->psMPU_CK);
610 err0:
611         PVR_DPF(PVR_DBG_ERROR,
612                  "%s: couldn't init clocks: mpu %p sys %p fck %p ick %p",
613                  __func__, psSysSpecData->psMPU_CK, sys_ck,
614                  psSysSpecData->psGPT11_FCK, psSysSpecData->psGPT11_ICK);
615
616         psSysSpecData->psMPU_CK = NULL;
617         psSysSpecData->psGPT11_FCK = NULL;
618         psSysSpecData->psGPT11_ICK = NULL;
619
620         return PVRSRV_ERROR_GENERIC;
621 }
622
623 static void CleanupDebugClocks(struct SYS_DATA *psSysData)
624 {
625         struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
626
627         if (psSysSpecData->psMPU_CK) {
628                 clk_put(psSysSpecData->psMPU_CK);
629                 psSysSpecData->psMPU_CK = NULL;
630         }
631         if (psSysSpecData->psGPT11_FCK) {
632                 clk_put(psSysSpecData->psGPT11_FCK);
633                 psSysSpecData->psGPT11_FCK = NULL;
634         }
635         if (psSysSpecData->psGPT11_ICK) {
636                 clk_put(psSysSpecData->psGPT11_ICK);
637                 psSysSpecData->psGPT11_ICK = NULL;
638         }
639 }
640
641 static enum PVRSRV_ERROR EnableDebugClocks(struct SYS_DATA *psSysData)
642 {
643         struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
644
645         if (clk_enable(psSysSpecData->psGPT11_FCK) < 0)
646                 goto err0;
647
648         if (clk_enable(psSysSpecData->psGPT11_ICK) < 0)
649                 goto err1;
650
651         gpt_write_reg(psSysData, SYS_OMAP3430_GPTIMER_ENABLE, 3);
652
653         return PVRSRV_OK;
654
655 err1:
656         clk_disable(psSysSpecData->psGPT11_FCK);
657 err0:
658         PVR_DPF(PVR_DBG_ERROR, "%s: can't enable clocks", __func__);
659
660         return PVRSRV_ERROR_GENERIC;
661 }
662
663 static inline void DisableDebugClocks(struct SYS_DATA *psSysData)
664 {
665         struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
666
667         gpt_write_reg(psSysData, SYS_OMAP3430_GPTIMER_ENABLE, 0);
668
669         clk_disable(psSysSpecData->psGPT11_ICK);
670         clk_disable(psSysSpecData->psGPT11_FCK);
671 }
672
673 #else
674
675 inline enum PVRSRV_ERROR InitDebugClocks(struct SYS_DATA *psSysData)
676 {
677         return PVRSRV_OK;
678 }
679
680 static inline void CleanupDebugClocks(struct SYS_DATA *psSysData)
681 {
682 }
683
684 static inline enum PVRSRV_ERROR EnableDebugClocks(struct SYS_DATA *psSysData)
685 {
686         return PVRSRV_OK;
687 }
688
689 static inline void DisableDebugClocks(struct SYS_DATA *psSysData)
690 {
691 }
692 #endif
693
694 enum PVRSRV_ERROR InitSystemClocks(struct SYS_DATA *psSysData)
695 {
696         if (InitSgxClocks(psSysData) != PVRSRV_OK)
697                 goto err0;
698
699         if (InitDebugClocks(psSysData) != PVRSRV_OK)
700                 goto err1;
701
702         return PVRSRV_OK;
703
704 err1:
705         CleanupSgxClocks(psSysData);
706 err0:
707         return PVRSRV_ERROR_GENERIC;
708 }
709
710 void CleanupSystemClocks(struct SYS_DATA *psSysData)
711 {
712         CleanupDebugClocks(psSysData);
713         CleanupSgxClocks(psSysData);
714 }
715
716 enum PVRSRV_ERROR EnableSystemClocks(struct SYS_DATA *psSysData)
717 {
718         PVR_TRACE("EnableSystemClocks: Enabling System Clocks");
719
720         /*
721          * We force clocks on by increasing their refcount here during
722          * module init time and decreasing it at cleanup time.
723          */
724         if (force_clocks_on())
725                 sgx_force_enable_clocks(gpsSysData);
726         if (EnableDebugClocks(psSysData) != PVRSRV_OK)
727                 goto err1;
728
729         return PVRSRV_OK;
730
731 err1:
732         return PVRSRV_ERROR_GENERIC;
733 }
734
735 void DisableSystemClocks(struct SYS_DATA *psSysData)
736 {
737         PVR_TRACE("DisableSystemClocks: Disabling System Clocks");
738
739         DisableDebugClocks(psSysData);
740         /* Decrease the clocks' refcount that was increased at init time. */
741         if (force_clocks_on())
742                 sgx_force_disable_clocks(gpsSysData);
743 }