diff options
Diffstat (limited to 'drivers/gpu/nvgpu')
-rw-r--r-- | drivers/gpu/nvgpu/gm20b/clk_gm20b.c | 38 |
1 files changed, 27 insertions, 11 deletions
diff --git a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c index b1d1af4d..6ee7dff9 100644 --- a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c | |||
@@ -43,9 +43,8 @@ | |||
43 | #define BOOT_GPU_UV 1000000 /* gpu rail boot voltage 1.0V */ | 43 | #define BOOT_GPU_UV 1000000 /* gpu rail boot voltage 1.0V */ |
44 | #define ADC_SLOPE_UV 10000 /* default ADC detection slope 10mV */ | 44 | #define ADC_SLOPE_UV 10000 /* default ADC detection slope 10mV */ |
45 | 45 | ||
46 | /* FIXME: need characterized safe margin constant or table, and minimum */ | 46 | #define DVFS_SAFE_MARGIN 8 /* 8% */ |
47 | #define DVFS_SAFE_MARGIN (2*38400) | 47 | static unsigned long dvfs_safe_max_freq; |
48 | #define DVFS_SAFE_MIN_FREQ (2*307200) | ||
49 | 48 | ||
50 | static struct pll_parms gpc_pll_params = { | 49 | static struct pll_parms gpc_pll_params = { |
51 | 128000, 2600000, /* freq */ | 50 | 128000, 2600000, /* freq */ |
@@ -55,6 +54,8 @@ static struct pll_parms gpc_pll_params = { | |||
55 | 8, 255, /* N */ | 54 | 8, 255, /* N */ |
56 | 1, 31, /* PL */ | 55 | 1, 31, /* PL */ |
57 | -58700, 86789, /* DFS_COEFF */ | 56 | -58700, 86789, /* DFS_COEFF */ |
57 | 0, 0, /* ADC char coeff - to be read from fuses */ | ||
58 | 0, /* FIXME: vco control data */ | ||
58 | }; | 59 | }; |
59 | 60 | ||
60 | #ifdef CONFIG_DEBUG_FS | 61 | #ifdef CONFIG_DEBUG_FS |
@@ -412,13 +413,19 @@ static int clk_enbale_pll_dvfs(struct gk20a *g) | |||
412 | struct pll_parms *p = &gpc_pll_params; | 413 | struct pll_parms *p = &gpc_pll_params; |
413 | bool calibrated = p->uvdet_slope && p->uvdet_offs; | 414 | bool calibrated = p->uvdet_slope && p->uvdet_offs; |
414 | 415 | ||
415 | /* FIXME: Set VCO_CTRL */ | ||
416 | |||
417 | /* Enable NA DVFS */ | 416 | /* Enable NA DVFS */ |
418 | data = gk20a_readl(g, trim_sys_gpcpll_dvfs1_r()); | 417 | data = gk20a_readl(g, trim_sys_gpcpll_dvfs1_r()); |
419 | data |= trim_sys_gpcpll_dvfs1_en_dfs_m(); | 418 | data |= trim_sys_gpcpll_dvfs1_en_dfs_m(); |
420 | gk20a_writel(g, trim_sys_gpcpll_dvfs1_r(), data); | 419 | gk20a_writel(g, trim_sys_gpcpll_dvfs1_r(), data); |
421 | 420 | ||
421 | /* Set VCO_CTRL */ | ||
422 | if (p->vco_ctrl) { | ||
423 | data = gk20a_readl(g, trim_sys_gpcpll_cfg3_r()); | ||
424 | data = set_field(data, trim_sys_gpcpll_cfg3_vco_ctrl_m(), | ||
425 | trim_sys_gpcpll_cfg3_vco_ctrl_f(p->vco_ctrl)); | ||
426 | gk20a_writel(g, trim_sys_gpcpll_cfg3_r(), data); | ||
427 | } | ||
428 | |||
422 | /* | 429 | /* |
423 | * If calibration parameters are known (either from fuses, or from | 430 | * If calibration parameters are known (either from fuses, or from |
424 | * internal calibration on boot) - use them. Internal calibration is | 431 | * internal calibration on boot) - use them. Internal calibration is |
@@ -884,8 +891,8 @@ static void clk_config_pll_safe_dvfs(struct gk20a *g, struct pll *gpll) | |||
884 | { | 891 | { |
885 | u32 nsafe, nmin; | 892 | u32 nsafe, nmin; |
886 | 893 | ||
887 | if (gpll->freq > DVFS_SAFE_MIN_FREQ) | 894 | if (gpll->freq > dvfs_safe_max_freq) |
888 | gpll->freq -= DVFS_SAFE_MARGIN; | 895 | gpll->freq = gpll->freq * (100 - DVFS_SAFE_MARGIN) / 100; |
889 | 896 | ||
890 | nmin = DIV_ROUND_UP(gpll->M * gpc_pll_params.min_vco, gpll->clk_in); | 897 | nmin = DIV_ROUND_UP(gpll->M * gpc_pll_params.min_vco, gpll->clk_in); |
891 | nsafe = gpll->M * gpll->freq / gpll->clk_in; | 898 | nsafe = gpll->M * gpll->freq / gpll->clk_in; |
@@ -956,7 +963,7 @@ static int clk_program_na_gpc_pll(struct gk20a *g, struct pll *gpll_new, | |||
956 | * i.e., it is low enough to be safe at any voltage in operating range | 963 | * i.e., it is low enough to be safe at any voltage in operating range |
957 | * with zero DVFS coefficient. | 964 | * with zero DVFS coefficient. |
958 | */ | 965 | */ |
959 | if (gpll_old->freq > DVFS_SAFE_MIN_FREQ) { | 966 | if (gpll_old->freq > dvfs_safe_max_freq) { |
960 | if (gpll_old->dvfs.mv < gpll_new->dvfs.mv) { | 967 | if (gpll_old->dvfs.mv < gpll_new->dvfs.mv) { |
961 | gpll_safe = *gpll_old; | 968 | gpll_safe = *gpll_old; |
962 | gpll_safe.dvfs.mv = gpll_new->dvfs.mv; | 969 | gpll_safe.dvfs.mv = gpll_new->dvfs.mv; |
@@ -1060,7 +1067,6 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g) | |||
1060 | struct clk_gk20a *clk = &g->clk; | 1067 | struct clk_gk20a *clk = &g->clk; |
1061 | static int initialized; | 1068 | static int initialized; |
1062 | struct clk *ref; | 1069 | struct clk *ref; |
1063 | unsigned long ref_rate; | ||
1064 | bool calibrated; | 1070 | bool calibrated; |
1065 | 1071 | ||
1066 | gk20a_dbg_fn(""); | 1072 | gk20a_dbg_fn(""); |
@@ -1073,13 +1079,17 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g) | |||
1073 | if (!gk20a_clk_get(g)) | 1079 | if (!gk20a_clk_get(g)) |
1074 | return -EINVAL; | 1080 | return -EINVAL; |
1075 | 1081 | ||
1082 | /* | ||
1083 | * On Tegra GPU clock exposed to frequency governor is a shared user on | ||
1084 | * GPCPLL bus (gbus). The latter can be accessed as GPU clock parent. | ||
1085 | * Respectively the grandparent is PLL reference clock. | ||
1086 | */ | ||
1076 | ref = clk_get_parent(clk_get_parent(clk->tegra_clk)); | 1087 | ref = clk_get_parent(clk_get_parent(clk->tegra_clk)); |
1077 | if (IS_ERR(ref)) { | 1088 | if (IS_ERR(ref)) { |
1078 | gk20a_err(dev_from_gk20a(g), | 1089 | gk20a_err(dev_from_gk20a(g), |
1079 | "failed to get GPCPLL reference clock"); | 1090 | "failed to get GPCPLL reference clock"); |
1080 | return -EINVAL; | 1091 | return -EINVAL; |
1081 | } | 1092 | } |
1082 | ref_rate = clk_get_rate(ref); | ||
1083 | 1093 | ||
1084 | /* | 1094 | /* |
1085 | * Locking time in both legacy and DVFS mode is 40us. However, in legacy | 1095 | * Locking time in both legacy and DVFS mode is 40us. However, in legacy |
@@ -1091,7 +1101,7 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g) | |||
1091 | clk->na_pll_delay = 40; /* usec*/ | 1101 | clk->na_pll_delay = 40; /* usec*/ |
1092 | 1102 | ||
1093 | clk->gpc_pll.id = GK20A_GPC_PLL; | 1103 | clk->gpc_pll.id = GK20A_GPC_PLL; |
1094 | clk->gpc_pll.clk_in = ref_rate / KHZ; | 1104 | clk->gpc_pll.clk_in = clk_get_rate(ref) / KHZ; |
1095 | 1105 | ||
1096 | /* Initial frequency: 1/3 VCO min (low enough to be safe at Vmin) */ | 1106 | /* Initial frequency: 1/3 VCO min (low enough to be safe at Vmin) */ |
1097 | if (!initialized) { | 1107 | if (!initialized) { |
@@ -1109,8 +1119,14 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g) | |||
1109 | if (ALLOW_NON_CALIBRATED_NA_MODE || calibrated) { | 1119 | if (ALLOW_NON_CALIBRATED_NA_MODE || calibrated) { |
1110 | /* NA mode is supported only at max update rate 38.4 MHz */ | 1120 | /* NA mode is supported only at max update rate 38.4 MHz */ |
1111 | if (clk->gpc_pll.clk_in == gpc_pll_params.max_u) { | 1121 | if (clk->gpc_pll.clk_in == gpc_pll_params.max_u) { |
1122 | unsigned long safe_rate; | ||
1112 | clk->gpc_pll.mode = GPC_PLL_MODE_DVFS; | 1123 | clk->gpc_pll.mode = GPC_PLL_MODE_DVFS; |
1113 | gpc_pll_params.min_u = gpc_pll_params.max_u; | 1124 | gpc_pll_params.min_u = gpc_pll_params.max_u; |
1125 | |||
1126 | safe_rate = tegra_dvfs_get_therm_safe_fmax( | ||
1127 | clk_get_parent(clk->tegra_clk)); | ||
1128 | safe_rate = safe_rate * (100 - DVFS_SAFE_MARGIN) / 100; | ||
1129 | dvfs_safe_max_freq = rate_gpu_to_gpc2clk(safe_rate); | ||
1114 | } | 1130 | } |
1115 | } | 1131 | } |
1116 | #endif | 1132 | #endif |