diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu-t18x b/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
index aaf029313..eb9d59773 100644
--- a/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
+++ b/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
@@ -41,7 +41,8 @@ nvgpu-y += \
$(nvgpu-t18x)/perf/perf.o \
$(nvgpu-t18x)/clk/clk.o \
$(nvgpu-t18x)/gp106/clk_gp106.o \
- $(nvgpu-t18x)/gp106/gp106_gating_reglist.o
+ $(nvgpu-t18x)/gp106/gp106_gating_reglist.o \
+ $(nvgpu-t18x)/gp106/therm_gp106.o
nvgpu-$(CONFIG_TEGRA_GK20A) += $(nvgpu-t18x)/gp10b/platform_gp10b_tegra.o
diff --git a/drivers/gpu/nvgpu/gp106/hal_gp106.c b/drivers/gpu/nvgpu/gp106/hal_gp106.c
index eb5c4eba0..d07da835e 100644
--- a/drivers/gpu/nvgpu/gp106/hal_gp106.c
+++ b/drivers/gpu/nvgpu/gp106/hal_gp106.c
@@ -28,7 +28,7 @@
#include "gp106/fifo_gp106.h"
#include "gp10b/regops_gp10b.h"
#include "gp10b/cde_gp10b.h"
-#include "gp10b/therm_gp10b.h"
+#include "gp106/therm_gp106.h"
#include "gm206/bios_gm206.h"
@@ -209,6 +209,7 @@ int gp106_init_hal(struct gk20a *g)
gk20a_init_css_ops(gops);
#endif
gm206_init_bios(gops);
+ gp106_init_therm_ops(gops);
gops->name = "gp10x";
gops->get_litter_value = gp106_get_litter_value;
gops->chip_init_gpu_characteristics = gk20a_init_gpu_characteristics;
diff --git a/drivers/gpu/nvgpu/gp106/hw_therm_gp106.h b/drivers/gpu/nvgpu/gp106/hw_therm_gp106.h
new file mode 100644
index 000000000..ecc509801
--- /dev/null
+++ b/drivers/gpu/nvgpu/gp106/hw_therm_gp106.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+/*
+ * Function naming determines intended use:
+ *
+ * _r(void) : Returns the offset for register .
+ *
+ * _o(void) : Returns the offset for element .
+ *
+ * _w(void) : Returns the word offset for word (4 byte) element .
+ *
+ * __s(void) : Returns size of field of register in bits.
+ *
+ * __f(u32 v) : Returns a value based on 'v' which has been shifted
+ * and masked to place it at field of register . This value
+ * can be |'d with others to produce a full register value for
+ * register .
+ *
+ * __m(void) : Returns a mask for field of register . This
+ * value can be ~'d and then &'d to clear the value of field for
+ * register .
+ *
+ * ___f(void) : Returns the constant value after being shifted
+ * to place it at field of register . This value can be |'d
+ * with others to produce a full register value for .
+ *
+ * __v(u32 r) : Returns the value of field from a full register
+ * value 'r' after being shifted to place its LSB at bit 0.
+ * This value is suitable for direct comparison with other unshifted
+ * values appropriate for use in field of register .
+ *
+ * ___v(void) : Returns the constant value for defined for
+ * field of register . This value is suitable for direct
+ * comparison with unshifted values appropriate for use in field
+ * of register .
+ */
+#ifndef _hw_therm_gp106_h_
+#define _hw_therm_gp106_h_
+
+static inline u32 therm_temp_sensor_tsense_r(void)
+{
+ return 0x00020460;
+}
+static inline u32 therm_temp_sensor_tsense_fixed_point_f(u32 v)
+{
+ return (v & 0x3fff) << 3;
+}
+static inline u32 therm_temp_sensor_tsense_fixed_point_m(void)
+{
+ return 0x3fff << 3;
+}
+static inline u32 therm_temp_sensor_tsense_fixed_point_v(u32 r)
+{
+ return (r >> 3) & 0x3fff;
+}
+static inline u32 therm_temp_sensor_tsense_fixed_point_min_v(void)
+{
+ return 0x00003b00;
+}
+static inline u32 therm_temp_sensor_tsense_fixed_point_max_v(void)
+{
+ return 0x000010e0;
+}
+static inline u32 therm_temp_sensor_tsense_state_f(u32 v)
+{
+ return (v & 0x3) << 29;
+}
+static inline u32 therm_temp_sensor_tsense_state_m(void)
+{
+ return 0x3 << 29;
+}
+static inline u32 therm_temp_sensor_tsense_state_v(u32 r)
+{
+ return (r >> 29) & 0x3;
+}
+static inline u32 therm_temp_sensor_tsense_state_valid_v(void)
+{
+ return 0x00000001;
+}
+static inline u32 therm_temp_sensor_tsense_state_shadow_v(void)
+{
+ return 0x00000002;
+}
+#endif
diff --git a/drivers/gpu/nvgpu/gp106/therm_gp106.c b/drivers/gpu/nvgpu/gp106/therm_gp106.c
new file mode 100644
index 000000000..153e953dd
--- /dev/null
+++ b/drivers/gpu/nvgpu/gp106/therm_gp106.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include "therm_gp106.h"
+#include
+#include "hw_therm_gp106.h"
+
+#ifdef CONFIG_DEBUG_FS
+static int therm_get_internal_sensor_curr_temp(void *data, u64 *val)
+{
+ struct gk20a *g = (struct gk20a *)data;
+ int err = 0;
+ u32 readval;
+
+ readval = gk20a_readl(g, therm_temp_sensor_tsense_r());
+
+ if (!(therm_temp_sensor_tsense_state_v(readval) &
+ therm_temp_sensor_tsense_state_valid_v())) {
+ gk20a_err(dev_from_gk20a(g),
+ "Attempt to read temperature while sensor is OFF!\n");
+ err = -EINVAL;
+ } else if (therm_temp_sensor_tsense_state_v(readval) &
+ therm_temp_sensor_tsense_state_shadow_v()) {
+ gk20a_err(dev_from_gk20a(g),
+ "Reading temperature from SHADOWed sensor!\n");
+ }
+
+ // Convert from F9.5 -> F27.5 -> F24.8.
+ readval &= therm_temp_sensor_tsense_fixed_point_m();
+
+ *val = readval;
+
+ return err;
+}
+DEFINE_SIMPLE_ATTRIBUTE(therm_ctrl_fops, therm_get_internal_sensor_curr_temp, NULL, "%llu\n");
+
+static void gp106_therm_debugfs_init(struct gk20a *g) {
+ struct gk20a_platform *platform = dev_get_drvdata(g->dev);
+ struct dentry *dbgentry;
+
+ dbgentry = debugfs_create_file(
+ "temp", S_IRUGO, platform->debugfs, g, &therm_ctrl_fops);
+ if (!dbgentry)
+ gk20a_err(dev_from_gk20a(g), "debugfs entry create failed for therm_curr_temp");
+}
+#endif
+
+void gp106_init_therm_ops(struct gpu_ops *gops) {
+#ifdef CONFIG_DEBUG_FS
+ gops->therm.therm_debugfs_init = gp106_therm_debugfs_init;
+#endif
+}
diff --git a/drivers/gpu/nvgpu/gp106/therm_gp106.h b/drivers/gpu/nvgpu/gp106/therm_gp106.h
new file mode 100644
index 000000000..6db17c477
--- /dev/null
+++ b/drivers/gpu/nvgpu/gp106/therm_gp106.h
@@ -0,0 +1,22 @@
+/*
+ * general thermal control structures & definitions
+ *
+ * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef NVGPU_THERM_GP106_H
+#define NVGPU_THERM_GP106_H
+
+#include "gk20a/gk20a.h"
+
+void gp106_init_therm_ops(struct gpu_ops *gops);
+#endif