1 /**********************************************************************
3 * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
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.
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.
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.
18 * The full GNU General Public License is included in this distribution in
19 * the file called "COPYING".
21 * Contact Information:
22 * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23 * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
25 ******************************************************************************/
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>
36 #include "services_headers.h"
38 #include "sgxapi_km.h"
39 #include "sysconfig.h"
40 #include "sgxinfokm.h"
45 #define HZ_TO_MHZ(m) ((m) / 1000000)
47 static inline unsigned long scale_by_rate(unsigned long val,
52 return val * (rate1 / rate2);
54 return val / (rate2 / rate1);
57 static inline unsigned long scale_prop_to_SGX_clock(unsigned long val,
60 return scale_by_rate(val, rate, sgx_get_max_freq());
63 void SysGetSGXTimingInformation(struct SGX_TIMING_INFORMATION *psTimingInfo)
67 #if defined(NO_HARDWARE)
68 rate = SYS_SGX_MAX_FREQ_NO_HW;
70 PVR_ASSERT(atomic_read(&gpsSysSpecificData->sSGXClocksEnabled) != 0);
72 rate = clk_get_rate(gpsSysSpecificData->psSGX_FCK);
73 PVR_ASSERT(rate != 0);
75 psTimingInfo->ui32CoreClockSpeed = rate;
76 psTimingInfo->ui32HWRecoveryFreq =
77 scale_prop_to_SGX_clock(SYS_SGX_HWRECOVERY_TIMEOUT_FREQ, rate);
78 psTimingInfo->ui32uKernelFreq =
79 scale_prop_to_SGX_clock(SYS_SGX_PDS_TIMER_FREQ, rate);
80 psTimingInfo->ui32ActivePowManLatencyms =
81 SYS_SGX_ACTIVE_POWER_LATENCY_MS;
84 static int vdd2_post_func(struct notifier_block *n, unsigned long event,
87 PVR_UNREFERENCED_PARAMETER(n);
88 PVR_UNREFERENCED_PARAMETER(event);
89 PVR_UNREFERENCED_PARAMETER(ptr);
91 if (atomic_read(&gpsSysSpecificData->sSGXClocksEnabled) != 0 &&
92 gpsSysSpecificData->bSGXInitComplete) {
93 #if defined(CONFIG_PVR_DEBUG_EXTRA)
96 rate = clk_get_rate(gpsSysSpecificData->psSGX_FCK);
98 PVR_ASSERT(rate != 0);
100 PVR_TRACE("%s: SGX clock rate: %dMHz", __func__,
103 PVRSRVDevicePostClockSpeedChange(gpsSysSpecificData->
104 psSGXDevNode->sDevId.
105 ui32DeviceIndex, IMG_TRUE,
111 static int vdd2_pre_func(struct notifier_block *n, unsigned long event,
114 PVR_UNREFERENCED_PARAMETER(n);
115 PVR_UNREFERENCED_PARAMETER(event);
116 PVR_UNREFERENCED_PARAMETER(ptr);
118 if (atomic_read(&gpsSysSpecificData->sSGXClocksEnabled) != 0 &&
119 gpsSysSpecificData->bSGXInitComplete) {
120 BUG_ON(gpsSysData->eCurrentPowerState > PVRSRV_POWER_STATE_D1);
121 PVRSRVDevicePreClockSpeedChange(gpsSysSpecificData->
122 psSGXDevNode->sDevId.
123 ui32DeviceIndex, IMG_TRUE,
130 static int vdd2_pre_post_func(struct notifier_block *n, unsigned long event,
133 struct clk_notifier_data *cnd;
135 PVR_UNREFERENCED_PARAMETER(n);
137 cnd = (struct clk_notifier_data *)ptr;
139 PVR_TRACE("vdd2_pre_post_func: %s clock rate = %lu",
140 (CLK_PRE_RATE_CHANGE == event) ? "old" :
141 (CLK_POST_RATE_CHANGE == event) ? "new" :
145 if (CLK_PRE_RATE_CHANGE == event) {
147 PVR_TRACE("vdd2_pre_post_func: CLK_PRE_RATE_CHANGE event");
148 vdd2_pre_func(n, event, ptr);
149 } else if (CLK_POST_RATE_CHANGE == event) {
150 PVR_TRACE("vdd2_pre_post_func: CLK_POST_RATE_CHANGE event");
151 vdd2_post_func(n, event, ptr);
153 } else if (CLK_ABORT_RATE_CHANGE == event) {
154 PVR_TRACE("vdd2_pre_post_func: CLK_ABORT_RATE_CHANGE event");
157 printk(KERN_ERR "vdd2_pre_post_func: unexpected event (%lu)\n",
159 PVR_DPF(PVR_DBG_ERROR,
160 "vdd2_pre_post_func: unexpected event (%lu)", event);
162 PVR_TRACE("vdd2_pre_post_func end.");
166 static struct notifier_block vdd2_pre_post = {
171 static void RegisterConstraintNotifications(struct SYS_SPECIFIC_DATA
174 PVR_TRACE("Registering constraint notifications");
176 clk_notifier_register(psSysSpecData->psSGX_FCK, &vdd2_pre_post);
177 PVR_TRACE("VDD2 constraint notifications registered");
180 static void UnRegisterConstraintNotifications(struct SYS_SPECIFIC_DATA
183 PVR_TRACE("Unregistering constraint notifications");
185 clk_notifier_unregister(psSysSpecData->psSGX_FCK, &vdd2_pre_post);
188 static struct device sgx_dev;
189 static int sgx_clock_enabled;
191 /* return value: current sgx load
195 static unsigned int sgx_current_load(void)
197 enum PVRSRV_ERROR eError;
198 struct SYS_DATA *psSysData;
199 struct SYS_SPECIFIC_DATA *psSysSpecData;
200 struct PVRSRV_DEVICE_NODE *psDeviceNode;
201 static unsigned int kicks_prev;
202 static long time_prev;
204 eError = SysAcquireData(&psSysData);
205 if (eError != PVRSRV_OK)
208 (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
209 if (!psSysSpecData ||
210 atomic_read(&psSysSpecData->sSGXClocksEnabled) == 0)
212 psDeviceNode = psSysData->psDeviceNodeList;
213 while (psDeviceNode) {
214 if ((psDeviceNode->sDevId.eDeviceType ==
215 PVRSRV_DEVICE_TYPE_SGX) &&
216 psDeviceNode->pvDevice) {
217 struct PVRSRV_SGXDEV_INFO *psDevInfo =
218 (struct PVRSRV_SGXDEV_INFO *)psDeviceNode->pvDevice;
219 unsigned int kicks = psDevInfo->ui32KickTACounter;
223 time_elapsed = jiffies - time_prev;
224 if (likely(time_elapsed))
226 1000 * (kicks - kicks_prev) / time_elapsed;
230 time_prev += time_elapsed;
232 * if the period between calls to this function was
233 * too long, then load stats are invalid
235 if (time_elapsed > 5 * HZ)
237 /*pr_err("SGX load %u\n", load); */
240 * 'load' shows how many times sgx was kicked
242 * 150 is arbitrarily chosen threshold.
243 * If the number of kicks is below threshold
245 * some small jobs and we can keep the clock freq low.
252 psDeviceNode = psDeviceNode->psNext;
257 static void sgx_lock_perf(struct work_struct *work)
263 struct delayed_work *d_work =
264 container_of(work, struct delayed_work, work);
265 struct ENV_DATA *psEnvData =
266 container_of(d_work, struct ENV_DATA, sPerfWork);
268 load = sgx_current_load();
279 omap_pm_set_min_bus_tput(&sgx_dev, OCP_INITIATOR_AGENT, vdd2);
283 if (sgx_clock_enabled || load)
284 queue_delayed_work(psEnvData->psPerfWorkqueue,
285 &psEnvData->sPerfWork, HZ / 5);
288 static void sgx_need_perf(struct SYS_DATA *psSysData, int ena)
290 struct ENV_DATA *psEnvData =
291 (struct ENV_DATA *)psSysData->pvEnvSpecificData;
293 sgx_clock_enabled = ena;
294 cancel_delayed_work(&psEnvData->sPerfWork);
295 queue_delayed_work(psEnvData->psPerfWorkqueue, &psEnvData->sPerfWork,
299 enum PVRSRV_ERROR OSInitPerf(void *pvSysData)
301 struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData;
302 struct ENV_DATA *psEnvData =
303 (struct ENV_DATA *)psSysData->pvEnvSpecificData;
305 if (psEnvData->psPerfWorkqueue) {
306 PVR_DPF(PVR_DBG_ERROR, "OSInitPerf: already inited");
307 return PVRSRV_ERROR_GENERIC;
310 PVR_TRACE("Initing DVFS %x", pvSysData);
312 psEnvData->psPerfWorkqueue = create_singlethread_workqueue("sgx_perf");
313 INIT_DELAYED_WORK(&psEnvData->sPerfWork, sgx_lock_perf);
318 enum PVRSRV_ERROR OSCleanupPerf(void *pvSysData)
320 struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData;
321 struct ENV_DATA *psEnvData =
322 (struct ENV_DATA *)psSysData->pvEnvSpecificData;
324 if (!psEnvData->psPerfWorkqueue) {
325 PVR_DPF(PVR_DBG_ERROR, "OSCleanupPerf: not inited");
326 return PVRSRV_ERROR_GENERIC;
329 PVR_TRACE("Cleaning up DVFS");
331 sgx_clock_enabled = 0;
332 flush_workqueue(psEnvData->psPerfWorkqueue);
333 destroy_workqueue(psEnvData->psPerfWorkqueue);
338 static inline void setup_int_bypass(void)
340 if (cpu_is_omap3630())
341 sgx_ocp_write_reg(EUR_CR_OCP_DEBUG_CONFIG,
342 EUR_CR_OCP_DEBUG_CONFIG_THALIA_INT_BYPASS_MASK);
347 static enum PVRSRV_ERROR sgx_force_enable_clocks(struct SYS_DATA *psSysData)
349 struct SYS_SPECIFIC_DATA *psSysSpecData =
350 (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
353 res = clk_enable(psSysSpecData->psSGX_FCK);
355 PVR_DPF(PVR_DBG_ERROR, "%s: "
356 "Couldn't enable SGX functional clock (%d)",
358 return PVRSRV_ERROR_GENERIC;
361 res = clk_enable(psSysSpecData->psSGX_ICK);
363 PVR_DPF(PVR_DBG_ERROR, "%s: "
364 "Couldn't enable SGX interface clock (%d)",
367 clk_disable(psSysSpecData->psSGX_FCK);
368 return PVRSRV_ERROR_GENERIC;
376 static void sgx_force_disable_clocks(struct SYS_DATA *psSysData)
378 struct SYS_SPECIFIC_DATA *psSysSpecData =
379 (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
381 if (psSysSpecData->psSGX_ICK)
382 clk_disable(psSysSpecData->psSGX_ICK);
384 if (psSysSpecData->psSGX_FCK)
385 clk_disable(psSysSpecData->psSGX_FCK);
388 #else /* NO_HARDWARE */
390 static enum PVRSRV_ERROR sgx_force_enable_clocks(struct SYS_DATA *psSYsData)
395 static void sgx_force_disable_clocks(struct SYS_DATA *psSYsData)
399 #endif /* NO_HARDWARE */
401 static bool force_clocks_on(void)
403 #ifdef CONFIG_PVR_FORCE_CLOCKS_ON
410 enum PVRSRV_ERROR EnableSGXClocks(struct SYS_DATA *psSysData)
412 struct SYS_SPECIFIC_DATA *psSysSpecData =
413 (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
414 enum PVRSRV_ERROR res = PVRSRV_OK;
416 if (atomic_xchg(&psSysSpecData->sSGXClocksEnabled, 1))
420 * In case of force clocks on we have already enabled the clocks
423 if (!force_clocks_on())
424 res = sgx_force_enable_clocks(psSysData);
426 if (res == PVRSRV_OK) {
427 BUG_ON(!atomic_read(&psSysSpecData->sSGXClocksEnabled));
428 sgx_need_perf(psSysData, 1);
430 atomic_set(&psSysSpecData->sSGXClocksEnabled, 0);
436 void DisableSGXClocks(struct SYS_DATA *psSysData)
438 struct SYS_SPECIFIC_DATA *psSysSpecData =
439 (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
441 if (!atomic_xchg(&psSysSpecData->sSGXClocksEnabled, 0))
444 if (!force_clocks_on())
445 sgx_force_disable_clocks(psSysData);
447 BUG_ON(atomic_read(&psSysSpecData->sSGXClocksEnabled));
449 sgx_need_perf(psSysData, 0);
452 static enum PVRSRV_ERROR InitSgxClocks(struct SYS_DATA *psSysData)
454 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
456 struct clk *core_ck = NULL;
459 psCLK = clk_get(NULL, "sgx_fck");
462 psSysSpecData->psSGX_FCK = psCLK;
464 psCLK = clk_get(NULL, "sgx_ick");
467 psSysSpecData->psSGX_ICK = psCLK;
469 core_ck = clk_get(NULL, "core_ck");
472 if (clk_set_parent(psSysSpecData->psSGX_FCK, core_ck) < 0) {
478 r = clk_set_rate(psSysSpecData->psSGX_FCK,
483 rate = clk_get_rate(psSysSpecData->psSGX_FCK);
485 pr_warning("error %d when setting SGX fclk to %luMHz, "
486 "falling back to %luMHz\n",
487 r, sgx_get_max_freq() / 1000000, rate);
490 RegisterConstraintNotifications(psSysSpecData);
494 clk_put(psSysSpecData->psSGX_ICK);
496 clk_put(psSysSpecData->psSGX_FCK);
498 PVR_DPF(PVR_DBG_ERROR,
499 "%s: couldn't init clocks fck %p ick %p core %p", __func__,
500 psSysSpecData->psSGX_FCK, psSysSpecData->psSGX_ICK, core_ck);
501 psSysSpecData->psSGX_FCK = NULL;
502 psSysSpecData->psSGX_ICK = NULL;
504 return PVRSRV_ERROR_GENERIC;
507 static void CleanupSgxClocks(struct SYS_DATA *psSysData)
509 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
510 UnRegisterConstraintNotifications(psSysSpecData);
512 if (psSysSpecData->psSGX_ICK) {
513 clk_put(psSysSpecData->psSGX_ICK);
514 psSysSpecData->psSGX_ICK = NULL;
517 if (psSysSpecData->psSGX_FCK) {
518 clk_put(psSysSpecData->psSGX_FCK);
519 psSysSpecData->psSGX_FCK = NULL;
523 #if defined(CONFIG_PVR_DEBUG_EXTRA) || defined(TIMING)
524 static inline u32 gpt_read_reg(struct SYS_DATA *psSysData, u32 reg)
526 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
528 return __raw_readl(psSysSpecData->gpt_base + reg);
531 static inline void gpt_write_reg(struct SYS_DATA *psSysData, u32 reg, u32 val)
533 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
535 __raw_writel(val, psSysSpecData->gpt_base + reg);
538 static enum PVRSRV_ERROR InitDebugClocks(struct SYS_DATA *psSysData)
540 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
542 struct clk *sys_ck = NULL;
545 psCLK = clk_get(NULL, "mpu_ck");
548 psSysSpecData->psMPU_CK = psCLK;
550 psCLK = clk_get(NULL, "gpt11_fck");
553 psSysSpecData->psGPT11_FCK = psCLK;
555 psCLK = clk_get(NULL, "gpt11_ick");
558 psSysSpecData->psGPT11_ICK = psCLK;
560 sys_ck = clk_get(NULL, "sys_ck");
563 if (clk_get_parent(psSysSpecData->psGPT11_FCK) != sys_ck)
564 if (clk_set_parent(psSysSpecData->psGPT11_FCK, sys_ck) < 0) {
570 PVR_TRACE("GPTIMER11 clock is %dMHz",
571 HZ_TO_MHZ(clk_get_rate(psSysSpecData->psGPT11_FCK)));
573 psSysSpecData->gpt_base = ioremap(SYS_OMAP3430_GP11TIMER_PHYS_BASE,
574 SYS_OMAP3430_GPTIMER_SIZE);
575 if (!psSysSpecData->gpt_base)
578 clk_enable(psSysSpecData->psGPT11_ICK);
579 clk_enable(psSysSpecData->psGPT11_FCK);
581 rate = gpt_read_reg(psSysData, SYS_OMAP3430_GPTIMER_TSICR);
583 PVR_TRACE("Setting GPTIMER11 mode to posted "
584 "(currently is non-posted)");
585 gpt_write_reg(psSysData, SYS_OMAP3430_GPTIMER_TSICR, rate | 4);
588 clk_disable(psSysSpecData->psGPT11_FCK);
589 clk_disable(psSysSpecData->psGPT11_ICK);
594 clk_put(psSysSpecData->psGPT11_ICK);
596 clk_put(psSysSpecData->psGPT11_FCK);
598 clk_put(psSysSpecData->psMPU_CK);
600 PVR_DPF(PVR_DBG_ERROR,
601 "%s: couldn't init clocks: mpu %p sys %p fck %p ick %p",
602 __func__, psSysSpecData->psMPU_CK, sys_ck,
603 psSysSpecData->psGPT11_FCK, psSysSpecData->psGPT11_ICK);
605 psSysSpecData->psMPU_CK = NULL;
606 psSysSpecData->psGPT11_FCK = NULL;
607 psSysSpecData->psGPT11_ICK = NULL;
609 return PVRSRV_ERROR_GENERIC;
612 static void CleanupDebugClocks(struct SYS_DATA *psSysData)
614 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
616 if (psSysSpecData->psMPU_CK) {
617 clk_put(psSysSpecData->psMPU_CK);
618 psSysSpecData->psMPU_CK = NULL;
620 if (psSysSpecData->psGPT11_FCK) {
621 clk_put(psSysSpecData->psGPT11_FCK);
622 psSysSpecData->psGPT11_FCK = NULL;
624 if (psSysSpecData->psGPT11_ICK) {
625 clk_put(psSysSpecData->psGPT11_ICK);
626 psSysSpecData->psGPT11_ICK = NULL;
630 static enum PVRSRV_ERROR EnableDebugClocks(struct SYS_DATA *psSysData)
632 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
634 if (clk_enable(psSysSpecData->psGPT11_FCK) < 0)
637 if (clk_enable(psSysSpecData->psGPT11_ICK) < 0)
640 gpt_write_reg(psSysData, SYS_OMAP3430_GPTIMER_ENABLE, 3);
645 clk_disable(psSysSpecData->psGPT11_FCK);
647 PVR_DPF(PVR_DBG_ERROR, "%s: can't enable clocks", __func__);
649 return PVRSRV_ERROR_GENERIC;
652 static inline void DisableDebugClocks(struct SYS_DATA *psSysData)
654 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
656 gpt_write_reg(psSysData, SYS_OMAP3430_GPTIMER_ENABLE, 0);
658 clk_disable(psSysSpecData->psGPT11_ICK);
659 clk_disable(psSysSpecData->psGPT11_FCK);
664 inline enum PVRSRV_ERROR InitDebugClocks(struct SYS_DATA *psSysData)
669 static inline void CleanupDebugClocks(struct SYS_DATA *psSysData)
673 static inline enum PVRSRV_ERROR EnableDebugClocks(struct SYS_DATA *psSysData)
678 static inline void DisableDebugClocks(struct SYS_DATA *psSysData)
683 enum PVRSRV_ERROR InitSystemClocks(struct SYS_DATA *psSysData)
685 if (InitSgxClocks(psSysData) != PVRSRV_OK)
688 if (InitDebugClocks(psSysData) != PVRSRV_OK)
694 CleanupSgxClocks(psSysData);
696 return PVRSRV_ERROR_GENERIC;
699 void CleanupSystemClocks(struct SYS_DATA *psSysData)
701 CleanupDebugClocks(psSysData);
702 CleanupSgxClocks(psSysData);
705 enum PVRSRV_ERROR EnableSystemClocks(struct SYS_DATA *psSysData)
707 PVR_TRACE("EnableSystemClocks: Enabling System Clocks");
710 * We force clocks on by increasing their refcount here during
711 * module init time and decreasing it at cleanup time.
713 if (force_clocks_on())
714 sgx_force_enable_clocks(gpsSysData);
715 if (EnableDebugClocks(psSysData) != PVRSRV_OK)
721 return PVRSRV_ERROR_GENERIC;
724 void DisableSystemClocks(struct SYS_DATA *psSysData)
726 PVR_TRACE("DisableSystemClocks: Disabling System Clocks");
728 DisableDebugClocks(psSysData);
729 /* Decrease the clocks' refcount that was increased at init time. */
730 if (force_clocks_on())
731 sgx_force_disable_clocks(gpsSysData);