diff options
Diffstat (limited to 'drivers/gpu/nvgpu/gp106/therm_gp106.c')
-rw-r--r-- | drivers/gpu/nvgpu/gp106/therm_gp106.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gp106/therm_gp106.c b/drivers/gpu/nvgpu/gp106/therm_gp106.c new file mode 100644 index 00000000..7bdf0b9e --- /dev/null +++ b/drivers/gpu/nvgpu/gp106/therm_gp106.c | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #include "therm_gp106.h" | ||
15 | #include <linux/debugfs.h> | ||
16 | #include "hw_therm_gp106.h" | ||
17 | |||
18 | static void gp106_get_internal_sensor_limits(s32 *max_24_8, s32 *min_24_8) | ||
19 | { | ||
20 | *max_24_8 = (0x87 << 8); | ||
21 | *min_24_8 = ((-216) << 8); | ||
22 | } | ||
23 | |||
24 | static int gp106_get_internal_sensor_curr_temp(struct gk20a *g, u32 *temp_f24_8) | ||
25 | { | ||
26 | int err = 0; | ||
27 | u32 readval; | ||
28 | |||
29 | readval = gk20a_readl(g, therm_temp_sensor_tsense_r()); | ||
30 | |||
31 | if (!(therm_temp_sensor_tsense_state_v(readval) & | ||
32 | therm_temp_sensor_tsense_state_valid_v())) { | ||
33 | gk20a_err(dev_from_gk20a(g), | ||
34 | "Attempt to read temperature while sensor is OFF!\n"); | ||
35 | err = -EINVAL; | ||
36 | } else if (therm_temp_sensor_tsense_state_v(readval) & | ||
37 | therm_temp_sensor_tsense_state_shadow_v()) { | ||
38 | gk20a_err(dev_from_gk20a(g), | ||
39 | "Reading temperature from SHADOWed sensor!\n"); | ||
40 | } | ||
41 | |||
42 | // Convert from F9.5 -> F27.5 -> F24.8. | ||
43 | readval &= therm_temp_sensor_tsense_fixed_point_m(); | ||
44 | |||
45 | *temp_f24_8 = readval; | ||
46 | |||
47 | return err; | ||
48 | } | ||
49 | |||
50 | #ifdef CONFIG_DEBUG_FS | ||
51 | static int therm_get_internal_sensor_curr_temp(void *data, u64 *val) | ||
52 | { | ||
53 | struct gk20a *g = (struct gk20a *)data; | ||
54 | u32 readval; | ||
55 | int err; | ||
56 | |||
57 | err = gp106_get_internal_sensor_curr_temp(g, &readval); | ||
58 | if (!err) | ||
59 | *val = readval; | ||
60 | |||
61 | return err; | ||
62 | } | ||
63 | DEFINE_SIMPLE_ATTRIBUTE(therm_ctrl_fops, therm_get_internal_sensor_curr_temp, NULL, "%llu\n"); | ||
64 | |||
65 | static void gp106_therm_debugfs_init(struct gk20a *g) { | ||
66 | struct gk20a_platform *platform = dev_get_drvdata(g->dev); | ||
67 | struct dentry *dbgentry; | ||
68 | |||
69 | dbgentry = debugfs_create_file( | ||
70 | "temp", S_IRUGO, platform->debugfs, g, &therm_ctrl_fops); | ||
71 | if (!dbgentry) | ||
72 | gk20a_err(dev_from_gk20a(g), "debugfs entry create failed for therm_curr_temp"); | ||
73 | } | ||
74 | #endif | ||
75 | |||
76 | static int gp106_elcg_init_idle_filters(struct gk20a *g) | ||
77 | { | ||
78 | u32 gate_ctrl, idle_filter; | ||
79 | u32 engine_id; | ||
80 | u32 active_engine_id = 0; | ||
81 | struct fifo_gk20a *f = &g->fifo; | ||
82 | |||
83 | gk20a_dbg_fn(""); | ||
84 | |||
85 | for (engine_id = 0; engine_id < f->num_engines; engine_id++) { | ||
86 | active_engine_id = f->active_engines_list[engine_id]; | ||
87 | gate_ctrl = gk20a_readl(g, therm_gate_ctrl_r(active_engine_id)); | ||
88 | |||
89 | if (tegra_platform_is_linsim()) { | ||
90 | gate_ctrl = set_field(gate_ctrl, | ||
91 | therm_gate_ctrl_eng_delay_after_m(), | ||
92 | therm_gate_ctrl_eng_delay_after_f(4)); | ||
93 | } | ||
94 | |||
95 | gate_ctrl = set_field(gate_ctrl, | ||
96 | therm_gate_ctrl_eng_idle_filt_exp_m(), | ||
97 | therm_gate_ctrl_eng_idle_filt_exp_f(2)); | ||
98 | gate_ctrl = set_field(gate_ctrl, | ||
99 | therm_gate_ctrl_eng_idle_filt_mant_m(), | ||
100 | therm_gate_ctrl_eng_idle_filt_mant_f(1)); | ||
101 | gate_ctrl = set_field(gate_ctrl, | ||
102 | therm_gate_ctrl_eng_delay_before_m(), | ||
103 | therm_gate_ctrl_eng_delay_before_f(0)); | ||
104 | gk20a_writel(g, therm_gate_ctrl_r(active_engine_id), gate_ctrl); | ||
105 | } | ||
106 | |||
107 | /* default fecs_idle_filter to 0 */ | ||
108 | idle_filter = gk20a_readl(g, therm_fecs_idle_filter_r()); | ||
109 | idle_filter &= ~therm_fecs_idle_filter_value_m(); | ||
110 | gk20a_writel(g, therm_fecs_idle_filter_r(), idle_filter); | ||
111 | /* default hubmmu_idle_filter to 0 */ | ||
112 | idle_filter = gk20a_readl(g, therm_hubmmu_idle_filter_r()); | ||
113 | idle_filter &= ~therm_hubmmu_idle_filter_value_m(); | ||
114 | gk20a_writel(g, therm_hubmmu_idle_filter_r(), idle_filter); | ||
115 | |||
116 | gk20a_dbg_fn("done"); | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | void gp106_init_therm_ops(struct gpu_ops *gops) { | ||
121 | #ifdef CONFIG_DEBUG_FS | ||
122 | gops->therm.therm_debugfs_init = gp106_therm_debugfs_init; | ||
123 | #endif | ||
124 | gops->therm.elcg_init_idle_filters = gp106_elcg_init_idle_filters; | ||
125 | gops->therm.get_internal_sensor_curr_temp = gp106_get_internal_sensor_curr_temp; | ||
126 | gops->therm.get_internal_sensor_limits = | ||
127 | gp106_get_internal_sensor_limits; | ||
128 | } | ||