diff options
author | Hyungwoo Yang <hyungwooy@nvidia.com> | 2013-08-01 12:19:40 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 13:39:43 -0700 |
commit | 034cca3d89ad00b545dfc30c1f86fc83d3516fb4 (patch) | |
tree | c76df286bfcc519940ba4d4b9ab0a75256cb9f2a /arch/arm/mach-tegra/tegra3_throttle.c | |
parent | 8f2b36ff928c680e24d827532f242a9a4522f4d5 (diff) |
ARM: tegra: add GPU frequency capping
add GPU frequency capping into balanced cooling device
In this chagne, GPU frequency capping is done by directly using gk20a driver.
This part will be removed when GPU clock tree is available in Linux Clock
Framework.
Bug 1315460
Change-Id: Ia6927eb3522875417d5a081d98f0ddde4927cfab
Signed-off-by: Hyungwoo Yang <hyungwooy@nvidia.com>
Reviewed-on: http://git-master/r/256975
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_throttle.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra3_throttle.c | 82 |
1 files changed, 61 insertions, 21 deletions
diff --git a/arch/arm/mach-tegra/tegra3_throttle.c b/arch/arm/mach-tegra/tegra3_throttle.c index 1ffd3c921eeb..0b42a547a2b0 100644 --- a/arch/arm/mach-tegra/tegra3_throttle.c +++ b/arch/arm/mach-tegra/tegra3_throttle.c @@ -33,6 +33,9 @@ #include "clock.h" #include "cpu-tegra.h" +/* TODO : remove when GPU clock is in Linux Clock Framework */ +struct gk20a_clk_cap_info *gk20a_clk_cap; + /* cpu_throttle_lock is tegra_cpu_lock from cpu-tegra.c */ static struct mutex *cpu_throttle_lock; static DEFINE_MUTEX(bthrot_list_lock); @@ -48,7 +51,13 @@ static struct { unsigned long cap_freq; } cap_freqs_table[] = { #ifdef CONFIG_TEGRA_DUAL_CBUS - { .cap_name = "cap.throttle.c2bus" }, +#ifdef CONFIG_TEGRA_GPU_DVFS + { .cap_name = "cap.throttle.gpu" }, +#else + /* TODO : use c2bus and remove gpu when CONFIG_TEGRA_GPU_DVFS==y */ + /* { .cap_name = "cap.throttle.c2bus" }, */ + { .cap_name = "cap.throttle.gpu" }, +#endif { .cap_name = "cap.throttle.c3bus" }, #else { .cap_name = "cap.throttle.cbus" }, @@ -138,19 +147,40 @@ static void tegra_throttle_set_cap_clk(struct throttle_table *throt_tab, int cap_clk_index) { unsigned long cap_rate, clk_rate; + struct nvhost_device_data *pdata; if (tegra_throttle_init_failed) return; cap_rate = throt_tab->cap_freqs[cap_clk_index]; - if (cap_rate == NO_CAP) - clk_rate = clk_get_max_rate(CAP_TBL_CAP_CLK(cap_clk_index-1)); - else + if (cap_rate == NO_CAP) { + /* TODO : remove when GPU clock is in Linux Clock Framework */ + if (strcmp(CAP_TBL_CAP_NAME(cap_clk_index-1), + "cap.throttle.gpu") != 0) + clk_rate = clk_get_max_rate( + CAP_TBL_CAP_CLK(cap_clk_index-1)); + else if (gk20a_clk_cap != NULL) + clk_rate = gk20a_clk_cap->get_max() * 1000000UL / 2; + + /* TODO : use when GPU clock is in Linux Clock Framework */ + /* clk_rate = */ + /* clk_get_max_rate(CAP_TBL_CAP_CLK(cap_clk_index-1)); */ + } else clk_rate = cap_rate * 1000UL; if (CAP_TBL_CAP_FREQ(cap_clk_index-1) != clk_rate) { - clk_set_rate(CAP_TBL_CAP_CLK(cap_clk_index-1), clk_rate); + /* TODO : remove when GPU clock is in Linux Clock Framework */ + if (strcmp(CAP_TBL_CAP_NAME(cap_clk_index-1), + "cap.throttle.gpu") != 0) + clk_set_rate(CAP_TBL_CAP_CLK(cap_clk_index-1), + clk_rate); + else if (gk20a_clk_cap != NULL) + gk20a_clk_cap->set_cap_thermal(gk20a_clk_cap->g, + clk_rate / 1000000UL * 2); + + /* TODO : use when GPU clock is in Linux Clock Framework */ + /* clk_set_rate(CAP_TBL_CAP_CLK(cap_clk_index-1), clk_rate); */ CAP_TBL_CAP_FREQ(cap_clk_index-1) = clk_rate; } } @@ -181,13 +211,7 @@ tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev, int num_of_cap_clocks = ARRAY_SIZE(cap_freqs_table); unsigned long bthrot_speed; struct throttle_table *throt_entry; - struct throttle_table cur_throt_freq = { -#ifdef CONFIG_TEGRA_DUAL_CBUS - { NO_CAP, NO_CAP, NO_CAP, NO_CAP, NO_CAP} -#else - { NO_CAP, NO_CAP, NO_CAP, NO_CAP} -#endif - }; + struct throttle_table cur_throt_freq; if (cpu_freq_table == NULL) return 0; @@ -201,6 +225,9 @@ tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev, direction = bthrot->cur_state >= cur_state; bthrot->cur_state = cur_state; + for (i = 0; i <= num_of_cap_clocks; i++) + cur_throt_freq.cap_freqs[i] = NO_CAP; + mutex_lock(&bthrot_list_lock); list_for_each_entry(bthrot, &bthrot_list, node) { if (bthrot->cur_state) { @@ -345,6 +372,12 @@ struct thermal_cooling_device *balanced_throttle_register( return bthrot->cdev; } +/* TODO : remove when GPU clock is available in Linux clock framework */ +int tegra_throttle_gk20a_clk_cap_register(struct gk20a_clk_cap_info *gk20a_clk) +{ + gk20a_clk_cap = gk20a_clk; +} + int __init tegra_throttle_init(struct mutex *cpu_lock) { int i; @@ -365,16 +398,23 @@ int __init tegra_throttle_init(struct mutex *cpu_lock) #endif for (i = 0; i < ARRAY_SIZE(cap_freqs_table); i++) { - c = tegra_get_clock_by_name(CAP_TBL_CAP_NAME(i)); - if (!c) { - pr_err("tegra_throttle: cannot get clock %s\n", - CAP_TBL_CAP_NAME(i)); - tegra_throttle_init_failed = true; - continue; - } + /* TODO : need to be modified when GPU clock is available in */ + /* Linux Clock Framework */ + if (strcmp(CAP_TBL_CAP_NAME(i), + "cap.throttle.gpu") != 0) { + c = tegra_get_clock_by_name(CAP_TBL_CAP_NAME(i)); + if (!c) { + pr_err("tegra_throttle: cannot get clock %s\n", + CAP_TBL_CAP_NAME(i)); + tegra_throttle_init_failed = true; + continue; + } - CAP_TBL_CAP_CLK(i) = c; - CAP_TBL_CAP_FREQ(i) = clk_get_max_rate(c); + CAP_TBL_CAP_CLK(i) = c; + CAP_TBL_CAP_FREQ(i) = clk_get_max_rate(c); + } else if (gk20a_clk_cap != NULL) + CAP_TBL_CAP_FREQ(i) = gk20a_clk_cap->get_max() * + 1000000UL / 2; } pr_info("tegra_throttle : init %s\n", tegra_throttle_init_failed ? "FAILED" : "passed"); |