summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/nvgpu/include/nvgpu/gk20a.h4
-rw-r--r--drivers/gpu/nvgpu/os/linux/clk.c118
-rw-r--r--drivers/gpu/nvgpu/os/linux/platform_gk20a.h3
-rw-r--r--drivers/gpu/nvgpu/os/linux/platform_gp10b_tegra.c26
-rw-r--r--drivers/gpu/nvgpu/os/linux/platform_gv11b_tegra.c6
-rw-r--r--drivers/gpu/nvgpu/os/linux/scale.c1
6 files changed, 158 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/include/nvgpu/gk20a.h b/drivers/gpu/nvgpu/include/nvgpu/gk20a.h
index 8f2881ec..5821f742 100644
--- a/drivers/gpu/nvgpu/include/nvgpu/gk20a.h
+++ b/drivers/gpu/nvgpu/include/nvgpu/gk20a.h
@@ -1086,6 +1086,10 @@ struct gpu_ops {
1086 int (*clk_domain_get_f_points)(struct gk20a *g, 1086 int (*clk_domain_get_f_points)(struct gk20a *g,
1087 u32 clkapidomain, u32 *pfpointscount, 1087 u32 clkapidomain, u32 *pfpointscount,
1088 u16 *pfreqpointsinmhz); 1088 u16 *pfreqpointsinmhz);
1089 int (*clk_get_round_rate)(struct gk20a *g, u32 api_domain,
1090 unsigned long rate_target, unsigned long *rounded_rate);
1091 int (*get_clk_range)(struct gk20a *g, u32 api_domain,
1092 u16 *min_mhz, u16 *max_mhz);
1089 unsigned long (*measure_freq)(struct gk20a *g, u32 api_domain); 1093 unsigned long (*measure_freq)(struct gk20a *g, u32 api_domain);
1090 u32 (*get_rate_cntr)(struct gk20a *g, struct namemap_cfg *c); 1094 u32 (*get_rate_cntr)(struct gk20a *g, struct namemap_cfg *c);
1091 unsigned long (*get_rate)(struct gk20a *g, u32 api_domain); 1095 unsigned long (*get_rate)(struct gk20a *g, u32 api_domain);
diff --git a/drivers/gpu/nvgpu/os/linux/clk.c b/drivers/gpu/nvgpu/os/linux/clk.c
index 414b17c4..cc420994 100644
--- a/drivers/gpu/nvgpu/os/linux/clk.c
+++ b/drivers/gpu/nvgpu/os/linux/clk.c
@@ -27,6 +27,8 @@
27 27
28#include "gk20a/gk20a.h" 28#include "gk20a/gk20a.h"
29 29
30#define HZ_TO_MHZ(x) ((x) / 1000000)
31
30static unsigned long nvgpu_linux_clk_get_rate(struct gk20a *g, u32 api_domain) 32static unsigned long nvgpu_linux_clk_get_rate(struct gk20a *g, u32 api_domain)
31{ 33{
32 struct gk20a_platform *platform = gk20a_get_platform(dev_from_gk20a(g)); 34 struct gk20a_platform *platform = gk20a_get_platform(dev_from_gk20a(g));
@@ -142,6 +144,119 @@ static unsigned long nvgpu_linux_get_maxrate(struct gk20a *g, u32 api_domain)
142 return ret; 144 return ret;
143} 145}
144 146
147/*
148 * This API is used to return a list of supported frequencies by igpu.
149 * Set *num_points as 0 to get the size of the freqs list, returned
150 * by *num_points itself. freqs array must be provided by caller.
151 * If *num_points is non-zero, then freqs array size must atleast
152 * equal *num_points.
153 */
154static int nvgpu_linux_clk_get_f_points(struct gk20a *g,
155 u32 api_domain, u32 *num_points, u16 *freqs)
156{
157 struct device *dev = dev_from_gk20a(g);
158 struct gk20a_platform *platform = gk20a_get_platform(dev);
159 unsigned long *gpu_freq_table;
160 int ret = 0;
161 int num_supported_freq = 0;
162 u32 i;
163
164 switch (api_domain) {
165 case CTRL_CLK_DOMAIN_GPCCLK:
166 ret = platform->get_clk_freqs(dev, &gpu_freq_table,
167 &num_supported_freq);
168
169 if (ret) {
170 return ret;
171 }
172
173 if (num_points == NULL) {
174 return -EINVAL;
175 }
176
177 if (*num_points != 0U) {
178 if (freqs == NULL || (*num_points > (u32)num_supported_freq)) {
179 return -EINVAL;
180 }
181 }
182
183 if (*num_points == 0) {
184 *num_points = num_supported_freq;
185 } else {
186 for (i = 0; i < *num_points; i++) {
187 freqs[i] = HZ_TO_MHZ(gpu_freq_table[i]);
188 }
189 }
190 break;
191 default:
192 nvgpu_err(g, "unknown clock: %u", api_domain);
193 ret = -EINVAL;
194 break;
195 }
196
197 return ret;
198}
199
200static int nvgpu_clk_get_range(struct gk20a *g, u32 api_domain,
201 u16 *min_mhz, u16 *max_mhz)
202{
203 struct device *dev = dev_from_gk20a(g);
204 struct gk20a_platform *platform = gk20a_get_platform(dev);
205 unsigned long *freqs;
206 int num_freqs;
207 int ret;
208
209 switch (api_domain) {
210 case CTRL_CLK_DOMAIN_GPCCLK:
211 ret = platform->get_clk_freqs(dev, &freqs, &num_freqs);
212
213 if (!ret) {
214 *min_mhz = HZ_TO_MHZ(freqs[0]);
215 *max_mhz = HZ_TO_MHZ(freqs[num_freqs - 1]);
216 }
217 break;
218 default:
219 nvgpu_err(g, "unknown clock: %u", api_domain);
220 ret = -EINVAL;
221 break;
222 }
223
224 return ret;
225}
226
227/* rate_target should be passed in as Hz
228 rounded_rate is returned in Hz */
229static int nvgpu_clk_get_round_rate(struct gk20a *g,
230 u32 api_domain, unsigned long rate_target,
231 unsigned long *rounded_rate)
232{
233 struct device *dev = dev_from_gk20a(g);
234 struct gk20a_platform *platform = gk20a_get_platform(dev);
235 unsigned long *freqs;
236 int num_freqs;
237 int i, ret = 0;
238
239 switch (api_domain) {
240 case CTRL_CLK_DOMAIN_GPCCLK:
241 ret = platform->get_clk_freqs(dev, &freqs, &num_freqs);
242
243 for (i = 0; i < num_freqs; ++i) {
244 if (freqs[i] >= rate_target) {
245 *rounded_rate = freqs[i];
246 return 0;
247 }
248 }
249 *rounded_rate = freqs[num_freqs - 1];
250 break;
251 default:
252 nvgpu_err(g, "unknown clock: %u", api_domain);
253 ret = -EINVAL;
254 break;
255 }
256
257 return ret;
258}
259
145static int nvgpu_linux_prepare_enable(struct clk_gk20a *clk) 260static int nvgpu_linux_prepare_enable(struct clk_gk20a *clk)
146{ 261{
147 return clk_prepare_enable(clk->tegra_clk); 262 return clk_prepare_enable(clk->tegra_clk);
@@ -162,4 +277,7 @@ void nvgpu_linux_init_clk_support(struct gk20a *g)
162 g->ops.clk.get_maxrate = nvgpu_linux_get_maxrate; 277 g->ops.clk.get_maxrate = nvgpu_linux_get_maxrate;
163 g->ops.clk.prepare_enable = nvgpu_linux_prepare_enable; 278 g->ops.clk.prepare_enable = nvgpu_linux_prepare_enable;
164 g->ops.clk.disable_unprepare = nvgpu_linux_disable_unprepare; 279 g->ops.clk.disable_unprepare = nvgpu_linux_disable_unprepare;
280 g->ops.clk.clk_domain_get_f_points = nvgpu_linux_clk_get_f_points;
281 g->ops.clk.get_clk_range = nvgpu_clk_get_range;
282 g->ops.clk.clk_get_round_rate = nvgpu_clk_get_round_rate;
165} 283}
diff --git a/drivers/gpu/nvgpu/os/linux/platform_gk20a.h b/drivers/gpu/nvgpu/os/linux/platform_gk20a.h
index f3e80b8c..b5beeefe 100644
--- a/drivers/gpu/nvgpu/os/linux/platform_gk20a.h
+++ b/drivers/gpu/nvgpu/os/linux/platform_gk20a.h
@@ -274,6 +274,9 @@ struct gk20a_platform {
274 274
275 /* scaling rate */ 275 /* scaling rate */
276 unsigned long cached_rate; 276 unsigned long cached_rate;
277
278 /* synchronized access to platform->clk_get_freqs */
279 struct nvgpu_mutex clk_get_freq_lock;
277}; 280};
278 281
279static inline struct gk20a_platform *gk20a_get_platform( 282static inline struct gk20a_platform *gk20a_get_platform(
diff --git a/drivers/gpu/nvgpu/os/linux/platform_gp10b_tegra.c b/drivers/gpu/nvgpu/os/linux/platform_gp10b_tegra.c
index c5464d5b..5fdcb05c 100644
--- a/drivers/gpu/nvgpu/os/linux/platform_gp10b_tegra.c
+++ b/drivers/gpu/nvgpu/os/linux/platform_gp10b_tegra.c
@@ -55,6 +55,9 @@
55static unsigned long 55static unsigned long
56gp10b_freq_table[GP10B_MAX_SUPPORTED_FREQS / GP10B_FREQ_SELECT_STEP]; 56gp10b_freq_table[GP10B_MAX_SUPPORTED_FREQS / GP10B_FREQ_SELECT_STEP];
57 57
58static bool freq_table_init_complete;
59static int num_supported_freq;
60
58#define TEGRA_GP10B_BW_PER_FREQ 64 61#define TEGRA_GP10B_BW_PER_FREQ 64
59#define TEGRA_DDR4_BW_PER_FREQ 16 62#define TEGRA_DDR4_BW_PER_FREQ 16
60 63
@@ -166,6 +169,8 @@ static int gp10b_tegra_probe(struct device *dev)
166 gp10b_tegra_get_clocks(dev); 169 gp10b_tegra_get_clocks(dev);
167 nvgpu_linux_init_clk_support(platform->g); 170 nvgpu_linux_init_clk_support(platform->g);
168 171
172 nvgpu_mutex_init(&platform->clk_get_freq_lock);
173
169 return 0; 174 return 0;
170} 175}
171 176
@@ -176,6 +181,8 @@ static int gp10b_tegra_late_probe(struct device *dev)
176 181
177static int gp10b_tegra_remove(struct device *dev) 182static int gp10b_tegra_remove(struct device *dev)
178{ 183{
184 struct gk20a_platform *platform = gk20a_get_platform(dev);
185
179 /* deinitialise tegra specific scaling quirks */ 186 /* deinitialise tegra specific scaling quirks */
180 gp10b_tegra_scale_exit(dev); 187 gp10b_tegra_scale_exit(dev);
181 188
@@ -183,6 +190,8 @@ static int gp10b_tegra_remove(struct device *dev)
183 nvgpu_free_nvhost_dev(get_gk20a(dev)); 190 nvgpu_free_nvhost_dev(get_gk20a(dev));
184#endif 191#endif
185 192
193 nvgpu_mutex_destroy(&platform->clk_get_freq_lock);
194
186 return 0; 195 return 0;
187} 196}
188 197
@@ -342,6 +351,18 @@ int gp10b_clk_get_freqs(struct device *dev,
342 int sel_freq_cnt; 351 int sel_freq_cnt;
343 unsigned long loc_freq_table[GP10B_MAX_SUPPORTED_FREQS]; 352 unsigned long loc_freq_table[GP10B_MAX_SUPPORTED_FREQS];
344 353
354 nvgpu_mutex_acquire(&platform->clk_get_freq_lock);
355
356 if (freq_table_init_complete) {
357
358 *freqs = gp10b_freq_table;
359 *num_freqs = num_supported_freq;
360
361 nvgpu_mutex_release(&platform->clk_get_freq_lock);
362
363 return 0;
364 }
365
345 max_rate = clk_round_rate(platform->clk[0], (UINT_MAX - 1)); 366 max_rate = clk_round_rate(platform->clk[0], (UINT_MAX - 1));
346 367
347 /* 368 /*
@@ -392,10 +413,15 @@ int gp10b_clk_get_freqs(struct device *dev,
392 /* Fill freq table */ 413 /* Fill freq table */
393 *freqs = gp10b_freq_table; 414 *freqs = gp10b_freq_table;
394 *num_freqs = sel_freq_cnt; 415 *num_freqs = sel_freq_cnt;
416 num_supported_freq = sel_freq_cnt;
417
418 freq_table_init_complete = true;
395 419
396 nvgpu_log_info(g, "min rate: %ld max rate: %ld num_of_freq %d\n", 420 nvgpu_log_info(g, "min rate: %ld max rate: %ld num_of_freq %d\n",
397 gp10b_freq_table[0], max_rate, *num_freqs); 421 gp10b_freq_table[0], max_rate, *num_freqs);
398 422
423 nvgpu_mutex_release(&platform->clk_get_freq_lock);
424
399 return 0; 425 return 0;
400} 426}
401 427
diff --git a/drivers/gpu/nvgpu/os/linux/platform_gv11b_tegra.c b/drivers/gpu/nvgpu/os/linux/platform_gv11b_tegra.c
index 1b4a5456..b055eb6e 100644
--- a/drivers/gpu/nvgpu/os/linux/platform_gv11b_tegra.c
+++ b/drivers/gpu/nvgpu/os/linux/platform_gv11b_tegra.c
@@ -97,6 +97,8 @@ static int gv11b_tegra_probe(struct device *dev)
97 gp10b_tegra_get_clocks(dev); 97 gp10b_tegra_get_clocks(dev);
98 nvgpu_linux_init_clk_support(platform->g); 98 nvgpu_linux_init_clk_support(platform->g);
99 99
100 nvgpu_mutex_init(&platform->clk_get_freq_lock);
101
100 return 0; 102 return 0;
101} 103}
102 104
@@ -108,12 +110,16 @@ static int gv11b_tegra_late_probe(struct device *dev)
108 110
109static int gv11b_tegra_remove(struct device *dev) 111static int gv11b_tegra_remove(struct device *dev)
110{ 112{
113 struct gk20a_platform *platform = gk20a_get_platform(dev);
114
111 gv11b_tegra_scale_exit(dev); 115 gv11b_tegra_scale_exit(dev);
112 116
113#ifdef CONFIG_TEGRA_GK20A_NVHOST 117#ifdef CONFIG_TEGRA_GK20A_NVHOST
114 nvgpu_free_nvhost_dev(get_gk20a(dev)); 118 nvgpu_free_nvhost_dev(get_gk20a(dev));
115#endif 119#endif
116 120
121 nvgpu_mutex_destroy(&platform->clk_get_freq_lock);
122
117 return 0; 123 return 0;
118} 124}
119 125
diff --git a/drivers/gpu/nvgpu/os/linux/scale.c b/drivers/gpu/nvgpu/os/linux/scale.c
index 72ed94bd..ecc8207a 100644
--- a/drivers/gpu/nvgpu/os/linux/scale.c
+++ b/drivers/gpu/nvgpu/os/linux/scale.c
@@ -124,6 +124,7 @@ static int gk20a_scale_make_freq_table(struct gk20a_scale_profile *profile)
124 /* get gpu frequency table */ 124 /* get gpu frequency table */
125 err = platform->get_clk_freqs(profile->dev, &freqs, 125 err = platform->get_clk_freqs(profile->dev, &freqs,
126 &num_freqs); 126 &num_freqs);
127
127 if (err) 128 if (err)
128 return -ENOSYS; 129 return -ENOSYS;
129 } else 130 } else