diff options
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/clk_gk20a.h | 22 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gm20b/clk_gm20b.c | 326 |
2 files changed, 340 insertions, 8 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/clk_gk20a.h b/drivers/gpu/nvgpu/gk20a/clk_gk20a.h index 274194be..ed54ba7a 100644 --- a/drivers/gpu/nvgpu/gk20a/clk_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/clk_gk20a.h | |||
@@ -29,6 +29,21 @@ enum { | |||
29 | GK20A_GPC_PLL = 0, | 29 | GK20A_GPC_PLL = 0, |
30 | }; | 30 | }; |
31 | 31 | ||
32 | enum gpc_pll_mode { | ||
33 | GPC_PLL_MODE_F = 0, | ||
34 | GPC_PLL_MODE_DVFS, | ||
35 | }; | ||
36 | |||
37 | struct na_dvfs { | ||
38 | u32 n_int; | ||
39 | u32 sdm_din; | ||
40 | int dfs_coeff; | ||
41 | int dfs_det_max; | ||
42 | int dfs_ext_cal; | ||
43 | int uv_cal; | ||
44 | int mv; | ||
45 | }; | ||
46 | |||
32 | struct pll { | 47 | struct pll { |
33 | u32 id; | 48 | u32 id; |
34 | u32 clk_in; /* KHz */ | 49 | u32 clk_in; /* KHz */ |
@@ -37,6 +52,8 @@ struct pll { | |||
37 | u32 PL; | 52 | u32 PL; |
38 | u32 freq; /* KHz */ | 53 | u32 freq; /* KHz */ |
39 | bool enabled; | 54 | bool enabled; |
55 | enum gpc_pll_mode mode; | ||
56 | struct na_dvfs dvfs; | ||
40 | }; | 57 | }; |
41 | 58 | ||
42 | struct pll_parms { | 59 | struct pll_parms { |
@@ -46,6 +63,10 @@ struct pll_parms { | |||
46 | u32 min_M, max_M; | 63 | u32 min_M, max_M; |
47 | u32 min_N, max_N; | 64 | u32 min_N, max_N; |
48 | u32 min_PL, max_PL; | 65 | u32 min_PL, max_PL; |
66 | /* NA mode parameters*/ | ||
67 | int coeff_slope, coeff_offs; /* coeff = slope * V + offs */ | ||
68 | int uvdet_slope, uvdet_offs; /* uV = slope * det + offs */ | ||
69 | u32 vco_ctrl; | ||
49 | }; | 70 | }; |
50 | 71 | ||
51 | struct clk_gk20a { | 72 | struct clk_gk20a { |
@@ -54,6 +75,7 @@ struct clk_gk20a { | |||
54 | struct pll gpc_pll; | 75 | struct pll gpc_pll; |
55 | struct pll gpc_pll_last; | 76 | struct pll gpc_pll_last; |
56 | u32 pll_delay; /* default PLL settle time */ | 77 | u32 pll_delay; /* default PLL settle time */ |
78 | u32 na_pll_delay; /* default PLL settle time in NA mode */ | ||
57 | struct mutex clk_mutex; | 79 | struct mutex clk_mutex; |
58 | bool sw_ready; | 80 | bool sw_ready; |
59 | bool clk_hw_on; | 81 | bool clk_hw_on; |
diff --git a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c index 2e3d96ac..6f7d04dd 100644 --- a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/debugfs.h> | 22 | #include <linux/debugfs.h> |
23 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
24 | #include <linux/clk/tegra.h> | 24 | #include <linux/clk/tegra.h> |
25 | #include <linux/tegra-fuse.h> | ||
25 | 26 | ||
26 | #include "gk20a/gk20a.h" | 27 | #include "gk20a/gk20a.h" |
27 | #include "hw_trim_gm20b.h" | 28 | #include "hw_trim_gm20b.h" |
@@ -29,10 +30,19 @@ | |||
29 | #include "hw_therm_gm20b.h" | 30 | #include "hw_therm_gm20b.h" |
30 | #include "clk_gm20b.h" | 31 | #include "clk_gm20b.h" |
31 | 32 | ||
33 | #define ALLOW_NON_CALIBRATED_NA_MODE 1 | ||
34 | |||
32 | #define gk20a_dbg_clk(fmt, arg...) \ | 35 | #define gk20a_dbg_clk(fmt, arg...) \ |
33 | gk20a_dbg(gpu_dbg_clk, fmt, ##arg) | 36 | gk20a_dbg(gpu_dbg_clk, fmt, ##arg) |
34 | 37 | ||
35 | /* from vbios PLL info table */ | 38 | #define DFS_DET_RANGE 6 /* -2^6 ... 2^6-1 */ |
39 | #define SDM_DIN_RANGE 12 /* -2^12 ... 2^12-1 */ | ||
40 | #define DFS_EXT_CAL_EN BIT(9) | ||
41 | #define DFS_EXT_STROBE BIT(16) | ||
42 | |||
43 | #define BOOT_GPU_UV 1000000 /* gpu rail boot voltage 1.0V */ | ||
44 | #define ADC_SLOPE_UV 10000 /* default ADC detection slope 10mV */ | ||
45 | |||
36 | static struct pll_parms gpc_pll_params = { | 46 | static struct pll_parms gpc_pll_params = { |
37 | 128000, 2600000, /* freq */ | 47 | 128000, 2600000, /* freq */ |
38 | 1300000, 2600000, /* vco */ | 48 | 1300000, 2600000, /* vco */ |
@@ -40,6 +50,7 @@ static struct pll_parms gpc_pll_params = { | |||
40 | 1, 255, /* M */ | 50 | 1, 255, /* M */ |
41 | 8, 255, /* N */ | 51 | 8, 255, /* N */ |
42 | 1, 31, /* PL */ | 52 | 1, 31, /* PL */ |
53 | -58700, 86789, /* DFS_COEFF */ | ||
43 | }; | 54 | }; |
44 | 55 | ||
45 | #ifdef CONFIG_DEBUG_FS | 56 | #ifdef CONFIG_DEBUG_FS |
@@ -218,6 +229,244 @@ found_match: | |||
218 | return 0; | 229 | return 0; |
219 | } | 230 | } |
220 | 231 | ||
232 | /* GPCPLL NA/DVFS mode methods */ | ||
233 | |||
234 | /* | ||
235 | * Read ADC characteristic parmeters from fuses. | ||
236 | * Determine clibration settings. | ||
237 | */ | ||
238 | static int clk_config_calibration_params(struct gk20a *g) | ||
239 | { | ||
240 | int slope, offs; | ||
241 | struct pll_parms *p = &gpc_pll_params; | ||
242 | |||
243 | if (!tegra_fuse_calib_gpcpll_get_adc(&slope, &offs)) { | ||
244 | p->uvdet_slope = slope; | ||
245 | p->uvdet_offs = offs; | ||
246 | } | ||
247 | |||
248 | if (!p->uvdet_slope || !p->uvdet_offs) { | ||
249 | /* | ||
250 | * If ADC conversion slope/offset parameters are not fused | ||
251 | * (non-production config), report error, but allow to use | ||
252 | * boot internal calibration with default slope. | ||
253 | */ | ||
254 | gk20a_err(dev_from_gk20a(g), "ADC coeff are not fused\n"); | ||
255 | return -EINVAL; | ||
256 | } | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * Determine DFS_COEFF for the requested voltage. Always select external | ||
262 | * calibration override equal to the voltage, and set maximum detection | ||
263 | * limit "0" (to make sure that PLL output remains under F/V curve when | ||
264 | * voltage increases). | ||
265 | */ | ||
266 | static void clk_config_dvfs_detection(int mv, struct na_dvfs *d) | ||
267 | { | ||
268 | u32 coeff, coeff_max; | ||
269 | struct pll_parms *p = &gpc_pll_params; | ||
270 | |||
271 | coeff_max = trim_sys_gpcpll_dvfs0_dfs_coeff_v( | ||
272 | trim_sys_gpcpll_dvfs0_dfs_coeff_m()); | ||
273 | coeff = DIV_ROUND_CLOSEST(mv * p->coeff_slope, 1000) + p->coeff_offs; | ||
274 | coeff = DIV_ROUND_CLOSEST(coeff, 1000); | ||
275 | coeff = min(coeff, coeff_max); | ||
276 | d->dfs_coeff = coeff; | ||
277 | |||
278 | d->dfs_ext_cal = DIV_ROUND_CLOSEST(mv * 1000 - p->uvdet_offs, | ||
279 | p->uvdet_slope); | ||
280 | BUG_ON(abs(d->dfs_ext_cal) >= (1 << DFS_DET_RANGE)); | ||
281 | d->uv_cal = p->uvdet_offs + d->dfs_ext_cal * p->uvdet_slope; | ||
282 | d->dfs_det_max = 0; | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | * Solve equation for integer and fractional part of the effective NDIV: | ||
287 | * | ||
288 | * n_eff = n_int + 1/2 + SDM_DIN / 2^(SDM_DIN_RANGE + 1) + | ||
289 | * DVFS_COEFF * DVFS_DET_DELTA / 2^DFS_DET_RANGE | ||
290 | * | ||
291 | * The SDM_DIN LSB is finally shifted out, since it is not accessible by s/w. | ||
292 | */ | ||
293 | static void clk_config_dvfs_ndiv(int mv, u32 n_eff, struct na_dvfs *d) | ||
294 | { | ||
295 | int n, det_delta; | ||
296 | u32 rem, rem_range; | ||
297 | struct pll_parms *p = &gpc_pll_params; | ||
298 | |||
299 | det_delta = (mv * 1000 - d->uv_cal); | ||
300 | det_delta = min(det_delta, d->dfs_det_max * p->uvdet_slope); | ||
301 | det_delta = det_delta * d->dfs_coeff; | ||
302 | det_delta = DIV_ROUND_CLOSEST(det_delta, p->uvdet_slope); | ||
303 | |||
304 | n = (int)(n_eff << DFS_DET_RANGE) - det_delta; | ||
305 | BUG_ON((n < 0) || (n > (p->max_N << DFS_DET_RANGE))); | ||
306 | d->n_int = ((u32)n) >> DFS_DET_RANGE; | ||
307 | |||
308 | rem = ((u32)n) & ((1 << DFS_DET_RANGE) - 1); | ||
309 | rem_range = SDM_DIN_RANGE + 1 - DFS_DET_RANGE; | ||
310 | d->sdm_din = (rem << rem_range) - (1 << SDM_DIN_RANGE); | ||
311 | d->sdm_din = (d->sdm_din >> BITS_PER_BYTE) & 0xff; | ||
312 | } | ||
313 | |||
314 | /* Voltage dependent configuration */ | ||
315 | static void clk_config_dvfs(struct gk20a *g, struct pll *gpll) | ||
316 | { | ||
317 | struct na_dvfs *d = &gpll->dvfs; | ||
318 | |||
319 | d->mv = tegra_dvfs_predict_millivolts_t( | ||
320 | clk_get_parent(g->clk.tegra_clk), | ||
321 | rate_gpc2clk_to_gpu(gpll->freq)); | ||
322 | clk_config_dvfs_detection(d->mv, d); | ||
323 | clk_config_dvfs_ndiv(d->mv, gpll->N, d); | ||
324 | } | ||
325 | |||
326 | /* Update DVFS detection settings in flight */ | ||
327 | static void clk_set_dfs_coeff(struct gk20a *g, u32 dfs_coeff) | ||
328 | { | ||
329 | u32 data = gk20a_readl(g, trim_gpc_bcast_gpcpll_dvfs2_r()); | ||
330 | data |= DFS_EXT_STROBE; | ||
331 | gk20a_writel(g, trim_gpc_bcast_gpcpll_dvfs2_r(), data); | ||
332 | |||
333 | data = gk20a_readl(g, trim_sys_gpcpll_dvfs0_r()); | ||
334 | data = set_field(data, trim_sys_gpcpll_dvfs0_dfs_coeff_m(), | ||
335 | trim_sys_gpcpll_dvfs0_dfs_coeff_f(dfs_coeff)); | ||
336 | gk20a_writel(g, trim_sys_gpcpll_dvfs0_r(), data); | ||
337 | |||
338 | data = gk20a_readl(g, trim_gpc_bcast_gpcpll_dvfs2_r()); | ||
339 | udelay(1); | ||
340 | data &= ~DFS_EXT_STROBE; | ||
341 | gk20a_writel(g, trim_gpc_bcast_gpcpll_dvfs2_r(), data); | ||
342 | } | ||
343 | |||
344 | static void __maybe_unused clk_set_dfs_det_max(struct gk20a *g, u32 dfs_det_max) | ||
345 | { | ||
346 | u32 data = gk20a_readl(g, trim_gpc_bcast_gpcpll_dvfs2_r()); | ||
347 | data |= DFS_EXT_STROBE; | ||
348 | gk20a_writel(g, trim_gpc_bcast_gpcpll_dvfs2_r(), data); | ||
349 | |||
350 | data = gk20a_readl(g, trim_sys_gpcpll_dvfs0_r()); | ||
351 | data = set_field(data, trim_sys_gpcpll_dvfs0_dfs_det_max_m(), | ||
352 | trim_sys_gpcpll_dvfs0_dfs_det_max_f(dfs_det_max)); | ||
353 | gk20a_writel(g, trim_sys_gpcpll_dvfs0_r(), data); | ||
354 | |||
355 | data = gk20a_readl(g, trim_gpc_bcast_gpcpll_dvfs2_r()); | ||
356 | udelay(1); | ||
357 | data &= ~DFS_EXT_STROBE; | ||
358 | gk20a_writel(g, trim_gpc_bcast_gpcpll_dvfs2_r(), data); | ||
359 | } | ||
360 | |||
361 | static void clk_set_dfs_ext_cal(struct gk20a *g, u32 dfs_det_cal) | ||
362 | { | ||
363 | u32 data; | ||
364 | |||
365 | data = gk20a_readl(g, trim_gpc_bcast_gpcpll_dvfs2_r()); | ||
366 | data &= ~(BIT(DFS_DET_RANGE + 1) - 1); | ||
367 | data |= dfs_det_cal; | ||
368 | gk20a_writel(g, trim_gpc_bcast_gpcpll_dvfs2_r(), data); | ||
369 | |||
370 | data = gk20a_readl(g, trim_sys_gpcpll_dvfs1_r()); | ||
371 | udelay(1); | ||
372 | if (~trim_sys_gpcpll_dvfs1_dfs_ctrl_v(data) & DFS_EXT_CAL_EN) { | ||
373 | data = set_field(data, trim_sys_gpcpll_dvfs1_dfs_ctrl_m(), | ||
374 | trim_sys_gpcpll_dvfs1_dfs_ctrl_f(DFS_EXT_CAL_EN)); | ||
375 | gk20a_writel(g, trim_sys_gpcpll_dvfs1_r(), data); | ||
376 | } | ||
377 | } | ||
378 | |||
379 | static void clk_setup_dvfs_detection(struct gk20a *g, struct pll *gpll) | ||
380 | { | ||
381 | struct na_dvfs *d = &gpll->dvfs; | ||
382 | |||
383 | u32 data = gk20a_readl(g, trim_gpc_bcast_gpcpll_dvfs2_r()); | ||
384 | data |= DFS_EXT_STROBE; | ||
385 | gk20a_writel(g, trim_gpc_bcast_gpcpll_dvfs2_r(), data); | ||
386 | |||
387 | data = gk20a_readl(g, trim_sys_gpcpll_dvfs0_r()); | ||
388 | data = set_field(data, trim_sys_gpcpll_dvfs0_dfs_coeff_m(), | ||
389 | trim_sys_gpcpll_dvfs0_dfs_coeff_f(d->dfs_coeff)); | ||
390 | data = set_field(data, trim_sys_gpcpll_dvfs0_dfs_det_max_m(), | ||
391 | trim_sys_gpcpll_dvfs0_dfs_det_max_f(d->dfs_det_max)); | ||
392 | gk20a_writel(g, trim_sys_gpcpll_dvfs0_r(), data); | ||
393 | |||
394 | data = gk20a_readl(g, trim_gpc_bcast_gpcpll_dvfs2_r()); | ||
395 | udelay(1); | ||
396 | data &= ~DFS_EXT_STROBE; | ||
397 | gk20a_writel(g, trim_gpc_bcast_gpcpll_dvfs2_r(), data); | ||
398 | |||
399 | clk_set_dfs_ext_cal(g, d->dfs_ext_cal); | ||
400 | } | ||
401 | |||
402 | /* Enable NA/DVFS mode */ | ||
403 | static int clk_enbale_pll_dvfs(struct gk20a *g) | ||
404 | { | ||
405 | u32 data; | ||
406 | int delay = 5; /* use for iddq exit delay & calib timeout */ | ||
407 | struct pll_parms *p = &gpc_pll_params; | ||
408 | bool calibrated = p->uvdet_slope && p->uvdet_offs; | ||
409 | |||
410 | /* FIXME: Set VCO_CTRL */ | ||
411 | |||
412 | /* Enable NA DVFS */ | ||
413 | data = gk20a_readl(g, trim_sys_gpcpll_dvfs1_r()); | ||
414 | data |= trim_sys_gpcpll_dvfs1_en_dfs_m(); | ||
415 | gk20a_writel(g, trim_sys_gpcpll_dvfs1_r(), data); | ||
416 | |||
417 | /* | ||
418 | * If calibration parameters are known (either from fuses, or from | ||
419 | * internal calibration on boot) - use them. Internal calibration is | ||
420 | * started anyway; it will complete, but results will not be used. | ||
421 | */ | ||
422 | if (calibrated) { | ||
423 | data = gk20a_readl(g, trim_sys_gpcpll_dvfs1_r()); | ||
424 | data |= trim_sys_gpcpll_dvfs1_en_dfs_cal_m(); | ||
425 | gk20a_writel(g, trim_sys_gpcpll_dvfs1_r(), data); | ||
426 | } | ||
427 | |||
428 | /* Exit IDDQ mode */ | ||
429 | data = gk20a_readl(g, trim_sys_gpcpll_cfg_r()); | ||
430 | data = set_field(data, trim_sys_gpcpll_cfg_iddq_m(), | ||
431 | trim_sys_gpcpll_cfg_iddq_power_on_v()); | ||
432 | gk20a_writel(g, trim_sys_gpcpll_cfg_r(), data); | ||
433 | gk20a_readl(g, trim_sys_gpcpll_cfg_r()); | ||
434 | udelay(delay); | ||
435 | |||
436 | if (calibrated) | ||
437 | return 0; | ||
438 | |||
439 | /* | ||
440 | * If calibration parameters are not fused, start internal calibration, | ||
441 | * wait for completion, and use results along with default slope to | ||
442 | * calculate ADC offset during boot. | ||
443 | */ | ||
444 | data = gk20a_readl(g, trim_sys_gpcpll_dvfs1_r()); | ||
445 | data |= trim_sys_gpcpll_dvfs1_en_dfs_cal_m(); | ||
446 | gk20a_writel(g, trim_sys_gpcpll_dvfs1_r(), data); | ||
447 | |||
448 | /* Wait for internal calibration done (spec < 2us). */ | ||
449 | do { | ||
450 | data = gk20a_readl(g, trim_sys_gpcpll_dvfs1_r()); | ||
451 | if (trim_sys_gpcpll_dvfs1_dfs_cal_done_v(data)) | ||
452 | break; | ||
453 | udelay(1); | ||
454 | delay--; | ||
455 | } while (delay > 0); | ||
456 | |||
457 | if (delay <= 0) { | ||
458 | gk20a_err(dev_from_gk20a(g), "GPCPLL calibration timeout"); | ||
459 | return -ETIMEDOUT; | ||
460 | } | ||
461 | |||
462 | data = gk20a_readl(g, trim_sys_gpcpll_cfg3_r()); | ||
463 | data = trim_sys_gpcpll_cfg3_dfs_testout_v(data); | ||
464 | p->uvdet_offs = BOOT_GPU_UV - data * ADC_SLOPE_UV; | ||
465 | p->uvdet_slope = ADC_SLOPE_UV; | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | /* GPCPLL slide methods */ | ||
221 | static void clk_setup_slide(struct gk20a *g, u32 clk_u) | 470 | static void clk_setup_slide(struct gk20a *g, u32 clk_u) |
222 | { | 471 | { |
223 | u32 data, step_a, step_b; | 472 | u32 data, step_a, step_b; |
@@ -320,6 +569,7 @@ static int clk_slide_gpc_pll(struct gk20a *g, struct pll *gpll) | |||
320 | return 0; | 569 | return 0; |
321 | } | 570 | } |
322 | 571 | ||
572 | /* GPCPLL bypass methods */ | ||
323 | static int clk_change_pldiv_under_bypass(struct gk20a *g, struct pll *gpll) | 573 | static int clk_change_pldiv_under_bypass(struct gk20a *g, struct pll *gpll) |
324 | { | 574 | { |
325 | u32 data, coeff; | 575 | u32 data, coeff; |
@@ -381,10 +631,24 @@ static int clk_lock_gpc_pll_under_bypass(struct gk20a *g, struct pll *gpll) | |||
381 | } | 631 | } |
382 | 632 | ||
383 | /* change coefficients */ | 633 | /* change coefficients */ |
384 | coeff = trim_sys_gpcpll_coeff_mdiv_f(gpll->M) | | 634 | if (gpll->mode == GPC_PLL_MODE_DVFS) { |
385 | trim_sys_gpcpll_coeff_ndiv_f(gpll->N) | | 635 | clk_setup_dvfs_detection(g, gpll); |
386 | trim_sys_gpcpll_coeff_pldiv_f(gpll->PL); | 636 | |
387 | gk20a_writel(g, trim_sys_gpcpll_coeff_r(), coeff); | 637 | coeff = gk20a_readl(g, trim_sys_gpcpll_cfg2_r()); |
638 | coeff = set_field(coeff, trim_sys_gpcpll_cfg2_sdm_din_m(), | ||
639 | trim_sys_gpcpll_cfg2_sdm_din_f(gpll->dvfs.sdm_din)); | ||
640 | gk20a_writel(g, trim_sys_gpcpll_cfg2_r(), coeff); | ||
641 | |||
642 | coeff = trim_sys_gpcpll_coeff_mdiv_f(gpll->M) | | ||
643 | trim_sys_gpcpll_coeff_ndiv_f(gpll->dvfs.n_int) | | ||
644 | trim_sys_gpcpll_coeff_pldiv_f(gpll->PL); | ||
645 | gk20a_writel(g, trim_sys_gpcpll_coeff_r(), coeff); | ||
646 | } else { | ||
647 | coeff = trim_sys_gpcpll_coeff_mdiv_f(gpll->M) | | ||
648 | trim_sys_gpcpll_coeff_ndiv_f(gpll->N) | | ||
649 | trim_sys_gpcpll_coeff_pldiv_f(gpll->PL); | ||
650 | gk20a_writel(g, trim_sys_gpcpll_coeff_r(), coeff); | ||
651 | } | ||
388 | 652 | ||
389 | /* enable PLL after changing coefficients */ | 653 | /* enable PLL after changing coefficients */ |
390 | cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r()); | 654 | cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r()); |
@@ -392,6 +656,13 @@ static int clk_lock_gpc_pll_under_bypass(struct gk20a *g, struct pll *gpll) | |||
392 | trim_sys_gpcpll_cfg_enable_yes_f()); | 656 | trim_sys_gpcpll_cfg_enable_yes_f()); |
393 | gk20a_writel(g, trim_sys_gpcpll_cfg_r(), cfg); | 657 | gk20a_writel(g, trim_sys_gpcpll_cfg_r(), cfg); |
394 | 658 | ||
659 | /* just delay in DVFS mode (lock cannot be used) */ | ||
660 | if (gpll->mode == GPC_PLL_MODE_DVFS) { | ||
661 | gk20a_readl(g, trim_sys_gpcpll_cfg_r()); | ||
662 | udelay(g->clk.na_pll_delay); | ||
663 | goto pll_locked; | ||
664 | } | ||
665 | |||
395 | /* lock pll */ | 666 | /* lock pll */ |
396 | cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r()); | 667 | cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r()); |
397 | if (cfg & trim_sys_gpcpll_cfg_enb_lckdet_power_off_f()){ | 668 | if (cfg & trim_sys_gpcpll_cfg_enb_lckdet_power_off_f()){ |
@@ -434,6 +705,7 @@ pll_locked: | |||
434 | return 0; | 705 | return 0; |
435 | } | 706 | } |
436 | 707 | ||
708 | /* GPCPLL programming in legacy (non-DVFS) mode */ | ||
437 | static int clk_program_gpc_pll(struct gk20a *g, struct pll *gpll_new, | 709 | static int clk_program_gpc_pll(struct gk20a *g, struct pll *gpll_new, |
438 | int allow_slide) | 710 | int allow_slide) |
439 | { | 711 | { |
@@ -549,6 +821,16 @@ set_pldiv: | |||
549 | return clk_slide_gpc_pll(g, gpll_new); | 821 | return clk_slide_gpc_pll(g, gpll_new); |
550 | } | 822 | } |
551 | 823 | ||
824 | /* GPCPLL programming in DVFS mode */ | ||
825 | static int clk_program_na_gpc_pll(struct gk20a *g, struct pll *gpll_new, | ||
826 | int allow_slide) | ||
827 | { | ||
828 | clk_config_dvfs(g, gpll_new); | ||
829 | |||
830 | /* always under bypass, for now */ | ||
831 | return clk_program_gpc_pll(g, gpll_new, 0); | ||
832 | } | ||
833 | |||
552 | static int clk_disable_gpcpll(struct gk20a *g, int allow_slide) | 834 | static int clk_disable_gpcpll(struct gk20a *g, int allow_slide) |
553 | { | 835 | { |
554 | u32 cfg, coeff; | 836 | u32 cfg, coeff; |
@@ -617,6 +899,7 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g) | |||
617 | static int initialized; | 899 | static int initialized; |
618 | struct clk *ref; | 900 | struct clk *ref; |
619 | unsigned long ref_rate; | 901 | unsigned long ref_rate; |
902 | bool calibrated; | ||
620 | 903 | ||
621 | gk20a_dbg_fn(""); | 904 | gk20a_dbg_fn(""); |
622 | 905 | ||
@@ -636,7 +919,14 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g) | |||
636 | } | 919 | } |
637 | ref_rate = clk_get_rate(ref); | 920 | ref_rate = clk_get_rate(ref); |
638 | 921 | ||
922 | /* | ||
923 | * Locking time in both legacy and DVFS mode is 40us. However, in legacy | ||
924 | * mode we rely on lock detection signal, and delay is just timeout | ||
925 | * limit, so we can afford set it longer. In DVFS mode each lock inserts | ||
926 | * specified delay, so it should be set as short as h/w allows. | ||
927 | */ | ||
639 | clk->pll_delay = 300; /* usec */ | 928 | clk->pll_delay = 300; /* usec */ |
929 | clk->na_pll_delay = 40; /* usec*/ | ||
640 | 930 | ||
641 | clk->gpc_pll.id = GK20A_GPC_PLL; | 931 | clk->gpc_pll.id = GK20A_GPC_PLL; |
642 | clk->gpc_pll.clk_in = ref_rate / KHZ; | 932 | clk->gpc_pll.clk_in = ref_rate / KHZ; |
@@ -652,6 +942,17 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g) | |||
652 | clk->gpc_pll.freq /= pl_to_div(clk->gpc_pll.PL); | 942 | clk->gpc_pll.freq /= pl_to_div(clk->gpc_pll.PL); |
653 | } | 943 | } |
654 | 944 | ||
945 | calibrated = !clk_config_calibration_params(g); | ||
946 | #ifdef CONFIG_TEGRA_USE_NA_GPCPLL | ||
947 | if (ALLOW_NON_CALIBRATED_NA_MODE || calibrated) { | ||
948 | /* NA mode is supported only at max update rate 38.4 MHz */ | ||
949 | if (clk->gpc_pll.clk_in == gpc_pll_params.max_u) { | ||
950 | clk->gpc_pll.mode = GPC_PLL_MODE_DVFS; | ||
951 | gpc_pll_params.min_u = gpc_pll_params.max_u; | ||
952 | } | ||
953 | } | ||
954 | #endif | ||
955 | |||
655 | mutex_init(&clk->clk_mutex); | 956 | mutex_init(&clk->clk_mutex); |
656 | 957 | ||
657 | clk->sw_ready = true; | 958 | clk->sw_ready = true; |
@@ -693,6 +994,9 @@ static int gm20b_init_clk_setup_hw(struct gk20a *g) | |||
693 | gk20a_writel(g, therm_clk_slowdown_r(0), data); | 994 | gk20a_writel(g, therm_clk_slowdown_r(0), data); |
694 | gk20a_readl(g, therm_clk_slowdown_r(0)); | 995 | gk20a_readl(g, therm_clk_slowdown_r(0)); |
695 | 996 | ||
997 | if (g->clk.gpc_pll.mode == GPC_PLL_MODE_DVFS) | ||
998 | return clk_enbale_pll_dvfs(g); | ||
999 | |||
696 | return 0; | 1000 | return 0; |
697 | } | 1001 | } |
698 | 1002 | ||
@@ -726,9 +1030,15 @@ static int set_pll_freq(struct gk20a *g, int allow_slide) | |||
726 | clk->gpc_pll_last.freq, clk->gpc_pll.freq); | 1030 | clk->gpc_pll_last.freq, clk->gpc_pll.freq); |
727 | 1031 | ||
728 | /* If programming with dynamic sliding failed, re-try under bypass */ | 1032 | /* If programming with dynamic sliding failed, re-try under bypass */ |
729 | err = clk_program_gpc_pll(g, &clk->gpc_pll, allow_slide); | 1033 | if (clk->gpc_pll.mode == GPC_PLL_MODE_DVFS) { |
730 | if (err && allow_slide) | 1034 | err = clk_program_na_gpc_pll(g, &clk->gpc_pll, allow_slide); |
731 | err = clk_program_gpc_pll(g, &clk->gpc_pll, 0); | 1035 | if (err && allow_slide) |
1036 | err = clk_program_na_gpc_pll(g, &clk->gpc_pll, 0); | ||
1037 | } else { | ||
1038 | err = clk_program_gpc_pll(g, &clk->gpc_pll, allow_slide); | ||
1039 | if (err && allow_slide) | ||
1040 | err = clk_program_gpc_pll(g, &clk->gpc_pll, 0); | ||
1041 | } | ||
732 | 1042 | ||
733 | if (!err) { | 1043 | if (!err) { |
734 | clk->gpc_pll.enabled = true; | 1044 | clk->gpc_pll.enabled = true; |