Merge commit 'main-jb-2012.08.03-B4' into t114-0806
[linux-2.6.git] / arch / arm / mach-tegra / tegra3_speedo.c
index cac288a..c0c4686 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-tegra/tegra3_speedo.c
  *
- * Copyright (c) 2011, NVIDIA Corporation.
+ * Copyright (c) 2011-2012, NVIDIA Corporation. All rights reserved.
  *
  * 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
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/err.h>
+#include <linux/bug.h>                 /* For BUG_ON.  */
+
 #include <mach/iomap.h>
+#include <mach/tegra_fuse.h>
+#include <mach/hardware.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
 
 #include "fuse.h"
 
 #define CORE_PROCESS_CORNERS_NUM       1
-#define CPU_PROCESS_CORNERS_NUM                4
+#define CPU_PROCESS_CORNERS_NUM        7
 
 #define FUSE_SPEEDO_CALIB_0    0x114
 #define FUSE_PACKAGE_INFO      0X1FC
+#define FUSE_TEST_PROG_VER     0X128
+#define FUSE_SPARE_BIT_58      0x32c
+#define FUSE_SPARE_BIT_59      0x330
+#define FUSE_SPARE_BIT_60      0x334
+#define FUSE_SPARE_BIT_61      0x338
+#define FUSE_SPARE_BIT_62      0x33c
+#define FUSE_SPARE_BIT_63      0x340
+#define FUSE_SPARE_BIT_64      0x344
+#define FUSE_SPARE_BIT_65      0x348
+
+#define G_SPEEDO_BIT_MINUS1    FUSE_SPARE_BIT_58
+#define G_SPEEDO_BIT_MINUS1_R  FUSE_SPARE_BIT_59
+#define G_SPEEDO_BIT_MINUS2    FUSE_SPARE_BIT_60
+#define G_SPEEDO_BIT_MINUS2_R  FUSE_SPARE_BIT_61
+#define LP_SPEEDO_BIT_MINUS1   FUSE_SPARE_BIT_62
+#define LP_SPEEDO_BIT_MINUS1_R FUSE_SPARE_BIT_63
+#define LP_SPEEDO_BIT_MINUS2   FUSE_SPARE_BIT_64
+#define LP_SPEEDO_BIT_MINUS2_R FUSE_SPARE_BIT_65
 
 /* Maximum speedo levels for each core process corner */
 static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
 /* proc_id 0 */
-       {180}, /* threshold_index 0: soc_speedo_id 0: any A01 */
+       {180}, /* [0]: soc_speedo_id 0: any A01 */
 
 /* T30 family */
-       {180}, /* threshold_index 1: soc_speedo_id 1: AP30 */
-       {204}, /* threshold_index 2: soc_speedo_id 2: T30  */
-       {192}, /* threshold_index 3: soc_speedo_id 2: T30S */
+       {170}, /* [1]: soc_speedo_id 1: AP30 */
+       {195}, /* [2]: soc_speedo_id 2: T30  */
+       {180}, /* [3]: soc_speedo_id 2: T30S */
 
 /* Characterization SKUs */
-       {168}, /* threshold_index 4: soc_speedo_id 1: AP30 char */
-       {192}, /* threshold_index 5: soc_speedo_id 2: T30  char */
-       {184}, /* threshold_index 6: soc_speedo_id 2: T30S char */
-
-/* T33 family: Numbers cloned from T30 family; FIXME: adjust these later */
-       {180}, /* threshold_index 7: soc_speedo_id = 1 - AP33 */
-       {196}, /* threshold_index 8: soc_speedo_id = 2 - T33  */
-       {196}, /* threshold_index 9: soc_speedo_id = 2 - T33S */
+       {168}, /* [4]: soc_speedo_id 1: AP30 char */
+       {192}, /* [5]: soc_speedo_id 2: T30  char */
+       {180}, /* [6]: soc_speedo_id 2: T30S char */
+
+/* T33 family */
+       {170}, /* [7]: soc_speedo_id = 1 - AP33 */
+       {195}, /* [8]: soc_speedo_id = 2 - T33  */
+       {180}, /* [9]: soc_speedo_id = 2 - T33S/AP37 */
+
+/* T30 'L' family */
+       {180}, /* [10]: soc_speedo_id 1: T30L */
+       {180}, /* [11]: soc_speedo_id 1: T30SL */
+
+/* T30 Automotives */
+       {185}, /* [12]: soc_speedo_id = 3 - Automotives */
+       {185}, /* [13]: soc_speedo_id = 3 - Automotives */
+
+/* T37 Family*/
+       {210}, /* [14]: soc_speedo_id 2: T37 */
 };
 
 /* Maximum speedo levels for each CPU process corner */
 static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
-/* proc_id 0    1    2    3 */
-       {306, 338, 360, 376}, /* threshold_index 0: cpu_speedo_id 0: any A01 */
+/* proc_id 0    1    2    3    4*/
+       {306, 338, 360, 376, UINT_MAX}, /* [0]: cpu_speedo_id 0: any A01 */
 
 /* T30 family */
-       {304, 336, 359, 375}, /* threshold_index 1: cpu_speedo_id 1: AP30 */
-       {336, 336, 359, 375}, /* threshold_index 2: cpu_speedo_id 2: T30  */
-       {336, 336, 359, 375}, /* threshold_index 3: cpu_speedo_id 3: T30S */
+       {295, 336, 358, 375, UINT_MAX}, /* [1]: cpu_speedo_id 1: AP30 */
+       {325, 325, 358, 375, UINT_MAX}, /* [2]: cpu_speedo_id 2: T30  */
+       {325, 325, 358, 375, UINT_MAX}, /* [3]: cpu_speedo_id 3: T30S */
 
 /* Characterization SKUs */
-       {292, 324, 348, 364}, /* threshold_index 4: cpu_speedo_id 1: AP30char */
-       {324, 324, 348, 364}, /* threshold_index 5: cpu_speedo_id 2: T30char  */
-       {324, 324, 348, 364}, /* threshold_index 6: cpu_speedo_id 3: T30Schar */
-
-/* T33 family: Numbers cloned from T30 family; FIXME: adjust these later */
-       {376, 376, 376, 376}, /* threshold_FIXME 7: cpu_speedo_id = 1 - AP33 */
-       {376, 376, 376, 376}, /* threshold_index 8: cpu_speedo_id = 2 - T33  */
-       {376, 376, 376, 376}, /* threshold_index 9: cpu_speedo_id = 3 - T33S */
+       {292, 324, 348, 364, UINT_MAX}, /* [4]: cpu_speedo_id 1: AP30char */
+       {324, 324, 348, 364, UINT_MAX}, /* [5]: cpu_speedo_id 2: T30char  */
+       {324, 324, 348, 364, UINT_MAX}, /* [6]: cpu_speedo_id 3: T30Schar */
+
+/* T33 family */
+       {295, 336, 358, 375, UINT_MAX},      /* [7]: cpu_speedo_id: 4: AP33 */
+       {358, 358, 358, 358, 397, UINT_MAX}, /* [8]: cpu_speedo_id: 5: T33  */
+       {364, 364, 364, 364, 397, UINT_MAX}, /* [9]: cpu_speedo_id: 6/12: T33S/AP37 */
+
+/* T30 'L' family */
+       {295, 336, 358, 375, 391, UINT_MAX}, /* [10]: cpu_speedo_id 7: T30L  */
+       {295, 336, 358, 375, 391, UINT_MAX}, /* [11]: cpu_speedo_id 8: T30SL */
+
+/* T30 Automotives */
+       /* threshold_index 12: cpu_speedo_id 9 & 10
+        * 0,1,2 values correspond to speedo_id  9/14
+        * 3,4,5 values correspond to speedo_id 10/15*/
+       {300, 311, 360, 371, 381, 415, 431},
+       {300, 311, 410, 431, UINT_MAX}, /* [13]: cpu_speedo_id 11: T30 auto */
+
+/* T37 family */
+       {358, 358, 358, 358, 397, UINT_MAX}, /* [14]: cpu_speedo_id 13: T37 */
 };
 
 /*
@@ -84,10 +133,16 @@ static int core_process_id;
 static int cpu_speedo_id;
 static int soc_speedo_id;
 static int package_id;
+/*
+ * Only AP37 supports App Profile
+ * This informs user space of support without exposing cpu id's
+ */
+static int enable_app_profiles;
 
 static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
 {
        u32 reg;
+       int ate_ver, bit_minus1, bit_minus2;
 
        BUG_ON(!speedo_g || !speedo_lp);
        reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0);
@@ -97,6 +152,33 @@ static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
 
        /* Speedo G = Upper 16-bits Multiplied by 4 */
        *speedo_g = ((reg >> 16) & 0xFFFF) * 4;
+
+       if (tegra_fuse_get_revision(&ate_ver))
+               return;
+       pr_info("%s: ATE prog ver %d.%d\n", __func__, ate_ver/10, ate_ver%10);
+
+       pr_debug("CPU speedo base value %u (0x%3x)\n", *speedo_g, *speedo_g);
+       pr_debug("Core speedo base value %u (0x%3x)\n", *speedo_lp, *speedo_lp);
+
+       if (ate_ver >= 26) {
+               /* read lower 2 bits of LP speedo from spare fuses */
+               bit_minus1 = tegra_fuse_readl(LP_SPEEDO_BIT_MINUS1) & 0x1;
+               bit_minus1 |= tegra_fuse_readl(LP_SPEEDO_BIT_MINUS1_R) & 0x1;
+               bit_minus2 = tegra_fuse_readl(LP_SPEEDO_BIT_MINUS2) & 0x1;
+               bit_minus2 |= tegra_fuse_readl(LP_SPEEDO_BIT_MINUS2_R) & 0x1;
+               *speedo_lp |= (bit_minus1 << 1) | bit_minus2;
+
+               /* read lower 2 bits of G speedo from spare fuses */
+               bit_minus1 = tegra_fuse_readl(G_SPEEDO_BIT_MINUS1) & 0x1;
+               bit_minus1 |= tegra_fuse_readl(G_SPEEDO_BIT_MINUS1_R) & 0x1;
+               bit_minus2 = tegra_fuse_readl(G_SPEEDO_BIT_MINUS2) & 0x1;
+               bit_minus2 |= tegra_fuse_readl(G_SPEEDO_BIT_MINUS2_R) & 0x1;
+               *speedo_g |= (bit_minus1 << 1) | bit_minus2;
+       } else {
+               /* set lower 2 bits for speedo ate-ver independent comparison */
+               *speedo_lp |= 0x3;
+               *speedo_g |= 0x3;
+       }
 }
 
 static void rev_sku_to_speedo_ids(int rev, int sku)
@@ -126,7 +208,7 @@ static void rev_sku_to_speedo_ids(int rev, int sku)
                                threshold_index = 2;
                                break;
                        case 2: /* DSC => AP33 */
-                               cpu_speedo_id = 1;
+                               cpu_speedo_id = 4;
                                soc_speedo_id = 1;
                                threshold_index = 7;
                                break;
@@ -141,12 +223,12 @@ static void rev_sku_to_speedo_ids(int rev, int sku)
                case 0x80: /* T33 or T33S */
                        switch (package_id) {
                        case 1: /* MID => T33 */
-                               cpu_speedo_id = 2;
+                               cpu_speedo_id = 5;
                                soc_speedo_id = 2;
                                threshold_index = 8;
                                break;
                        case 2: /* DSC => T33S */
-                               cpu_speedo_id = 3;
+                               cpu_speedo_id = 6;
                                soc_speedo_id = 2;
                                threshold_index = 9;
                                break;
@@ -158,10 +240,51 @@ static void rev_sku_to_speedo_ids(int rev, int sku)
                        }
                        break;
 
-               case 0x83: /* T30S */
-                       cpu_speedo_id = 3;
-                       soc_speedo_id = 2;
-                       threshold_index = 3;
+               case 0x83: /* T30L or T30S */
+                       switch (package_id) {
+                       case 1: /* MID => T30L */
+                               cpu_speedo_id = 7;
+                               soc_speedo_id = 1;
+                               threshold_index = 10;
+                               break;
+                       case 2: /* DSC => T30S */
+                               cpu_speedo_id = 3;
+                               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: /* T30SL */
+                       cpu_speedo_id = 8;
+                       soc_speedo_id = 1;
+                       threshold_index = 11;
+                       break;
+
+               case 0xA0: /* T37 or A37 */
+                       switch (package_id) {
+                       case 1: /* MID => T37 */
+                               cpu_speedo_id = 13;
+                               soc_speedo_id = 2;
+                               threshold_index = 14;
+                               break;
+                       case 2: /* DSC => AP37 */
+                               cpu_speedo_id = 12;
+                               soc_speedo_id = 2;
+                               threshold_index = 9;
+                               enable_app_profiles = 1;
+                               break;
+                       default:
+                               pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
+                                               package_id);
+                               BUG();
+                               break;
+                       }
                        break;
 
 /* Characterization SKUs */
@@ -181,6 +304,18 @@ static void rev_sku_to_speedo_ids(int rev, int sku)
                        threshold_index = 6;
                        break;
 
+               case 0x91: /* T30AGS-Ax */
+               case 0xb0: /* T30IQS-Ax */
+               case 0xb1: /* T30MQS-Ax */
+               case 0x90: /* T30AQS-Ax */
+                       soc_speedo_id = 3;
+                       threshold_index = 12;
+                       break;
+               case 0x93: /* T30AG-Ax */
+                       cpu_speedo_id = 11;
+                       soc_speedo_id = 3;
+                       threshold_index = 13;
+                       break;
                case 0:    /* ENG - check package_id */
                        pr_info("Tegra3 ENG SKU: Checking package_id\n");
                        switch (package_id) {
@@ -221,6 +356,9 @@ void tegra_init_speedo_data(void)
 {
        u32 cpu_speedo_val, core_speedo_val;
        int iv;
+       int fuse_sku = tegra_sku_id;
+       int sku_override = tegra_get_sku_override();
+       int new_sku = fuse_sku;
 
        /* Package info: 4 bits - 0,3:reserved 1:MID 2:DSC */
        package_id = tegra_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
@@ -229,7 +367,66 @@ void tegra_init_speedo_data(void)
        BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
               ARRAY_SIZE(core_process_speedos));
 
-       rev_sku_to_speedo_ids(tegra_get_revision(), tegra_sku_id());
+       /* SKU Overrides
+       * T33   => T30, T30L
+       * T33S  => T30S, T30SL
+       * T30   => T30L
+       * T30S  => T30SL
+       * AP33  => AP30
+       */
+       switch (sku_override) {
+       case 1:
+               /* Base sku override */
+               if (fuse_sku == 0x80) {
+                       if (package_id == 1) {
+                               /* T33 to T30 */
+                               pr_info("%s: SKU OR: T33->T30\n", __func__);
+                               new_sku = 0x81;
+                       } else if (package_id == 2) {
+                               /* T33S->T30S */
+                               pr_info("%s: SKU OR: T33S->T30S\n", __func__);
+                               new_sku = 0x83;
+                       }
+               } else if (fuse_sku == 0x81) {
+                       if (package_id == 2) {
+                               /* AP33->AP30 */
+                               pr_info("%s: SKU OR: AP33->AP30\n", __func__);
+                               new_sku = 0x87;
+                       }
+               }
+               break;
+       case 2:
+               /* L sku override */
+               if (fuse_sku == 0x80) {
+                       if (package_id == 1) {
+                               /* T33->T30L */
+                               pr_info("%s: SKU OR: T33->T30L\n", __func__);
+                               new_sku = 0x83;
+                       } else if (package_id == 2) {
+                               /* T33S->T33SL */
+                               pr_info("%s: SKU OR: T33S->T30SL\n", __func__);
+                               new_sku = 0x8f;
+                       }
+               } else if (fuse_sku == 0x81) {
+                       if (package_id == 1) {
+                               pr_info("%s: SKU OR: T30->T30L\n", __func__);
+                               /* T30->T30L */
+                               new_sku = 0x83;
+                       }
+               } else if (fuse_sku == 0x83) {
+                       if (package_id == 2) {
+                               pr_info("%s: SKU OR: T30S->T30SL\n", __func__);
+                               /* T30S to T30SL */
+                               new_sku = 0x8f;
+                       }
+               }
+               break;
+       default:
+               /* no override */
+               break;
+       }
+
+       rev_sku_to_speedo_ids(tegra_revision, new_sku);
        BUG_ON(threshold_index >= ARRAY_SIZE(cpu_process_speedos));
 
        fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val);
@@ -275,7 +472,33 @@ void tegra_init_speedo_data(void)
                core_process_id = INVALID_PROCESS_ID;
                soc_speedo_id = 1;
        }
-
+       if (threshold_index == 12 && cpu_process_id != INVALID_PROCESS_ID) {
+               if (cpu_process_id <= 2) {
+                       switch(fuse_sku) {
+                       case 0xb0:
+                       case 0xb1:
+                               cpu_speedo_id = 9;
+                               break;
+                       case 0x90:
+                       case 0x91:
+                               cpu_speedo_id = 14;
+                       default:
+                               break;
+                       }
+               } else if (cpu_process_id >= 3 && cpu_process_id < 6) {
+                       switch(fuse_sku) {
+                       case 0xb0:
+                       case 0xb1:
+                               cpu_speedo_id = 10;
+                               break;
+                       case 0x90:
+                       case 0x91:
+                               cpu_speedo_id = 15;
+                       default:
+                               break;
+                       }
+               }
+       }
        pr_info("Tegra3: CPU Speedo ID %d, Soc Speedo ID %d",
                 cpu_speedo_id, soc_speedo_id);
 }
@@ -312,3 +535,50 @@ int tegra_package_id(void)
 {
        return package_id;
 }
+
+/*
+ * CPU and core nominal voltage levels as determined by chip SKU and speedo
+ * (not final - can be lowered by dvfs tables and rail dependencies; the
+ * latter is resolved by the dvfs code)
+ */
+static const int cpu_speedo_nominal_millivolts[] =
+/* speedo_id 0,    1,    2,    3,    4,    5,    6,    7,    8,   9,  10,  11,   12,    13,  14,  15 */
+       { 1125, 1150, 1150, 1150, 1237, 1237, 1237, 1150, 1150, 1007, 916, 850, 1237, 1237, 950, 900};
+
+int tegra_cpu_speedo_mv(void)
+{
+       return cpu_speedo_nominal_millivolts[cpu_speedo_id];
+}
+
+int tegra_core_speedo_mv(void)
+{
+       switch (soc_speedo_id) {
+       case 0:
+               return 1200;
+       case 1:
+               if ((cpu_speedo_id != 7) && (cpu_speedo_id != 8))
+                       return 1200;
+               /* fall thru for T30L or T30SL */
+       case 2:
+               if (cpu_speedo_id != 13)
+                       return 1300;
+               /* T37 */
+               return 1350;
+       case 3:
+               return 1250;
+       default:
+               BUG();
+       }
+}
+
+static int get_enable_app_profiles(char *val, const struct kernel_param *kp)
+{
+       return param_get_uint(val, kp);
+}
+
+static struct kernel_param_ops tegra_profiles_ops = {
+       .get = get_enable_app_profiles,
+};
+
+module_param_cb(tegra_enable_app_profiles,
+       &tegra_profiles_ops, &enable_app_profiles, 0444);