diff mbox

[4/9] arm/tegra: fuse: add functions to access chip revision

Message ID 1324599468-12845-5-git-send-email-olof@lixom.net
State Superseded, archived
Headers show

Commit Message

Olof Johansson Dec. 23, 2011, 12:17 a.m. UTC
Add function to get chip revision, and print it out at boot time.

Restructure the fuse access to just use cached variables instead
of always reading the fuses, and export those variables directly
instead of using accessor functions.

Add a SKU ID table of currently known values.

Based on code originally by Colin Cross <ccross@android.com>.

Signed-off-by: Olof Johansson <olof@lixom.net>
---
 arch/arm/mach-tegra/fuse.c          |   80 +++++++++++++++++++++++------------
 arch/arm/mach-tegra/fuse.h          |   31 +++++++++++--
 arch/arm/mach-tegra/tegra2_clocks.c |    2 +-
 3 files changed, 80 insertions(+), 33 deletions(-)

Comments

Henning Heinold Dec. 23, 2011, 10:47 a.m. UTC | #1
On Thu, Dec 22, 2011 at 04:17:43PM -0800, Olof Johansson wrote:
> Add function to get chip revision, and print it out at boot time.
> 
> Restructure the fuse access to just use cached variables instead
> of always reading the fuses, and export those variables directly
> instead of using accessor functions.
> 
> Add a SKU ID table of currently known values.
> 
> Based on code originally by Colin Cross <ccross@android.com>.
> 
> Signed-off-by: Olof Johansson <olof@lixom.net>
> ---
>  arch/arm/mach-tegra/fuse.c          |   80 +++++++++++++++++++++++------------
>  arch/arm/mach-tegra/fuse.h          |   31 +++++++++++--
>  arch/arm/mach-tegra/tegra2_clocks.c |    2 +-
>  3 files changed, 80 insertions(+), 33 deletions(-)
> 
> diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
> index daf3f57..2ddede9 100644
> --- a/arch/arm/mach-tegra/fuse.c
> +++ b/arch/arm/mach-tegra/fuse.c
> @@ -30,20 +30,70 @@
>  #define FUSE_SKU_INFO		0x110
>  #define FUSE_SPARE_BIT		0x200
>  
> +int tegra_sku_id;
> +int tegra_cpu_process_id;
> +int tegra_core_process_id;
> +enum tegra_revision tegra_revision;
> +
> +static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
> +	[TEGRA_REVISION_UNKNOWN] = "unknown",
> +	[TEGRA_REVISION_A02]     = "A02",
> +	[TEGRA_REVISION_A03]     = "A03",
> +	[TEGRA_REVISION_A03p]    = "A03 prime",
> +	[TEGRA_REVISION_A04]     = "A04",
> +};
> +

Hi Olof,

can you please add here [TEGRA_REVISION_A01] = "A01", too. It is used in the nvidia git tree and affects the new beta xorg
driver.

Bye Henning
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Olof Johansson Jan. 4, 2012, 3:46 a.m. UTC | #2
Hi,

On Fri, Dec 23, 2011 at 2:47 AM, Henning Heinold
<heinold@inf.fu-berlin.de> wrote:
> On Thu, Dec 22, 2011 at 04:17:43PM -0800, Olof Johansson wrote:
>> +static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
>> +     [TEGRA_REVISION_UNKNOWN] = "unknown",
>> +     [TEGRA_REVISION_A02]     = "A02",
>> +     [TEGRA_REVISION_A03]     = "A03",
>> +     [TEGRA_REVISION_A03p]    = "A03 prime",
>> +     [TEGRA_REVISION_A04]     = "A04",
>> +};
>> +
>
> Hi Olof,
>
> can you please add here [TEGRA_REVISION_A01] = "A01", too. It is used in the nvidia git tree and affects the new beta xorg
> driver.


How does it affect the xorg driver? Do you have hardware that is based
on A01? I wouldn't expect there to be any products out there with it
-- A01 has a handful of errata that is not handled in mainline, etc.


-Olof
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stephen Warren Jan. 4, 2012, 11:20 p.m. UTC | #3
Olof Johansson wrote at Thursday, December 22, 2011 5:18 PM:
> Add function to get chip revision, and print it out at boot time.
> 
> Restructure the fuse access to just use cached variables instead
> of always reading the fuses, and export those variables directly
> instead of using accessor functions.
> 
> Add a SKU ID table of currently known values.

> +static enum tegra_revision tegra_get_revision(void)
> +{
> +	void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804;
> +	u32 id = readl(chip_id);
> +
> +	switch ((id >> 16) & 0xf) {

We probably should decode A01 too; I certainly had a Tegra30 A01 until
recently, so it's entirely possible others do and want a meaningful
result.

Should the "A" should be decoded from the register too? It's bits 7:4
of the register and IIRC, 0=??? 1=A, presumably 2=B etc.

> +	case 2:
> +		return TEGRA_REVISION_A02;
> +	case 3:
> +		if (get_spare_fuse(18) || get_spare_fuse(19))
> +			return TEGRA_REVISION_A03p;

Does that apply equally to Tegra30 as well as Tegra20? I'm afraid I don't
know, but if you need I can try and find out.

> +		else
> +			return TEGRA_REVISION_A03;
> +	case 4:
> +		return TEGRA_REVISION_A04;

And there's space in the register for numbers higher than 4, although I
don't think there's any current silicon where this would matter.

> +	default:
> +		return TEGRA_REVISION_UNKNOWN;
> +	}
> +}
Olof Johansson Jan. 4, 2012, 11:36 p.m. UTC | #4
On Wed, Jan 4, 2012 at 3:20 PM, Stephen Warren <swarren@nvidia.com> wrote:
> Olof Johansson wrote at Thursday, December 22, 2011 5:18 PM:
>> Add function to get chip revision, and print it out at boot time.
>>
>> Restructure the fuse access to just use cached variables instead
>> of always reading the fuses, and export those variables directly
>> instead of using accessor functions.
>>
>> Add a SKU ID table of currently known values.
>
>> +static enum tegra_revision tegra_get_revision(void)
>> +{
>> +     void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804;
>> +     u32 id = readl(chip_id);
>> +
>> +     switch ((id >> 16) & 0xf) {
>
> We probably should decode A01 too; I certainly had a Tegra30 A01 until
> recently, so it's entirely possible others do and want a meaningful
> result.

Ah yes, T30. I was thinking of T20/25 A01. I'll add it.

> Should the "A" should be decoded from the register too? It's bits 7:4
> of the register and IIRC, 0=??? 1=A, presumably 2=B etc.

Well, only A is documented in my TRM. :-)   I think it's safe to keep
it UNKNOWN until known.

>> +     case 2:
>> +             return TEGRA_REVISION_A02;
>> +     case 3:
>> +             if (get_spare_fuse(18) || get_spare_fuse(19))
>> +                     return TEGRA_REVISION_A03p;
>
> Does that apply equally to Tegra30 as well as Tegra20? I'm afraid I don't
> know, but if you need I can try and find out.

I doubt it, so it needs to be conditional. Will add.

>> +             else
>> +                     return TEGRA_REVISION_A03;
>> +     case 4:
>> +             return TEGRA_REVISION_A04;
>
> And there's space in the register for numbers higher than 4, although I
> don't think there's any current silicon where this would matter.

Same here, not necessarily need to allocate all that much more than
what's known to be needed.


-Olof
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index daf3f57..2ddede9 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -30,20 +30,70 @@ 
 #define FUSE_SKU_INFO		0x110
 #define FUSE_SPARE_BIT		0x200
 
+int tegra_sku_id;
+int tegra_cpu_process_id;
+int tegra_core_process_id;
+enum tegra_revision tegra_revision;
+
+static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
+	[TEGRA_REVISION_UNKNOWN] = "unknown",
+	[TEGRA_REVISION_A02]     = "A02",
+	[TEGRA_REVISION_A03]     = "A03",
+	[TEGRA_REVISION_A03p]    = "A03 prime",
+	[TEGRA_REVISION_A04]     = "A04",
+};
+
 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)
+{
+	return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4);
+}
+
+static enum tegra_revision tegra_get_revision(void)
+{
+	void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804;
+	u32 id = readl(chip_id);
+
+	switch ((id >> 16) & 0xf) {
+	case 2:
+		return TEGRA_REVISION_A02;
+	case 3:
+		if (get_spare_fuse(18) || get_spare_fuse(19))
+			return TEGRA_REVISION_A03p;
+		else
+			return TEGRA_REVISION_A03;
+	case 4:
+		return TEGRA_REVISION_A04;
+	default:
+		return TEGRA_REVISION_UNKNOWN;
+	}
+}
+
 void tegra_init_fuse(void)
 {
 	u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
 	reg |= 1 << 28;
 	writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
 
-	pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n",
-		tegra_sku_id(), tegra_cpu_process_id(),
-		tegra_core_process_id());
+	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;
+
+	tegra_revision = tegra_get_revision();
+
+	pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
+		tegra_revision_name[tegra_get_revision()],
+		tegra_sku_id, tegra_cpu_process_id,
+		tegra_core_process_id);
 }
 
 unsigned long long tegra_chip_uid(void)
@@ -54,27 +104,3 @@  unsigned long long tegra_chip_uid(void)
 	hi = tegra_fuse_readl(FUSE_UID_HIGH);
 	return (hi << 32ull) | lo;
 }
-
-int tegra_sku_id(void)
-{
-	int sku_id;
-	u32 reg = tegra_fuse_readl(FUSE_SKU_INFO);
-	sku_id = reg & 0xFF;
-	return sku_id;
-}
-
-int tegra_cpu_process_id(void)
-{
-	int cpu_process_id;
-	u32 reg = tegra_fuse_readl(FUSE_SPARE_BIT);
-	cpu_process_id = (reg >> 6) & 3;
-	return cpu_process_id;
-}
-
-int tegra_core_process_id(void)
-{
-	int core_process_id;
-	u32 reg = tegra_fuse_readl(FUSE_SPARE_BIT);
-	core_process_id = (reg >> 12) & 3;
-	return core_process_id;
-}
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
index 584b2e2..e418d40 100644
--- a/arch/arm/mach-tegra/fuse.h
+++ b/arch/arm/mach-tegra/fuse.h
@@ -1,6 +1,4 @@ 
 /*
- * arch/arm/mach-tegra/fuse.c
- *
  * Copyright (C) 2010 Google, Inc.
  *
  * Author:
@@ -17,8 +15,31 @@ 
  *
  */
 
+#ifndef __MACH_TEGRA_FUSE_H
+#define __MACH_TEGRA_FUSE_H
+
+enum tegra_revision {
+	TEGRA_REVISION_UNKNOWN = 0,
+	TEGRA_REVISION_A02,
+	TEGRA_REVISION_A03,
+	TEGRA_REVISION_A03p,
+	TEGRA_REVISION_A04,
+	TEGRA_REVISION_MAX,
+};
+
+#define SKU_ID_T20	8
+#define SKU_ID_T25SE	20
+#define SKU_ID_AP25	23
+#define SKU_ID_T25	24
+#define SKU_ID_AP25E	27
+#define SKU_ID_T25E	28
+
+extern int tegra_sku_id;
+extern int tegra_cpu_process_id;
+extern int tegra_core_process_id;
+extern enum tegra_revision tegra_revision;
+
 unsigned long long tegra_chip_uid(void);
-int tegra_sku_id(void);
-int tegra_cpu_process_id(void);
-int tegra_core_process_id(void);
 void tegra_init_fuse(void);
+
+#endif
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index ff9e6b6..74d314fd 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -720,7 +720,7 @@  static void tegra2_pllx_clk_init(struct clk *c)
 {
 	tegra2_pll_clk_init(c);
 
-	if (tegra_sku_id() == 7)
+	if (tegra_sku_id == 7)
 		c->max_rate = 750000000;
 }