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"
44 #include "pvr_bridge_km.h"
46 #define HZ_TO_MHZ(m) ((m) / 1000000)
48 static inline unsigned long scale_by_rate(unsigned long val,
53 return val * (rate1 / rate2);
55 return val / (rate2 / rate1);
58 static inline unsigned long scale_prop_to_SGX_clock(unsigned long val,
61 return scale_by_rate(val, rate, sgx_get_max_freq());
64 void SysGetSGXTimingInformation(struct SGX_TIMING_INFORMATION *psTimingInfo)
68 #if defined(NO_HARDWARE)
69 rate = SYS_SGX_MAX_FREQ_NO_HW;
71 rate = clk_get_rate(gpsSysSpecificData->psSGX_FCK);
72 PVR_ASSERT(rate != 0);
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;
83 static int vdd2_post_func(struct notifier_block *n, unsigned long event,
86 PVR_UNREFERENCED_PARAMETER(n);
87 PVR_UNREFERENCED_PARAMETER(event);
88 PVR_UNREFERENCED_PARAMETER(ptr);
90 if (atomic_read(&gpsSysSpecificData->sSGXClocksEnabled) != 0 &&
91 gpsSysSpecificData->bSGXInitComplete) {
92 #if defined(CONFIG_PVR_DEBUG_EXTRA)
95 rate = clk_get_rate(gpsSysSpecificData->psSGX_FCK);
97 PVR_ASSERT(rate != 0);
99 PVR_TRACE("%s: SGX clock rate: %dMHz", __func__,
102 PVRSRVDevicePostClockSpeedChange(gpsSysSpecificData->
103 psSGXDevNode->sDevId.
104 ui32DeviceIndex, IMG_TRUE,
110 static int vdd2_pre_func(struct notifier_block *n, unsigned long event,
113 PVR_UNREFERENCED_PARAMETER(n);
114 PVR_UNREFERENCED_PARAMETER(event);
115 PVR_UNREFERENCED_PARAMETER(ptr);
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,
129 static int vdd2_pre_post_func(struct notifier_block *n, unsigned long event,
132 struct clk_notifier_data *cnd;
134 PVR_UNREFERENCED_PARAMETER(n);
136 cnd = (struct clk_notifier_data *)ptr;
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" :
144 if (CLK_PRE_RATE_CHANGE == event) {
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);
152 } else if (CLK_ABORT_RATE_CHANGE == event) {
153 PVR_TRACE("vdd2_pre_post_func: CLK_ABORT_RATE_CHANGE event");
156 printk(KERN_ERR "vdd2_pre_post_func: unexpected event (%lu)\n",
158 PVR_DPF(PVR_DBG_ERROR,
159 "vdd2_pre_post_func: unexpected event (%lu)", event);
161 PVR_TRACE("vdd2_pre_post_func end.");
165 static struct notifier_block vdd2_pre_post = {
170 static void RegisterConstraintNotifications(struct SYS_SPECIFIC_DATA
173 PVR_TRACE("Registering constraint notifications");
175 clk_notifier_register(psSysSpecData->psSGX_FCK, &vdd2_pre_post);
176 PVR_TRACE("VDD2 constraint notifications registered");
179 static void UnRegisterConstraintNotifications(struct SYS_SPECIFIC_DATA
182 PVR_TRACE("Unregistering constraint notifications");
184 clk_notifier_unregister(psSysSpecData->psSGX_FCK, &vdd2_pre_post);
187 static struct device sgx_dev;
188 static int sgx_clock_enabled;
190 /* return value: current sgx load
194 static unsigned int sgx_current_load(void)
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;
203 eError = SysAcquireData(&psSysData);
204 if (eError != PVRSRV_OK)
207 (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
208 if (!psSysSpecData ||
209 atomic_read(&psSysSpecData->sSGXClocksEnabled) == 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;
222 time_elapsed = jiffies - time_prev;
223 if (likely(time_elapsed))
225 1000 * (kicks - kicks_prev) / time_elapsed;
229 time_prev += time_elapsed;
231 * if the period between calls to this function was
232 * too long, then load stats are invalid
234 if (time_elapsed > 5 * HZ)
236 /*pr_err("SGX load %u\n", load); */
239 * 'load' shows how many times sgx was kicked
241 * 150 is arbitrarily chosen threshold.
242 * If the number of kicks is below threshold
244 * some small jobs and we can keep the clock freq low.
251 psDeviceNode = psDeviceNode->psNext;
256 static void sgx_lock_perf(struct work_struct *work)
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);
269 if (pvr_is_disabled()) {
274 load = sgx_current_load();
288 omap_pm_set_min_bus_tput(&sgx_dev, OCP_INITIATOR_AGENT, vdd2);
292 if (sgx_clock_enabled || load)
293 queue_delayed_work(psEnvData->psPerfWorkqueue,
294 &psEnvData->sPerfWork, HZ / 5);
297 static void sgx_need_perf(struct SYS_DATA *psSysData, int ena)
299 struct ENV_DATA *psEnvData =
300 (struct ENV_DATA *)psSysData->pvEnvSpecificData;
302 sgx_clock_enabled = ena;
303 cancel_delayed_work(&psEnvData->sPerfWork);
304 queue_delayed_work(psEnvData->psPerfWorkqueue, &psEnvData->sPerfWork,
308 enum PVRSRV_ERROR OSInitPerf(void *pvSysData)
310 struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData;
311 struct ENV_DATA *psEnvData =
312 (struct ENV_DATA *)psSysData->pvEnvSpecificData;
314 if (psEnvData->psPerfWorkqueue) {
315 PVR_DPF(PVR_DBG_ERROR, "OSInitPerf: already inited");
316 return PVRSRV_ERROR_GENERIC;
319 PVR_TRACE("Initing DVFS %x", pvSysData);
321 psEnvData->psPerfWorkqueue = create_singlethread_workqueue("sgx_perf");
322 INIT_DELAYED_WORK(&psEnvData->sPerfWork, sgx_lock_perf);
327 enum PVRSRV_ERROR OSCleanupPerf(void *pvSysData)
329 struct SYS_DATA *psSysData = (struct SYS_DATA *)pvSysData;
330 struct ENV_DATA *psEnvData =
331 (struct ENV_DATA *)psSysData->pvEnvSpecificData;
333 if (!psEnvData->psPerfWorkqueue) {
334 PVR_DPF(PVR_DBG_ERROR, "OSCleanupPerf: not inited");
335 return PVRSRV_ERROR_GENERIC;
338 PVR_TRACE("Cleaning up DVFS");
340 sgx_clock_enabled = 0;
341 flush_workqueue(psEnvData->psPerfWorkqueue);
342 destroy_workqueue(psEnvData->psPerfWorkqueue);
347 static inline void setup_int_bypass(void)
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);
356 static enum PVRSRV_ERROR sgx_force_enable_clocks(struct SYS_DATA *psSysData)
358 struct SYS_SPECIFIC_DATA *psSysSpecData =
359 (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
362 res = clk_enable(psSysSpecData->psSGX_FCK);
364 PVR_DPF(PVR_DBG_ERROR, "%s: "
365 "Couldn't enable SGX functional clock (%d)",
367 return PVRSRV_ERROR_GENERIC;
370 res = clk_enable(psSysSpecData->psSGX_ICK);
372 PVR_DPF(PVR_DBG_ERROR, "%s: "
373 "Couldn't enable SGX interface clock (%d)",
376 clk_disable(psSysSpecData->psSGX_FCK);
377 return PVRSRV_ERROR_GENERIC;
385 static void sgx_force_disable_clocks(struct SYS_DATA *psSysData)
387 struct SYS_SPECIFIC_DATA *psSysSpecData =
388 (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
390 if (psSysSpecData->psSGX_ICK)
391 clk_disable(psSysSpecData->psSGX_ICK);
393 if (psSysSpecData->psSGX_FCK)
394 clk_disable(psSysSpecData->psSGX_FCK);
397 #else /* NO_HARDWARE */
399 static enum PVRSRV_ERROR sgx_force_enable_clocks(struct SYS_DATA *psSYsData)
404 static void sgx_force_disable_clocks(struct SYS_DATA *psSYsData)
408 #endif /* NO_HARDWARE */
410 static bool force_clocks_on(void)
412 #ifdef CONFIG_PVR_FORCE_CLOCKS_ON
419 enum PVRSRV_ERROR EnableSGXClocks(struct SYS_DATA *psSysData)
421 struct SYS_SPECIFIC_DATA *psSysSpecData =
422 (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
423 enum PVRSRV_ERROR res = PVRSRV_OK;
425 if (atomic_xchg(&psSysSpecData->sSGXClocksEnabled, 1))
429 * In case of force clocks on we have already enabled the clocks
432 if (!force_clocks_on())
433 res = sgx_force_enable_clocks(psSysData);
435 if (res == PVRSRV_OK) {
436 BUG_ON(!atomic_read(&psSysSpecData->sSGXClocksEnabled));
437 sgx_need_perf(psSysData, 1);
439 atomic_set(&psSysSpecData->sSGXClocksEnabled, 0);
445 void DisableSGXClocks(struct SYS_DATA *psSysData)
447 struct SYS_SPECIFIC_DATA *psSysSpecData =
448 (struct SYS_SPECIFIC_DATA *)psSysData->pvSysSpecificData;
450 if (!atomic_xchg(&psSysSpecData->sSGXClocksEnabled, 0))
453 if (!force_clocks_on())
454 sgx_force_disable_clocks(psSysData);
456 BUG_ON(atomic_read(&psSysSpecData->sSGXClocksEnabled));
458 sgx_need_perf(psSysData, 0);
461 static enum PVRSRV_ERROR InitSgxClocks(struct SYS_DATA *psSysData)
463 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
465 struct clk *core_ck = NULL;
469 psCLK = clk_get(NULL, "sgx_fck");
472 psSysSpecData->psSGX_FCK = psCLK;
474 psCLK = clk_get(NULL, "sgx_ick");
477 psSysSpecData->psSGX_ICK = psCLK;
479 core_ck = clk_get(NULL, "core_ck");
482 if (clk_set_parent(psSysSpecData->psSGX_FCK, core_ck) < 0) {
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);
492 unsigned long current_rate;
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);
498 pr_info("SGX clock rate %lu MHz\n", rate / 1000000);
501 RegisterConstraintNotifications(psSysSpecData);
505 clk_put(psSysSpecData->psSGX_ICK);
507 clk_put(psSysSpecData->psSGX_FCK);
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;
515 return PVRSRV_ERROR_GENERIC;
518 static void CleanupSgxClocks(struct SYS_DATA *psSysData)
520 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
521 UnRegisterConstraintNotifications(psSysSpecData);
523 if (psSysSpecData->psSGX_ICK) {
524 clk_put(psSysSpecData->psSGX_ICK);
525 psSysSpecData->psSGX_ICK = NULL;
528 if (psSysSpecData->psSGX_FCK) {
529 clk_put(psSysSpecData->psSGX_FCK);
530 psSysSpecData->psSGX_FCK = NULL;
534 #if defined(CONFIG_PVR_DEBUG_EXTRA) || defined(TIMING)
535 static inline u32 gpt_read_reg(struct SYS_DATA *psSysData, u32 reg)
537 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
539 return __raw_readl(psSysSpecData->gpt_base + reg);
542 static inline void gpt_write_reg(struct SYS_DATA *psSysData, u32 reg, u32 val)
544 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
546 __raw_writel(val, psSysSpecData->gpt_base + reg);
549 static enum PVRSRV_ERROR InitDebugClocks(struct SYS_DATA *psSysData)
551 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
553 struct clk *sys_ck = NULL;
556 psCLK = clk_get(NULL, "mpu_ck");
559 psSysSpecData->psMPU_CK = psCLK;
561 psCLK = clk_get(NULL, "gpt11_fck");
564 psSysSpecData->psGPT11_FCK = psCLK;
566 psCLK = clk_get(NULL, "gpt11_ick");
569 psSysSpecData->psGPT11_ICK = psCLK;
571 sys_ck = clk_get(NULL, "sys_ck");
574 if (clk_get_parent(psSysSpecData->psGPT11_FCK) != sys_ck)
575 if (clk_set_parent(psSysSpecData->psGPT11_FCK, sys_ck) < 0) {
581 PVR_TRACE("GPTIMER11 clock is %dMHz",
582 HZ_TO_MHZ(clk_get_rate(psSysSpecData->psGPT11_FCK)));
584 psSysSpecData->gpt_base = ioremap(SYS_OMAP3430_GP11TIMER_PHYS_BASE,
585 SYS_OMAP3430_GPTIMER_SIZE);
586 if (!psSysSpecData->gpt_base)
589 clk_enable(psSysSpecData->psGPT11_ICK);
590 clk_enable(psSysSpecData->psGPT11_FCK);
592 rate = gpt_read_reg(psSysData, SYS_OMAP3430_GPTIMER_TSICR);
594 PVR_TRACE("Setting GPTIMER11 mode to posted "
595 "(currently is non-posted)");
596 gpt_write_reg(psSysData, SYS_OMAP3430_GPTIMER_TSICR, rate | 4);
599 clk_disable(psSysSpecData->psGPT11_FCK);
600 clk_disable(psSysSpecData->psGPT11_ICK);
605 clk_put(psSysSpecData->psGPT11_ICK);
607 clk_put(psSysSpecData->psGPT11_FCK);
609 clk_put(psSysSpecData->psMPU_CK);
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);
616 psSysSpecData->psMPU_CK = NULL;
617 psSysSpecData->psGPT11_FCK = NULL;
618 psSysSpecData->psGPT11_ICK = NULL;
620 return PVRSRV_ERROR_GENERIC;
623 static void CleanupDebugClocks(struct SYS_DATA *psSysData)
625 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
627 if (psSysSpecData->psMPU_CK) {
628 clk_put(psSysSpecData->psMPU_CK);
629 psSysSpecData->psMPU_CK = NULL;
631 if (psSysSpecData->psGPT11_FCK) {
632 clk_put(psSysSpecData->psGPT11_FCK);
633 psSysSpecData->psGPT11_FCK = NULL;
635 if (psSysSpecData->psGPT11_ICK) {
636 clk_put(psSysSpecData->psGPT11_ICK);
637 psSysSpecData->psGPT11_ICK = NULL;
641 static enum PVRSRV_ERROR EnableDebugClocks(struct SYS_DATA *psSysData)
643 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
645 if (clk_enable(psSysSpecData->psGPT11_FCK) < 0)
648 if (clk_enable(psSysSpecData->psGPT11_ICK) < 0)
651 gpt_write_reg(psSysData, SYS_OMAP3430_GPTIMER_ENABLE, 3);
656 clk_disable(psSysSpecData->psGPT11_FCK);
658 PVR_DPF(PVR_DBG_ERROR, "%s: can't enable clocks", __func__);
660 return PVRSRV_ERROR_GENERIC;
663 static inline void DisableDebugClocks(struct SYS_DATA *psSysData)
665 struct SYS_SPECIFIC_DATA *psSysSpecData = psSysData->pvSysSpecificData;
667 gpt_write_reg(psSysData, SYS_OMAP3430_GPTIMER_ENABLE, 0);
669 clk_disable(psSysSpecData->psGPT11_ICK);
670 clk_disable(psSysSpecData->psGPT11_FCK);
675 inline enum PVRSRV_ERROR InitDebugClocks(struct SYS_DATA *psSysData)
680 static inline void CleanupDebugClocks(struct SYS_DATA *psSysData)
684 static inline enum PVRSRV_ERROR EnableDebugClocks(struct SYS_DATA *psSysData)
689 static inline void DisableDebugClocks(struct SYS_DATA *psSysData)
694 enum PVRSRV_ERROR InitSystemClocks(struct SYS_DATA *psSysData)
696 if (InitSgxClocks(psSysData) != PVRSRV_OK)
699 if (InitDebugClocks(psSysData) != PVRSRV_OK)
705 CleanupSgxClocks(psSysData);
707 return PVRSRV_ERROR_GENERIC;
710 void CleanupSystemClocks(struct SYS_DATA *psSysData)
712 CleanupDebugClocks(psSysData);
713 CleanupSgxClocks(psSysData);
716 enum PVRSRV_ERROR EnableSystemClocks(struct SYS_DATA *psSysData)
718 PVR_TRACE("EnableSystemClocks: Enabling System Clocks");
721 * We force clocks on by increasing their refcount here during
722 * module init time and decreasing it at cleanup time.
724 if (force_clocks_on())
725 sgx_force_enable_clocks(gpsSysData);
726 if (EnableDebugClocks(psSysData) != PVRSRV_OK)
732 return PVRSRV_ERROR_GENERIC;
735 void DisableSystemClocks(struct SYS_DATA *psSysData)
737 PVR_TRACE("DisableSystemClocks: Disabling System Clocks");
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);