summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra2_speedo.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-02-11 01:20:39 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:41:55 -0800
commit6151ab38e5e1f7fba98a52a291323a37cb2c237e (patch)
tree69c15b8fcd0af0498097edc65926f199edc50bc0 /arch/arm/mach-tegra/tegra2_speedo.c
parent637ced4998739267fb9eca41951e9126a098be0e (diff)
ARM: tegra: Add speedo-based process identification
Original-Change-Id: If6cd2914551331bd49b128ad3143a0d7adf0f120 Reviewed-on: http://git-master/r/13396 Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com> Tested-by: Bharat Nihalani <bnihalani@nvidia.com> Rebase-Id: Re61c7e38519e6fde84f95f1c7ecb883c92b2d0db
Diffstat (limited to 'arch/arm/mach-tegra/tegra2_speedo.c')
-rw-r--r--arch/arm/mach-tegra/tegra2_speedo.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/tegra2_speedo.c b/arch/arm/mach-tegra/tegra2_speedo.c
new file mode 100644
index 000000000000..1e5fa26a5c41
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra2_speedo.c
@@ -0,0 +1,140 @@
+/*
+ * arch/arm/mach-tegra/tegra2_speedo.c
+ *
+ * Copyright (c) 2010, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include <mach/iomap.h>
+
+#include "fuse.h"
+
+#define CPU_SPEEDO_LSBIT 20
+#define CPU_SPEEDO_MSBIT 29
+#define CPU_SPEEDO_REDUND_LSBIT 30
+#define CPU_SPEEDO_REDUND_MSBIT 39
+#define CPU_SPEEDO_REDUND_OFFS (CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT)
+
+#define CORE_SPEEDO_LSBIT 40
+#define CORE_SPEEDO_MSBIT 47
+#define CORE_SPEEDO_REDUND_LSBIT 48
+#define CORE_SPEEDO_REDUND_MSBIT 55
+#define CORE_SPEEDO_REDUND_OFFS (CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT)
+
+#define SPEEDO_MULT 4
+
+#define CHIP_ID 0x804
+#define CHIP_MINOR_SHIFT 16
+#define CHIP_MINOR_MASK (0xF << CHIP_MINOR_SHIFT)
+
+#define PROCESS_CORNERS_NUM 4
+
+#define SPEEDO_ID_SELECT_0(rev) ((rev) <= 2)
+#define SPEEDO_ID_SELECT_1(sku) \
+ (((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \
+ ((sku) != 27) && ((sku) != 28))
+
+/* Maximum speedo levels for each CPU process corner */
+static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
+/* proc_id 0 1 2 3 */
+ {315, 366, 420, UINT_MAX}, /* speedo_id 0 */
+ {303, 368, 419, UINT_MAX}, /* speedo_id 1 */
+ {316, 331, 383, UINT_MAX}, /* speedo_id 2 */
+};
+
+/* Maximum speedo levels for each core process corner */
+static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = {
+/* proc_id 0 1 2 3 */
+ {165, 195, 224, UINT_MAX}, /* speedo_id 0 */
+ {165, 195, 224, UINT_MAX}, /* speedo_id 1 */
+ {165, 195, 224, UINT_MAX}, /* speedo_id 2 */
+};
+
+static int cpu_process_id;
+static int core_process_id;
+static int soc_speedo_id;
+
+void tegra_init_speedo_data(void)
+{
+ u32 reg, val;
+ int i, bit, rev;
+ int sku = tegra_sku_id();
+ void __iomem *apb_misc = IO_ADDRESS(TEGRA_APB_MISC_BASE);
+
+ reg = readl(apb_misc + CHIP_ID);
+ rev = (reg & CHIP_MINOR_MASK) >> CHIP_MINOR_SHIFT;
+ if (SPEEDO_ID_SELECT_0(rev))
+ soc_speedo_id = 0;
+ else if (SPEEDO_ID_SELECT_1(sku))
+ soc_speedo_id = 1;
+ else
+ soc_speedo_id = 2;
+ BUG_ON(soc_speedo_id >= ARRAY_SIZE(cpu_process_speedos));
+ BUG_ON(soc_speedo_id >= ARRAY_SIZE(core_process_speedos));
+
+ val = 0;
+ for (bit = CPU_SPEEDO_MSBIT; bit >= CPU_SPEEDO_LSBIT; bit--) {
+ reg = tegra_spare_fuse(bit) |
+ tegra_spare_fuse(bit + CPU_SPEEDO_REDUND_OFFS);
+ val = (val << 1) | (reg & 0x1);
+ }
+ val = val * SPEEDO_MULT;
+ pr_debug("%s CPU speedo level %u\n", __func__, val);
+
+ for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
+ if (val <= cpu_process_speedos[soc_speedo_id][i])
+ break;
+ }
+ cpu_process_id = i;
+
+ val = 0;
+ for (bit = CORE_SPEEDO_MSBIT; bit >= CORE_SPEEDO_LSBIT; bit--) {
+ reg = tegra_spare_fuse(bit) |
+ tegra_spare_fuse(bit + CORE_SPEEDO_REDUND_OFFS);
+ val = (val << 1) | (reg & 0x1);
+ }
+ val = val * SPEEDO_MULT;
+ pr_debug("%s Core speedo level %u\n", __func__, val);
+
+ for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
+ if (val <= core_process_speedos[soc_speedo_id][i])
+ break;
+ }
+ core_process_id = i;
+
+ pr_info("Tegra SKU: %d Rev: A%.2d CPU Process: %d Core Process: %d"
+ " Speedo ID: %d\n", sku, rev, cpu_process_id, core_process_id,
+ soc_speedo_id);
+}
+
+int tegra_cpu_process_id(void)
+{
+ return cpu_process_id;
+}
+
+int tegra_core_process_id(void)
+{
+ return core_process_id;
+}
+
+int tegra_soc_speedo_id(void)
+{
+ return soc_speedo_id;
+}