diff options
author | Srikar Srimath Tirumala <srikars@nvidia.com> | 2016-12-05 21:28:51 -0500 |
---|---|---|
committer | Tejal Kudav <tkudav@nvidia.com> | 2016-12-20 19:17:33 -0500 |
commit | a918003694984b6fca9e6b6c07fd7cdf3503055e (patch) | |
tree | 81c2018fa8ac28898efb51634420508bdb678571 /drivers | |
parent | 8ccfe2569c924c5f13f09baf54cedcc6d04fc18b (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')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c | 5 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gm20b/clk_gm20b.c | 92 |
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 | ||
375 | static 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 */ |
376 | static void clk_config_dvfs(struct gk20a *g, struct pll *gpll) | 388 | static 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 | ||
1123 | static int gm20b_init_clk_setup_sw(struct gk20a *g) | 1136 | #ifdef CONFIG_TEGRA_CLK_FRAMEWORK |
1137 | static 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*/ | ||
1178 | static 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 | |||
1204 | static 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; |