summaryrefslogtreecommitdiff
path: root/arch
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
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')
-rw-r--r--arch/arm/mach-tegra/include/mach/thermal.h17
-rw-r--r--arch/arm/mach-tegra/tegra3_throttle.c82
2 files changed, 78 insertions, 21 deletions
diff --git a/arch/arm/mach-tegra/include/mach/thermal.h b/arch/arm/mach-tegra/include/mach/thermal.h
index 7bddb97e58fb..b03185985398 100644
--- a/arch/arm/mach-tegra/include/mach/thermal.h
+++ b/arch/arm/mach-tegra/include/mach/thermal.h
@@ -31,7 +31,11 @@ struct tegra_cooling_device {
#define CPU_THROT_LOW 0 /* lowest throttle freq. only used for CPU */
#ifdef CONFIG_TEGRA_DUAL_CBUS
+#ifdef CONFIG_TEGRA_GPU_DVFS
+#define NUM_OF_CAP_FREQS 5 /* cpu, gpu, c3bus, sclk, emc */
+#else
#define NUM_OF_CAP_FREQS 5 /* cpu, c2bus, c3bus, sclk, emc */
+#endif
#else
#define NUM_OF_CAP_FREQS 4 /* cpu, cbus, sclk, emc */
#endif
@@ -49,6 +53,13 @@ struct balanced_throttle {
struct throttle_table *throt_tab;
};
+/* TODO : remove when GPU clock is available in Linux Clock Framework */
+struct gk20a_clk_cap_info {
+ struct gk20a *g;
+ int (*set_cap_thermal)(struct gk20a *g, unsigned long rate);
+ unsigned long (*get_max)(void);
+};
+
#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
int tegra_throttle_init(struct mutex *cpu_lock);
struct thermal_cooling_device *balanced_throttle_register(
@@ -57,6 +68,8 @@ struct thermal_cooling_device *balanced_throttle_register(
void tegra_throttle_exit(void);
bool tegra_is_throttling(int *count);
unsigned long tegra_throttle_governor_speed(unsigned long requested_speed);
+/* 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);
#else
static inline int tegra_throttle_init(struct mutex *cpu_lock)
{ return 0; }
@@ -71,6 +84,10 @@ static inline bool tegra_is_throttling(int *count)
static inline unsigned long tegra_throttle_governor_speed(
unsigned long requested_speed)
{ return requested_speed; }
+/* TODO : remove when GPU clock is available in Linux Clock Framework */
+static int tegra_throttle_gk20a_clk_cap_register(
+ struct gk20a_clk_cap_info *gk20a_clk)
+{ return 0; }
#endif /* CONFIG_TEGRA_THERMAL_THROTTLE */
#endif /* __MACH_THERMAL_H */
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");