summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra3_throttle.c
diff options
context:
space:
mode:
authorHyungwoo Yang <hyungwooy@nvidia.com>2013-08-01 12:19:40 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:39:43 -0700
commit034cca3d89ad00b545dfc30c1f86fc83d3516fb4 (patch)
treec76df286bfcc519940ba4d4b9ab0a75256cb9f2a /arch/arm/mach-tegra/tegra3_throttle.c
parent8f2b36ff928c680e24d827532f242a9a4522f4d5 (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.c82
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");