summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/os/linux/clk.c
diff options
context:
space:
mode:
authorddutta <ddutta@nvidia.com>2018-09-14 01:18:48 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2018-09-20 13:50:02 -0400
commit1c7258411da89aea5279e9a8d117479928f8bf64 (patch)
tree854c2a248bf7b88141ecb3f27e804fa8065a0983 /drivers/gpu/nvgpu/os/linux/clk.c
parentfeefb7046a88311d88a37ad2cc934ec7b9a9c28f (diff)
gpu: nvgpu: expose linux clock controls via HAL
Expose the linux specific clock implementations via the HAL interface to allow nvgpu to use the controls globally. This patch does the following. 1) Implement a new ops interface and a corresponding linux specific implementation for allowing nvgpu to iterate through a list of available clock frequencies via nvgpu_linux_clk_get_f_points(). 2) Implement nvgpu_linux_clk_get_range(). Bug 2061372 Change-Id: I7ce9a999dbdcd9fafcc84301af148545f6ca97a9 Signed-off-by: Debarshi Dutta <ddutta@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1774280 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
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}