summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu
diff options
context:
space:
mode:
authorMahantesh Kumbar <mkumbar@nvidia.com>2016-11-03 11:46:21 -0400
committerDeepak Nibade <dnibade@nvidia.com>2016-12-27 04:56:53 -0500
commite5824d8014c321fbe2c1e04e12307125dd50a472 (patch)
tree82657cd43c0dcd313b3251f3776e5e80b488fabc /drivers/gpu/nvgpu
parent62d13e613807e9bce3a9d1ef0c61725ef3a885ce (diff)
gpu: nvgpu: MSCG support
- update gp106 pg engine init/list/features HALs to support MS engine - Added defines & interface for lpwr tables read from vbios. - lpwr module which reads idx/gr/ms table from vbios to map rppg/mscg support with respective p-state - lpwr module public functions to control lpwr features enable/disable mscg/rppg & mclk-change request whenever change in mclk-change parameters - lpwr public functions to know rppg/mscg support for requested pstate, - added mutex t prevent PG transition while arbiter executes pstate transition - nvgpu_clk_arb_get_current_pstate() of clk arbiter to get current pstate JIRA DNVGPU-71 Change-Id: Ifcd640cc19ef630be1e2a9ba07ec84023d8202a0 Signed-off-by: Mahantesh Kumbar <mkumbar@nvidia.com> Reviewed-on: http://git-master/r/1247553 (cherry picked from commit 8a441dea2410e1b5196ef24e56a7768b6980e46b) Reviewed-on: http://git-master/r/1270989 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu')
-rw-r--r--drivers/gpu/nvgpu/Makefile.nvgpu-t18x3
-rw-r--r--drivers/gpu/nvgpu/clk/clk_arb.c102
-rw-r--r--drivers/gpu/nvgpu/clk/clk_arb.h5
-rw-r--r--drivers/gpu/nvgpu/gp106/pmu_gp106.c27
-rw-r--r--drivers/gpu/nvgpu/gp10b/pmu_gp10b.c3
-rw-r--r--drivers/gpu/nvgpu/include/bios.h64
-rw-r--r--drivers/gpu/nvgpu/lpwr/lpwr.c423
-rw-r--r--drivers/gpu/nvgpu/lpwr/lpwr.h92
-rw-r--r--drivers/gpu/nvgpu/perf/perf.h2
-rw-r--r--drivers/gpu/nvgpu/pstate/pstate.c9
-rw-r--r--drivers/gpu/nvgpu/pstate/pstate.h4
11 files changed, 691 insertions, 43 deletions
diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu-t18x b/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
index 2b650ad8..30119345 100644
--- a/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
+++ b/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
@@ -63,7 +63,8 @@ nvgpu-y += \
63 $(nvgpu-t18x)/therm/thrmdev.o \ 63 $(nvgpu-t18x)/therm/thrmdev.o \
64 $(nvgpu-t18x)/therm/thrmchannel.o \ 64 $(nvgpu-t18x)/therm/thrmchannel.o \
65 $(nvgpu-t18x)/therm/thrmpmu.o \ 65 $(nvgpu-t18x)/therm/thrmpmu.o \
66 $(nvgpu-t18x)/lpwr/rppg.o 66 $(nvgpu-t18x)/lpwr/rppg.o \
67 $(nvgpu-t18x)/lpwr/lpwr.o
67 68
68nvgpu-$(CONFIG_TEGRA_GK20A) += $(nvgpu-t18x)/gp10b/platform_gp10b_tegra.o 69nvgpu-$(CONFIG_TEGRA_GK20A) += $(nvgpu-t18x)/gp10b/platform_gp10b_tegra.o
69 70
diff --git a/drivers/gpu/nvgpu/clk/clk_arb.c b/drivers/gpu/nvgpu/clk/clk_arb.c
index 3f35fac7..c440dc3b 100644
--- a/drivers/gpu/nvgpu/clk/clk_arb.c
+++ b/drivers/gpu/nvgpu/clk/clk_arb.c
@@ -44,14 +44,6 @@ static void nvgpu_clk_arb_free_session(struct kref *refcount);
44static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target, 44static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target,
45 u16 sys2clk_target, u16 xbar2clk_target, u16 mclk_target, u32 voltuv, 45 u16 sys2clk_target, u16 xbar2clk_target, u16 mclk_target, u32 voltuv,
46 u32 voltuv_sram); 46 u32 voltuv_sram);
47static int nvgpu_clk_arb_change_vf_point_prefix(struct gk20a *g,
48 u16 gpc2clk_target, u16 sys2clk_target, u16 xbar2clk_target,
49 u16 mclk_target, u32 voltuv, u32 voltuv_sram, u32 nuvmin,
50 u32 nuvmin_sram);
51static int nvgpu_clk_arb_change_vf_point_postfix(struct gk20a *g,
52 u16 gpc2clk_target, u16 sys2clk_target, u16 xbar2clk_target,
53 u16 mclk_target, u32 voltuv, u32 voltuv_sram, u32 nuvmin,
54 u32 nuvmin_sram);
55static u8 nvgpu_clk_arb_find_vf_point(struct nvgpu_clk_arb *arb, 47static u8 nvgpu_clk_arb_find_vf_point(struct nvgpu_clk_arb *arb,
56 u16 *gpc2clk, u16 *sys2clk, u16 *xbar2clk, u16 *mclk, 48 u16 *gpc2clk, u16 *sys2clk, u16 *xbar2clk, u16 *mclk,
57 u32 *voltuv, u32 *voltuv_sram, u32 *nuvmin, u32 *nuvmin_sram); 49 u32 *voltuv, u32 *voltuv_sram, u32 *nuvmin, u32 *nuvmin_sram);
@@ -105,6 +97,7 @@ struct nvgpu_clk_arb {
105 spinlock_t sessions_lock; 97 spinlock_t sessions_lock;
106 spinlock_t users_lock; 98 spinlock_t users_lock;
107 99
100 struct mutex pstate_lock;
108 struct list_head users; 101 struct list_head users;
109 struct list_head sessions; 102 struct list_head sessions;
110 struct llist_head requests; 103 struct llist_head requests;
@@ -235,6 +228,7 @@ int nvgpu_clk_arb_init_arbiter(struct gk20a *g)
235 g->clk_arb = arb; 228 g->clk_arb = arb;
236 arb->g = g; 229 arb->g = g;
237 230
231 mutex_init(&arb->pstate_lock);
238 spin_lock_init(&arb->sessions_lock); 232 spin_lock_init(&arb->sessions_lock);
239 spin_lock_init(&arb->users_lock); 233 spin_lock_init(&arb->users_lock);
240 234
@@ -943,12 +937,23 @@ static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work)
943 /* Program clocks */ 937 /* Program clocks */
944 /* A change in both mclk of gpc2clk may require a change in voltage */ 938 /* A change in both mclk of gpc2clk may require a change in voltage */
945 939
946 status = nvgpu_clk_arb_change_vf_point_prefix(g, gpc2clk_target, 940 mutex_lock(&arb->pstate_lock);
947 sys2clk_target, xbar2clk_target, mclk_target, voltuv, 941 status = nvgpu_lpwr_disable_pg(g, false);
948 voltuv_sram, nuvmin, nuvmin_sram);
949 942
943 status = clk_pmu_freq_controller_load(g, false);
944 if (status < 0) {
945 arb->status = status;
946 mutex_unlock(&arb->pstate_lock);
947
948 /* make status visible */
949 smp_mb();
950 goto exit_arb;
951 }
952 status = volt_set_noiseaware_vmin(g, nuvmin, nuvmin_sram);
950 if (status < 0) { 953 if (status < 0) {
951 arb->status = status; 954 arb->status = status;
955 mutex_unlock(&arb->pstate_lock);
956
952 /* make status visible */ 957 /* make status visible */
953 smp_mb(); 958 smp_mb();
954 goto exit_arb; 959 goto exit_arb;
@@ -957,20 +962,30 @@ static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work)
957 status = nvgpu_clk_arb_change_vf_point(g, gpc2clk_target, 962 status = nvgpu_clk_arb_change_vf_point(g, gpc2clk_target,
958 sys2clk_target, xbar2clk_target, mclk_target, voltuv, 963 sys2clk_target, xbar2clk_target, mclk_target, voltuv,
959 voltuv_sram); 964 voltuv_sram);
960
961 if (status < 0) { 965 if (status < 0) {
962 arb->status = status; 966 arb->status = status;
967 mutex_unlock(&arb->pstate_lock);
968
963 /* make status visible */ 969 /* make status visible */
964 smp_mb(); 970 smp_mb();
965 goto exit_arb; 971 goto exit_arb;
966 } 972 }
967 973
968 status = nvgpu_clk_arb_change_vf_point_postfix(g, gpc2clk_target, 974 status = clk_pmu_freq_controller_load(g, true);
969 sys2clk_target, xbar2clk_target, mclk_target, voltuv, 975 if (status < 0) {
970 voltuv_sram, nuvmin, nuvmin_sram); 976 arb->status = status;
977 mutex_unlock(&arb->pstate_lock);
978
979 /* make status visible */
980 smp_mb();
981 goto exit_arb;
982 }
971 983
984 status = nvgpu_lwpr_mclk_change(g, pstate);
972 if (status < 0) { 985 if (status < 0) {
973 arb->status = status; 986 arb->status = status;
987 mutex_unlock(&arb->pstate_lock);
988
974 /* make status visible */ 989 /* make status visible */
975 smp_mb(); 990 smp_mb();
976 goto exit_arb; 991 goto exit_arb;
@@ -991,15 +1006,24 @@ static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work)
991 smp_wmb(); 1006 smp_wmb();
992 xchg(&arb->actual, actual); 1007 xchg(&arb->actual, actual);
993 1008
1009 status = nvgpu_lpwr_enable_pg(g, false);
1010 if (status < 0) {
1011 arb->status = status;
1012 mutex_unlock(&arb->pstate_lock);
1013
1014 /* make status visible */
1015 smp_mb();
1016 goto exit_arb;
1017 }
1018
994 /* status must be visible before atomic inc */ 1019 /* status must be visible before atomic inc */
995 smp_wmb(); 1020 smp_wmb();
996 atomic_inc(&arb->req_nr); 1021 atomic_inc(&arb->req_nr);
997 1022
998 wake_up_interruptible(&arb->request_wq); 1023 /* Unlock pstate change for PG */
1024 mutex_unlock(&arb->pstate_lock);
999 1025
1000 if (status < 0) 1026 wake_up_interruptible(&arb->request_wq);
1001 gk20a_err(dev_from_gk20a(g),
1002 "Error in arbiter update");
1003 1027
1004#ifdef CONFIG_DEBUG_FS 1028#ifdef CONFIG_DEBUG_FS
1005 g->ops.read_ptimer(g, &t1); 1029 g->ops.read_ptimer(g, &t1);
@@ -1036,6 +1060,9 @@ static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work)
1036#endif 1060#endif
1037 1061
1038exit_arb: 1062exit_arb:
1063 if (status < 0)
1064 gk20a_err(dev_from_gk20a(g),
1065 "Error in arbiter update");
1039 1066
1040 /* notify completion for all requests */ 1067 /* notify completion for all requests */
1041 head = llist_del_all(&arb->requests); 1068 head = llist_del_all(&arb->requests);
@@ -1300,6 +1327,7 @@ recalculate_vf_point:
1300 } 1327 }
1301 if (index == table->mclk_num_points) { 1328 if (index == table->mclk_num_points) {
1302 mclk_vf = &table->mclk_points[index-1]; 1329 mclk_vf = &table->mclk_points[index-1];
1330 index = table->mclk_num_points - 1;
1303 } 1331 }
1304 index_mclk = index; 1332 index_mclk = index;
1305 1333
@@ -1378,28 +1406,11 @@ find_exit:
1378 return pstate; 1406 return pstate;
1379} 1407}
1380 1408
1381static int nvgpu_clk_arb_change_vf_point_prefix(struct gk20a *g, 1409/* This function is inherently unsafe to call while arbiter is running
1382 u16 gpc2clk_target, u16 sys2clk_target, u16 xbar2clk_target, 1410 * arbiter must be blocked before calling this function */
1383 u16 mclk_target, u32 voltuv, u32 voltuv_sram, u32 nuvmin, 1411int nvgpu_clk_arb_get_current_pstate(struct gk20a *g)
1384 u32 nuvmin_sram)
1385{
1386
1387 int status;
1388
1389 status = clk_pmu_freq_controller_load(g, false);
1390 if (status < 0)
1391 return status;
1392
1393 status = volt_set_noiseaware_vmin(g, nuvmin, nuvmin_sram);
1394 return status;
1395}
1396
1397static int nvgpu_clk_arb_change_vf_point_postfix(struct gk20a *g,
1398 u16 gpc2clk_target, u16 sys2clk_target, u16 xbar2clk_target,
1399 u16 mclk_target, u32 voltuv, u32 voltuv_sram, u32 nuvmin,
1400 u32 nuvmin_sram)
1401{ 1412{
1402 return clk_pmu_freq_controller_load(g, true); 1413 return ACCESS_ONCE(g->clk_arb->actual->pstate);
1403} 1414}
1404 1415
1405static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target, 1416static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target,
@@ -1456,6 +1467,17 @@ static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target,
1456 return 0; 1467 return 0;
1457} 1468}
1458 1469
1470void nvgpu_clk_arb_pstate_change_lock(struct gk20a *g, bool lock)
1471{
1472 struct nvgpu_clk_arb *arb = g->clk_arb;
1473
1474 if (lock)
1475 mutex_lock(&arb->pstate_lock);
1476 else
1477 mutex_unlock(&arb->pstate_lock);
1478
1479}
1480
1459#ifdef CONFIG_DEBUG_FS 1481#ifdef CONFIG_DEBUG_FS
1460static int nvgpu_clk_arb_stats_show(struct seq_file *s, void *unused) 1482static int nvgpu_clk_arb_stats_show(struct seq_file *s, void *unused)
1461{ 1483{
diff --git a/drivers/gpu/nvgpu/clk/clk_arb.h b/drivers/gpu/nvgpu/clk/clk_arb.h
index 8355dac5..700804b3 100644
--- a/drivers/gpu/nvgpu/clk/clk_arb.h
+++ b/drivers/gpu/nvgpu/clk/clk_arb.h
@@ -62,5 +62,10 @@ int nvgpu_clk_arb_install_request_fd(struct gk20a *g,
62 struct nvgpu_clk_session *session, int *event_fd); 62 struct nvgpu_clk_session *session, int *event_fd);
63 63
64void nvgpu_clk_arb_schedule_vf_table_update(struct gk20a *g); 64void nvgpu_clk_arb_schedule_vf_table_update(struct gk20a *g);
65
66int nvgpu_clk_arb_get_current_pstate(struct gk20a *g);
67
68void nvgpu_clk_arb_pstate_change_lock(struct gk20a *g, bool lock);
69
65#endif /* _CLK_ARB_H_ */ 70#endif /* _CLK_ARB_H_ */
66 71
diff --git a/drivers/gpu/nvgpu/gp106/pmu_gp106.c b/drivers/gpu/nvgpu/gp106/pmu_gp106.c
index 6f5e71eb..eecd7351 100644
--- a/drivers/gpu/nvgpu/gp106/pmu_gp106.c
+++ b/drivers/gpu/nvgpu/gp106/pmu_gp106.c
@@ -24,6 +24,7 @@
24#include "clk/clk_mclk.h" 24#include "clk/clk_mclk.h"
25#include "hw_mc_gp106.h" 25#include "hw_mc_gp106.h"
26#include "hw_pwr_gp106.h" 26#include "hw_pwr_gp106.h"
27#include "lpwr/lpwr.h"
27#include "lpwr/rppg.h" 28#include "lpwr/rppg.h"
28 29
29#define PMU_MEM_SCRUBBING_TIMEOUT_MAX 1000 30#define PMU_MEM_SCRUBBING_TIMEOUT_MAX 1000
@@ -180,12 +181,16 @@ static u32 gp106_pmu_pg_feature_list(struct gk20a *g, u32 pg_engine_id)
180 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS) 181 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
181 return PMU_PG_FEATURE_GR_RPPG_ENABLED; 182 return PMU_PG_FEATURE_GR_RPPG_ENABLED;
182 183
184 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_MS)
185 return NVGPU_PMU_MS_FEATURE_MASK_ALL;
186
183 return 0; 187 return 0;
184} 188}
185 189
186static u32 gp106_pmu_pg_engines_list(struct gk20a *g) 190static u32 gp106_pmu_pg_engines_list(struct gk20a *g)
187{ 191{
188 return BIT(PMU_PG_ELPG_ENGINE_ID_GRAPHICS); 192 return BIT(PMU_PG_ELPG_ENGINE_ID_GRAPHICS) |
193 BIT(PMU_PG_ELPG_ENGINE_ID_MS);
189} 194}
190 195
191static void pmu_handle_param_msg(struct gk20a *g, struct pmu_msg *msg, 196static void pmu_handle_param_msg(struct gk20a *g, struct pmu_msg *msg,
@@ -231,6 +236,23 @@ static int gp106_pg_param_init(struct gk20a *g, u32 pg_engine_id)
231 gp106_dbg_pmu("cmd post GR PMU_PG_CMD_ID_PG_PARAM"); 236 gp106_dbg_pmu("cmd post GR PMU_PG_CMD_ID_PG_PARAM");
232 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ, 237 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
233 pmu_handle_param_msg, pmu, &seq, ~0); 238 pmu_handle_param_msg, pmu, &seq, ~0);
239 } else if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_MS) {
240 cmd.hdr.unit_id = PMU_UNIT_PG;
241 cmd.hdr.size = PMU_CMD_HDR_SIZE +
242 sizeof(struct pmu_pg_cmd_ms_init_param);
243 cmd.cmd.pg.ms_init_param.cmd_type =
244 PMU_PG_CMD_ID_PG_PARAM;
245 cmd.cmd.pg.ms_init_param.cmd_id =
246 PMU_PG_PARAM_CMD_MS_INIT_PARAM;
247 cmd.cmd.pg.ms_init_param.support_mask =
248 NVGPU_PMU_MS_FEATURE_MASK_CLOCK_GATING |
249 NVGPU_PMU_MS_FEATURE_MASK_SW_ASR |
250 NVGPU_PMU_MS_FEATURE_MASK_RPPG |
251 NVGPU_PMU_MS_FEATURE_MASK_FB_TRAINING;
252
253 gp106_dbg_pmu("cmd post MS PMU_PG_CMD_ID_PG_PARAM");
254 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
255 pmu_handle_param_msg, pmu, &seq, ~0);
234 } 256 }
235 257
236 return 0; 258 return 0;
@@ -261,6 +283,9 @@ void gp106_init_pmu_ops(struct gpu_ops *gops)
261 gops->pmu.pmu_pg_init_param = gp106_pg_param_init; 283 gops->pmu.pmu_pg_init_param = gp106_pg_param_init;
262 gops->pmu.pmu_pg_supported_engines_list = gp106_pmu_pg_engines_list; 284 gops->pmu.pmu_pg_supported_engines_list = gp106_pmu_pg_engines_list;
263 gops->pmu.pmu_pg_engines_feature_list = gp106_pmu_pg_feature_list; 285 gops->pmu.pmu_pg_engines_feature_list = gp106_pmu_pg_feature_list;
286 gops->pmu.pmu_lpwr_enable_pg = nvgpu_lpwr_enable_pg;
287 gops->pmu.pmu_lpwr_disable_pg = nvgpu_lpwr_disable_pg;
288 gops->pmu.pmu_pg_param_post_init = nvgpu_lpwr_post_init;
264 gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd = NULL; 289 gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd = NULL;
265 gops->pmu.dump_secure_fuses = NULL; 290 gops->pmu.dump_secure_fuses = NULL;
266 gops->pmu.reset = gp106_falcon_reset; 291 gops->pmu.reset = gp106_falcon_reset;
diff --git a/drivers/gpu/nvgpu/gp10b/pmu_gp10b.c b/drivers/gpu/nvgpu/gp10b/pmu_gp10b.c
index cd9cd0b0..9274990a 100644
--- a/drivers/gpu/nvgpu/gp10b/pmu_gp10b.c
+++ b/drivers/gpu/nvgpu/gp10b/pmu_gp10b.c
@@ -482,6 +482,9 @@ void gp10b_init_pmu_ops(struct gpu_ops *gops)
482 gops->pmu.pmu_pg_init_param = gp10b_pg_gr_init; 482 gops->pmu.pmu_pg_init_param = gp10b_pg_gr_init;
483 gops->pmu.pmu_pg_supported_engines_list = gk20a_pmu_pg_engines_list; 483 gops->pmu.pmu_pg_supported_engines_list = gk20a_pmu_pg_engines_list;
484 gops->pmu.pmu_pg_engines_feature_list = gk20a_pmu_pg_feature_list; 484 gops->pmu.pmu_pg_engines_feature_list = gk20a_pmu_pg_feature_list;
485 gops->pmu.pmu_lpwr_enable_pg = NULL;
486 gops->pmu.pmu_lpwr_disable_pg = NULL;
487 gops->pmu.pmu_pg_param_post_init = NULL;
485 gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd = 488 gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd =
486 send_ecc_overide_en_dis_cmd; 489 send_ecc_overide_en_dis_cmd;
487 gops->pmu.reset = gk20a_pmu_reset; 490 gops->pmu.reset = gk20a_pmu_reset;
diff --git a/drivers/gpu/nvgpu/include/bios.h b/drivers/gpu/nvgpu/include/bios.h
index f3939d14..097e90ec 100644
--- a/drivers/gpu/nvgpu/include/bios.h
+++ b/drivers/gpu/nvgpu/include/bios.h
@@ -925,4 +925,68 @@ struct vbios_fct_1x_entry {
925#define NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_NEG_MASK GENMASK(31, 16) 925#define NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_NEG_MASK GENMASK(31, 16)
926#define NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_NEG_SHIFT 16 926#define NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_NEG_SHIFT 16
927 927
928/* LPWR Index Table */
929struct nvgpu_bios_lpwr_idx_table_1x_header {
930 u8 version;
931 u8 header_size;
932 u8 entry_size;
933 u8 entry_count;
934 u16 base_sampling_period;
935} __packed;
936
937struct nvgpu_bios_lpwr_idx_table_1x_entry {
938 u8 pcie_idx;
939 u8 gr_idx;
940 u8 ms_idx;
941 u8 di_idx;
942 u8 gc6_idx;
943} __packed;
944
945/* LPWR MS Table*/
946struct nvgpu_bios_lpwr_ms_table_1x_header {
947 u8 version;
948 u8 header_size;
949 u8 entry_size;
950 u8 entry_count;
951 u8 default_entry_idx;
952 u16 idle_threshold_us;
953} __packed;
954
955struct nvgpu_bios_lpwr_ms_table_1x_entry {
956 u32 feautre_mask;
957 u16 dynamic_current_logic;
958 u16 dynamic_current_sram;
959} __packed;
960
961#define NV_VBIOS_LPWR_MS_FEATURE_MASK_MS_MASK GENMASK(0, 0)
962#define NV_VBIOS_LPWR_MS_FEATURE_MASK_MS_SHIFT 0
963#define NV_VBIOS_LPWR_MS_FEATURE_MASK_MS_SWASR_MASK GENMASK(2, 2)
964#define NV_VBIOS_LPWR_MS_FEATURE_MASK_MS_SWASR_SHIFT 2
965#define NV_VBIOS_LPWR_MS_FEATURE_MASK_MS_CLOCK_GATING_MASK \
966 GENMASK(3, 3)
967#define NV_VBIOS_LPWR_MS_FEATURE_MASK_MS_CLOCK_GATING_SHIFT 3
968#define NV_VBIOS_LPWR_MS_FEATURE_MASK_MS_RPPG_MASK GENMASK(5, 5)
969#define NV_VBIOS_LPWR_MS_FEATURE_MASK_MS_RPPG_SHIFT 5
970
971/* LPWR GR Table */
972struct nvgpu_bios_lpwr_gr_table_1x_header {
973 u8 version;
974 u8 header_size;
975 u8 entry_size;
976 u8 entry_count;
977 u8 default_entry_idx;
978 u16 idle_threshold_us;
979 u8 adaptive_gr_multiplier;
980} __packed;
981
982struct nvgpu_bios_lpwr_gr_table_1x_entry {
983 u32 feautre_mask;
984} __packed;
985
986#define NV_VBIOS_LPWR_GR_FEATURE_MASK_GR_MASK GENMASK(0, 0)
987#define NV_VBIOS_LPWR_GR_FEATURE_MASK_GR_SHIFT 0
988
989#define NV_VBIOS_LPWR_GR_FEATURE_MASK_GR_RPPG_MASK GENMASK(4, 4)
990#define NV_VBIOS_LPWR_GR_FEATURE_MASK_GR_RPPG_SHIFT 4
991
928#endif 992#endif
diff --git a/drivers/gpu/nvgpu/lpwr/lpwr.c b/drivers/gpu/nvgpu/lpwr/lpwr.c
new file mode 100644
index 00000000..4f8d2eec
--- /dev/null
+++ b/drivers/gpu/nvgpu/lpwr/lpwr.c
@@ -0,0 +1,423 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include "gk20a/pmu_gk20a.h"
16#include "gp106/pmu_gp106.h"
17#include "gk20a/pmu_api.h"
18#include "gm206/bios_gm206.h"
19#include "pstate/pstate.h"
20#include "include/bios.h"
21#include "perf/perf.h"
22#include "lpwr.h"
23
24static int get_lpwr_idx_table(struct gk20a *g)
25{
26 u32 *lpwr_idx_table_ptr;
27 u8 *entry_addr;
28 u32 idx;
29 struct nvgpu_lpwr_bios_idx_data *pidx_data =
30 &g->perf_pmu.lpwr.lwpr_bios_data.idx;
31 struct nvgpu_bios_lpwr_idx_table_1x_header header = { 0 };
32 struct nvgpu_bios_lpwr_idx_table_1x_entry entry = { 0 };
33
34 if (g->ops.bios.get_perf_table_ptrs) {
35 lpwr_idx_table_ptr = (u32 *)g->ops.bios.get_perf_table_ptrs(g,
36 g->bios.perf_token, LOWPOWER_TABLE);
37 if (lpwr_idx_table_ptr == NULL)
38 return -EINVAL;
39 } else
40 return -EINVAL;
41
42 memcpy(&header, lpwr_idx_table_ptr,
43 sizeof(struct nvgpu_bios_lpwr_idx_table_1x_header));
44
45 if (header.entry_count >= LPWR_VBIOS_IDX_ENTRY_COUNT_MAX)
46 return -EINVAL;
47
48 pidx_data->base_sampling_period = (u16)header.base_sampling_period;
49
50 /* Parse the LPWR Index Table entries.*/
51 for (idx = 0; idx < header.entry_count; idx++) {
52 entry_addr = (u8 *)lpwr_idx_table_ptr + header.header_size +
53 (idx * header.entry_size);
54
55 memcpy(&entry, entry_addr,
56 sizeof(struct nvgpu_bios_lpwr_idx_table_1x_entry));
57
58 pidx_data->entry[idx].pcie_idx = entry.pcie_idx;
59 pidx_data->entry[idx].gr_idx = entry.gr_idx;
60 pidx_data->entry[idx].ms_idx = entry.ms_idx;
61 pidx_data->entry[idx].di_idx = entry.di_idx;
62 pidx_data->entry[idx].gc6_idx = entry.gc6_idx;
63
64 }
65
66 return 0;
67}
68
69static int get_lpwr_gr_table(struct gk20a *g)
70{
71 u32 *lpwr_gr_table_ptr;
72 u8 *entry_addr;
73 u32 idx;
74 struct nvgpu_lpwr_bios_gr_data *pgr_data =
75 &g->perf_pmu.lpwr.lwpr_bios_data.gr;
76 struct nvgpu_bios_lpwr_gr_table_1x_header header = { 0 };
77 struct nvgpu_bios_lpwr_gr_table_1x_entry entry = { 0 };
78
79 if (g->ops.bios.get_perf_table_ptrs) {
80 lpwr_gr_table_ptr = (u32 *)g->ops.bios.get_perf_table_ptrs(g,
81 g->bios.perf_token, LOWPOWER_GR_TABLE);
82 if (lpwr_gr_table_ptr == NULL)
83 return -EINVAL;
84 } else
85 return -EINVAL;
86
87 memcpy(&header, lpwr_gr_table_ptr,
88 sizeof(struct nvgpu_bios_lpwr_gr_table_1x_header));
89
90 /* Parse the LPWR Index Table entries.*/
91 for (idx = 0; idx < header.entry_count; idx++) {
92 entry_addr = (u8 *)lpwr_gr_table_ptr + header.header_size +
93 (idx * header.entry_size);
94
95 memcpy(&entry, entry_addr,
96 sizeof(struct nvgpu_bios_lpwr_gr_table_1x_entry));
97
98 if (BIOS_GET_FIELD(entry.feautre_mask,
99 NV_VBIOS_LPWR_MS_FEATURE_MASK_MS)) {
100 pgr_data->entry[idx].gr_enabled = true;
101
102 pgr_data->entry[idx].feature_mask =
103 NVGPU_PMU_GR_FEATURE_MASK_ALL;
104
105 if (!BIOS_GET_FIELD(entry.feautre_mask,
106 NV_VBIOS_LPWR_GR_FEATURE_MASK_GR_RPPG))
107 pgr_data->entry[idx].feature_mask &=
108 ~NVGPU_PMU_GR_FEATURE_MASK_RPPG;
109 }
110
111 }
112
113 return 0;
114}
115
116static int get_lpwr_ms_table(struct gk20a *g)
117{
118 u32 *lpwr_ms_table_ptr;
119 u8 *entry_addr;
120 u32 idx;
121 struct nvgpu_lpwr_bios_ms_data *pms_data =
122 &g->perf_pmu.lpwr.lwpr_bios_data.ms;
123 struct nvgpu_bios_lpwr_ms_table_1x_header header = { 0 };
124 struct nvgpu_bios_lpwr_ms_table_1x_entry entry = { 0 };
125
126 if (g->ops.bios.get_perf_table_ptrs) {
127 lpwr_ms_table_ptr = (u32 *)g->ops.bios.get_perf_table_ptrs(g,
128 g->bios.perf_token, LOWPOWER_MS_TABLE);
129 if (lpwr_ms_table_ptr == NULL)
130 return -EINVAL;
131 } else
132 return -EINVAL;
133
134 memcpy(&header, lpwr_ms_table_ptr,
135 sizeof(struct nvgpu_bios_lpwr_ms_table_1x_header));
136
137 if (header.entry_count >= LPWR_VBIOS_MS_ENTRY_COUNT_MAX)
138 return -EINVAL;
139
140 pms_data->default_entry_idx = (u8)header.default_entry_idx;
141
142 pms_data->idle_threshold_us = (u32)(header.idle_threshold_us * 10);
143
144 /* Parse the LPWR MS Table entries.*/
145 for (idx = 0; idx < header.entry_count; idx++) {
146 entry_addr = (u8 *)lpwr_ms_table_ptr + header.header_size +
147 (idx * header.entry_size);
148
149 memcpy(&entry, entry_addr,
150 sizeof(struct nvgpu_bios_lpwr_ms_table_1x_entry));
151
152 if (BIOS_GET_FIELD(entry.feautre_mask,
153 NV_VBIOS_LPWR_MS_FEATURE_MASK_MS)) {
154 pms_data->entry[idx].ms_enabled = true;
155
156 pms_data->entry[idx].feature_mask =
157 NVGPU_PMU_MS_FEATURE_MASK_ALL;
158
159 if (!BIOS_GET_FIELD(entry.feautre_mask,
160 NV_VBIOS_LPWR_MS_FEATURE_MASK_MS_CLOCK_GATING))
161 pms_data->entry[idx].feature_mask &=
162 ~NVGPU_PMU_MS_FEATURE_MASK_CLOCK_GATING;
163
164 if (!BIOS_GET_FIELD(entry.feautre_mask,
165 NV_VBIOS_LPWR_MS_FEATURE_MASK_MS_SWASR))
166 pms_data->entry[idx].feature_mask &=
167 ~NVGPU_PMU_MS_FEATURE_MASK_SW_ASR;
168
169 if (!BIOS_GET_FIELD(entry.feautre_mask,
170 NV_VBIOS_LPWR_MS_FEATURE_MASK_MS_RPPG))
171 pms_data->entry[idx].feature_mask &=
172 ~NVGPU_PMU_MS_FEATURE_MASK_RPPG;
173 }
174
175 pms_data->entry[idx].dynamic_current_logic =
176 entry.dynamic_current_logic;
177
178 pms_data->entry[idx].dynamic_current_sram =
179 entry.dynamic_current_sram;
180 }
181
182 return 0;
183}
184
185u32 nvgpu_lpwr_pg_setup(struct gk20a *g)
186{
187 u32 err = 0;
188
189 gk20a_dbg_fn("");
190
191 err = get_lpwr_gr_table(g);
192 if (err)
193 return err;
194
195 err = get_lpwr_ms_table(g);
196 if (err)
197 return err;
198
199 err = get_lpwr_idx_table(g);
200
201 return err;
202}
203
204static void nvgpu_pmu_handle_param_lpwr_msg(struct gk20a *g,
205 struct pmu_msg *msg, void *param,
206 u32 handle, u32 status)
207{
208 u32 *ack_status = param;
209
210 gk20a_dbg_fn("");
211
212 if (status != 0) {
213 gk20a_err(dev_from_gk20a(g), "LWPR PARAM cmd aborted");
214 return;
215 }
216
217 *ack_status = 1;
218
219 gp106_dbg_pmu("lpwr-param is acknowledged from PMU %x",
220 msg->msg.pg.msg_type);
221}
222
223int nvgpu_lwpr_mclk_change(struct gk20a *g, u32 pstate)
224{
225 struct pmu_cmd cmd;
226 u32 seq, status = 0;
227 u32 payload = NV_PMU_PG_PARAM_MCLK_CHANGE_MS_SWASR_ENABLED;
228 struct clk_set_info *pstate_info;
229 u32 ack_status = 0;
230
231 gk20a_dbg_fn("");
232
233 pstate_info = pstate_get_clk_set_info(g, pstate,
234 clkwhich_mclk);
235 if (!pstate_info)
236 return -EINVAL;
237
238 if (pstate_info->max_mhz >
239 MAX_SWASR_MCLK_FREQ_WITHOUT_WR_TRAINING_MAXWELL_MHZ)
240 payload |=
241 NV_PMU_PG_PARAM_MCLK_CHANGE_GDDR5_WR_TRAINING_ENABLED;
242
243 if (payload != g->perf_pmu.lpwr.mclk_change_cache) {
244 g->perf_pmu.lpwr.mclk_change_cache = payload;
245
246 cmd.hdr.unit_id = PMU_UNIT_PG;
247 cmd.hdr.size = PMU_CMD_HDR_SIZE +
248 sizeof(struct pmu_pg_cmd_mclk_change);
249 cmd.cmd.pg.mclk_change.cmd_type =
250 PMU_PG_CMD_ID_PG_PARAM;
251 cmd.cmd.pg.mclk_change.cmd_id =
252 PMU_PG_PARAM_CMD_MCLK_CHANGE;
253 cmd.cmd.pg.mclk_change.data = payload;
254
255 gp106_dbg_pmu("cmd post MS PMU_PG_PARAM_CMD_MCLK_CHANGE");
256 status = gk20a_pmu_cmd_post(g, &cmd, NULL, NULL,
257 PMU_COMMAND_QUEUE_HPQ,
258 nvgpu_pmu_handle_param_lpwr_msg, &ack_status, &seq, ~0);
259
260 pmu_wait_message_cond(&g->pmu, gk20a_get_gr_idle_timeout(g),
261 &ack_status, 1);
262 if (ack_status == 0) {
263 status = -EINVAL;
264 gk20a_err(dev_from_gk20a(g), "MCLK-CHANGE ACK failed");
265 }
266 }
267
268 return status;
269}
270
271u32 nvgpu_lpwr_post_init(struct gk20a *g)
272{
273 struct pmu_cmd cmd;
274 u32 seq;
275 u32 status = 0;
276 u32 ack_status = 0;
277
278 memset(&cmd, 0, sizeof(struct pmu_cmd));
279 cmd.hdr.unit_id = PMU_UNIT_PG;
280 cmd.hdr.size = PMU_CMD_HDR_SIZE +
281 sizeof(struct pmu_pg_cmd_post_init_param);
282
283 cmd.cmd.pg.post_init.cmd_type =
284 PMU_PG_CMD_ID_PG_PARAM;
285 cmd.cmd.pg.post_init.cmd_id =
286 PMU_PG_PARAM_CMD_POST_INIT;
287
288 gp106_dbg_pmu("cmd post post-init PMU_PG_PARAM_CMD_POST_INIT");
289 status = gk20a_pmu_cmd_post(g, &cmd, NULL, NULL,
290 PMU_COMMAND_QUEUE_LPQ,
291 nvgpu_pmu_handle_param_lpwr_msg, &ack_status, &seq, ~0);
292
293 pmu_wait_message_cond(&g->pmu, gk20a_get_gr_idle_timeout(g),
294 &ack_status, 1);
295 if (ack_status == 0) {
296 status = -EINVAL;
297 gk20a_err(dev_from_gk20a(g), "post-init ack failed");
298 }
299
300 return status;
301}
302
303u32 nvgpu_lpwr_is_mscg_supported(struct gk20a *g, u32 pstate_num)
304{
305 struct nvgpu_lpwr_bios_ms_data *pms_data =
306 &g->perf_pmu.lpwr.lwpr_bios_data.ms;
307 struct nvgpu_lpwr_bios_idx_data *pidx_data =
308 &g->perf_pmu.lpwr.lwpr_bios_data.idx;
309 struct pstate *pstate = pstate_find(g, pstate_num);
310 u32 ms_idx;
311
312 gk20a_dbg_fn("");
313
314 if (!pstate)
315 return 0;
316
317 ms_idx = pidx_data->entry[pstate->lpwr_entry_idx].ms_idx;
318 if (pms_data->entry[ms_idx].ms_enabled)
319 return 1;
320 else
321 return 0;
322}
323
324u32 nvgpu_lpwr_is_rppg_supported(struct gk20a *g, u32 pstate_num)
325{
326 struct nvgpu_lpwr_bios_gr_data *pgr_data =
327 &g->perf_pmu.lpwr.lwpr_bios_data.gr;
328 struct nvgpu_lpwr_bios_idx_data *pidx_data =
329 &g->perf_pmu.lpwr.lwpr_bios_data.idx;
330 struct pstate *pstate = pstate_find(g, pstate_num);
331 u32 idx;
332
333 gk20a_dbg_fn("");
334
335 if (!pstate)
336 return 0;
337
338 idx = pidx_data->entry[pstate->lpwr_entry_idx].gr_idx;
339 if (pgr_data->entry[idx].gr_enabled)
340 return 1;
341 else
342 return 0;
343}
344
345
346int nvgpu_lpwr_enable_pg(struct gk20a *g, bool pstate_lock)
347{
348 struct pmu_gk20a *pmu = &g->pmu;
349 u32 status = 0;
350 u32 is_mscg_supported = 0;
351 u32 is_rppg_supported = 0;
352 u32 present_pstate = 0;
353
354 gk20a_dbg_fn("");
355
356 if (pstate_lock)
357 nvgpu_clk_arb_pstate_change_lock(g, true);
358 mutex_lock(&pmu->pg_mutex);
359
360 present_pstate = nvgpu_clk_arb_get_current_pstate(g);
361
362 is_mscg_supported = nvgpu_lpwr_is_mscg_supported(g,
363 present_pstate);
364 if (is_mscg_supported && g->mscg_enabled) {
365 if (!pmu->mscg_stat)
366 pmu->mscg_stat = PMU_MSCG_ENABLED;
367 }
368
369 is_rppg_supported = nvgpu_lpwr_is_rppg_supported(g,
370 present_pstate);
371 if (is_rppg_supported) {
372 if (support_gk20a_pmu(g->dev) && g->elpg_enabled)
373 status = gk20a_pmu_enable_elpg(g);
374 }
375
376 mutex_unlock(&pmu->pg_mutex);
377 if (pstate_lock)
378 nvgpu_clk_arb_pstate_change_lock(g, false);
379
380 return status;
381}
382
383int nvgpu_lpwr_disable_pg(struct gk20a *g, bool pstate_lock)
384{
385 struct pmu_gk20a *pmu = &g->pmu;
386 int status = 0;
387 u32 is_mscg_supported = 0;
388 u32 is_rppg_supported = 0;
389 u32 present_pstate = 0;
390
391 gk20a_dbg_fn("");
392
393 if (pstate_lock)
394 nvgpu_clk_arb_pstate_change_lock(g, true);
395 mutex_lock(&pmu->pg_mutex);
396
397 present_pstate = nvgpu_clk_arb_get_current_pstate(g);
398
399 is_rppg_supported = nvgpu_lpwr_is_rppg_supported(g,
400 present_pstate);
401 if (is_rppg_supported) {
402 if (support_gk20a_pmu(g->dev) && g->elpg_enabled) {
403 status = gk20a_pmu_disable_elpg(g);
404 if (status)
405 goto exit_unlock;
406 }
407 }
408
409 is_mscg_supported = nvgpu_lpwr_is_mscg_supported(g,
410 present_pstate);
411 if (is_mscg_supported && g->mscg_enabled) {
412 if (pmu->mscg_stat)
413 pmu->mscg_stat = PMU_MSCG_DISABLED;
414 }
415
416exit_unlock:
417 mutex_unlock(&pmu->pg_mutex);
418 if (pstate_lock)
419 nvgpu_clk_arb_pstate_change_lock(g, false);
420
421 gk20a_dbg_fn("done");
422 return status;
423}
diff --git a/drivers/gpu/nvgpu/lpwr/lpwr.h b/drivers/gpu/nvgpu/lpwr/lpwr.h
new file mode 100644
index 00000000..6b3259df
--- /dev/null
+++ b/drivers/gpu/nvgpu/lpwr/lpwr.h
@@ -0,0 +1,92 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13#ifndef _MSCG_H_
14#define _MSCG_H_
15
16#define MAX_SWASR_MCLK_FREQ_WITHOUT_WR_TRAINING_MAXWELL_MHZ 540
17
18#define NV_PMU_PG_PARAM_MCLK_CHANGE_MS_SWASR_ENABLED BIT(0x1)
19#define NV_PMU_PG_PARAM_MCLK_CHANGE_GDDR5_WR_TRAINING_ENABLED BIT(0x3)
20
21#define LPWR_ENTRY_COUNT_MAX 0x06
22
23#define LPWR_VBIOS_IDX_ENTRY_COUNT_MAX (LPWR_ENTRY_COUNT_MAX)
24
25#define LPWR_VBIOS_IDX_ENTRY_RSVD \
26 (LPWR_VBIOS_IDX_ENTRY_COUNT_MAX - 1)
27
28#define LPWR_VBIOS_BASE_SAMPLING_PERIOD_DEFAULT (500)
29
30struct nvgpu_lpwr_bios_idx_entry {
31 u8 pcie_idx;
32 u8 gr_idx;
33 u8 ms_idx;
34 u8 di_idx;
35 u8 gc6_idx;
36};
37
38struct nvgpu_lpwr_bios_idx_data {
39 u16 base_sampling_period;
40 struct nvgpu_lpwr_bios_idx_entry entry[LPWR_VBIOS_IDX_ENTRY_COUNT_MAX];
41};
42
43#define LPWR_VBIOS_MS_ENTRY_COUNT_MAX (LPWR_ENTRY_COUNT_MAX)
44
45struct nvgpu_lpwr_bios_ms_entry {
46 bool ms_enabled;
47 u32 feature_mask;
48 u32 asr_efficiency_thresholdl;
49 u16 dynamic_current_logic;
50 u16 dynamic_current_sram;
51};
52
53struct nvgpu_lpwr_bios_ms_data {
54 u8 default_entry_idx;
55 u32 idle_threshold_us;
56 struct nvgpu_lpwr_bios_ms_entry entry[LPWR_VBIOS_MS_ENTRY_COUNT_MAX];
57};
58
59#define LPWR_VBIOS_GR_ENTRY_COUNT_MAX (LPWR_ENTRY_COUNT_MAX)
60
61struct nvgpu_lpwr_bios_gr_entry {
62 bool gr_enabled;
63 u32 feature_mask;
64};
65
66struct nvgpu_lpwr_bios_gr_data {
67 u8 default_entry_idx;
68 u32 idle_threshold_us;
69 u8 adaptive_gr_multiplier;
70 struct nvgpu_lpwr_bios_gr_entry entry[LPWR_VBIOS_GR_ENTRY_COUNT_MAX];
71};
72
73struct nvgpu_lpwr_bios_data {
74 struct nvgpu_lpwr_bios_idx_data idx;
75 struct nvgpu_lpwr_bios_ms_data ms;
76 struct nvgpu_lpwr_bios_gr_data gr;
77};
78
79struct obj_lwpr {
80 struct nvgpu_lpwr_bios_data lwpr_bios_data;
81 u32 mclk_change_cache;
82};
83
84u32 nvgpu_lpwr_pg_setup(struct gk20a *g);
85int nvgpu_lwpr_mclk_change(struct gk20a *g, u32 pstate);
86int nvgpu_lpwr_enable_pg(struct gk20a *g, bool pstate_lock);
87int nvgpu_lpwr_disable_pg(struct gk20a *g, bool pstate_lock);
88u32 nvgpu_lpwr_is_mscg_supported(struct gk20a *g, u32 pstate_num);
89u32 nvgpu_lpwr_is_rppg_supported(struct gk20a *g, u32 pstate_num);
90u32 nvgpu_lpwr_post_init(struct gk20a *g);
91
92#endif
diff --git a/drivers/gpu/nvgpu/perf/perf.h b/drivers/gpu/nvgpu/perf/perf.h
index c03bf2ae..a3213f7a 100644
--- a/drivers/gpu/nvgpu/perf/perf.h
+++ b/drivers/gpu/nvgpu/perf/perf.h
@@ -18,6 +18,7 @@
18#include "pstate/pstate.h" 18#include "pstate/pstate.h"
19#include "gk20a/gk20a.h" 19#include "gk20a/gk20a.h"
20#include "volt/volt.h" 20#include "volt/volt.h"
21#include "lpwr/lpwr.h"
21 22
22#define CTRL_PERF_VFE_VAR_TYPE_INVALID 0x00 23#define CTRL_PERF_VFE_VAR_TYPE_INVALID 0x00
23#define CTRL_PERF_VFE_VAR_TYPE_DERIVED 0x01 24#define CTRL_PERF_VFE_VAR_TYPE_DERIVED 0x01
@@ -57,6 +58,7 @@ struct perf_pmupstate {
57 struct vfe_equs vfe_equobjs; 58 struct vfe_equs vfe_equobjs;
58 struct pstates pstatesobjs; 59 struct pstates pstatesobjs;
59 struct obj_volt volt; 60 struct obj_volt volt;
61 struct obj_lwpr lpwr;
60}; 62};
61 63
62u32 perf_pmu_vfe_load(struct gk20a *g); 64u32 perf_pmu_vfe_load(struct gk20a *g);
diff --git a/drivers/gpu/nvgpu/pstate/pstate.c b/drivers/gpu/nvgpu/pstate/pstate.c
index 2e08ef01..82e809bb 100644
--- a/drivers/gpu/nvgpu/pstate/pstate.c
+++ b/drivers/gpu/nvgpu/pstate/pstate.c
@@ -83,6 +83,10 @@ int gk20a_init_pstate_support(struct gk20a *g)
83 return err; 83 return err;
84 84
85 err = clk_freq_controller_sw_setup(g); 85 err = clk_freq_controller_sw_setup(g);
86 if (err)
87 return err;
88
89 err = nvgpu_lpwr_pg_setup(g);
86 90
87 return err; 91 return err;
88} 92}
@@ -327,6 +331,9 @@ static int pstate_sw_setup(struct gk20a *g)
327 331
328 gk20a_dbg_fn(""); 332 gk20a_dbg_fn("");
329 333
334 init_waitqueue_head(&g->perf_pmu.pstatesobjs.pstate_notifier_wq);
335 mutex_init(&g->perf_pmu.pstatesobjs.pstate_mutex);
336
330 err = boardobjgrpconstruct_e32(&g->perf_pmu.pstatesobjs.super); 337 err = boardobjgrpconstruct_e32(&g->perf_pmu.pstatesobjs.super);
331 if (err) { 338 if (err) {
332 gk20a_err(dev_from_gk20a(g), 339 gk20a_err(dev_from_gk20a(g),
@@ -361,7 +368,7 @@ done:
361 return err; 368 return err;
362} 369}
363 370
364static struct pstate *pstate_find(struct gk20a *g, u32 num) 371struct pstate *pstate_find(struct gk20a *g, u32 num)
365{ 372{
366 struct pstates *pstates = &(g->perf_pmu.pstatesobjs); 373 struct pstates *pstates = &(g->perf_pmu.pstatesobjs);
367 struct pstate *pstate; 374 struct pstate *pstate;
diff --git a/drivers/gpu/nvgpu/pstate/pstate.h b/drivers/gpu/nvgpu/pstate/pstate.h
index b6519c20..af0956e8 100644
--- a/drivers/gpu/nvgpu/pstate/pstate.h
+++ b/drivers/gpu/nvgpu/pstate/pstate.h
@@ -48,6 +48,9 @@ struct pstate {
48struct pstates { 48struct pstates {
49 struct boardobjgrp_e32 super; 49 struct boardobjgrp_e32 super;
50 u32 num_levels; 50 u32 num_levels;
51 wait_queue_head_t pstate_notifier_wq;
52 u32 is_pstate_switch_on;
53 struct mutex pstate_mutex; /* protect is_pstate_switch_on */
51}; 54};
52 55
53int gk20a_init_pstate_support(struct gk20a *g); 56int gk20a_init_pstate_support(struct gk20a *g);
@@ -55,5 +58,6 @@ int gk20a_init_pstate_pmu_support(struct gk20a *g);
55 58
56struct clk_set_info *pstate_get_clk_set_info(struct gk20a *g, u32 pstate_num, 59struct clk_set_info *pstate_get_clk_set_info(struct gk20a *g, u32 pstate_num,
57 enum nv_pmu_clk_clkwhich clkwhich); 60 enum nv_pmu_clk_clkwhich clkwhich);
61struct pstate *pstate_find(struct gk20a *g, u32 num);
58 62
59#endif /* __PSTATE_H__ */ 63#endif /* __PSTATE_H__ */