diff options
-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; |