summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorSrikar Srimath Tirumala <srikars@nvidia.com>2016-12-05 21:28:51 -0500
committerTejal Kudav <tkudav@nvidia.com>2016-12-20 19:17:33 -0500
commita918003694984b6fca9e6b6c07fd7cdf3503055e (patch)
tree81c2018fa8ac28898efb51634420508bdb678571 /drivers/gpu
parent8ccfe2569c924c5f13f09baf54cedcc6d04fc18b (diff)
gpu: nvgpu: fix gpcclk for K4.4
Move the sw initialization of the gpcclk from gpu rail ungate path to the nvgpu probe path. This allows gpcclk to register itself successfully with CCF and makes it discoverable for other clients early on during boot. Bug 200233943 Bug 200259437 Change-Id: I88d94542092f92e68dc63c40444a70991d1f6129 Signed-off-by: Srikar Srimath Tirumala <srikars@nvidia.com> Reviewed-on: http://git-master/r/1265549 Reviewed-by: Tejal Kudav <tkudav@nvidia.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c5
-rw-r--r--drivers/gpu/nvgpu/gm20b/clk_gm20b.c92
2 files changed, 77 insertions, 20 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c b/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c
index 1b4d2c07..978ad5aa 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c
+++ b/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c
@@ -18,12 +18,17 @@
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */ 19 */
20 20
21#include <linux/version.h>
21#include <linux/device.h> 22#include <linux/device.h>
22#include <linux/pm_runtime.h> 23#include <linux/pm_runtime.h>
23#include <linux/kernel.h> 24#include <linux/kernel.h>
24#include <linux/fb.h> 25#include <linux/fb.h>
25#include <linux/gk20a.h> 26#include <linux/gk20a.h>
27#include <mach/clk.h>
26#include <linux/clk/tegra.h> 28#include <linux/clk/tegra.h>
29#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
30#include <soc/tegra/tegra-dvfs.h>
31#endif
27 32
28#include "gk20a.h" 33#include "gk20a.h"
29#include "gr_gk20a.h" 34#include "gr_gk20a.h"
diff --git a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
index 501be537..060a5775 100644
--- a/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
+++ b/drivers/gpu/nvgpu/gm20b/clk_gm20b.c
@@ -372,6 +372,18 @@ static void clk_config_dvfs_ndiv(int mv, u32 n_eff, struct na_dvfs *d)
372 d->sdm_din = (d->sdm_din >> BITS_PER_BYTE) & 0xff; 372 d->sdm_din = (d->sdm_din >> BITS_PER_BYTE) & 0xff;
373} 373}
374 374
375static void gm20b_calc_dvfs_safe_max_freq(struct clk *c)
376{
377 unsigned long safe_rate;
378
379 if (dvfs_safe_max_freq)
380 return;
381
382 safe_rate = tegra_dvfs_get_fmax_at_vmin_safe_t(c);
383 safe_rate = safe_rate * (100 - DVFS_SAFE_MARGIN) / 100;
384 dvfs_safe_max_freq = rate_gpu_to_gpc2clk(safe_rate);
385}
386
375/* Voltage dependent configuration */ 387/* Voltage dependent configuration */
376static void clk_config_dvfs(struct gk20a *g, struct pll *gpll) 388static void clk_config_dvfs(struct gk20a *g, struct pll *gpll)
377{ 389{
@@ -383,6 +395,7 @@ static void clk_config_dvfs(struct gk20a *g, struct pll *gpll)
383 clk = clk_get_parent(clk); 395 clk = clk_get_parent(clk);
384#endif 396#endif
385 397
398 gm20b_calc_dvfs_safe_max_freq(clk);
386 d->mv = tegra_dvfs_predict_mv_at_hz_cur_tfloor(clk, 399 d->mv = tegra_dvfs_predict_mv_at_hz_cur_tfloor(clk,
387 rate_gpc2clk_to_gpu(gpll->freq)); 400 rate_gpc2clk_to_gpu(gpll->freq));
388 401
@@ -1120,32 +1133,23 @@ static int gm20b_init_clk_reset_enable_hw(struct gk20a *g)
1120 return 0; 1133 return 0;
1121} 1134}
1122 1135
1123static int gm20b_init_clk_setup_sw(struct gk20a *g) 1136#ifdef CONFIG_TEGRA_CLK_FRAMEWORK
1137static int gm20b_init_gpc_pll(struct gk20a *g)
1124{ 1138{
1125 struct clk_gk20a *clk = &g->clk; 1139 struct clk_gk20a *clk = &g->clk;
1126 unsigned long safe_rate; 1140 struct clk *c, *ref;
1127 struct clk *ref, *c;
1128
1129 gk20a_dbg_fn("");
1130
1131 if (clk->sw_ready) {
1132 gk20a_dbg_fn("skip init");
1133 return 0;
1134 }
1135 1141
1136 if (!gk20a_clk_get(g)) 1142 if (!gk20a_clk_get(g))
1137 return -EINVAL; 1143 return -EINVAL;
1138 1144
1139 c = clk->tegra_clk;
1140#ifdef CONFIG_TEGRA_CLK_FRAMEWORK
1141 /* 1145 /*
1142 * On Tegra GPU clock exposed to frequency governor is a shared user on 1146 * On Tegra GPU clock exposed to frequency governor is a shared user on
1143 * GPCPLL bus (gbus). The latter can be accessed as GPU clock parent. 1147 * GPCPLL bus (gbus). The latter can be accessed as GPU clock parent.
1144 * Respectively the grandparent is PLL reference clock. 1148 * Respectively the grandparent is PLL reference clock.
1145 */ 1149 */
1146 c = clk_get_parent(c); 1150 c = clk_get_parent(clk->tegra_clk);
1147#endif
1148 ref = clk_get_parent(c); 1151 ref = clk_get_parent(c);
1152
1149 if (IS_ERR(ref)) { 1153 if (IS_ERR(ref)) {
1150 gk20a_err(dev_from_gk20a(g), 1154 gk20a_err(dev_from_gk20a(g),
1151 "failed to get GPCPLL reference clock"); 1155 "failed to get GPCPLL reference clock");
@@ -1155,9 +1159,7 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g)
1155 clk->gpc_pll.id = GK20A_GPC_PLL; 1159 clk->gpc_pll.id = GK20A_GPC_PLL;
1156 clk->gpc_pll.clk_in = clk_get_rate(ref) / KHZ; 1160 clk->gpc_pll.clk_in = clk_get_rate(ref) / KHZ;
1157 1161
1158 safe_rate = tegra_dvfs_get_fmax_at_vmin_safe_t(c); 1162 gm20b_calc_dvfs_safe_max_freq(c);
1159 safe_rate = safe_rate * (100 - DVFS_SAFE_MARGIN) / 100;
1160 dvfs_safe_max_freq = rate_gpu_to_gpc2clk(safe_rate);
1161 clk->gpc_pll.PL = (dvfs_safe_max_freq == 0) ? 0 : 1163 clk->gpc_pll.PL = (dvfs_safe_max_freq == 0) ? 0 :
1162 DIV_ROUND_UP(gpc_pll_params.min_vco, dvfs_safe_max_freq); 1164 DIV_ROUND_UP(gpc_pll_params.min_vco, dvfs_safe_max_freq);
1163 1165
@@ -1169,7 +1171,51 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g)
1169 clk->gpc_pll.freq = clk->gpc_pll.clk_in * clk->gpc_pll.N; 1171 clk->gpc_pll.freq = clk->gpc_pll.clk_in * clk->gpc_pll.N;
1170 clk->gpc_pll.freq /= pl_to_div(clk->gpc_pll.PL); 1172 clk->gpc_pll.freq /= pl_to_div(clk->gpc_pll.PL);
1171 1173
1172 /* 1174 return 0;
1175}
1176
1177#else /*COMMON_CLOCK_FRAMEWORK*/
1178static int gm20b_init_gpc_pll(struct gk20a *g)
1179{
1180 struct clk_gk20a *clk = &g->clk;
1181 struct clk *ref;
1182
1183 ref = clk_get_sys("gpu_ref", "gpu_ref");
1184 if (IS_ERR(ref)) {
1185 gk20a_err(dev_from_gk20a(g),
1186 "failed to get GPCPLL reference clock");
1187 return -EINVAL;
1188 }
1189 clk->gpc_pll.id = GK20A_GPC_PLL;
1190 clk->gpc_pll.clk_in = clk_get_rate(ref) / KHZ;
1191
1192 /* Initial freq: low enough to be safe at Vmin (default 1/3 VCO min) */
1193 clk->gpc_pll.M = 1;
1194 clk->gpc_pll.N = DIV_ROUND_UP(gpc_pll_params.min_vco,
1195 clk->gpc_pll.clk_in);
1196 clk->gpc_pll.PL = 3;
1197 clk->gpc_pll.freq = clk->gpc_pll.clk_in * clk->gpc_pll.N;
1198 clk->gpc_pll.freq /= pl_to_div(clk->gpc_pll.PL);
1199
1200 return 0;
1201}
1202#endif
1203
1204static int gm20b_init_clk_setup_sw(struct gk20a *g)
1205{
1206 struct clk_gk20a *clk = &g->clk;
1207
1208 gk20a_dbg_fn("");
1209
1210 if (clk->sw_ready) {
1211 gk20a_dbg_fn("skip init");
1212 return 0;
1213 }
1214
1215 if (gm20b_init_gpc_pll(g))
1216 return -EINVAL;
1217
1218 /*
1173 * All production parts should have ADC fuses burnt. Therefore, check 1219 * All production parts should have ADC fuses burnt. Therefore, check
1174 * ADC fuses always, regardless of whether NA mode is selected; and if 1220 * ADC fuses always, regardless of whether NA mode is selected; and if
1175 * NA mode is indeed selected, and part can support it, switch to NA 1221 * NA mode is indeed selected, and part can support it, switch to NA
@@ -1187,7 +1233,6 @@ static int gm20b_init_clk_setup_sw(struct gk20a *g)
1187#endif 1233#endif
1188 1234
1189 mutex_init(&clk->clk_mutex); 1235 mutex_init(&clk->clk_mutex);
1190
1191 clk->sw_ready = true; 1236 clk->sw_ready = true;
1192 1237
1193 gk20a_dbg_fn("done"); 1238 gk20a_dbg_fn("done");
@@ -1293,6 +1338,11 @@ int gm20b_register_gpcclk(struct gk20a *g) {
1293 struct clk_gk20a *clk = &g->clk; 1338 struct clk_gk20a *clk = &g->clk;
1294 struct clk_init_data init; 1339 struct clk_init_data init;
1295 struct clk *c; 1340 struct clk *c;
1341 int err = 0;
1342
1343 err = gm20b_init_clk_setup_sw(g);
1344 if (err)
1345 return err;
1296 1346
1297 init.name = "gpcclk"; 1347 init.name = "gpcclk";
1298 init.ops = &gk20a_clk_ops; 1348 init.ops = &gk20a_clk_ops;
@@ -1312,7 +1362,7 @@ int gm20b_register_gpcclk(struct gk20a *g) {
1312 clk->tegra_clk = c; 1362 clk->tegra_clk = c;
1313 clk_register_clkdev(c, "gpcclk", "gpcclk"); 1363 clk_register_clkdev(c, "gpcclk", "gpcclk");
1314 1364
1315 return 0; 1365 return err;
1316} 1366}
1317#endif /* CONFIG_COMMON_CLK */ 1367#endif /* CONFIG_COMMON_CLK */
1318 1368
@@ -1522,9 +1572,11 @@ static int gm20b_init_clk_support(struct gk20a *g)
1522 if (err) 1572 if (err)
1523 return err; 1573 return err;
1524 1574
1575#ifdef CONFIG_TEGRA_CLK_FRAMEWORK
1525 err = gm20b_init_clk_setup_sw(g); 1576 err = gm20b_init_clk_setup_sw(g);
1526 if (err) 1577 if (err)
1527 return err; 1578 return err;
1579#endif
1528 1580
1529 mutex_lock(&clk->clk_mutex); 1581 mutex_lock(&clk->clk_mutex);
1530 clk->clk_hw_on = true; 1582 clk->clk_hw_on = true;