Merge commit 'main-jb-2012.08.03-B4' into t114-0806
[linux-2.6.git] / arch / arm / mach-tegra / tegra3_speedo.c
index 4db14c5..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"
 
@@ -109,8 +113,8 @@ static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
 
 /* T30 Automotives */
        /* threshold_index 12: cpu_speedo_id 9 & 10
-        * 0,1,2 values correspond to speedo_id  9
-        * 3,4,5 values correspond to speedo_id 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 */
 
@@ -129,6 +133,11 @@ 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)
 {
@@ -268,6 +277,7 @@ static void rev_sku_to_speedo_ids(int rev, int sku)
                                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",
@@ -346,11 +356,78 @@ 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;
 
-       rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id);
+       /* Arrays must be of equal size - each index corresponds to a SKU */
+       BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
+              ARRAY_SIZE(core_process_speedos));
+
+       /* 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);
        pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val);
@@ -396,10 +473,31 @@ void tegra_init_speedo_data(void)
                soc_speedo_id = 1;
        }
        if (threshold_index == 12 && cpu_process_id != INVALID_PROCESS_ID) {
-               if (cpu_process_id <= 2)
-                       cpu_speedo_id = 9;
-               else if (cpu_process_id >= 3 && cpu_process_id < 6)
-                       cpu_speedo_id = 10;
+               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);
@@ -444,8 +542,8 @@ int tegra_package_id(void)
  * 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 */
-       { 1125, 1150, 1150, 1150, 1237, 1237, 1237, 1150, 1150, 912, 850, 850, 1237, 1237};
+/* 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)
 {
@@ -472,3 +570,15 @@ int tegra_core_speedo_mv(void)
                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);