summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/os/linux/clk.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/os/linux/clk.c')
-rw-r--r--drivers/gpu/nvgpu/os/linux/clk.c118
1 files changed, 118 insertions, 0 deletions
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}