linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] ARM: tegra: add speedo identification for T20/T30
@ 2012-10-29  7:21 Danny Huang
  2012-10-29  7:21 ` [PATCH 1/2] ARM: tegra: Add speedo-based process identification Danny Huang
  2012-10-29  7:21 ` [PATCH 2/2] ARM: tegra: T30 speedo-based identification Danny Huang
  0 siblings, 2 replies; 5+ messages in thread
From: Danny Huang @ 2012-10-29  7:21 UTC (permalink / raw)
  To: swarren; +Cc: linux-arm-kernel, linux-tegra, linux-kernel, Danny Huang

This patch series adds speedo identification functionality for tegra
T20 and T30. It reads speedo value from fuse and chooses CPU and core 
process ID by checking speedo corner tables.

Danny Huang (2):
  ARM: tegra: Add speedo-based process identification
  ARM: tegra: T30 speedo-based identification

 arch/arm/mach-tegra/Makefile         |   2 +
 arch/arm/mach-tegra/fuse.c           |  35 +++--
 arch/arm/mach-tegra/fuse.h           |  16 ++
 arch/arm/mach-tegra/tegra20_speedo.c | 102 ++++++++++++
 arch/arm/mach-tegra/tegra30_speedo.c | 290 +++++++++++++++++++++++++++++++++++
 5 files changed, 433 insertions(+), 12 deletions(-)
 create mode 100644 arch/arm/mach-tegra/tegra20_speedo.c
 create mode 100644 arch/arm/mach-tegra/tegra30_speedo.c

-- 
1.8.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] ARM: tegra: Add speedo-based process identification
  2012-10-29  7:21 [PATCH 0/2] ARM: tegra: add speedo identification for T20/T30 Danny Huang
@ 2012-10-29  7:21 ` Danny Huang
  2012-10-29 17:40   ` Stephen Warren
  2012-10-29  7:21 ` [PATCH 2/2] ARM: tegra: T30 speedo-based identification Danny Huang
  1 sibling, 1 reply; 5+ messages in thread
From: Danny Huang @ 2012-10-29  7:21 UTC (permalink / raw)
  To: swarren; +Cc: linux-arm-kernel, linux-tegra, linux-kernel, Danny Huang

Detect CPU and core process ID by checking speedo corner tables.
This can provide a more accurate process ID.

Signed-off-by: Danny Huang <dahuang@nvidia.com>
---
 arch/arm/mach-tegra/Makefile         |   1 +
 arch/arm/mach-tegra/fuse.c           |  13 ++---
 arch/arm/mach-tegra/fuse.h           |   8 +++
 arch/arm/mach-tegra/tegra20_speedo.c | 102 +++++++++++++++++++++++++++++++++++
 4 files changed, 116 insertions(+), 8 deletions(-)
 create mode 100644 arch/arm/mach-tegra/tegra20_speedo.c

diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 9aa653b..7ab6092 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_CPU_IDLE)			+= sleep.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra20_clocks.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra20_clocks_data.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra2_emc.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra20_speedo.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= sleep-t20.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks_data.o
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index 0b7db17..b28e6d2 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -35,6 +35,7 @@ int tegra_sku_id;
 int tegra_cpu_process_id;
 int tegra_core_process_id;
 int tegra_chip_id;
+int tegra_soc_speedo_id;
 enum tegra_revision tegra_revision;
 
 /* The BCT to use at boot is specified by board straps that can be read
@@ -62,7 +63,7 @@ static inline u32 tegra_fuse_readl(unsigned long offset)
 	return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
 }
 
-static inline bool get_spare_fuse(int bit)
+unsigned int tegra_spare_fuse(int bit)
 {
 	return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4);
 }
@@ -78,7 +79,7 @@ static enum tegra_revision tegra_get_revision(u32 id)
 		return TEGRA_REVISION_A02;
 	case 3:
 		if (tegra_chip_id == TEGRA20 &&
-			(get_spare_fuse(18) || get_spare_fuse(19)))
+			(tegra_spare_fuse(18) || tegra_spare_fuse(19)))
 			return TEGRA_REVISION_A03p;
 		else
 			return TEGRA_REVISION_A03;
@@ -100,12 +101,6 @@ void tegra_init_fuse(void)
 	reg = tegra_fuse_readl(FUSE_SKU_INFO);
 	tegra_sku_id = reg & 0xFF;
 
-	reg = tegra_fuse_readl(FUSE_SPARE_BIT);
-	tegra_cpu_process_id = (reg >> 6) & 3;
-
-	reg = tegra_fuse_readl(FUSE_SPARE_BIT);
-	tegra_core_process_id = (reg >> 12) & 3;
-
 	reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
 	tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
 
@@ -114,6 +109,8 @@ void tegra_init_fuse(void)
 
 	tegra_revision = tegra_get_revision(id);
 
+	tegra20_init_speedo_data();
+
 	pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
 		tegra_revision_name[tegra_revision],
 		tegra_sku_id, tegra_cpu_process_id,
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
index d2107b2..f1cafb9 100644
--- a/arch/arm/mach-tegra/fuse.h
+++ b/arch/arm/mach-tegra/fuse.h
@@ -42,11 +42,19 @@ extern int tegra_sku_id;
 extern int tegra_cpu_process_id;
 extern int tegra_core_process_id;
 extern int tegra_chip_id;
+extern int tegra_soc_speedo_id;
 extern enum tegra_revision tegra_revision;
 
 extern int tegra_bct_strapping;
 
 unsigned long long tegra_chip_uid(void);
 void tegra_init_fuse(void);
+unsigned int tegra_spare_fuse(int bit);
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+void tegra20_init_speedo_data(void);
+#else
+static inline void tegra20_init_speedo_data(void) {}
+#endif
 
 #endif
diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c
new file mode 100644
index 0000000..b9202ea
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra20_speedo.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.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 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))
+
+static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
+	{315, 366, 420, UINT_MAX},
+	{303, 368, 419, UINT_MAX},
+	{316, 331, 383, UINT_MAX},
+};
+
+static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = {
+	{165, 195, 224, UINT_MAX},
+	{165, 195, 224, UINT_MAX},
+	{165, 195, 224, UINT_MAX},
+};
+
+void tegra20_init_speedo_data(void)
+{
+	u32 reg;
+	u32 val;
+	int i;
+
+	if (SPEEDO_ID_SELECT_0(tegra_revision))
+		tegra_soc_speedo_id = 0;
+	else if (SPEEDO_ID_SELECT_1(tegra_sku_id))
+		tegra_soc_speedo_id = 1;
+	else
+		tegra_soc_speedo_id = 2;
+
+	WARN_ON(tegra_soc_speedo_id >= ARRAY_SIZE(cpu_process_speedos));
+	WARN_ON(tegra_soc_speedo_id >= ARRAY_SIZE(core_process_speedos));
+
+	val = 0;
+	for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) {
+		reg = tegra_spare_fuse(i) |
+			tegra_spare_fuse(i + CPU_SPEEDO_REDUND_OFFS);
+		val = (val << 1) | (reg & 0x1);
+	}
+	val = val * SPEEDO_MULT;
+	pr_debug("%s CPU speedo value %u\n", __func__, val);
+
+	for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
+		if (val <= cpu_process_speedos[tegra_soc_speedo_id][i])
+			break;
+	}
+	tegra_cpu_process_id = i;
+
+	val = 0;
+	for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) {
+		reg = tegra_spare_fuse(i) |
+			tegra_spare_fuse(i + CORE_SPEEDO_REDUND_OFFS);
+		val = (val << 1) | (reg & 0x1);
+	}
+	val = val * SPEEDO_MULT;
+	pr_debug("%s Core speedo value %u\n", __func__, val);
+
+	for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
+		if (val <= core_process_speedos[tegra_soc_speedo_id][i])
+			break;
+	}
+	tegra_core_process_id = i;
+
+	pr_info("Tegra2 Soc Speedo ID %d", tegra_soc_speedo_id);
+}
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] ARM: tegra: T30 speedo-based identification
  2012-10-29  7:21 [PATCH 0/2] ARM: tegra: add speedo identification for T20/T30 Danny Huang
  2012-10-29  7:21 ` [PATCH 1/2] ARM: tegra: Add speedo-based process identification Danny Huang
@ 2012-10-29  7:21 ` Danny Huang
  2012-10-29 17:55   ` Stephen Warren
  1 sibling, 1 reply; 5+ messages in thread
From: Danny Huang @ 2012-10-29  7:21 UTC (permalink / raw)
  To: swarren; +Cc: linux-arm-kernel, linux-tegra, linux-kernel, Danny Huang

This patch adds speedo-based identification support for T30.

Signed-off-by: Danny Huang <dahuang@nvidia.com>
---
 arch/arm/mach-tegra/Makefile         |   1 +
 arch/arm/mach-tegra/fuse.c           |  26 +++-
 arch/arm/mach-tegra/fuse.h           |   8 +
 arch/arm/mach-tegra/tegra30_speedo.c | 290 +++++++++++++++++++++++++++++++++++
 4 files changed, 319 insertions(+), 6 deletions(-)
 create mode 100644 arch/arm/mach-tegra/tegra30_speedo.c

diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 7ab6092..fae982a 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= tegra20_speedo.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= sleep-t20.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_clocks_data.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= tegra30_speedo.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= sleep-t30.o
 obj-$(CONFIG_SMP)			+= platsmp.o headsmp.o
 obj-$(CONFIG_SMP)                       += reset.o
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index b28e6d2..03e697a 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -29,12 +29,17 @@
 #define FUSE_UID_LOW		0x108
 #define FUSE_UID_HIGH		0x10c
 #define FUSE_SKU_INFO		0x110
-#define FUSE_SPARE_BIT		0x200
+
+#define TEGRA20_FUSE_SPARE_BIT		0x200
+#define TEGRA30_FUSE_SPARE_BIT		0x244
+
+static int tegra_fuse_spare_bit;
 
 int tegra_sku_id;
 int tegra_cpu_process_id;
 int tegra_core_process_id;
 int tegra_chip_id;
+int tegra_cpu_speedo_id;
 int tegra_soc_speedo_id;
 enum tegra_revision tegra_revision;
 
@@ -58,14 +63,14 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
 	[TEGRA_REVISION_A04]     = "A04",
 };
 
-static inline u32 tegra_fuse_readl(unsigned long offset)
+u32 tegra_fuse_readl(unsigned long offset)
 {
 	return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
 }
 
 unsigned int tegra_spare_fuse(int bit)
 {
-	return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4);
+	return tegra_fuse_readl(tegra_fuse_spare_bit + bit * 4);
 }
 
 static enum tegra_revision tegra_get_revision(u32 id)
@@ -107,9 +112,18 @@ void tegra_init_fuse(void)
 	id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
 	tegra_chip_id = (id >> 8) & 0xff;
 
-	tegra_revision = tegra_get_revision(id);
-
-	tegra20_init_speedo_data();
+	switch (tegra_chip_id) {
+	case TEGRA20:
+		tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
+		tegra_revision = tegra_get_revision(id);
+		tegra20_init_speedo_data();
+		break;
+	case TEGRA30:
+		tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT;
+		tegra_revision = tegra_get_revision(id);
+		tegra30_init_speedo_data();
+		break;
+	}
 
 	pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
 		tegra_revision_name[tegra_revision],
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
index f1cafb9..544769c 100644
--- a/arch/arm/mach-tegra/fuse.h
+++ b/arch/arm/mach-tegra/fuse.h
@@ -42,6 +42,7 @@ extern int tegra_sku_id;
 extern int tegra_cpu_process_id;
 extern int tegra_core_process_id;
 extern int tegra_chip_id;
+extern int tegra_cpu_speedo_id;
 extern int tegra_soc_speedo_id;
 extern enum tegra_revision tegra_revision;
 
@@ -50,6 +51,7 @@ extern int tegra_bct_strapping;
 unsigned long long tegra_chip_uid(void);
 void tegra_init_fuse(void);
 unsigned int tegra_spare_fuse(int bit);
+u32 tegra_fuse_readl(unsigned long offset);
 
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
 void tegra20_init_speedo_data(void);
@@ -57,4 +59,10 @@ void tegra20_init_speedo_data(void);
 static inline void tegra20_init_speedo_data(void) {}
 #endif
 
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+void tegra30_init_speedo_data(void);
+#else
+static inline void tegra30_init_speedo_data(void) {}
+#endif
+
 #endif
diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/arch/arm/mach-tegra/tegra30_speedo.c
new file mode 100644
index 0000000..d3f4885
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30_speedo.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+
+#include "fuse.h"
+
+#define CORE_PROCESS_CORNERS_NUM	1
+#define CPU_PROCESS_CORNERS_NUM		6
+
+#define FUSE_SPEEDO_CALIB_0	0x114
+#define FUSE_PACKAGE_INFO	0X1FC
+#define FUSE_TEST_PROG_VER	0X128
+
+#define G_SPEEDO_BIT_MINUS1	58
+#define G_SPEEDO_BIT_MINUS1_R	59
+#define G_SPEEDO_BIT_MINUS2	60
+#define G_SPEEDO_BIT_MINUS2_R	61
+#define LP_SPEEDO_BIT_MINUS1	62
+#define LP_SPEEDO_BIT_MINUS1_R	63
+#define LP_SPEEDO_BIT_MINUS2	64
+#define LP_SPEEDO_BIT_MINUS2_R	65
+
+static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
+	{180},
+	{170},
+	{195},
+	{180},
+	{168},
+	{192},
+	{180},
+	{170},
+	{195},
+	{180},
+	{180},
+	{180},
+};
+
+static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
+	{306, 338, 360, 376, UINT_MAX},
+	{295, 336, 358, 375, UINT_MAX},
+	{325, 325, 358, 375, UINT_MAX},
+	{325, 325, 358, 375, UINT_MAX},
+	{292, 324, 348, 364, UINT_MAX},
+	{324, 324, 348, 364, UINT_MAX},
+	{324, 324, 348, 364, UINT_MAX},
+	{295, 336, 358, 375, UINT_MAX},
+	{358, 358, 358, 358, 397, UINT_MAX},
+	{364, 364, 364, 364, 397, UINT_MAX},
+	{295, 336, 358, 375, 391, UINT_MAX},
+	{295, 336, 358, 375, 391, UINT_MAX},
+};
+
+static int threshold_index;
+static int package_id;
+
+static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
+{
+	u32 reg;
+	int ate_ver;
+	int bit_minus1;
+	int bit_minus2;
+
+	WARN_ON(!speedo_g || !speedo_lp);
+	reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0);
+
+	*speedo_lp = (reg & 0xFFFF) * 4;
+	*speedo_g = ((reg >> 16) & 0xFFFF) * 4;
+
+	ate_ver = tegra_fuse_readl(FUSE_TEST_PROG_VER);
+	pr_info("%s: ATE prog ver %d.%d\n", __func__, ate_ver/10, ate_ver%10);
+
+	if (ate_ver >= 26) {
+		bit_minus1 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1) & 0x1;
+		bit_minus1 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1_R) & 0x1;
+		bit_minus2 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2) & 0x1;
+		bit_minus2 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2_R) & 0x1;
+		*speedo_lp |= (bit_minus1 << 1) | bit_minus2;
+
+		bit_minus1 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS1) & 0x1;
+		bit_minus1 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS1_R) & 0x1;
+		bit_minus2 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS2) & 0x1;
+		bit_minus2 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS2_R) & 0x1;
+		*speedo_g |= (bit_minus1 << 1) | bit_minus2;
+	} else {
+		*speedo_lp |= 0x3;
+		*speedo_g |= 0x3;
+	}
+}
+
+static void rev_sku_to_speedo_ids(int rev, int sku)
+{
+	switch (rev) {
+	case TEGRA_REVISION_A01:
+		tegra_cpu_speedo_id = 0;
+		tegra_soc_speedo_id = 0;
+		threshold_index = 0;
+		break;
+	case TEGRA_REVISION_A02:
+	case TEGRA_REVISION_A03:
+		switch (sku) {
+		case 0x87:
+		case 0x82:
+			tegra_cpu_speedo_id = 1;
+			tegra_soc_speedo_id = 1;
+			threshold_index = 1;
+			break;
+		case 0x81:
+			switch (package_id) {
+			case 1:
+				tegra_cpu_speedo_id = 2;
+				tegra_soc_speedo_id = 2;
+				threshold_index = 2;
+				break;
+			case 2:
+				tegra_cpu_speedo_id = 4;
+				tegra_soc_speedo_id = 1;
+				threshold_index = 7;
+				break;
+			default:
+				pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
+				       package_id);
+				BUG();
+				break;
+			}
+			break;
+		case 0x80:
+			switch (package_id) {
+			case 1:
+				tegra_cpu_speedo_id = 5;
+				tegra_soc_speedo_id = 2;
+				threshold_index = 8;
+				break;
+			case 2:
+				tegra_cpu_speedo_id = 6;
+				tegra_soc_speedo_id = 2;
+				threshold_index = 9;
+				break;
+			default:
+				pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
+				       package_id);
+				BUG();
+				break;
+			}
+			break;
+		case 0x83:
+			switch (package_id) {
+			case 1:
+				tegra_cpu_speedo_id = 7;
+				tegra_soc_speedo_id = 1;
+				threshold_index = 10;
+				break;
+			case 2:
+				tegra_cpu_speedo_id = 3;
+				tegra_soc_speedo_id = 2;
+				threshold_index = 3;
+				break;
+			default:
+				pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
+				       package_id);
+				BUG();
+				break;
+			}
+			break;
+		case 0x8F:
+			tegra_cpu_speedo_id = 8;
+			tegra_soc_speedo_id = 1;
+			threshold_index = 11;
+			break;
+		case 0x08:
+			tegra_cpu_speedo_id = 1;
+			tegra_soc_speedo_id = 1;
+			threshold_index = 4;
+			break;
+		case 0x02:
+			tegra_cpu_speedo_id = 2;
+			tegra_soc_speedo_id = 2;
+			threshold_index = 5;
+			break;
+		case 0x04:
+			tegra_cpu_speedo_id = 3;
+			tegra_soc_speedo_id = 2;
+			threshold_index = 6;
+			break;
+		case 0:
+			pr_info("Tegra3 ENG SKU: Checking package_id\n");
+			switch (package_id) {
+			case 1:
+				tegra_cpu_speedo_id = 2;
+				tegra_soc_speedo_id = 2;
+				threshold_index = 2;
+				break;
+			case 2:
+				tegra_cpu_speedo_id = 3;
+				tegra_soc_speedo_id = 2;
+				threshold_index = 3;
+				break;
+			default:
+				pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
+				       package_id);
+				BUG();
+				break;
+			}
+			break;
+		default:
+			pr_err("Tegra3: Unknown SKU %d\n", sku);
+			tegra_cpu_speedo_id = 0;
+			tegra_soc_speedo_id = 0;
+			threshold_index = 0;
+			break;
+		}
+		break;
+	default:
+		BUG();
+		break;
+	}
+}
+
+void tegra30_init_speedo_data(void)
+{
+	u32 cpu_speedo_val;
+	u32 core_speedo_val;
+	int i;
+
+	package_id = tegra_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
+
+	WARN_ON(ARRAY_SIZE(cpu_process_speedos) !=
+		ARRAY_SIZE(core_process_speedos));
+
+	rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id);
+	WARN_ON(threshold_index >= ARRAY_SIZE(cpu_process_speedos));
+
+	fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val);
+	pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val);
+	pr_debug("%s Core speedo value %u\n", __func__, core_speedo_val);
+
+	for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) {
+		if (cpu_speedo_val <
+		    cpu_process_speedos[threshold_index][i]) {
+			break;
+		}
+	}
+	tegra_cpu_process_id = i - 1;
+
+	if (tegra_cpu_process_id == -1) {
+		pr_err("****************************************************");
+		pr_err("****************************************************");
+		pr_err("* tegra3_speedo: CPU speedo value %3d out of range *",
+		       cpu_speedo_val);
+		pr_err("****************************************************");
+		pr_err("****************************************************");
+
+		tegra_cpu_speedo_id = 1;
+	}
+
+	for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) {
+		if (core_speedo_val <
+		    core_process_speedos[threshold_index][i]) {
+			break;
+		}
+	}
+	tegra_core_process_id = i - 1;
+
+	if (tegra_core_process_id == -1) {
+		pr_err("****************************************************");
+		pr_err("****************************************************");
+		pr_err("* tegra3_speedo: CORE speedo value %3d out of range *",
+		       core_speedo_val);
+		pr_err("****************************************************");
+		pr_err("****************************************************");
+
+		tegra_soc_speedo_id = 1;
+	}
+	pr_info("Tegra3: CPU Speedo ID %d, Soc Speedo ID %d",
+		tegra_cpu_speedo_id, tegra_soc_speedo_id);
+}
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] ARM: tegra: Add speedo-based process identification
  2012-10-29  7:21 ` [PATCH 1/2] ARM: tegra: Add speedo-based process identification Danny Huang
@ 2012-10-29 17:40   ` Stephen Warren
  0 siblings, 0 replies; 5+ messages in thread
From: Stephen Warren @ 2012-10-29 17:40 UTC (permalink / raw)
  To: Danny Huang; +Cc: linux-arm-kernel, linux-tegra, linux-kernel

On 10/29/2012 01:21 AM, Danny Huang wrote:
> Detect CPU and core process ID by checking speedo corner tables.
> This can provide a more accurate process ID.

> diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c

> @@ -114,6 +109,8 @@ void tegra_init_fuse(void)
>  
>  	tegra_revision = tegra_get_revision(id);
>  
> +	tegra20_init_speedo_data();

This code executes on both Tegra20 and Tegra30. Calling a
Tegra20-specific function unconditionally isn't correct. This is
important because if someone does "git bisect" across this patch, patch
1 might be applied, but patch 2 not.

I think you need to add the switch statement from patch 2 here rather
than later in patch 2. Also, I think you need to keep the following
chunk of code in the Tegra30 case, and only remove it completely in patch 2

-	reg = tegra_fuse_readl(FUSE_SPARE_BIT);
-	tegra_cpu_process_id = (reg >> 6) & 3;
-
-	reg = tegra_fuse_readl(FUSE_SPARE_BIT);
-	tegra_core_process_id = (reg >> 12) & 3;

> diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c

> +static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
> +	{315, 366, 420, UINT_MAX},
> +	{303, 368, 419, UINT_MAX},
> +	{316, 331, 383, UINT_MAX},
> +};
> +
> +static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = {
> +	{165, 195, 224, UINT_MAX},
> +	{165, 195, 224, UINT_MAX},
> +	{165, 195, 224, UINT_MAX},
> +};
> +
> +void tegra20_init_speedo_data(void)
> +{
> +	u32 reg;
> +	u32 val;
> +	int i;
> +
> +	if (SPEEDO_ID_SELECT_0(tegra_revision))
> +		tegra_soc_speedo_id = 0;
> +	else if (SPEEDO_ID_SELECT_1(tegra_sku_id))
> +		tegra_soc_speedo_id = 1;
> +	else
> +		tegra_soc_speedo_id = 2;
> +
> +	WARN_ON(tegra_soc_speedo_id >= ARRAY_SIZE(cpu_process_speedos));
> +	WARN_ON(tegra_soc_speedo_id >= ARRAY_SIZE(core_process_speedos));

Can this be a BUILD_BUG_ON() instead;

#define SPEEDO_ID_0 0
#define SPEEDO_ID_1 1
#define SPEEDO_ID_2 2
#define SPEEDO_ID_COUNT (SPEEDO_ID_2 + 1)
BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) == SPEEDO_ID_COUNT)
BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) == SPEEDO_ID_COUNT)

and use those #defines in the assignments to tegra_soc_speedod_id above,
rather than literals?

Or even just the following without the BUILD_BUG_ONs:

> static const u32 core_process_speedos[SPEEDO_ID_COUNT][PROCESS_CORNERS_NUM] = {

> +	val = 0;
> +	for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) {
> +		reg = tegra_spare_fuse(i) |
> +			tegra_spare_fuse(i + CPU_SPEEDO_REDUND_OFFS);
> +		val = (val << 1) | (reg & 0x1);

Out of curiosity, why did the prototype of tegra_spare_fuse() change
from returning a bool to an int, if only bit 0 is going to be used?

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] ARM: tegra: T30 speedo-based identification
  2012-10-29  7:21 ` [PATCH 2/2] ARM: tegra: T30 speedo-based identification Danny Huang
@ 2012-10-29 17:55   ` Stephen Warren
  0 siblings, 0 replies; 5+ messages in thread
From: Stephen Warren @ 2012-10-29 17:55 UTC (permalink / raw)
  To: Danny Huang; +Cc: linux-arm-kernel, linux-tegra, linux-kernel

On 10/29/2012 01:21 AM, Danny Huang wrote:
> This patch adds speedo-based identification support for T30.

> diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c

> -#define FUSE_SPARE_BIT		0x200
> +
> +#define TEGRA20_FUSE_SPARE_BIT		0x200
> +#define TEGRA30_FUSE_SPARE_BIT		0x244
> +
> +static int tegra_fuse_spare_bit;

Can all the spare bit rework, and also prototype changes for
tegra_fuse_readl() and tegra_spare_fuse() be pulled out into a separate
patch at the start of the series?

> +int tegra_cpu_speedo_id;

Does Tegra20 not have a separate cpu_speedo_id? Should this variable be
added in patch 1 and appropriately initialized for Tegra20? If it's
Tegra30-specific, or Tegra30-and-later, a comment to that effect would
be useful. Is there a way to ensure that Tegra20-specific code doesn't
use that variable if it's not applicable?

> @@ -107,9 +112,18 @@ void tegra_init_fuse(void)
>  	id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
>  	tegra_chip_id = (id >> 8) & 0xff;
>  
> -	tegra_revision = tegra_get_revision(id);
> -
> -	tegra20_init_speedo_data();
> +	switch (tegra_chip_id) {
> +	case TEGRA20:
> +		tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
> +		tegra_revision = tegra_get_revision(id);
> +		tegra20_init_speedo_data();
> +		break;
> +	case TEGRA30:
> +		tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT;
> +		tegra_revision = tegra_get_revision(id);
> +		tegra30_init_speedo_data();
> +		break;
> +	}

I think there, I'd prefer to see:


switch (tegra_chip_id) {
case TEGRA20:
	tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
	break;
case TEGRA30:
	tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT;
	break;
}

tegra_revision = tegra_get_revision(id);

switch (tegra_chip_id) {
case TEGRA20:
	tegra20_init_speedo_data();
	break;
case TEGRA30:
	tegra30_init_speedo_data();
	break;
}

... to avoid duplicating the tegra_get_revision() call.

If this ends up needing a lot of separate switch statements in sequence,
you can always put the SoC-specific data into a struct, and do:

struct tegra_fuse_soc_data *sd = ...;
sd->set_spare_fuse_bit();
tegra_revision = tegra_get_revision(id);
sd->init_speedo_data();

although I don't think the complexity requires that yet.

> diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/arch/arm/mach-tegra/tegra30_speedo.c

(similar comments apply here as for the table/array size checking in
patch 1)

> +static int threshold_index;
> +static int package_id;

Do those need to be globals? Can they simply be passed between the
appropriate functions?

> +static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)

> +	WARN_ON(!speedo_g || !speedo_lp);

That hardly seems worth checking since this function is called from one
specific place later in this file...

> +static void rev_sku_to_speedo_ids(int rev, int sku)
> +{
> +	switch (rev) {
> +	case TEGRA_REVISION_A01:
> +		tegra_cpu_speedo_id = 0;
> +		tegra_soc_speedo_id = 0;
> +		threshold_index = 0;
> +		break;
> +	case TEGRA_REVISION_A02:
> +	case TEGRA_REVISION_A03:
> +		switch (sku) {
> +		case 0x87:
...
> +			default:
> +				pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
> +				       package_id);
> +				BUG();
> +				break;
> +			}
> +			break;

Why BUG() there, but not:

> +		default:
> +			pr_err("Tegra3: Unknown SKU %d\n", sku);
> +			tegra_cpu_speedo_id = 0;
> +			tegra_soc_speedo_id = 0;
> +			threshold_index = 0;
> +			break;
> +		}
> +		break;
> +	default:

... but do here:

> +		BUG();
> +		break;
> +	}
> +}

> +void tegra30_init_speedo_data(void)

> +	for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) {
> +		if (cpu_speedo_val <
> +		    cpu_process_speedos[threshold_index][i]) {
> +			break;
> +		}
> +	}
> +	tegra_cpu_process_id = i - 1;
> +
> +	if (tegra_cpu_process_id == -1) {
> +		pr_err("****************************************************");
> +		pr_err("****************************************************");
> +		pr_err("* tegra3_speedo: CPU speedo value %3d out of range *",
> +		       cpu_speedo_val);
> +		pr_err("****************************************************");
> +		pr_err("****************************************************");

Just drop the lines of ***, and the * around the text in the middle
pr_err() too.

> +
> +		tegra_cpu_speedo_id = 1;

Shouldn't that fix the out-of-range tegra_cpu_process_id value?

This and the previous comment apply to the following calculation of
tegra_core_process_id too.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2012-10-29 17:56 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-29  7:21 [PATCH 0/2] ARM: tegra: add speedo identification for T20/T30 Danny Huang
2012-10-29  7:21 ` [PATCH 1/2] ARM: tegra: Add speedo-based process identification Danny Huang
2012-10-29 17:40   ` Stephen Warren
2012-10-29  7:21 ` [PATCH 2/2] ARM: tegra: T30 speedo-based identification Danny Huang
2012-10-29 17:55   ` Stephen Warren

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).