ARM: tegra: dvfs: Remove obsolete gpu_dvfs debugfs node
[linux-3.10.git] / arch / arm / mach-tegra / tegra12_dvfs.c
index 1c1f418..20967a4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-tegra/tegra12_dvfs.c
  *
- * Copyright (C) 2012 NVIDIA Corporation.
+ * Copyright (c) 2012-2013 NVIDIA CORPORATION. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
 #include <linux/clk.h>
 #include <linux/kobject.h>
 #include <linux/err.h>
+#include <linux/pm_qos.h>
 
 #include "clock.h"
 #include "dvfs.h"
 #include "fuse.h"
 #include "board.h"
 #include "tegra_cl_dvfs.h"
+#include "tegra_core_sysfs_limits.h"
 
 static bool tegra_dvfs_cpu_disabled;
 static bool tegra_dvfs_core_disabled;
@@ -38,12 +40,38 @@ static bool tegra_dvfs_gpu_disabled;
 /* FIXME: need tegra12 step */
 #define VDD_SAFE_STEP                  100
 
+static int vdd_core_therm_trips_table[MAX_THERMAL_LIMITS] = { 20, };
+static int vdd_core_therm_floors_table[MAX_THERMAL_LIMITS] = { 900, };
+
+static struct tegra_cooling_device cpu_vmin_cdev = {
+       .cdev_type = "cpu_cold",
+};
+
+static struct tegra_cooling_device core_vmin_cdev = {
+       .cdev_type = "core_cold",
+};
+
+static struct tegra_cooling_device gpu_vmin_cdev = {
+       .cdev_type = "gpu_cold",
+};
+
+static struct tegra_cooling_device gpu_vts_cdev = {
+       .cdev_type = "gpu_scaling",
+};
+
 static struct dvfs_rail tegra12_dvfs_rail_vdd_cpu = {
        .reg_id = "vdd_cpu",
        .max_millivolts = 1400,
        .min_millivolts = 800,
        .step = VDD_SAFE_STEP,
        .jmp_to_zero = true,
+       .vmin_cdev = &cpu_vmin_cdev,
+       .alignment = {
+               .step_uv = 10000, /* 10mV */
+       },
+       .stats = {
+               .bin_uV = 10000, /* 10mV */
+       }
 };
 
 static struct dvfs_rail tegra12_dvfs_rail_vdd_core = {
@@ -51,14 +79,24 @@ static struct dvfs_rail tegra12_dvfs_rail_vdd_core = {
        .max_millivolts = 1400,
        .min_millivolts = 800,
        .step = VDD_SAFE_STEP,
+       .vmin_cdev = &core_vmin_cdev,
 };
 
 /* TBD: fill in actual hw number */
 static struct dvfs_rail tegra12_dvfs_rail_vdd_gpu = {
        .reg_id = "vdd_gpu",
        .max_millivolts = 1350,
-       .min_millivolts = 850,
+       .min_millivolts = 700,
        .step = VDD_SAFE_STEP,
+       .in_band_pm = true,
+       .vts_cdev = &gpu_vts_cdev,
+       .vmin_cdev = &gpu_vmin_cdev,
+       .alignment = {
+               .step_uv = 10000, /* 10mV */
+       },
+       .stats = {
+               .bin_uV = 10000, /* 10mV */
+       }
 };
 
 static struct dvfs_rail *tegra12_dvfs_rails[] = {
@@ -67,45 +105,97 @@ static struct dvfs_rail *tegra12_dvfs_rails[] = {
        &tegra12_dvfs_rail_vdd_gpu,
 };
 
-/* default cvb alignment on Tegra11 - 10mV */
-int __attribute__((weak)) tegra_get_cvb_alignment_uV(void)
+void __init tegra12x_vdd_cpu_align(int step_uv, int offset_uv)
 {
-       return 10000;
+       tegra12_dvfs_rail_vdd_cpu.alignment.step_uv = step_uv;
+       tegra12_dvfs_rail_vdd_cpu.alignment.offset_uv = offset_uv;
 }
 
 /* CPU DVFS tables */
-/* FIXME: real data */
 static struct cpu_cvb_dvfs cpu_cvb_dvfs_table[] = {
        {
                .speedo_id = 0,
-               .max_mv = 1250,
-               .min_dfll_mv = 1000,
-               .freqs_mult = MHZ,
+               .process_id = -1,
+               .dfll_tune_data  = {
+                       .tune0          = 0x005020FF,
+                       .tune0_high_mv  = 0x005040FF,
+                       .tune1          = 0x00000060,
+                       .droop_rate_min = 1000000,
+                       .tune_high_min_millivolts = 900,
+                       .min_millivolts = 800,
+               },
+               .max_mv = 1260,
+               .freqs_mult = KHZ,
                .speedo_scale = 100,
-               .voltage_scale = 100,
+               .voltage_scale = 1000,
                .cvb_table = {
-                       /*f    dfll: c0,     c1,   c2  pll:  c0,   c1,    c2 */
-                       { 306, { 107330,  -1569,   0}, {  90000,    0,    0} },
-                       { 408, { 111250,  -1666,   0}, {  90000,    0,    0} },
-                       { 510, { 110000,  -1460,   0}, {  94000,    0,    0} },
-                       { 612, { 117290,  -1745,   0}, {  94000,    0,    0} },
-                       { 714, { 122700,  -1910,   0}, {  99000,    0,    0} },
-                       { 816, { 125620,  -1945,   0}, {  99000,    0,    0} },
-                       { 918, { 130560,  -2076,   0}, { 103000,    0,    0} },
-                       {1020, { 137280,  -2303,   0}, { 103000,    0,    0} },
-                       {1122, { 146440,  -2660,   0}, { 109000,    0,    0} },
-                       {1224, { 152190,  -2825,   0}, { 109000,    0,    0} },
-                       {1326, { 157520,  -2953,   0}, { 112000,    0,    0} },
-                       {1428, { 166100,  -3261,   0}, { 140000,    0,    0} },
-                       {1530, { 176410,  -3647,   0}, { 140000,    0,    0} },
-                       {1632, { 189620,  -4186,   0}, { 140000,    0,    0} },
-                       {1734, { 203190,  -4725,   0}, { 140000,    0,    0} },
-                       {1836, { 222670,  -5573,   0}, { 140000,    0,    0} },
-                       {1938, { 256210,  -7165,   0}, { 140000,    0,    0} },
-                       {2040, { 250050,  -6544,   0}, { 140000,    0,    0} },
-                       {   0, {      0,      0,   0}, {      0,    0,    0} },
+                       /*f       dfll: c0,     c1,   c2  pll:  c0,   c1,    c2 */
+                       {306000,        {1150460, -30585, 402}, {740000, 0, 0}},
+                       {408000,        {1190122, -31865, 402}, {750000, 0, 0}},
+                       {510000,        {1231606, -33155, 402}, {760000, 0, 0}},
+                       {612000,        {1274912, -34435, 402}, {780000, 0, 0}},
+                       {714000,        {1320040, -35725, 402}, {800000, 0, 0}},
+                       {816000,        {1366990, -37005, 402}, {820000, 0, 0}},
+                       {918000,        {1415762, -38295, 402}, {840000, 0, 0}},
+                       {1020000,       {1466355, -39575, 402}, {880000, 0, 0}},
+                       {1122000,       {1518771, -40865, 402}, {900000, 0, 0}},
+                       {1224000,       {1573009, -42145, 402}, {930000, 0, 0}},
+                       {1326000,       {1629068, -43435, 402}, {960000, 0, 0}},
+                       {1428000,       {1686950, -44715, 402}, {990000, 0, 0}},
+                       {1530000,       {1746653, -46005, 402}, {1020000, 0, 0}},
+                       {1632000,       {1808179, -47285, 402}, {1070000, 0, 0}},
+                       {1734000,       {1871526, -48575, 402}, {1100000, 0, 0}},
+                       {1836000,       {1936696, -49855, 402}, {1140000, 0, 0}},
+                       {1938000,       {2003687, -51145, 402}, {1180000, 0, 0}},
+                       {2014500,       {2054787, -52095, 402}, {1220000, 0, 0}},
+                       {      0 ,      {      0,      0,   0}, {      0, 0, 0}},
                },
-       }
+               .vmin_trips_table = { 20, },
+               .therm_floors_table = { 900, },
+       },
+       {
+               .speedo_id = 1,
+               .process_id = -1,
+               .dfll_tune_data  = {
+                       .tune0          = 0x005020FF,
+                       .tune0_high_mv  = 0x005040FF,
+                       .tune1          = 0x00000060,
+                       .droop_rate_min = 1000000,
+                       .tune_high_min_millivolts = 900,
+                       .min_millivolts = 800,
+               },
+               .max_mv = 1260,
+               .freqs_mult = KHZ,
+               .speedo_scale = 100,
+               .voltage_scale = 1000,
+               .cvb_table = {
+                       /*f       dfll: c0,     c1,   c2  pll:  c0,   c1,    c2 */
+                       {306000,        {1150460, -30585, 402}, {710000, 0, 0}},
+                       {408000,        {1190122, -31865, 402}, {730000, 0, 0}},
+                       {510000,        {1231606, -33155, 402}, {740000, 0, 0}},
+                       {612000,        {1274912, -34435, 402}, {750000, 0, 0}},
+                       {714000,        {1320040, -35725, 402}, {770000, 0, 0}},
+                       {816000,        {1366990, -37005, 402}, {790000, 0, 0}},
+                       {918000,        {1415762, -38295, 402}, {810000, 0, 0}},
+                       {1020000,       {1466355, -39575, 402}, {830000, 0, 0}},
+                       {1122000,       {1518771, -40865, 402}, {860000, 0, 0}},
+                       {1224000,       {1573009, -42145, 402}, {890000, 0, 0}},
+                       {1326000,       {1629068, -43435, 402}, {920000, 0, 0}},
+                       {1428000,       {1686950, -44715, 402}, {950000, 0, 0}},
+                       {1530000,       {1746653, -46005, 402}, {980000, 0, 0}},
+                       {1632000,       {1808179, -47285, 402}, {1010000, 0, 0}},
+                       {1734000,       {1871526, -48575, 402}, {1050000, 0, 0}},
+                       {1836000,       {1936696, -49855, 402}, {1090000, 0, 0}},
+                       {1938000,       {2003687, -51145, 402}, {1130000, 0, 0}},
+                       {2014500,       {2054787, -52095, 402}, {1160000, 0, 0}},
+                       {2116500,       {2124957, -53385, 402}, {1200000, 0, 0}},
+                       {2218500,       {2196950, -54665, 402}, {1250000, 0, 0}},
+                       {2320500,       {2270765, -55955, 402}, {1300000, 0, 0}},
+                       {      0 ,      {      0,      0,   0}, {      0, 0, 0}},
+               },
+               .vmin_trips_table = { 20, },
+               .therm_floors_table = { 900, },
+       },
 };
 
 static int cpu_millivolts[MAX_DVFS_FREQS];
@@ -113,28 +203,21 @@ static int cpu_dfll_millivolts[MAX_DVFS_FREQS];
 
 static struct dvfs cpu_dvfs = {
        .clk_name       = "cpu_g",
-       .process_id     = -1,
        .millivolts     = cpu_millivolts,
        .dfll_millivolts = cpu_dfll_millivolts,
        .auto_dvfs      = true,
        .dvfs_rail      = &tegra12_dvfs_rail_vdd_cpu,
-       .dfll_data      = {
-               .tune0          = 0x00b0019d,
-               .tune1          = 0x0000001f,
-               .droop_rate_min = 1000000,
-       },
 };
 
 /* Core DVFS tables */
-/* FIXME: real data */
 static const int core_millivolts[MAX_DVFS_FREQS] = {
-       837,  900,  950, 1000, 1050, 1100, 1125};
+       800, 850, 900, 950, 1000, 1050, 1100, 1150};
 
-#define CORE_DVFS(_clk_name, _speedo_id, _auto, _mult, _freqs...)      \
+#define CORE_DVFS(_clk_name, _speedo_id, _process_id, _auto, _mult, _freqs...) \
        {                                                       \
                .clk_name       = _clk_name,                    \
                .speedo_id      = _speedo_id,                   \
-               .process_id     = -1,                           \
+               .process_id     = _process_id,                  \
                .freqs          = {_freqs},                     \
                .freqs_mult     = _mult,                        \
                .millivolts     = core_millivolts,              \
@@ -142,78 +225,104 @@ static const int core_millivolts[MAX_DVFS_FREQS] = {
                .dvfs_rail      = &tegra12_dvfs_rail_vdd_core,  \
        }
 
+#define OVRRD_DVFS(_clk_name, _speedo_id, _process_id, _auto, _mult, _freqs...) \
+       {                                                       \
+               .clk_name       = _clk_name,                    \
+               .speedo_id      = _speedo_id,                   \
+               .process_id     = _process_id,                  \
+               .freqs          = {_freqs},                     \
+               .freqs_mult     = _mult,                        \
+               .millivolts     = core_millivolts,              \
+               .auto_dvfs      = _auto,                        \
+               .can_override   = true,                         \
+               .dvfs_rail      = &tegra12_dvfs_rail_vdd_core,  \
+       }
+
 static struct dvfs core_dvfs_table[] = {
-       /* Core voltages (mV):              837,    900,    950,   1000,   1050,    1100,    1125, */
+       /* Core voltages (mV):                   800,    850,    900,    950,    1000,  1050,    1100,   1150 */
        /* Clock limits for internal blocks, PLLs */
-#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
-       CORE_DVFS("cpu_lp", -1, 1, KHZ,       1, 144000, 252000, 288000, 372000,  468000,  468000),
-       CORE_DVFS("emc",   -1, 1, KHZ,        1, 264000, 348000, 384000, 528000,  800000,  800000),
-       CORE_DVFS("sbus",  -1, 1, KHZ,        1,  81600, 102000, 136000, 204000,  204000,  204000),
 
-       CORE_DVFS("vi",    -1, 1, KHZ,        1, 102000, 144000, 144000, 192000,  240000,  240000),
+        CORE_DVFS("emc",        -1, -1, 1, KHZ, 264000, 348000, 384000, 384000, 528000, 528000, 924000, 924000),
+
+        CORE_DVFS("cpu_lp",     0, 0, 1, KHZ,   396000, 528000, 660000, 804000, 912000, 1044000, 1140000, 1140000),
+        CORE_DVFS("cpu_lp",     0, 1, 1, KHZ,   420000, 564000, 696000, 828000, 960000, 1092000, 1140000, 1140000),
+        CORE_DVFS("cpu_lp",     1, -1, 1, KHZ,  420000, 564000, 696000, 828000, 960000, 1092000, 1188000, 1188000),
+
+        CORE_DVFS("sbus",       0, 0, 1, KHZ,   156000, 192000, 228000, 264000, 312000, 348000, 372000, 372000),
+        CORE_DVFS("sbus",       0, 1, 1, KHZ,   156000, 204000, 252000, 288000, 324000, 360000, 372000, 372000),
+        CORE_DVFS("sbus",       1, -1, 1, KHZ,  156000, 204000, 252000, 288000, 324000, 360000, 384000, 384000),
+
+        CORE_DVFS("vic03",      0, 0, 1, KHZ,   228000, 324000, 408000, 492000, 588000, 660000, 708000, 756000),
+        CORE_DVFS("vic03",      0, 1, 1, KHZ,   228000, 336000, 420000, 504000, 600000, 684000, 756000, 756000),
+        CORE_DVFS("vic03",      1, -1, 1, KHZ,  228000, 336000, 420000, 504000, 600000, 684000, 756000, 828000),
+
+        CORE_DVFS("tsec",       0, 0, 1, KHZ,   228000, 324000, 408000, 492000, 588000, 660000, 708000, 756000),
+        CORE_DVFS("tsec",       0, 1, 1, KHZ,   228000, 336000, 420000, 504000, 600000, 684000, 756000, 756000),
+        CORE_DVFS("tsec",       1, -1, 1, KHZ,  228000, 336000, 420000, 504000, 600000, 684000, 756000, 828000),
+
+        CORE_DVFS("msenc",      0, 0, 1, KHZ,   156000, 216000, 288000, 336000, 384000, 432000, 456000, 480000),
+        CORE_DVFS("msenc",      0, 1, 1, KHZ,   168000, 228000, 276000, 348000, 396000, 444000, 480000, 480000),
+        CORE_DVFS("msenc",      1, -1, 1, KHZ,  168000, 228000, 276000, 348000, 396000, 444000, 480000, 528000),
 
-       CORE_DVFS("2d",    -1, 1, KHZ,        1, 132000, 180000, 204000, 264000,  336000,  336000),
-       CORE_DVFS("3d",    -1, 1, KHZ,        1, 132000, 180000, 204000, 264000,  336000,  336000),
-       CORE_DVFS("vic03", -1, 1, KHZ,        1, 132000, 180000, 204000, 264000,  336000,  336000),
+        CORE_DVFS("se",         0, 0, 1, KHZ,   156000, 216000, 288000, 336000, 384000, 432000, 456000, 480000),
+        CORE_DVFS("se",         0, 1, 1, KHZ,   168000, 228000, 276000, 348000, 396000, 444000, 480000, 480000),
+        CORE_DVFS("se",         1, -1, 1, KHZ,  168000, 228000, 276000, 348000, 396000, 444000, 480000, 528000),
 
-       CORE_DVFS("epp",   -1, 1, KHZ,        1, 120000, 144000, 168000, 216000,  276000,  276000),
-       CORE_DVFS("msenc", -1, 1, KHZ,        1, 120000, 144000, 168000, 216000,  276000,  276000),
-       CORE_DVFS("se",    -1, 1, KHZ,        1, 120000, 144000, 168000, 216000,  276000,  276000),
-       CORE_DVFS("tsec",  -1, 1, KHZ,        1, 120000, 144000, 168000, 216000,  276000,  276000),
-       CORE_DVFS("vde",   -1, 1, KHZ,        1, 120000, 144000, 168000, 216000,  276000,  276000),
+        CORE_DVFS("vde",        0, 0, 1, KHZ,   156000, 216000, 288000, 336000, 384000, 432000, 456000, 480000),
+        CORE_DVFS("vde",        0, 1, 1, KHZ,   168000, 228000, 276000, 348000, 396000, 444000, 480000, 480000),
+        CORE_DVFS("vde",        1, -1, 1, KHZ,  168000, 228000, 276000, 348000, 396000, 444000, 480000, 528000),
 
-       CORE_DVFS("host1x", -1, 1, KHZ,       1,  81600, 102000, 136000, 163200,  204000,  204000),
+        CORE_DVFS("host1x",     0, 0, 1, KHZ,   108000, 156000, 204000, 240000, 348000, 372000, 408000, 408000),
+        CORE_DVFS("host1x",     0, 1, 1, KHZ,   108000, 156000, 204000, 252000, 348000, 384000, 408000, 408000),
+        CORE_DVFS("host1x",     1, -1, 1, KHZ,  108000, 156000, 204000, 252000, 348000, 384000, 444000, 444000),
+
+        CORE_DVFS("vi",         0, 0, 1, KHZ,   300000, 408000, 480000, 600000, 600000, 600000, 600000, 600000),
+        CORE_DVFS("vi",         0, 1, 1, KHZ,   300000, 420000, 480000, 600000, 600000, 600000, 600000, 600000),
+        CORE_DVFS("vi",         1, -1, 1, KHZ,  300000, 420000, 480000, 600000, 600000, 600000, 600000, 600000),
+
+        CORE_DVFS("isp",        0, 0, 1, KHZ,   300000, 408000, 480000, 600000, 600000, 600000, 600000, 600000),
+        CORE_DVFS("isp",        0, 1, 1, KHZ,   300000, 420000, 480000, 600000, 600000, 600000, 600000, 600000),
+        CORE_DVFS("isp",        1, -1, 1, KHZ,  300000, 420000, 480000, 600000, 600000, 600000, 600000, 600000),
 
 #ifdef CONFIG_TEGRA_DUAL_CBUS
-       CORE_DVFS("c2bus", -1, 1, KHZ,        1, 132000, 180000, 204000, 264000,  336000,  336000),
-       CORE_DVFS("c3bus", -1, 1, KHZ,        1, 120000, 144000, 168000, 216000,  276000,  276000),
+        CORE_DVFS("c2bus",      0, 0, 1, KHZ,   156000, 216000, 288000, 336000, 384000, 432000, 456000, 480000),
+        CORE_DVFS("c2bus",      0, 1, 1, KHZ,   168000, 228000, 276000, 348000, 396000, 444000, 480000, 480000),
+        CORE_DVFS("c2bus",      1, -1, 1, KHZ,  168000, 228000, 276000, 348000, 396000, 444000, 480000, 528000),
+
+        CORE_DVFS("c3bus",      0, 0, 1, KHZ,   228000, 324000, 408000, 492000, 588000, 660000, 708000, 756000),
+        CORE_DVFS("c3bus",      0, 1, 1, KHZ,   228000, 336000, 420000, 504000, 600000, 684000, 756000, 756000),
+        CORE_DVFS("c3bus",      1, -1, 1, KHZ,  228000, 336000, 420000, 504000, 600000, 684000, 756000, 828000),
 #else
-       CORE_DVFS("cbus",  -1, 1, KHZ,        1, 120000, 144000, 168000, 216000,  276000,  276000),
+       CORE_DVFS("cbus",      -1, -1, 1, KHZ,  120000, 144000, 168000, 168000, 216000, 216000, 372000, 372000),
 #endif
 
-       CORE_DVFS("pll_m", -1, 1, KHZ,        1, 480000, 588000, 660000, 792000,  936000,  936000),
-       CORE_DVFS("pll_c", -1, 1, KHZ,        1, 480000, 588000, 660000, 792000,  936000,  936000),
-       CORE_DVFS("pll_c2", -1, 1, KHZ,       1, 480000, 588000, 660000, 792000,  936000,  936000),
-       CORE_DVFS("pll_c3", -1, 1, KHZ,       1, 480000, 588000, 660000, 792000,  936000,  936000),
-       CORE_DVFS("pll_d_out0", -1, 1, KHZ,   1, 480000, 588000, 660000, 792000,  936000,  936000),
-       CORE_DVFS("pll_d2_out0", -1, 1, KHZ,  1, 480000, 588000, 660000, 792000,  936000,  936000),
-       CORE_DVFS("pll_re_out", -1, 1, KHZ,   1, 480000, 588000, 660000, 792000,  936000,  936000),
+        CORE_DVFS("c4bus",      0, 0, 1, KHZ,   300000, 408000, 480000, 600000, 600000, 600000, 600000, 600000),
+        CORE_DVFS("c4bus",      0, 1, 1, KHZ,   300000, 420000, 480000, 600000, 600000, 600000, 600000, 600000),
+        CORE_DVFS("c4bus",      1, -1, 1, KHZ,  300000, 420000, 480000, 600000, 600000, 600000, 600000, 600000),
+
+       CORE_DVFS("pll_m",  -1, -1, 1, KHZ,   800000,  800000, 1066000, 1066000, 1066000, 1066000, 1066000, 1066000),
+       CORE_DVFS("pll_c",  -1, -1, 1, KHZ,   800000,  800000, 1066000, 1066000, 1066000, 1066000, 1066000, 1066000),
+       CORE_DVFS("pll_c2", -1, -1, 1, KHZ,   800000,  800000, 1066000, 1066000, 1066000, 1066000, 1066000, 1066000),
+       CORE_DVFS("pll_c3", -1, -1, 1, KHZ,   800000,  800000, 1066000, 1066000, 1066000, 1066000, 1066000, 1066000),
 
-       /* Core voltages (mV):              837,    900,    950,   1000,   1050,    1100,    1125, */
+       /* Core voltages (mV):                   800,    850,    900,    950,    1000,  1050,    1100,   1150 */
        /* Clock limits for I/O peripherals */
-       CORE_DVFS("i2c1", -1, 1, KHZ,         1,  58300,  68000,  81600, 102000,  136000,  136000),
-       CORE_DVFS("i2c2", -1, 1, KHZ,         1,  58300,  68000,  81600, 102000,  136000,  136000),
-       CORE_DVFS("i2c3", -1, 1, KHZ,         1,  58300,  68000,  81600, 102000,  136000,  136000),
-       CORE_DVFS("i2c4", -1, 1, KHZ,         1,  58300,  68000,  81600, 102000,  136000,  136000),
-
-       CORE_DVFS("sbc1", -1, 1, KHZ,         1,  24000,  24000,  48000,  48000,   48000,   48000),
-       CORE_DVFS("sbc2", -1, 1, KHZ,         1,  24000,  24000,  48000,  48000,   48000,   48000),
-       CORE_DVFS("sbc3", -1, 1, KHZ,         1,  24000,  24000,  48000,  48000,   48000,   48000),
-       CORE_DVFS("sbc4", -1, 1, KHZ,         1,  24000,  24000,  48000,  48000,   48000,   48000),
-       CORE_DVFS("sbc5", -1, 1, KHZ,         1,  24000,  24000,  48000,  48000,   48000,   48000),
-       CORE_DVFS("sbc6", -1, 1, KHZ,         1,  24000,  24000,  48000,  48000,   48000,   48000),
-
-       /* FIXME: re-enable after UART hs driver is updated */
-#if 0
-       CORE_DVFS("uarta", -1, 1, KHZ,        1,  58300,  58300, 102000, 102000,  102000,  102000),
-       CORE_DVFS("uartb", -1, 1, KHZ,        1,  58300,  58300, 102000, 102000,  102000,  102000),
-       CORE_DVFS("uartc", -1, 1, KHZ,        1,  58300,  58300, 102000, 102000,  102000,  102000),
-       CORE_DVFS("uartd", -1, 1, KHZ,        1,  58300,  58300, 102000, 102000,  102000,  102000),
-       CORE_DVFS("uarte", -1, 1, KHZ,        1,  58300,  58300, 102000, 102000,  102000,  102000),
-#endif
-       CORE_DVFS("sdmmc1", -1, 1, KHZ,       1, 102000, 102000, 163200, 163200,  163200,  163200),
-       CORE_DVFS("sdmmc2", -1, 1, KHZ,       1, 102000, 102000, 163200, 163200,  163200,  163200),
-       CORE_DVFS("sdmmc3", -1, 1, KHZ,       1, 102000, 102000, 163200, 163200,  163200,  163200),
-       CORE_DVFS("sdmmc4", -1, 1, KHZ,       1, 102000, 102000, 163200, 163200,  163200,  163200),
+       CORE_DVFS("sbc1",   -1, -1, 1, KHZ,    33000,  33000,  33000,  33000,   33000,  33000,  51000,  51000),
+       CORE_DVFS("sbc2",   -1, -1, 1, KHZ,    33000,  33000,  33000,  33000,   33000,  33000,  51000,  51000),
+       CORE_DVFS("sbc3",   -1, -1, 1, KHZ,    33000,  33000,  33000,  33000,   33000,  33000,  51000,  51000),
+       CORE_DVFS("sbc4",   -1, -1, 1, KHZ,    33000,  33000,  33000,  33000,   33000,  33000,  51000,  51000),
+       CORE_DVFS("sbc5",   -1, -1, 1, KHZ,    33000,  33000,  33000,  33000,   33000,  33000,  51000,  51000),
+       CORE_DVFS("sbc6",   -1, -1, 1, KHZ,    33000,  33000,  33000,  33000,   33000,  33000,  51000,  51000),
+
+       OVRRD_DVFS("sdmmc1", -1, -1, 1, KHZ,  100000, 100000, 100000, 100000,  136000, 136000, 136000, 204000),
+       OVRRD_DVFS("sdmmc3", -1, -1, 1, KHZ,  100000, 100000, 100000, 100000,  136000, 136000, 136000, 204000),
+       OVRRD_DVFS("sdmmc4", -1, -1, 1, KHZ,  102000, 102000, 102000, 102000,  136000, 136000, 136000, 200000),
 
-       CORE_DVFS("pwm",  -1, 1, KHZ,         1,  40800,  48000,  48000,  48000,   48000,   48000),
+       CORE_DVFS("hdmi",   -1, -1, 1, KHZ,        1, 148500, 148500, 297000,  297000, 297000, 297000, 297000),
+       /* FIXME: Finalize these values for NOR after qual */
+       CORE_DVFS("nor",    -1, -1, 1, KHZ,   102000, 102000, 102000, 102000,  102000, 102000, 102000, 102000),
 
-       CORE_DVFS("csi",  -1, 1, KHZ,         1,      1,      1, 102000, 102000,  102000,  102000),
-       CORE_DVFS("dsia", -1, 1, KHZ,         1, 100000, 125000, 125000, 125000,  500000,  500000),
-       CORE_DVFS("dsib", -1, 1, KHZ,         1, 100000, 125000, 125000, 125000,  500000,  500000),
-       CORE_DVFS("dsialp", -1, 1, KHZ,       1, 102000, 102000, 102000, 102000,  156000,  156000),
-       CORE_DVFS("dsiblp", -1, 1, KHZ,       1, 102000, 102000, 102000, 102000,  156000,  156000),
-       CORE_DVFS("hdmi", -1, 1, KHZ,         1,  99000, 118800, 148500, 198000,  198000,  198000),
+       CORE_DVFS("pciex",  -1,  -1, 1, KHZ,  250000, 250000, 250000, 500000,  500000, 500000, 500000, 500000),
 
        /*
         * The clock rate for the display controllers that determines the
@@ -221,39 +330,83 @@ static struct dvfs core_dvfs_table[] = {
         * to the display block.  Disable auto-dvfs on the display clocks,
         * and let the display driver call tegra_dvfs_set_rate manually
         */
-       CORE_DVFS("disp1", -1, 0, KHZ,         1, 108000, 120000, 144000, 192000,  240000,  240000),
-       CORE_DVFS("disp2", -1, 0, KHZ,         1, 108000, 120000, 144000, 192000,  240000,  240000),
-
-       CORE_DVFS("xusb_falcon_src", -1, 1, KHZ, 1, 204000, 204000, 204000, 336000,  336000,  336000),
-       CORE_DVFS("xusb_host_src",   -1, 1, KHZ, 1,  58300,  58300,  58300, 112000,  112000,  112000),
-       CORE_DVFS("xusb_dev_src",    -1, 1, KHZ, 1,  58300,  58300,  58300, 112000,  112000,  112000),
-       CORE_DVFS("xusb_ss_src",     -1, 1, KHZ, 1,  60000,  60000,  60000, 120000,  120000,  120000),
-       CORE_DVFS("xusb_fs_src",     -1, 1, KHZ, 1,      1,  48000,  48000,  48000,   48000,   48000),
-       CORE_DVFS("xusb_hs_src",     -1, 1, KHZ, 1,      1,  60000,  60000,  60000,   60000,   60000),
-#endif
-};
+        CORE_DVFS("disp1",       0, 0, 0, KHZ,   148500, 241000, 297000, 297000, 297000, 474000, 474000, 474000),
+        CORE_DVFS("disp1",       0, 1, 0, KHZ,   148500, 241000, 297000, 297000, 474000, 474000, 474000, 474000),
+        CORE_DVFS("disp1",       1, -1, 0, KHZ,  148500, 241000, 297000, 297000, 474000, 474000, 474000, 533000),
 
-/* TBD: fill in actual hw numbers */
-static const int gpu_millivolts[MAX_DVFS_FREQS] = {
-       850,  900,  950, 1000, 1050, 1100, 1125};
+        CORE_DVFS("disp2",       0, 0, 0, KHZ,   148500, 241000, 297000, 297000, 297000, 474000, 474000, 474000),
+        CORE_DVFS("disp2",       0, 1, 0, KHZ,   148500, 241000, 297000, 297000, 474000, 474000, 474000, 474000),
+        CORE_DVFS("disp2",       1, -1, 0, KHZ,  148500, 241000, 297000, 297000, 474000, 474000, 474000, 533000),
 
-#define GPU_DVFS(_clk_name, _speedo_id, _auto, _mult, _freqs...)       \
-       {                                                       \
-               .clk_name       = _clk_name,                    \
-               .speedo_id      = _speedo_id,                   \
-               .process_id     = -1,                           \
-               .freqs          = {_freqs},                     \
-               .freqs_mult     = _mult,                        \
-               .millivolts     = gpu_millivolts,               \
-               .auto_dvfs      = _auto,                        \
-               .dvfs_rail      = &tegra12_dvfs_rail_vdd_gpu,   \
+};
+
+static struct gpu_cvb_dvfs gpu_cvb_dvfs_table[] = {
+       {
+               .speedo_id =   0,
+               .process_id = -1,
+               .max_mv = 1200,
+               .min_mv = 800,
+               .freqs_mult = KHZ,
+               .speedo_scale = 100,
+               .thermal_scale = 10,
+               .voltage_scale = 1000,
+               .cvb_table = {
+                       /*f        dfll  pll:   c0,     c1,   c2,   c3,      c4,   c5 */
+                       {   72000, {  }, { 1013806, -14060, -127,   954, -27008,  781}, },
+                       {  108000, {  }, {  983062,  -9373, -263,   954, -26703,  650}, },
+                       {  180000, {  }, { 1040909, -12008, -224,   775, -23193,  376}, },
+                       {  252000, {  }, { 1150002, -20683,  -17,   298, -13428,  232}, },
+                       {  324000, {  }, { 1081549, -10827, -274,   179, -10681,  238}, },
+                       {  396000, {  }, { 1136931, -12086, -274,   119, -10071,  238}, },
+                       {  468000, {  }, { 1195664, -13329, -274,    60,  -8850,  221}, },
+                       {  540000, {  }, { 1257766, -14587, -274,     0,  -7019,  179}, },
+                       {  612000, {  }, { 1323069, -15830, -274,     0,  -4578,  113}, },
+                       {  648000, {  }, { 1356986, -16459, -274,     0,  -3204,   72}, },
+                       {       0, {  }, { }, },
+               },
+               .vmin_trips_table = { 20, },
+               .therm_floors_table = { 900, },
+               .vts_trips_table = { -10, 10, 30, 50, 70, },
+       },
+       {
+               .speedo_id =   1,
+               .process_id = -1,
+               .max_mv = 1200,
+               .min_mv = 800,
+               .freqs_mult = KHZ,
+               .speedo_scale = 100,
+               .thermal_scale = 10,
+               .voltage_scale = 1000,
+               .cvb_table = {
+                       /*f        dfll  pll:   c0,     c1,   c2,   c3,      c4,   c5 */
+                       {   72000, {  }, { 1013806, -14060, -127,   954, -27008,  781}, },
+                       {  108000, {  }, {  983062,  -9373, -263,   954, -26703,  650}, },
+                       {  180000, {  }, { 1040909, -12008, -224,   775, -23193,  376}, },
+                       {  252000, {  }, { 1150002, -20683,  -17,   298, -13428,  232}, },
+                       {  324000, {  }, { 1081549, -10827, -274,   179, -10681,  238}, },
+                       {  396000, {  }, { 1136931, -12086, -274,   119, -10071,  238}, },
+                       {  468000, {  }, { 1195664, -13329, -274,    60,  -8850,  221}, },
+                       {  540000, {  }, { 1257766, -14587, -274,     0,  -7019,  179}, },
+                       {  612000, {  }, { 1323069, -15830, -274,     0,  -4578,  113}, },
+                       {  648000, {  }, { 1356986, -16459, -274,     0,  -3204,   72}, },
+                       {  684000, {  }, { 1391884, -17078, -274,   -60,  -1526,   30}, },
+                       {  708000, {  }, { 1415522, -17497, -274,   -60,   -458,    0}, },
+                       {  756000, {  }, { 1464061, -18331, -274,  -119,   1831,  -72}, },
+                       {  804000, {  }, { 1524225, -20064, -254,  -119,   4272, -155}, },
+                       {  852000, {  }, { 1608418, -21643, -269,     0,    763,  -48}, },
+                       {       0, {  }, { }, },
+               },
+               .vmin_trips_table = { 20, },
+               .therm_floors_table = { 900, },
+               .vts_trips_table = { -10, 10, 30, 50, 70, },
        }
+};
 
-/* TBD: fill in actual hw numbers */
-static struct dvfs gpu_dvfs_table[] = {
-       /* Gpu voltages (mV):               837,    900,    950,   1000,   1050,    1100,    1125 */
-       /* Clock limits for internal blocks, PLLs */
-       GPU_DVFS("gpu",     -1, 1, KHZ,    403000, 650000,  676000, 702000, 728000, 806000,  810000),
+static int gpu_millivolts[MAX_THERMAL_RANGES][MAX_DVFS_FREQS];
+static struct dvfs gpu_dvfs = {
+       .clk_name       = "gbus",
+       .auto_dvfs      = true,
+       .dvfs_rail      = &tegra12_dvfs_rail_vdd_gpu,
 };
 
 int tegra_dvfs_disable_core_set(const char *arg, const struct kernel_param *kp)
@@ -331,7 +484,6 @@ module_param_cb(disable_cpu, &tegra_dvfs_disable_cpu_ops,
 module_param_cb(disable_gpu, &tegra_dvfs_disable_gpu_ops,
        &tegra_dvfs_gpu_disabled, 0644);
 
-
 static bool __init can_update_max_rate(struct clk *c, struct dvfs *d)
 {
        /* Don't update manual dvfs clocks */
@@ -397,22 +549,22 @@ static void __init init_dvfs_one(struct dvfs *d, int max_freq_index)
                pr_err("tegra12_dvfs: failed to enable dvfs on %s\n", c->name);
 }
 
-static bool __init match_dvfs_one(struct dvfs *d, int speedo_id, int process_id)
+static bool __init match_dvfs_one(const char *name,
+       int dvfs_speedo_id, int dvfs_process_id,
+       int speedo_id, int process_id)
 {
-       if ((d->process_id != -1 && d->process_id != process_id) ||
-               (d->speedo_id != -1 && d->speedo_id != speedo_id)) {
-               pr_debug("tegra12_dvfs: rejected %s speedo %d,"
-                       " process %d\n", d->clk_name, d->speedo_id,
-                       d->process_id);
+       if ((dvfs_process_id != -1 && dvfs_process_id != process_id) ||
+               (dvfs_speedo_id != -1 && dvfs_speedo_id != speedo_id)) {
+               pr_debug("tegra12_dvfs: rejected %s speedo %d, process %d\n",
+                        name, dvfs_speedo_id, dvfs_process_id);
                return false;
        }
        return true;
 }
 
-
 /* cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) / v_scale */
 static inline int get_cvb_voltage(int speedo, int s_scale,
-                                 struct cpu_cvb_dvfs_parameters *cvb)
+                                 struct cvb_dvfs_parameters *cvb)
 {
        /* apply only speedo scale: output mv = cvb_mv * v_scale */
        int mv;
@@ -421,39 +573,56 @@ static inline int get_cvb_voltage(int speedo, int s_scale,
        return mv;
 }
 
-static inline int round_cvb_voltage(int mv, int v_scale)
+/* cvb_t_mv =
+   ((c3 * speedo / s_scale + c4 + c5 * T / t_scale) * T / t_scale) / v_scale */
+static inline int get_cvb_t_voltage(int speedo, int s_scale, int t, int t_scale,
+                                   struct cvb_dvfs_parameters *cvb)
+{
+       /* apply speedo & temperature scales: output mv = cvb_t_mv * v_scale */
+       int mv;
+       mv = DIV_ROUND_CLOSEST(cvb->c3 * speedo, s_scale) + cvb->c4 +
+               DIV_ROUND_CLOSEST(cvb->c5 * t, t_scale);
+       mv = DIV_ROUND_CLOSEST(mv * t, t_scale);
+       return mv;
+}
+
+static int round_cvb_voltage(int mv, int v_scale, struct rail_alignment *align)
 {
        /* combined: apply voltage scale and round to cvb alignment step */
-       int cvb_align_step_uv = tegra_get_cvb_alignment_uV();
+       int uv;
+       int step = (align->step_uv ? : 1000) * v_scale;
+       int offset = align->offset_uv * v_scale;
+
+       uv = max(mv * 1000, offset) - offset;
+       uv = DIV_ROUND_UP(uv, step) * align->step_uv + align->offset_uv;
+       return uv / 1000;
+}
 
-       return DIV_ROUND_UP(mv * 1000, v_scale * cvb_align_step_uv) *
-               cvb_align_step_uv / 1000;
+static int round_voltage(int mv, struct rail_alignment *align, bool up)
+{
+       if (align->step_uv) {
+               int uv = max(mv * 1000, align->offset_uv) - align->offset_uv;
+               uv = (uv + (up ? align->step_uv - 1 : 0)) / align->step_uv;
+               return (uv * align->step_uv + align->offset_uv) / 1000;
+       }
+       return mv;
 }
 
-static int __init set_cpu_dvfs_data(int speedo_id, struct dvfs *cpu_dvfs,
-                                   int *max_freq_index)
+static int __init set_cpu_dvfs_data(
+       struct cpu_cvb_dvfs *d, struct dvfs *cpu_dvfs, int *max_freq_index)
 {
-       int i, j, mv, dfll_mv;
+       int i, j, mv, dfll_mv, min_dfll_mv;
        unsigned long fmax_at_vmin = 0;
        unsigned long fmax_pll_mode = 0;
        unsigned long fmin_use_dfll = 0;
-       struct cpu_cvb_dvfs *d = NULL;
-       struct cpu_cvb_dvfs_table *table = NULL;
+       struct cvb_dvfs_table *table = NULL;
        int speedo = tegra_cpu_speedo_value();
+       struct rail_alignment *align = &tegra12_dvfs_rail_vdd_cpu.alignment;
 
-       /* Find matching cvb dvfs entry */
-       for (i = 0; i < ARRAY_SIZE(cpu_cvb_dvfs_table); i++) {
-               d = &cpu_cvb_dvfs_table[i];
-               if (speedo_id == d->speedo_id)
-                       break;
-       }
-
-       if (!d) {
-               pr_err("tegra12_dvfs: no cpu dvfs table for speedo_id %d\n",
-                      speedo_id);
-               return -ENOENT;
-       }
-       BUG_ON(d->min_dfll_mv < tegra12_dvfs_rail_vdd_cpu.min_millivolts);
+       min_dfll_mv = d->dfll_tune_data.min_millivolts;
+       min_dfll_mv =  round_voltage(min_dfll_mv, align, true);
+       d->max_mv = round_voltage(d->max_mv, align, false);
+       BUG_ON(min_dfll_mv < tegra12_dvfs_rail_vdd_cpu.min_millivolts);
 
        /*
         * Use CVB table to fill in CPU dvfs frequencies and voltages. Each
@@ -473,17 +642,21 @@ static int __init set_cpu_dvfs_data(int speedo_id, struct dvfs *cpu_dvfs,
 
                dfll_mv = get_cvb_voltage(
                        speedo, d->speedo_scale, &table->cvb_dfll_param);
-               dfll_mv = round_cvb_voltage(dfll_mv, d->voltage_scale);
+               dfll_mv = round_cvb_voltage(dfll_mv, d->voltage_scale, align);
 
                mv = get_cvb_voltage(
                        speedo, d->speedo_scale, &table->cvb_pll_param);
-               mv = round_cvb_voltage(mv, d->voltage_scale);
+               mv = round_cvb_voltage(mv, d->voltage_scale, align);
 
-               /* Check maximum frequency at minimum voltage for dfll source */
-               dfll_mv = max(dfll_mv, d->min_dfll_mv);
-               if (dfll_mv > d->min_dfll_mv) {
+               /*
+                * Check maximum frequency at minimum voltage for dfll source;
+                * round down unless all table entries are above Vmin, then use
+                * the 1st entry as is.
+                */
+               dfll_mv = max(dfll_mv, min_dfll_mv);
+               if (dfll_mv > min_dfll_mv) {
                        if (!j)
-                               break;  /* 1st entry already above Vmin */
+                               fmax_at_vmin = table->freq;
                        if (!fmax_at_vmin)
                                fmax_at_vmin = cpu_dvfs->freqs[j - 1];
                }
@@ -497,7 +670,7 @@ static int __init set_cpu_dvfs_data(int speedo_id, struct dvfs *cpu_dvfs,
                }
 
                /* Minimum rate with pll source voltage above dfll Vmin */
-               if ((mv >= d->min_dfll_mv) && (!fmin_use_dfll))
+               if ((mv >= min_dfll_mv) && (!fmin_use_dfll))
                        fmin_use_dfll = table->freq;
 
                /* fill in dvfs tables */
@@ -515,11 +688,10 @@ static int __init set_cpu_dvfs_data(int speedo_id, struct dvfs *cpu_dvfs,
                if (dfll_mv > d->max_mv)
                        break;
        }
-       /* Table must not be empty and must have and at least one entry below,
-          and one entry above Vmin */
+
+       /* Table must not be empty, must have at least one entry above Vmin */
        if (!i || !j || !fmax_at_vmin) {
-               pr_err("tegra12_dvfs: invalid cpu dvfs table for speedo_id %d\n",
-                      speedo_id);
+               pr_err("tegra12_dvfs: invalid cpu dvfs table\n");
                return -ENOENT;
        }
 
@@ -532,67 +704,152 @@ static int __init set_cpu_dvfs_data(int speedo_id, struct dvfs *cpu_dvfs,
        }
 
        /* dvfs tables are successfully populated - fill in the rest */
-       cpu_dvfs->speedo_id = speedo_id;
+       cpu_dvfs->speedo_id = d->speedo_id;
+       cpu_dvfs->process_id = d->process_id;
        cpu_dvfs->freqs_mult = d->freqs_mult;
        cpu_dvfs->dvfs_rail->nominal_millivolts = min(d->max_mv,
                max(cpu_millivolts[j - 1], cpu_dfll_millivolts[j - 1]));
        *max_freq_index = j - 1;
 
+       cpu_dvfs->dfll_data = d->dfll_tune_data;
        cpu_dvfs->dfll_data.max_rate_boost = fmax_pll_mode ?
                (cpu_dvfs->freqs[j - 1] - fmax_pll_mode) * d->freqs_mult : 0;
-
-
        cpu_dvfs->dfll_data.out_rate_min = fmax_at_vmin * d->freqs_mult;
        cpu_dvfs->dfll_data.use_dfll_rate_min = fmin_use_dfll * d->freqs_mult;
-       cpu_dvfs->dfll_data.min_millivolts = d->min_dfll_mv;
+       cpu_dvfs->dfll_data.min_millivolts = min_dfll_mv;
+
+       /* Init cpu thermal floors */
+       tegra_dvfs_rail_init_vmin_thermal_profile(
+               d->vmin_trips_table, d->therm_floors_table,
+               &tegra12_dvfs_rail_vdd_cpu, &cpu_dvfs->dfll_data);
+
        return 0;
 }
 
-static int __init get_core_nominal_mv_index(int speedo_id)
+static int __init set_gpu_dvfs_data(
+       struct gpu_cvb_dvfs *d, struct dvfs *gpu_dvfs, int *max_freq_index)
 {
-       int i;
-       int mv = tegra_core_speedo_mv();
-       int core_edp_limit = get_core_edp();
+       int i, j, thermal_ranges, mv;
+       struct cvb_dvfs_table *table = NULL;
+       int speedo = tegra_gpu_speedo_value();
+       struct dvfs_rail *rail = &tegra12_dvfs_rail_vdd_gpu;
+       struct rail_alignment *align = &rail->alignment;
+
+       d->max_mv = round_voltage(d->max_mv, align, false);
+       d->min_mv = round_voltage(d->min_mv, align, true);
+       BUG_ON(d->min_mv < tegra12_dvfs_rail_vdd_gpu.min_millivolts);
 
        /*
-        * Start with nominal level for the chips with this speedo_id. Then,
-        * make sure core nominal voltage is below edp limit for the board
-        * (if edp limit is set).
+        * Init thermal trips, find number of thermal ranges; note that the
+        * first trip-point is used for voltage calculations within the lowest
+        * range, but should not be actually set. Hence, at least 2 trip-points
+        * must be specified.
         */
-       if (core_edp_limit)
-               mv = min(mv, core_edp_limit);
+       if (tegra_dvfs_rail_init_thermal_dvfs_trips(d->vts_trips_table, rail))
+               return -ENOENT;
+       thermal_ranges = rail->vts_cdev->trip_temperatures_num;
+       rail->vts_cdev->trip_temperatures_num--;
 
-       /* Round nominal level down to the nearest core scaling step */
+       if (thermal_ranges < 2)
+               WARN(1, "tegra12_dvfs: %d gpu trip: thermal dvfs is broken\n",
+                    thermal_ranges);
+
+       /*
+        * Use CVB table to fill in gpu dvfs frequencies and voltages. Each
+        * CVB entry specifies gpu frequency and CVB coefficients to calculate
+        * the respective voltage.
+        */
        for (i = 0; i < MAX_DVFS_FREQS; i++) {
-               if ((core_millivolts[i] == 0) || (mv < core_millivolts[i]))
+               table = &d->cvb_table[i];
+               if (!table->freq)
+                       break;
+
+               mv = get_cvb_voltage(
+                       speedo, d->speedo_scale, &table->cvb_pll_param);
+
+               for (j = 0; j < thermal_ranges; j++) {
+                       int mvj = mv;
+                       int t = rail->vts_cdev->trip_temperatures[j];
+
+                       /* get thermal offset for this trip-point */
+                       mvj += get_cvb_t_voltage(speedo, d->speedo_scale,
+                               t, d->thermal_scale, &table->cvb_pll_param);
+                       mvj = round_cvb_voltage(mvj, d->voltage_scale, align);
+
+                       /* clip to minimum, abort if above maximum */
+                       mvj = max(mvj, d->min_mv);
+                       if (mvj > d->max_mv)
+                               break;
+
+                       /* update voltage for adjacent ranges bounded by this
+                          trip-point (cvb & dvfs are transpose matrices) */
+                       gpu_millivolts[j][i] = mvj;
+                       if (j && (gpu_millivolts[j-1][i] < mvj))
+                               gpu_millivolts[j-1][i] = mvj;
+               }
+               /* Make sure all voltages for this frequency are below max */
+               if (j < thermal_ranges)
                        break;
+
+               /* fill in gpu dvfs tables */
+               gpu_dvfs->freqs[i] = table->freq;
        }
 
-       if (i == 0) {
-               pr_err("tegra12_dvfs: unable to adjust core dvfs table to"
-                      " nominal voltage %d\n", mv);
-               return -ENOSYS;
+       /*
+        * Table must not be empty, must have at least one entry in range, and
+        * must specify monotonically increasing voltage on frequency dependency
+        * in each temperature range.
+        */
+       if (!i || tegra_dvfs_init_thermal_dvfs_voltages(
+               &gpu_millivolts[0][0], i, thermal_ranges, gpu_dvfs)) {
+               pr_err("tegra12_dvfs: invalid gpu dvfs table\n");
+               return -ENOENT;
        }
-       return i - 1;
+
+       /* Shift out the 1st trip-point */
+       for (j = 1; j < thermal_ranges; j++)
+               rail->vts_cdev->trip_temperatures[j - 1] =
+               rail->vts_cdev->trip_temperatures[j];
+
+       /* dvfs tables are successfully populated - fill in the gpu dvfs */
+       gpu_dvfs->speedo_id = d->speedo_id;
+       gpu_dvfs->process_id = d->process_id;
+       gpu_dvfs->freqs_mult = d->freqs_mult;
+       gpu_dvfs->dvfs_rail->nominal_millivolts = d->max_mv;
+
+       *max_freq_index = i - 1;
+
+       /* Init thermal floors */
+       tegra_dvfs_rail_init_vmin_thermal_profile(d->vmin_trips_table,
+               d->therm_floors_table, &tegra12_dvfs_rail_vdd_gpu, NULL);
+
+       return 0;
 }
 
-static int __init get_gpu_nominal_mv_index(int speedo_id)
+static int __init get_core_nominal_mv_index(int speedo_id)
 {
        int i;
-       int mv = 1100; /* TBD: move to fuse */
+       int mv = tegra_core_speedo_mv();
+       int core_edp_voltage = get_core_edp();
 
-       /* TBD: do we have dependency between gpu and core ??
-        * Find maximum gpu voltage that satisfies gpu_to_core dependency for
-        * nominal core voltage ("solve from cpu to core at nominal"). Clip
-        * result to the nominal cpu level for the chips with this speedo_id.
+       /*
+        * Start with nominal level for the chips with this speedo_id. Then,
+        * make sure core nominal voltage is below edp limit for the board
+        * (if edp limit is set).
         */
+       if (!core_edp_voltage)
+               core_edp_voltage = 1150;        /* default 1.15V EDP limit */
+
+       mv = min(mv, core_edp_voltage);
+
+       /* Round nominal level down to the nearest core scaling step */
        for (i = 0; i < MAX_DVFS_FREQS; i++) {
-               if (gpu_millivolts[i] == 0 || mv < gpu_millivolts[i])
+               if ((core_millivolts[i] == 0) || (mv < core_millivolts[i]))
                        break;
        }
 
        if (i == 0) {
-               pr_err("tegra12_dvfs: unable to adjust gpu dvfs table to"
+               pr_err("tegra12_dvfs: unable to adjust core dvfs table to"
                       " nominal voltage %d\n", mv);
                return -ENOSYS;
        }
@@ -609,14 +866,16 @@ int tegra_cpu_dvfs_alter(int edp_thermal_index, const cpumask_t *cpus,
 void __init tegra12x_init_dvfs(void)
 {
        int cpu_speedo_id = tegra_cpu_speedo_id();
+       int cpu_process_id = tegra_cpu_process_id();
        int soc_speedo_id = tegra_soc_speedo_id();
-       int gpu_speedo_id = -1; /* TBD: use gpu speedo */
        int core_process_id = tegra_core_process_id();
+       int gpu_speedo_id = tegra_gpu_speedo_id();
+       int gpu_process_id = tegra_gpu_process_id();
 
-       int i;
+       int i, ret;
        int core_nominal_mv_index;
-       int cpu_max_freq_index;
-       int gpu_nominal_mv_index;
+       int gpu_max_freq_index = 0;
+       int cpu_max_freq_index = 0;
 
 #ifndef CONFIG_TEGRA_CORE_DVFS
        tegra_dvfs_core_disabled = true;
@@ -627,6 +886,12 @@ void __init tegra12x_init_dvfs(void)
 #ifndef CONFIG_TEGRA_GPU_DVFS
        tegra_dvfs_gpu_disabled = true;
 #endif
+#ifdef CONFIG_TEGRA_PRE_SILICON_SUPPORT
+       if (!tegra_platform_is_silicon()) {
+               tegra_dvfs_core_disabled = true;
+               tegra_dvfs_cpu_disabled = true;
+       }
+#endif
 
        /*
         * Find nominal voltages for core (1st) and cpu rails before rail
@@ -645,18 +910,6 @@ void __init tegra12x_init_dvfs(void)
                core_millivolts[core_nominal_mv_index];
 
        /*
-        * TBD: Find nomial voltages for gpu rail
-        */
-       gpu_nominal_mv_index = get_gpu_nominal_mv_index(gpu_speedo_id);
-       if (gpu_nominal_mv_index < 0) {
-               tegra12_dvfs_rail_vdd_gpu.disabled = true;
-               tegra_dvfs_gpu_disabled = true;
-               gpu_nominal_mv_index = 0;
-       }
-       tegra12_dvfs_rail_vdd_gpu.nominal_millivolts =
-               gpu_millivolts[gpu_nominal_mv_index];
-
-       /*
         * Setup cpu dvfs and dfll tables from cvb data, determine nominal
         * voltage for cpu rail, and cpu maximum frequency. Note that entire
         * frequency range is guaranteed only when dfll is used as cpu clock
@@ -666,8 +919,36 @@ void __init tegra12x_init_dvfs(void)
         * voltage limit is not violated). Error when cpu dvfs table can not
         * be constructed must never happen.
         */
-       if (set_cpu_dvfs_data(cpu_speedo_id, &cpu_dvfs, &cpu_max_freq_index))
-               BUG();
+       for (ret = 0, i = 0; i <  ARRAY_SIZE(cpu_cvb_dvfs_table); i++) {
+               struct cpu_cvb_dvfs *d = &cpu_cvb_dvfs_table[i];
+               if (match_dvfs_one("cpu cvb", d->speedo_id, d->process_id,
+                                  cpu_speedo_id, cpu_process_id)) {
+                       ret = set_cpu_dvfs_data(
+                               d, &cpu_dvfs, &cpu_max_freq_index);
+                       break;
+               }
+       }
+       BUG_ON((i == ARRAY_SIZE(cpu_cvb_dvfs_table)) || ret);
+
+       /*
+        * Setup gpu dvfs tables from cvb data, determine nominal voltage for
+        * gpu rail, and gpu maximum frequency. Error when gpu dvfs table can
+        * not be constructed must never happen.
+        */
+       for (ret = 0, i = 0; i < ARRAY_SIZE(gpu_cvb_dvfs_table); i++) {
+               struct gpu_cvb_dvfs *d = &gpu_cvb_dvfs_table[i];
+               if (match_dvfs_one("gpu cvb", d->speedo_id, d->process_id,
+                                  gpu_speedo_id, gpu_process_id)) {
+                       ret = set_gpu_dvfs_data(
+                               d, &gpu_dvfs, &gpu_max_freq_index);
+                       break;
+               }
+       }
+       BUG_ON((i == ARRAY_SIZE(gpu_cvb_dvfs_table)) || ret);
+
+       /* Init core thermal profile */
+       tegra_dvfs_rail_init_vmin_thermal_profile(vdd_core_therm_trips_table,
+               vdd_core_therm_floors_table, &tegra12_dvfs_rail_vdd_core, NULL);
 
        /* Init rail structures and dependencies */
        tegra_dvfs_init_rails(tegra12_dvfs_rails,
@@ -675,21 +956,19 @@ void __init tegra12x_init_dvfs(void)
 
        /* Search core dvfs table for speedo/process matching entries and
           initialize dvfs-ed clocks */
-       for (i = 0; i <  ARRAY_SIZE(core_dvfs_table); i++) {
-               struct dvfs *d = &core_dvfs_table[i];
-               if (!match_dvfs_one(d, soc_speedo_id, core_process_id))
-                       continue;
-               init_dvfs_one(d, core_nominal_mv_index);
+       if (!tegra_platform_is_linsim()) {
+               for (i = 0; i <  ARRAY_SIZE(core_dvfs_table); i++) {
+                       struct dvfs *d = &core_dvfs_table[i];
+                       if (!match_dvfs_one(d->clk_name, d->speedo_id,
+                               d->process_id, soc_speedo_id, core_process_id))
+                               continue;
+                       init_dvfs_one(d, core_nominal_mv_index);
+               }
        }
 
-       /* Search gpu dvfs table for speedo/process matching entries and
-          initialize dvfs-ed clocks */
-       for (i = 0; i <  ARRAY_SIZE(gpu_dvfs_table); i++) {
-               struct dvfs *d = &gpu_dvfs_table[i];
-               if (!match_dvfs_one(d, soc_speedo_id, core_process_id))
-                       continue;
-               init_dvfs_one(d, gpu_nominal_mv_index);
-       }
+       /* Initialize matching gpu dvfs entry already found when nominal
+          voltage was determined */
+       init_dvfs_one(&gpu_dvfs, gpu_max_freq_index);
 
        /* Initialize matching cpu dvfs entry already found when nominal
           voltage was determined */
@@ -711,7 +990,7 @@ void __init tegra12x_init_dvfs(void)
                tegra_dvfs_core_disabled ? "disabled" : "enabled");
        pr_info("tegra dvfs: VDD_GPU nominal %dmV, scaling %s\n",
                tegra12_dvfs_rail_vdd_gpu.nominal_millivolts,
-               tegra_dvfs_core_disabled ? "disabled" : "enabled");
+               tegra_dvfs_gpu_disabled ? "disabled" : "enabled");
 }
 
 int tegra_dvfs_rail_disable_prepare(struct dvfs_rail *rail)
@@ -724,27 +1003,11 @@ int tegra_dvfs_rail_post_enable(struct dvfs_rail *rail)
        return 0;
 }
 
-/*
- * sysfs and dvfs interfaces to cap tegra core domains frequencies
- */
-static DEFINE_MUTEX(core_cap_lock);
-
-struct core_cap {
-       int refcnt;
-       int level;
-};
-static struct core_cap core_buses_cap;
-static struct core_cap kdvfs_core_cap;
-static struct core_cap user_core_cap;
-
+/* Core voltage and bus cap object and tables */
 static struct kobject *cap_kobj;
+static struct kobject *gpu_kobj;
 
-/* Arranged in order required for enabling/lowering the cap */
-static struct {
-       const char *cap_name;
-       struct clk *cap_clk;
-       unsigned long freqs[MAX_DVFS_FREQS];
-} core_cap_table[] = {
+static struct core_dvfs_cap_table tegra12_core_cap_table[] = {
 #ifdef CONFIG_TEGRA_DUAL_CBUS
        { .cap_name = "cap.c2bus" },
        { .cap_name = "cap.c3bus" },
@@ -753,222 +1016,86 @@ static struct {
 #endif
        { .cap_name = "cap.sclk" },
        { .cap_name = "cap.emc" },
+       { .cap_name = "cap.host1x" },
 };
 
+static struct core_bus_limit_table tegra12_gpu_cap_syfs = {
+       .limit_clk_name = "cap.profile.gbus",
+       .refcnt_attr = {.attr = {.name = "gpu_cap_state", .mode = 0644} },
+       .level_attr  = {.attr = {.name = "gpu_cap_rate", .mode = 0644} },
+       .pm_qos_class = PM_QOS_GPU_FREQ_MAX,
+};
 
-static void core_cap_level_set(int level)
-{
-       int i, j;
-
-       for (j = 0; j < ARRAY_SIZE(core_millivolts); j++) {
-               int v = core_millivolts[j];
-               if ((v == 0) || (level < v))
-                       break;
-       }
-       j = (j == 0) ? 0 : j - 1;
-       level = core_millivolts[j];
-
-       if (level < core_buses_cap.level) {
-               for (i = 0; i < ARRAY_SIZE(core_cap_table); i++)
-                       if (core_cap_table[i].cap_clk)
-                               clk_set_rate(core_cap_table[i].cap_clk,
-                                            core_cap_table[i].freqs[j]);
-       } else if (level > core_buses_cap.level) {
-               for (i = ARRAY_SIZE(core_cap_table) - 1; i >= 0; i--)
-                       if (core_cap_table[i].cap_clk)
-                               clk_set_rate(core_cap_table[i].cap_clk,
-                                            core_cap_table[i].freqs[j]);
-       }
-       core_buses_cap.level = level;
-}
-
-static void core_cap_update(void)
-{
-       int new_level = tegra12_dvfs_rail_vdd_core.max_millivolts;
-
-       if (kdvfs_core_cap.refcnt)
-               new_level = min(new_level, kdvfs_core_cap.level);
-       if (user_core_cap.refcnt)
-               new_level = min(new_level, user_core_cap.level);
-
-       if (core_buses_cap.level != new_level)
-               core_cap_level_set(new_level);
-}
-
-static void core_cap_enable(bool enable)
-{
-       if (enable)
-               core_buses_cap.refcnt++;
-       else if (core_buses_cap.refcnt)
-               core_buses_cap.refcnt--;
+static struct core_bus_limit_table tegra12_gpu_floor_sysfs = {
+       .limit_clk_name = "floor.profile.gbus",
+       .refcnt_attr = {.attr = {.name = "gpu_floor_state", .mode = 0644} },
+       .level_attr  = {.attr = {.name = "gpu_floor_rate", .mode = 0644} },
+       .pm_qos_class = PM_QOS_GPU_FREQ_MIN,
+};
 
-       core_cap_update();
-}
+static struct core_bus_rates_table tegra12_gpu_rates_sysfs = {
+       .bus_clk_name = "gbus",
+       .rate_attr = {.attr = {.name = "gpu_rate", .mode = 0444} },
+       .available_rates_attr = {
+               .attr = {.name = "gpu_available_rates", .mode = 0444} },
+};
 
-static ssize_t
-core_cap_state_show(struct kobject *kobj, struct kobj_attribute *attr,
-                   char *buf)
-{
-       return sprintf(buf, "%d (%d)\n", core_buses_cap.refcnt ? 1 : 0,
-                       user_core_cap.refcnt ? 1 : 0);
-}
-static ssize_t
-core_cap_state_store(struct kobject *kobj, struct kobj_attribute *attr,
-                    const char *buf, size_t count)
+static int __init tegra12_dvfs_init_core_cap(void)
 {
-       int state;
-
-       if (sscanf(buf, "%d", &state) != 1)
-               return -1;
-
-       mutex_lock(&core_cap_lock);
+       int ret;
 
-       if (state) {
-               user_core_cap.refcnt++;
-               if (user_core_cap.refcnt == 1)
-                       core_cap_enable(true);
-       } else if (user_core_cap.refcnt) {
-               user_core_cap.refcnt--;
-               if (user_core_cap.refcnt == 0)
-                       core_cap_enable(false);
+       cap_kobj = kobject_create_and_add("tegra_cap", kernel_kobj);
+       if (!cap_kobj) {
+               pr_err("tegra12_dvfs: failed to create sysfs cap object\n");
+               return 0;
        }
 
-       mutex_unlock(&core_cap_lock);
-       return count;
-}
-
-static ssize_t
-core_cap_level_show(struct kobject *kobj, struct kobj_attribute *attr,
-                   char *buf)
-{
-       return sprintf(buf, "%d (%d)\n", core_buses_cap.level,
-                       user_core_cap.level);
-}
-static ssize_t
-core_cap_level_store(struct kobject *kobj, struct kobj_attribute *attr,
-                    const char *buf, size_t count)
-{
-       int level;
+       ret = tegra_init_core_cap(
+               tegra12_core_cap_table, ARRAY_SIZE(tegra12_core_cap_table),
+               core_millivolts, ARRAY_SIZE(core_millivolts), cap_kobj);
 
-       if (sscanf(buf, "%d", &level) != 1)
-               return -1;
-
-       mutex_lock(&core_cap_lock);
-       user_core_cap.level = level;
-       core_cap_update();
-       mutex_unlock(&core_cap_lock);
-       return count;
-}
-
-static struct kobj_attribute cap_state_attribute =
-       __ATTR(core_cap_state, 0644, core_cap_state_show, core_cap_state_store);
-static struct kobj_attribute cap_level_attribute =
-       __ATTR(core_cap_level, 0644, core_cap_level_show, core_cap_level_store);
-
-const struct attribute *cap_attributes[] = {
-       &cap_state_attribute.attr,
-       &cap_level_attribute.attr,
-       NULL,
-};
-
-void tegra_dvfs_core_cap_enable(bool enable)
-{
-       mutex_lock(&core_cap_lock);
-
-       if (enable) {
-               kdvfs_core_cap.refcnt++;
-               if (kdvfs_core_cap.refcnt == 1)
-                       core_cap_enable(true);
-       } else if (kdvfs_core_cap.refcnt) {
-               kdvfs_core_cap.refcnt--;
-               if (kdvfs_core_cap.refcnt == 0)
-                       core_cap_enable(false);
+       if (ret) {
+               pr_err("tegra12_dvfs: failed to init core cap interface (%d)\n",
+                      ret);
+               kobject_del(cap_kobj);
+               return 0;
        }
-       mutex_unlock(&core_cap_lock);
-}
-
-void tegra_dvfs_core_cap_level_set(int level)
-{
-       mutex_lock(&core_cap_lock);
-       kdvfs_core_cap.level = level;
-       core_cap_update();
-       mutex_unlock(&core_cap_lock);
-}
-
-static int __init init_core_cap_one(struct clk *c, unsigned long *freqs)
-{
-       int i, v, next_v = 0;
-       unsigned long rate, next_rate = 0;
-
-       for (i = 0; i < ARRAY_SIZE(core_millivolts); i++) {
-               v = core_millivolts[i];
-               if (v == 0)
-                       break;
-
-               for (;;) {
-                       rate = next_rate;
-                       next_rate = clk_round_rate(c->parent, rate + 1000);
-                       if (IS_ERR_VALUE(next_rate)) {
-                               pr_debug("tegra12_dvfs: failed to round %s rate %lu\n",
-                                        c->name, rate);
-                               return -EINVAL;
-                       }
-                       if (rate == next_rate)
-                               break;
-
-                       next_v = tegra_dvfs_predict_millivolts(
-                               c->parent, next_rate);
-                       if (IS_ERR_VALUE(next_v)) {
-                               pr_debug("tegra12_dvfs: failed to predict %s mV for rate %lu\n",
-                                        c->name, next_rate);
-                               return -EINVAL;
-                       }
-                       if (next_v > v)
-                               break;
-               }
+       pr_info("tegra dvfs: tegra sysfs cap interface is initialized\n");
 
-               if (rate == 0) {
-                       rate = next_rate;
-                       pr_warn("tegra12_dvfs: minimum %s rate %lu requires %d mV\n",
-                               c->name, rate, next_v);
-               }
-               freqs[i] = rate;
-               next_rate = rate;
+       gpu_kobj = kobject_create_and_add("tegra_gpu", kernel_kobj);
+       if (!gpu_kobj) {
+               pr_err("tegra12_dvfs: failed to create sysfs gpu object\n");
+               return 0;
        }
-       return 0;
-}
 
-static int __init tegra_dvfs_init_core_cap(void)
-{
-       int i;
-       struct clk *c = NULL;
-
-       core_buses_cap.level = kdvfs_core_cap.level = user_core_cap.level =
-               tegra12_dvfs_rail_vdd_core.max_millivolts;
-
-       for (i = 0; i < ARRAY_SIZE(core_cap_table); i++) {
-               c = tegra_get_clock_by_name(core_cap_table[i].cap_name);
-               if (!c || !c->parent ||
-                   init_core_cap_one(c, core_cap_table[i].freqs)) {
-                       pr_err("tegra12_dvfs: failed to initialize %s table\n",
-                              core_cap_table[i].cap_name);
-                       continue;
-               }
-               core_cap_table[i].cap_clk = c;
+       ret = tegra_init_shared_bus_cap(&tegra12_gpu_cap_syfs,
+                                       1, gpu_kobj);
+       if (ret) {
+               pr_err("tegra12_dvfs: failed to init gpu cap interface (%d)\n",
+                      ret);
+               kobject_del(gpu_kobj);
+               return 0;
        }
 
-       cap_kobj = kobject_create_and_add("tegra_cap", kernel_kobj);
-       if (!cap_kobj) {
-               pr_err("tegra12_dvfs: failed to create sysfs cap object\n");
+       ret = tegra_init_shared_bus_floor(&tegra12_gpu_floor_sysfs,
+                                         1, gpu_kobj);
+       if (ret) {
+               pr_err("tegra12_dvfs: failed to init gpu floor interface (%d)\n",
+                      ret);
+               kobject_del(gpu_kobj);
                return 0;
        }
 
-       if (sysfs_create_files(cap_kobj, cap_attributes)) {
-               pr_err("tegra12_dvfs: failed to create sysfs cap interface\n");
+       ret = tegra_init_sysfs_shared_bus_rate(&tegra12_gpu_rates_sysfs,
+                                              1, gpu_kobj);
+       if (ret) {
+               pr_err("tegra12_dvfs: failed to init gpu rates interface (%d)\n",
+                      ret);
+               kobject_del(gpu_kobj);
                return 0;
        }
-       pr_info("tegra dvfs: tegra sysfs cap interface is initialized\n");
+       pr_info("tegra dvfs: tegra sysfs gpu interface is initialized\n");
 
        return 0;
 }
-late_initcall(tegra_dvfs_init_core_cap);
+late_initcall(tegra12_dvfs_init_core_cap);