diff options
author | Vijayakumar <vsubbu@nvidia.com> | 2016-09-16 09:26:22 -0400 |
---|---|---|
committer | Deepak Nibade <dnibade@nvidia.com> | 2016-12-27 04:56:50 -0500 |
commit | c7fbd76e7101b7dedc8c0f04437288d1d6b78adc (patch) | |
tree | 6d1ab41af52a481ddeb148307a69113582569edd /drivers/gpu/nvgpu/clk/clk.c | |
parent | 3c351f5bb2d04c1f70c72f3f2fd758bbb340877c (diff) |
gpu: nvgpu: create function to program coreclk
JIRA DNVGPU-123
now a function can be called with GPC2CLK value
It will take care calculating slave clock values
and calling VF inject to program clock
Made programming of boot clock code to use this
newly created function.
Change-Id: I74de7e9d98e379e94175ed2d9745ce3ab6c70691
Signed-off-by: Vijayakumar <vsubbu@nvidia.com>
Reviewed-on: http://git-master/r/1221976
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/1235056
Diffstat (limited to 'drivers/gpu/nvgpu/clk/clk.c')
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk.c | 229 |
1 files changed, 217 insertions, 12 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk.c b/drivers/gpu/nvgpu/clk/clk.c index 7ee4f283..918cd43c 100644 --- a/drivers/gpu/nvgpu/clk/clk.c +++ b/drivers/gpu/nvgpu/clk/clk.c | |||
@@ -104,7 +104,7 @@ done: | |||
104 | return status; | 104 | return status; |
105 | } | 105 | } |
106 | 106 | ||
107 | u32 clk_pmu_vf_inject(struct gk20a *g) | 107 | static u32 clk_pmu_vf_inject(struct gk20a *g, struct set_fll_clk *setfllclk) |
108 | { | 108 | { |
109 | struct pmu_cmd cmd; | 109 | struct pmu_cmd cmd; |
110 | struct pmu_msg msg; | 110 | struct pmu_msg msg; |
@@ -115,35 +115,48 @@ u32 clk_pmu_vf_inject(struct gk20a *g) | |||
115 | struct clkrpc_pmucmdhandler_params handler = {0}; | 115 | struct clkrpc_pmucmdhandler_params handler = {0}; |
116 | struct nv_pmu_clk_vf_change_inject *vfchange; | 116 | struct nv_pmu_clk_vf_change_inject *vfchange; |
117 | 117 | ||
118 | if ((setfllclk->gpc2clkmhz == 0) || (setfllclk->xbar2clkmhz == 0) || | ||
119 | (setfllclk->sys2clkmhz == 0) || (setfllclk->voltuv == 0)) | ||
120 | return -EINVAL; | ||
121 | |||
122 | if ((setfllclk->target_regime_id_gpc > CTRL_CLK_FLL_REGIME_ID_FR) || | ||
123 | (setfllclk->target_regime_id_sys > CTRL_CLK_FLL_REGIME_ID_FR) || | ||
124 | (setfllclk->target_regime_id_xbar > CTRL_CLK_FLL_REGIME_ID_FR)) | ||
125 | return -EINVAL; | ||
126 | |||
118 | rpccall.function = NV_PMU_CLK_RPC_ID_CLK_VF_CHANGE_INJECT; | 127 | rpccall.function = NV_PMU_CLK_RPC_ID_CLK_VF_CHANGE_INJECT; |
119 | vfchange = &rpccall.params.clk_vf_change_inject; | 128 | vfchange = &rpccall.params.clk_vf_change_inject; |
120 | vfchange->flags = 0; | 129 | vfchange->flags = 0; |
121 | vfchange->clk_list.num_domains = 3; | 130 | vfchange->clk_list.num_domains = 3; |
122 | vfchange->clk_list.clk_domains[0].clk_domain = CTRL_CLK_DOMAIN_GPC2CLK; | 131 | vfchange->clk_list.clk_domains[0].clk_domain = CTRL_CLK_DOMAIN_GPC2CLK; |
123 | vfchange->clk_list.clk_domains[0].clk_freq_khz = 2581 * 1000; | 132 | vfchange->clk_list.clk_domains[0].clk_freq_khz = |
133 | setfllclk->gpc2clkmhz * 1000; | ||
124 | vfchange->clk_list.clk_domains[0].clk_flags = 0; | 134 | vfchange->clk_list.clk_domains[0].clk_flags = 0; |
125 | vfchange->clk_list.clk_domains[0].current_regime_id = | 135 | vfchange->clk_list.clk_domains[0].current_regime_id = |
126 | CTRL_CLK_FLL_REGIME_ID_FFR; | 136 | setfllclk->current_regime_id_gpc; |
127 | vfchange->clk_list.clk_domains[0].target_regime_id = | 137 | vfchange->clk_list.clk_domains[0].target_regime_id = |
128 | CTRL_CLK_FLL_REGIME_ID_FR; | 138 | setfllclk->target_regime_id_gpc; |
129 | vfchange->clk_list.clk_domains[1].clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK; | 139 | vfchange->clk_list.clk_domains[1].clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK; |
130 | vfchange->clk_list.clk_domains[1].clk_freq_khz = 2505 * 1000; | 140 | vfchange->clk_list.clk_domains[1].clk_freq_khz = |
141 | setfllclk->xbar2clkmhz * 1000; | ||
131 | vfchange->clk_list.clk_domains[1].clk_flags = 0; | 142 | vfchange->clk_list.clk_domains[1].clk_flags = 0; |
132 | vfchange->clk_list.clk_domains[1].current_regime_id = | 143 | vfchange->clk_list.clk_domains[1].current_regime_id = |
133 | CTRL_CLK_FLL_REGIME_ID_FFR; | 144 | setfllclk->current_regime_id_xbar; |
134 | vfchange->clk_list.clk_domains[1].target_regime_id = | 145 | vfchange->clk_list.clk_domains[1].target_regime_id = |
135 | CTRL_CLK_FLL_REGIME_ID_FR; | 146 | setfllclk->target_regime_id_xbar; |
136 | vfchange->clk_list.clk_domains[2].clk_domain = CTRL_CLK_DOMAIN_SYS2CLK; | 147 | vfchange->clk_list.clk_domains[2].clk_domain = CTRL_CLK_DOMAIN_SYS2CLK; |
137 | vfchange->clk_list.clk_domains[2].clk_freq_khz = 2328 * 1000; | 148 | vfchange->clk_list.clk_domains[2].clk_freq_khz = |
149 | setfllclk->sys2clkmhz * 1000; | ||
138 | vfchange->clk_list.clk_domains[2].clk_flags = 0; | 150 | vfchange->clk_list.clk_domains[2].clk_flags = 0; |
139 | vfchange->clk_list.clk_domains[2].current_regime_id = | 151 | vfchange->clk_list.clk_domains[2].current_regime_id = |
140 | CTRL_CLK_FLL_REGIME_ID_FFR; | 152 | setfllclk->current_regime_id_sys; |
141 | vfchange->clk_list.clk_domains[2].target_regime_id = | 153 | vfchange->clk_list.clk_domains[2].target_regime_id = |
142 | CTRL_CLK_FLL_REGIME_ID_FR; | 154 | setfllclk->target_regime_id_sys; |
143 | vfchange->volt_list.num_rails = 1; | 155 | vfchange->volt_list.num_rails = 1; |
144 | vfchange->volt_list.rails[0].volt_domain = CTRL_VOLT_DOMAIN_LOGIC; | 156 | vfchange->volt_list.rails[0].volt_domain = CTRL_VOLT_DOMAIN_LOGIC; |
145 | vfchange->volt_list.rails[0].voltage_uv = 825000; | 157 | vfchange->volt_list.rails[0].voltage_uv = setfllclk->voltuv; |
146 | vfchange->volt_list.rails[0].voltage_min_noise_unaware_uv = 825000; | 158 | vfchange->volt_list.rails[0].voltage_min_noise_unaware_uv = |
159 | setfllclk->voltuv; | ||
147 | 160 | ||
148 | cmd.hdr.unit_id = PMU_UNIT_CLK; | 161 | cmd.hdr.unit_id = PMU_UNIT_CLK; |
149 | cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) + | 162 | cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) + |
@@ -189,6 +202,198 @@ done: | |||
189 | return status; | 202 | return status; |
190 | } | 203 | } |
191 | 204 | ||
205 | static u32 find_regime_id(struct gk20a *g, u32 domain, u16 clkmhz) | ||
206 | { | ||
207 | struct fll_device *pflldev; | ||
208 | u8 j; | ||
209 | struct clk_pmupstate *pclk = &g->clk_pmu; | ||
210 | |||
211 | BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super), | ||
212 | struct fll_device *, pflldev, j) { | ||
213 | if (pflldev->clk_domain == domain) { | ||
214 | if (pflldev->regime_desc.fixed_freq_regime_limit_mhz >= | ||
215 | clkmhz) | ||
216 | return CTRL_CLK_FLL_REGIME_ID_FR; | ||
217 | else | ||
218 | return CTRL_CLK_FLL_REGIME_ID_FFR; | ||
219 | } | ||
220 | } | ||
221 | return CTRL_CLK_FLL_REGIME_ID_INVALID; | ||
222 | } | ||
223 | |||
224 | static int set_regime_id(struct gk20a *g, u32 domain, u32 regimeid) | ||
225 | { | ||
226 | struct fll_device *pflldev; | ||
227 | u8 j; | ||
228 | struct clk_pmupstate *pclk = &g->clk_pmu; | ||
229 | |||
230 | BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super), | ||
231 | struct fll_device *, pflldev, j) { | ||
232 | if (pflldev->clk_domain == domain) { | ||
233 | pflldev->regime_desc.regime_id = regimeid; | ||
234 | return 0; | ||
235 | } | ||
236 | } | ||
237 | return -EINVAL; | ||
238 | } | ||
239 | |||
240 | static int get_regime_id(struct gk20a *g, u32 domain, u32 *regimeid) | ||
241 | { | ||
242 | struct fll_device *pflldev; | ||
243 | u8 j; | ||
244 | struct clk_pmupstate *pclk = &g->clk_pmu; | ||
245 | |||
246 | BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super), | ||
247 | struct fll_device *, pflldev, j) { | ||
248 | if (pflldev->clk_domain == domain) { | ||
249 | *regimeid = pflldev->regime_desc.regime_id; | ||
250 | return 0; | ||
251 | } | ||
252 | } | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | |||
256 | int clk_program_fllclks(struct gk20a *g, struct change_fll_clk *fllclk) | ||
257 | { | ||
258 | int status = -EINVAL; | ||
259 | struct clk_domain *pdomain; | ||
260 | u8 i; | ||
261 | struct clk_pmupstate *pclk = &g->clk_pmu; | ||
262 | u16 clkmhz = 0; | ||
263 | struct clk_domain_3x_master *p3xmaster; | ||
264 | struct clk_domain_3x_slave *p3xslave; | ||
265 | unsigned long slaveidxmask; | ||
266 | struct set_fll_clk setfllclk; | ||
267 | bool foundxbar2clk = false; | ||
268 | bool foundsys2clk = false; | ||
269 | |||
270 | memset(&setfllclk, 0, sizeof(setfllclk)); | ||
271 | if (fllclk->api_clk_domain != CTRL_CLK_DOMAIN_GPC2CLK) | ||
272 | return -EINVAL; | ||
273 | if (fllclk->voltuv == 0) | ||
274 | return -EINVAL; | ||
275 | if (fllclk->clkmhz == 0) | ||
276 | return -EINVAL; | ||
277 | |||
278 | mutex_lock(&pclk->changeclkmutex); | ||
279 | |||
280 | setfllclk.voltuv = fllclk->voltuv; | ||
281 | setfllclk.gpc2clkmhz = fllclk->clkmhz; | ||
282 | |||
283 | BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super), | ||
284 | struct clk_domain *, pdomain, i) { | ||
285 | |||
286 | if (pdomain->api_domain == fllclk->api_clk_domain) { | ||
287 | |||
288 | if (!pdomain->super.implements(g, &pdomain->super, | ||
289 | CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)) { | ||
290 | status = -EINVAL; | ||
291 | goto done; | ||
292 | } | ||
293 | p3xmaster = (struct clk_domain_3x_master *)pdomain; | ||
294 | slaveidxmask = p3xmaster->slave_idxs_mask; | ||
295 | for_each_set_bit(i, &slaveidxmask, 32) { | ||
296 | p3xslave = (struct clk_domain_3x_slave *) | ||
297 | CLK_CLK_DOMAIN_GET(pclk, i); | ||
298 | if ((p3xslave->super.super.super.api_domain != | ||
299 | CTRL_CLK_DOMAIN_XBAR2CLK) && | ||
300 | (p3xslave->super.super.super.api_domain != | ||
301 | CTRL_CLK_DOMAIN_SYS2CLK)) | ||
302 | continue; | ||
303 | clkmhz = 0; | ||
304 | status = p3xslave->clkdomainclkgetslaveclk(g, | ||
305 | pclk, | ||
306 | (struct clk_domain *)p3xslave, | ||
307 | &clkmhz, | ||
308 | fllclk->clkmhz); | ||
309 | if (status) { | ||
310 | status = -EINVAL; | ||
311 | goto done; | ||
312 | } | ||
313 | if (p3xslave->super.super.super.api_domain == | ||
314 | CTRL_CLK_DOMAIN_XBAR2CLK) { | ||
315 | setfllclk.xbar2clkmhz = clkmhz; | ||
316 | foundxbar2clk = true; | ||
317 | } | ||
318 | if (p3xslave->super.super.super.api_domain == | ||
319 | CTRL_CLK_DOMAIN_SYS2CLK) { | ||
320 | setfllclk.sys2clkmhz = clkmhz; | ||
321 | foundsys2clk = true; | ||
322 | } | ||
323 | } | ||
324 | } | ||
325 | } | ||
326 | if (!(foundxbar2clk && foundsys2clk)) { | ||
327 | status = -EINVAL; | ||
328 | goto done; | ||
329 | } | ||
330 | /*set regime ids */ | ||
331 | status = get_regime_id(g, CTRL_CLK_DOMAIN_GPC2CLK, | ||
332 | &setfllclk.current_regime_id_gpc); | ||
333 | if (status) | ||
334 | goto done; | ||
335 | |||
336 | setfllclk.target_regime_id_gpc = find_regime_id(g, | ||
337 | CTRL_CLK_DOMAIN_GPC2CLK, setfllclk.gpc2clkmhz); | ||
338 | |||
339 | status = get_regime_id(g, CTRL_CLK_DOMAIN_SYS2CLK, | ||
340 | &setfllclk.current_regime_id_sys); | ||
341 | if (status) | ||
342 | goto done; | ||
343 | |||
344 | setfllclk.target_regime_id_sys = find_regime_id(g, | ||
345 | CTRL_CLK_DOMAIN_SYS2CLK, setfllclk.sys2clkmhz); | ||
346 | |||
347 | status = get_regime_id(g, CTRL_CLK_DOMAIN_XBAR2CLK, | ||
348 | &setfllclk.current_regime_id_xbar); | ||
349 | if (status) | ||
350 | goto done; | ||
351 | |||
352 | setfllclk.target_regime_id_xbar = find_regime_id(g, | ||
353 | CTRL_CLK_DOMAIN_XBAR2CLK, setfllclk.xbar2clkmhz); | ||
354 | |||
355 | status = clk_pmu_vf_inject(g, &setfllclk); | ||
356 | |||
357 | if (status) | ||
358 | gk20a_err(dev_from_gk20a(g), | ||
359 | "vf inject to change clk failed"); | ||
360 | |||
361 | /* save regime ids */ | ||
362 | status = set_regime_id(g, CTRL_CLK_DOMAIN_XBAR2CLK, | ||
363 | setfllclk.target_regime_id_xbar); | ||
364 | if (status) | ||
365 | goto done; | ||
366 | |||
367 | status = set_regime_id(g, CTRL_CLK_DOMAIN_GPC2CLK, | ||
368 | setfllclk.target_regime_id_gpc); | ||
369 | if (status) | ||
370 | goto done; | ||
371 | |||
372 | status = set_regime_id(g, CTRL_CLK_DOMAIN_SYS2CLK, | ||
373 | setfllclk.target_regime_id_sys); | ||
374 | if (status) | ||
375 | goto done; | ||
376 | done: | ||
377 | mutex_unlock(&pclk->changeclkmutex); | ||
378 | return status; | ||
379 | } | ||
380 | |||
381 | int clk_set_boot_fll_clk(struct gk20a *g) | ||
382 | { | ||
383 | int status; | ||
384 | struct change_fll_clk bootfllclk; | ||
385 | |||
386 | mutex_init(&g->clk_pmu.changeclkmutex); | ||
387 | |||
388 | bootfllclk.api_clk_domain = CTRL_CLK_DOMAIN_GPC2CLK; | ||
389 | bootfllclk.clkmhz = 2581; | ||
390 | bootfllclk.voltuv = 825000; | ||
391 | status = clk_program_fllclks(g, &bootfllclk); | ||
392 | if (status) | ||
393 | gk20a_err(dev_from_gk20a(g), "attemp to set boot clk failed"); | ||
394 | return status; | ||
395 | } | ||
396 | |||
192 | u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain) | 397 | u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain) |
193 | { | 398 | { |
194 | u32 status = -EINVAL; | 399 | u32 status = -EINVAL; |