summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorPeter Boonstoppel <pboonstoppel@nvidia.com>2011-07-15 10:54:05 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:47:46 -0800
commite36812cf4e50ab703f5a1cb01ecced693816750f (patch)
treecdc598b6f6e3c49ad5c80da718e74e5dc32e5e71 /arch/arm
parent57204119111421f3005b5902475a33abcaef4d56 (diff)
ARM: tegra: power: Added global EDP Capping table
- Added table with EDP Capping values for different SKUs/regulator currents in new file edp.c - New entry point tegra_init_cpu_edp_limits() - Added DebugFS entry under debug/edp to list the currently selected EDP table - Populated EDP table in edp.c with data from Bug 844268 - edp.c keeps main EDP table; cpu-tegra.c and board-cardhu-power.c both read from there Bug 840255 Original-Change-Id: I55c2ee16278be8cd3005218bedebe76846d137d8 Reviewed-on: http://git-master/r/40938 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: R9a5f2bcfc1e6e0b5aee37cd700d75f9ef5cea30b
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-tegra/Makefile1
-rw-r--r--arch/arm/mach-tegra/board-cardhu-power.c21
-rw-r--r--arch/arm/mach-tegra/board-cardhu-sensors.c7
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c8
-rw-r--r--arch/arm/mach-tegra/edp.c229
-rw-r--r--arch/arm/mach-tegra/include/mach/edp.h26
-rw-r--r--arch/arm/mach-tegra/tegra3_clocks.c8
7 files changed, 261 insertions, 39 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 8ffa0d924c6b..bca96608c759 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -40,6 +40,7 @@ obj-y += dvfs.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_dvfs.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra3_dvfs.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += latency_allowance.o
+obj-$(CONFIG_TEGRA_EDP_LIMITS) += edp.o
endif
ifeq ($(CONFIG_TEGRA_SILICON_PLATFORM),y)
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_speedo.o
diff --git a/arch/arm/mach-tegra/board-cardhu-power.c b/arch/arm/mach-tegra/board-cardhu-power.c
index 725c84ff143e..b7c9ae9a128b 100644
--- a/arch/arm/mach-tegra/board-cardhu-power.c
+++ b/arch/arm/mach-tegra/board-cardhu-power.c
@@ -982,27 +982,12 @@ int __init cardhu_power_off_init(void)
}
#ifdef CONFIG_TEGRA_EDP_LIMITS
-/*
- * placeholder for now. needs to be changed with characterized data.
- * step size cannot be less than 4C
- */
-static struct tegra_edp_limits cardhu_edp_limits[] = {
-/* Temperature 1 CPU 2 CPUs 3 CPUs 4 CPUs */
- {60, {1400000, 1300000, 1300000, 1300000} },
- {70, {1400000, 1300000, 1300000, 1260000} },
- {80, {1400000, 1300000, 1300000, 1200000} },
- {90, {1400000, 1300000, 1300000, 1100000} },
-};
-
-void cardhu_thermal_zones_info(struct tegra_edp_limits **z, int *sz)
-{
- *z = cardhu_edp_limits;
- *sz = ARRAY_SIZE(cardhu_edp_limits);
-}
int __init cardhu_edp_init(void)
{
- tegra_init_cpu_edp_limits(cardhu_edp_limits, ARRAY_SIZE(cardhu_edp_limits));
+ /* Temporary initalization, needs to be set to the actual
+ regulator current */
+ tegra_init_cpu_edp_limits(5000);
return 0;
}
#endif
diff --git a/arch/arm/mach-tegra/board-cardhu-sensors.c b/arch/arm/mach-tegra/board-cardhu-sensors.c
index 8e29cd48027d..6ed5a8f0cdd7 100644
--- a/arch/arm/mach-tegra/board-cardhu-sensors.c
+++ b/arch/arm/mach-tegra/board-cardhu-sensors.c
@@ -548,16 +548,13 @@ static struct i2c_board_info cardhu_i2c4_nct1008_board_info[] = {
}
};
-#ifdef CONFIG_TEGRA_EDP_LIMITS
-extern void cardhu_thermal_zones_info(struct tegra_edp_limits **, int *);
-#endif
static int cardhu_nct1008_init(void)
{
int nct1008_port = -1;
int ret;
#ifdef CONFIG_TEGRA_EDP_LIMITS
- struct tegra_edp_limits *z;
+ const struct tegra_edp_limits *z;
int zones_sz;
int i;
bool throttle_ok = false;
@@ -589,7 +586,7 @@ static int cardhu_nct1008_init(void)
}
#ifdef CONFIG_TEGRA_EDP_LIMITS
- cardhu_thermal_zones_info(&z, &zones_sz);
+ tegra_get_cpu_edp_limits(&z, &zones_sz);
zones_sz = min(zones_sz, MAX_ZONES);
for (i = 0; i < zones_sz; i++) {
cardhu_nct1008_pdata.thermal_zones[i] = z[i].temperature;
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index 1eb1a29b2f58..ad8c359e2249 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -304,6 +304,8 @@ static struct notifier_block tegra_cpu_edp_notifier = {
static void tegra_cpu_edp_init(bool resume)
{
+ tegra_get_cpu_edp_limits(&cpu_edp_limits, &cpu_edp_limits_size);
+
if (!cpu_edp_limits) {
if (!resume)
pr_info("cpu-tegra: no EDP table is provided\n");
@@ -332,12 +334,6 @@ static void tegra_cpu_edp_exit(void)
unregister_hotcpu_notifier(&tegra_cpu_edp_notifier);
}
-void tegra_init_cpu_edp_limits(const struct tegra_edp_limits *limits, int size)
-{
- cpu_edp_limits = limits;
- cpu_edp_limits_size = size;
-}
-
#else /* CONFIG_TEGRA_EDP_LIMITS */
#define edp_governor_speed(requested_speed) (requested_speed)
diff --git a/arch/arm/mach-tegra/edp.c b/arch/arm/mach-tegra/edp.c
new file mode 100644
index 000000000000..9d935292841d
--- /dev/null
+++ b/arch/arm/mach-tegra/edp.c
@@ -0,0 +1,229 @@
+/*
+ * arch/arm/mach-tegra/edp.c
+ *
+ * Copyright (C) 2011 NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <mach/edp.h>
+
+#include "fuse.h"
+
+
+static const struct tegra_edp_limits *edp_limits;
+static int edp_limits_size;
+
+
+/*
+ * Temperature step size cannot be less than 4C because of hysteresis
+ * delta
+ * Code assumes different temperatures for the same speedo_id /
+ * regulator_cur are adjacent in the table, and higest regulator_cur
+ * comes first
+ */
+static char __initdata tegra_edp_map[] = {
+ 0x00, 0x3d, 0x2d, 0x8c, 0x82, 0x82, 0x82, 0x00,
+ 0x3d, 0x3c, 0x8c, 0x82, 0x82, 0x82, 0x00, 0x3d,
+ 0x4b, 0x8c, 0x82, 0x82, 0x82, 0x00, 0x3d, 0x5a,
+ 0x8c, 0x82, 0x82, 0x82, 0x00, 0x32, 0x2d, 0x8c,
+ 0x82, 0x82, 0x82, 0x00, 0x32, 0x3c, 0x8c, 0x82,
+ 0x82, 0x82, 0x00, 0x32, 0x4b, 0x8c, 0x82, 0x82,
+ 0x78, 0x00, 0x32, 0x5a, 0x8c, 0x82, 0x82, 0x6e,
+ 0x00, 0x28, 0x2d, 0x8c, 0x82, 0x82, 0x78, 0x00,
+ 0x28, 0x3c, 0x8c, 0x82, 0x82, 0x73, 0x00, 0x28,
+ 0x4b, 0x8c, 0x82, 0x78, 0x6e, 0x00, 0x28, 0x5a,
+ 0x8c, 0x82, 0x73, 0x5f, 0x00, 0x23, 0x2d, 0x8c,
+ 0x82, 0x82, 0x6e, 0x00, 0x23, 0x3c, 0x8c, 0x82,
+ 0x78, 0x69, 0x00, 0x23, 0x4b, 0x8c, 0x82, 0x73,
+ 0x5f, 0x00, 0x23, 0x5a, 0x8c, 0x82, 0x69, 0x55,
+ 0x01, 0x2f, 0x2d, 0x8c, 0x78, 0x78, 0x78, 0x01,
+ 0x2f, 0x3c, 0x8c, 0x78, 0x78, 0x78, 0x01, 0x2f,
+ 0x4b, 0x8c, 0x78, 0x78, 0x78, 0x01, 0x2f, 0x5a,
+ 0x8c, 0x78, 0x78, 0x78, 0x01, 0x28, 0x2d, 0x8c,
+ 0x78, 0x78, 0x78, 0x01, 0x28, 0x3c, 0x8c, 0x78,
+ 0x78, 0x78, 0x01, 0x28, 0x4b, 0x8c, 0x78, 0x78,
+ 0x73, 0x01, 0x28, 0x5a, 0x8c, 0x78, 0x73, 0x69,
+ 0x01, 0x23, 0x2d, 0x8c, 0x78, 0x78, 0x78, 0x01,
+ 0x23, 0x3c, 0x8c, 0x78, 0x78, 0x6e, 0x01, 0x23,
+ 0x4b, 0x8c, 0x78, 0x78, 0x64, 0x01, 0x23, 0x5a,
+ 0x8c, 0x78, 0x6e, 0x5a, 0x01, 0x1e, 0x2d, 0x8c,
+ 0x78, 0x78, 0x69, 0x01, 0x1e, 0x3c, 0x8c, 0x78,
+ 0x78, 0x64, 0x01, 0x1e, 0x4b, 0x8c, 0x78, 0x6e,
+ 0x5a, 0x01, 0x1e, 0x5a, 0x8c, 0x78, 0x64, 0x5a,
+ 0x01, 0x19, 0x2d, 0x8c, 0x78, 0x6e, 0x5a, 0x01,
+ 0x19, 0x3c, 0x8c, 0x78, 0x69, 0x55, 0x01, 0x19,
+ 0x4b, 0x8c, 0x78, 0x5f, 0x4b, 0x01, 0x19, 0x5a,
+ 0x8c, 0x73, 0x5a, 0x3c, 0x02, 0x3d, 0x2d, 0x8c,
+ 0x82, 0x82, 0x82, 0x02, 0x3d, 0x3c, 0x8c, 0x82,
+ 0x82, 0x82, 0x02, 0x3d, 0x4b, 0x8c, 0x82, 0x82,
+ 0x82, 0x02, 0x3d, 0x5a, 0x8c, 0x82, 0x82, 0x82,
+ 0x02, 0x32, 0x2d, 0x8c, 0x82, 0x82, 0x82, 0x02,
+ 0x32, 0x3c, 0x8c, 0x82, 0x82, 0x82, 0x02, 0x32,
+ 0x4b, 0x8c, 0x82, 0x82, 0x78, 0x02, 0x32, 0x5a,
+ 0x8c, 0x82, 0x82, 0x6e, 0x02, 0x28, 0x2d, 0x8c,
+ 0x82, 0x82, 0x78, 0x02, 0x28, 0x3c, 0x8c, 0x82,
+ 0x82, 0x73, 0x02, 0x28, 0x4b, 0x8c, 0x82, 0x78,
+ 0x6e, 0x02, 0x28, 0x5a, 0x8c, 0x82, 0x73, 0x5f,
+ 0x02, 0x23, 0x2d, 0x8c, 0x82, 0x82, 0x6e, 0x02,
+ 0x23, 0x3c, 0x8c, 0x82, 0x78, 0x69, 0x02, 0x23,
+ 0x4b, 0x8c, 0x82, 0x73, 0x5f, 0x02, 0x23, 0x5a,
+ 0x8c, 0x82, 0x69, 0x55, 0x03, 0x3d, 0x2d, 0x8c,
+ 0x82, 0x82, 0x82, 0x03, 0x3d, 0x3c, 0x8c, 0x82,
+ 0x82, 0x82, 0x03, 0x3d, 0x4b, 0x8c, 0x82, 0x82,
+ 0x82, 0x03, 0x3d, 0x5a, 0x8c, 0x82, 0x82, 0x82,
+ 0x03, 0x32, 0x2d, 0x8c, 0x82, 0x82, 0x82, 0x03,
+ 0x32, 0x3c, 0x8c, 0x82, 0x82, 0x82, 0x03, 0x32,
+ 0x4b, 0x8c, 0x82, 0x82, 0x73, 0x03, 0x32, 0x5a,
+ 0x8c, 0x82, 0x82, 0x6e, 0x03, 0x28, 0x2d, 0x8c,
+ 0x82, 0x82, 0x78, 0x03, 0x28, 0x3c, 0x8c, 0x82,
+ 0x82, 0x73, 0x03, 0x28, 0x4b, 0x8c, 0x82, 0x7d,
+ 0x6e, 0x03, 0x28, 0x5a, 0x8c, 0x82, 0x73, 0x5f,
+ 0x03, 0x23, 0x2d, 0x8c, 0x82, 0x82, 0x6e, 0x03,
+ 0x23, 0x3c, 0x8c, 0x82, 0x78, 0x6e, 0x03, 0x23,
+ 0x4b, 0x8c, 0x82, 0x78, 0x5f, 0x03, 0x23, 0x5a,
+ 0x8c, 0x82, 0x6e, 0x5a,
+};
+
+
+/*
+ * "Safe entry" to be used when no match for speedo_id /
+ * regulator_cur is found; must be the last one
+ */
+static struct tegra_edp_limits edp_default_limits[] = {
+ {90, {1000000, 1000000, 1000000, 1000000} },
+};
+
+
+
+/*
+ * Specify regulator current in mA, e.g. 5000mA
+ * Use 0 for default
+ */
+void __init tegra_init_cpu_edp_limits(unsigned int regulator_mA)
+{
+ int cpu_speedo_id = tegra_cpu_speedo_id();
+ int i, j;
+ struct tegra_edp_limits *e;
+ struct tegra_edp_entry *t = (struct tegra_edp_entry *)tegra_edp_map;
+ int tsize = sizeof(tegra_edp_map)/sizeof(struct tegra_edp_entry);
+
+ if (!regulator_mA) {
+ edp_limits = edp_default_limits;
+ edp_limits_size = ARRAY_SIZE(edp_default_limits);
+ return;
+ }
+
+ for (i = 0; i < tsize; i++) {
+ if (t[i].speedo_id == cpu_speedo_id &&
+ t[i].regulator_100mA <= regulator_mA / 100)
+ break;
+ }
+
+ /* No entry found in tegra_edp_map */
+ if (i >= tsize) {
+ edp_limits = edp_default_limits;
+ edp_limits_size = ARRAY_SIZE(edp_default_limits);
+ return;
+ }
+
+ /* Find all rows for this entry */
+ for (j = i + 1; j < tsize; j++) {
+ if (t[i].speedo_id != t[j].speedo_id ||
+ t[i].regulator_100mA != t[j].regulator_100mA)
+ break;
+ }
+
+ edp_limits_size = j - i;
+ e = kmalloc(sizeof(struct tegra_edp_limits) * edp_limits_size,
+ GFP_KERNEL);
+ BUG_ON(!e);
+
+ for (j = 0; j < edp_limits_size; j++) {
+ e[j].temperature = (int)t[i+j].temperature;
+ e[j].freq_limits[0] = (unsigned int)t[i+j].freq_limits[0] * 10000;
+ e[j].freq_limits[1] = (unsigned int)t[i+j].freq_limits[1] * 10000;
+ e[j].freq_limits[2] = (unsigned int)t[i+j].freq_limits[2] * 10000;
+ e[j].freq_limits[3] = (unsigned int)t[i+j].freq_limits[3] * 10000;
+ }
+
+ if (edp_limits && edp_limits != edp_default_limits)
+ kfree(edp_limits);
+
+ edp_limits = e;
+}
+
+void tegra_get_cpu_edp_limits(const struct tegra_edp_limits **limits, int *size)
+{
+ *limits = edp_limits;
+ *size = edp_limits_size;
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+static int edp_debugfs_show(struct seq_file *s, void *data)
+{
+ int i;
+ const struct tegra_edp_limits *limits;
+ int size;
+
+ tegra_get_cpu_edp_limits(&limits, &size);
+
+ seq_printf(s, "-- EDP table --\n");
+ for (i = 0; i < size; i++) {
+ seq_printf(s, "%4dC: %10d %10d %10d %10d\n",
+ limits[i].temperature,
+ limits[i].freq_limits[0],
+ limits[i].freq_limits[1],
+ limits[i].freq_limits[2],
+ limits[i].freq_limits[3]);
+ }
+
+ return 0;
+}
+
+
+static int edp_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, edp_debugfs_show, inode->i_private);
+}
+
+
+static const struct file_operations edp_debugfs_fops = {
+ .open = edp_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
+static int __init tegra_edp_debugfs_init()
+{
+ struct dentry *d;
+
+ d = debugfs_create_file("edp", S_IRUGO, NULL, NULL,
+ &edp_debugfs_fops);
+ if (!d)
+ return -ENOMEM;
+
+ return 0;
+}
+
+late_initcall(tegra_edp_debugfs_init);
+#endif /* CONFIG_DEBUG_FS */
diff --git a/arch/arm/mach-tegra/include/mach/edp.h b/arch/arm/mach-tegra/include/mach/edp.h
index 21a56ebc5a8d..1af8d9e55a95 100644
--- a/arch/arm/mach-tegra/include/mach/edp.h
+++ b/arch/arm/mach-tegra/include/mach/edp.h
@@ -21,20 +21,36 @@
#ifndef __MACH_EDP_H
#define __MACH_EDP_H
+#include <linux/debugfs.h>
+
+struct tegra_edp_entry {
+ char speedo_id;
+ char regulator_100mA;
+ char temperature;
+ char freq_limits[4];
+};
+
struct tegra_edp_limits {
- int temperature;
+ int temperature;
unsigned int freq_limits[4];
};
+
#ifdef CONFIG_TEGRA_EDP_LIMITS
+
+
int tegra_edp_update_thermal_zone(int temperature);
-void tegra_init_cpu_edp_limits(const struct tegra_edp_limits *limits, int size);
+void tegra_init_cpu_edp_limits(unsigned int regulator_mA);
+void tegra_get_cpu_edp_limits(const struct tegra_edp_limits **limits, int *size);
+
#else
-static inline void tegra_init_cpu_edp_limits(
- const struct tegra_edp_limits *limits, int size)
-{ }
+static inline void tegra_init_cpu_edp_limits(int regulator_mA)
+{}
static inline int tegra_edp_update_thermal_zone(int temperature)
{ return -1; }
+static inline void tegra_get_cpu_edp_limits(struct tegra_edp_limits **limits,
+ int *size)
+{}
#endif
#endif /* __MACH_EDP_H */
diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c
index ab5b695e9aab..77e3542fea7d 100644
--- a/arch/arm/mach-tegra/tegra3_clocks.c
+++ b/arch/arm/mach-tegra/tegra3_clocks.c
@@ -4086,9 +4086,6 @@ struct clk *tegra_ptr_clks[] = {
&tegra_clk_cbus,
};
-static struct tegra_edp_limits default_cpu_edp_limits[] = {
- {90, { 1000000, 1000000, 1000000, 1000000 } },
-};
static void tegra3_init_one_clock(struct clk *c)
{
@@ -4134,9 +4131,10 @@ void __init tegra_soc_init_clocks(void)
for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
tegra3_init_one_clock(&tegra_clk_out_list[i]);
- tegra_init_cpu_edp_limits(default_cpu_edp_limits,
- ARRAY_SIZE(default_cpu_edp_limits));
emc_bridge = &tegra_clk_emc_bridge;
+
+ /* Initialize to default */
+ tegra_init_cpu_edp_limits(0);
}
#ifdef CONFIG_CPU_FREQ