summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2014-09-04 00:01:10 -0400
committerDan Willemsen <dwillemsen@nvidia.com>2015-03-18 15:11:16 -0400
commit5bb95a3e41be5ceec13653b7c3040f2bbcfc2076 (patch)
tree8b164bfad33e9f5e93b10fdd730107d526bb7d7c /drivers/gpu/nvgpu/gm20b/clk_gm20b.c
parent59f00a42e47ccf4aacfac01d1e97b66537a01aed (diff)
gpu: nvgpu: Update GM20B GPCPLL bypass operations
- Skipped PLL re-locking if only post-divider is changing under bypass - Added 1us delay after switch to bypass clock source - Changed wait for lock under bypass resolution from 2us to 1us Change-Id: I259581c00c417752263ef3b2ea057200bb78ecbf Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/495473 (cherry picked from commit d90a19b8bf59c608a2a3a891b34ca714dfe990e9) Reviewed-on: http://git-master/r/499192 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gm20b/clk_gm20b.c')
-rw-r--r--drivers/gpu/nvgpu/gm20b/clk_gm20b.c50
1 files changed, 40 insertions, 10 deletions
diff --git a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
index 86aa6e8b..a1614a7a 100644
--- a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
+++ b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
@@ -302,6 +302,33 @@ static int clk_slide_gpc_pll(struct gk20a *g, struct pll *gpll)
302 return 0; 302 return 0;
303} 303}
304 304
305static int clk_change_pldiv_under_bypass(struct gk20a *g, struct pll *gpll)
306{
307 u32 data, coeff;
308
309 /* put PLL in bypass before programming it */
310 data = gk20a_readl(g, trim_sys_sel_vco_r());
311 data = set_field(data, trim_sys_sel_vco_gpc2clk_out_m(),
312 trim_sys_sel_vco_gpc2clk_out_bypass_f());
313 gk20a_writel(g, trim_sys_sel_vco_r(), data);
314
315 /* change PLDIV */
316 coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r());
317 udelay(1);
318 coeff = set_field(coeff, trim_sys_gpcpll_coeff_pldiv_m(),
319 trim_sys_gpcpll_coeff_pldiv_f(gpll->PL));
320 gk20a_writel(g, trim_sys_gpcpll_coeff_r(), coeff);
321
322 /* put PLL back on vco */
323 data = gk20a_readl(g, trim_sys_sel_vco_r());
324 udelay(1);
325 data = set_field(data, trim_sys_sel_vco_gpc2clk_out_m(),
326 trim_sys_sel_vco_gpc2clk_out_vco_f());
327 gk20a_writel(g, trim_sys_sel_vco_r(), data);
328
329 return 0;
330}
331
305static int clk_lock_gpc_pll_under_bypass(struct gk20a *g, struct pll *gpll) 332static int clk_lock_gpc_pll_under_bypass(struct gk20a *g, struct pll *gpll)
306{ 333{
307 u32 data, cfg, coeff, timeout; 334 u32 data, cfg, coeff, timeout;
@@ -313,6 +340,7 @@ static int clk_lock_gpc_pll_under_bypass(struct gk20a *g, struct pll *gpll)
313 gk20a_writel(g, trim_sys_sel_vco_r(), data); 340 gk20a_writel(g, trim_sys_sel_vco_r(), data);
314 341
315 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r()); 342 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r());
343 udelay(1);
316 if (trim_sys_gpcpll_cfg_iddq_v(cfg)) { 344 if (trim_sys_gpcpll_cfg_iddq_v(cfg)) {
317 /* get out from IDDQ (1st power up) */ 345 /* get out from IDDQ (1st power up) */
318 cfg = set_field(cfg, trim_sys_gpcpll_cfg_iddq_m(), 346 cfg = set_field(cfg, trim_sys_gpcpll_cfg_iddq_m(),
@@ -352,15 +380,16 @@ static int clk_lock_gpc_pll_under_bypass(struct gk20a *g, struct pll *gpll)
352 cfg = set_field(cfg, trim_sys_gpcpll_cfg_enb_lckdet_m(), 380 cfg = set_field(cfg, trim_sys_gpcpll_cfg_enb_lckdet_m(),
353 trim_sys_gpcpll_cfg_enb_lckdet_power_on_f()); 381 trim_sys_gpcpll_cfg_enb_lckdet_power_on_f());
354 gk20a_writel(g, trim_sys_gpcpll_cfg_r(), cfg); 382 gk20a_writel(g, trim_sys_gpcpll_cfg_r(), cfg);
383 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r());
355 } 384 }
356 385
357 /* wait pll lock */ 386 /* wait pll lock */
358 timeout = g->clk.pll_delay / 2 + 1; 387 timeout = g->clk.pll_delay + 1;
359 do { 388 do {
389 udelay(1);
360 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r()); 390 cfg = gk20a_readl(g, trim_sys_gpcpll_cfg_r());
361 if (cfg & trim_sys_gpcpll_cfg_pll_lock_true_f()) 391 if (cfg & trim_sys_gpcpll_cfg_pll_lock_true_f())
362 goto pll_locked; 392 goto pll_locked;
363 udelay(2);
364 } while (--timeout > 0); 393 } while (--timeout > 0);
365 394
366 /* PLL is messed up. What can we do here? */ 395 /* PLL is messed up. What can we do here? */
@@ -390,13 +419,11 @@ pll_locked:
390static int clk_program_gpc_pll(struct gk20a *g, struct pll *gpll_new, 419static int clk_program_gpc_pll(struct gk20a *g, struct pll *gpll_new,
391 int allow_slide) 420 int allow_slide)
392{ 421{
393#if PLDIV_GLITCHLESS 422#if !PLDIV_GLITCHLESS
394 bool skip_bypass;
395#else
396 u32 data; 423 u32 data;
397#endif 424#endif
398 u32 cfg, coeff; 425 u32 cfg, coeff;
399 bool can_slide; 426 bool can_slide, pldiv_only;
400 struct pll gpll; 427 struct pll gpll;
401 428
402 gk20a_dbg_fn(""); 429 gk20a_dbg_fn("");
@@ -427,15 +454,15 @@ static int clk_program_gpc_pll(struct gk20a *g, struct pll *gpll_new,
427 if (ret) 454 if (ret)
428 return ret; 455 return ret;
429 } 456 }
457 pldiv_only = can_slide && (gpll_new->M == gpll.M);
430 458
431#if PLDIV_GLITCHLESS 459#if PLDIV_GLITCHLESS
432 /* 460 /*
433 * Limit either FO-to-FO (path A below) or FO-to-bypass (path B below) 461 * Limit either FO-to-FO (path A below) or FO-to-bypass (path B below)
434 * jump to min_vco/2 by setting post divider >= 1:2. 462 * jump to min_vco/2 by setting post divider >= 1:2.
435 */ 463 */
436 skip_bypass = can_slide && (gpll_new->M == gpll.M);
437 coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r()); 464 coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r());
438 if ((skip_bypass && (gpll_new->PL < 2)) || (gpll.PL < 2)) { 465 if ((pldiv_only && (gpll_new->PL < 2)) || (gpll.PL < 2)) {
439 if (gpll.PL != 2) { 466 if (gpll.PL != 2) {
440 coeff = set_field(coeff, 467 coeff = set_field(coeff,
441 trim_sys_gpcpll_coeff_pldiv_m(), 468 trim_sys_gpcpll_coeff_pldiv_m(),
@@ -446,7 +473,7 @@ static int clk_program_gpc_pll(struct gk20a *g, struct pll *gpll_new,
446 } 473 }
447 } 474 }
448 475
449 if (skip_bypass) 476 if (pldiv_only)
450 goto set_pldiv; /* path A: no need to bypass */ 477 goto set_pldiv; /* path A: no need to bypass */
451 478
452 /* path B: bypass if either M changes or PLL is disabled */ 479 /* path B: bypass if either M changes or PLL is disabled */
@@ -473,7 +500,10 @@ static int clk_program_gpc_pll(struct gk20a *g, struct pll *gpll_new,
473#if PLDIV_GLITCHLESS 500#if PLDIV_GLITCHLESS
474 gpll.PL = (gpll_new->PL < 2) ? 2 : gpll_new->PL; 501 gpll.PL = (gpll_new->PL < 2) ? 2 : gpll_new->PL;
475#endif 502#endif
476 clk_lock_gpc_pll_under_bypass(g, &gpll); 503 if (pldiv_only)
504 clk_change_pldiv_under_bypass(g, &gpll);
505 else
506 clk_lock_gpc_pll_under_bypass(g, &gpll);
477 507
478#if PLDIV_GLITCHLESS 508#if PLDIV_GLITCHLESS
479 coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r()); 509 coeff = gk20a_readl(g, trim_sys_gpcpll_coeff_r());