diff options
Diffstat (limited to 'drivers/gpu/nvgpu/os/linux/clk.c')
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/clk.c | 118 |
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 | |||
30 | static unsigned long nvgpu_linux_clk_get_rate(struct gk20a *g, u32 api_domain) | 32 | static 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 | */ | ||
154 | static 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 | |||
200 | static 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 */ | ||
229 | static 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 | |||
145 | static int nvgpu_linux_prepare_enable(struct clk_gk20a *clk) | 260 | static 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 | } |