diff options
author | Peter Boonstoppel <pboonstoppel@nvidia.com> | 2011-07-15 10:54:05 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:47:46 -0800 |
commit | e36812cf4e50ab703f5a1cb01ecced693816750f (patch) | |
tree | cdc598b6f6e3c49ad5c80da718e74e5dc32e5e71 /arch/arm/mach-tegra/edp.c | |
parent | 57204119111421f3005b5902475a33abcaef4d56 (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/mach-tegra/edp.c')
-rw-r--r-- | arch/arm/mach-tegra/edp.c | 229 |
1 files changed, 229 insertions, 0 deletions
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 */ |