summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMahantesh Kumbar <mkumbar@nvidia.com>2016-11-03 05:51:43 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2016-12-20 18:15:46 -0500
commit75e52218cec5ccfbb8ec61cb8ba5e41f5e5ec7e5 (patch)
treef931c856ba99844cb2121df36961c4a45326c775
parentd301c02246b95214b13ee7ac8eeceb34acd0899a (diff)
gpu: nvgpu: PG engines init/allow/disallow update
- pmu_init_powergating loops & init multiple PG engines based on PG engines supported - generalize pg init param HAL to support multiple PG-engine init based on PG engine parameter - HAL's to return supported PG engines on chip & its sub features of engine. - Send Allow/Disallow for PG engines which are enabled & supported. - Added defines for pg engines JIRA DNVGPU-71 Change-Id: I236601e092e519a269fcb17c7d1c523a4b51405f Signed-off-by: Mahantesh Kumbar <mkumbar@nvidia.com> Reviewed-on: http://git-master/r/1247409 (cherry-picked from commit 1c138cc475bac7d3c3fbbd5fb18cfcb2e7fdf67a) Reviewed-on: http://git-master/r/1269319 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.h6
-rw-r--r--drivers/gpu/nvgpu/gk20a/pmu_gk20a.c234
-rw-r--r--drivers/gpu/nvgpu/gk20a/pmu_gk20a.h7
-rw-r--r--drivers/gpu/nvgpu/gm206/pmu_gm206.c4
-rw-r--r--drivers/gpu/nvgpu/gm20b/pmu_gm20b.c4
5 files changed, 176 insertions, 79 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h
index 987dd517..a1a8bf36 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.h
@@ -606,8 +606,10 @@ struct gpu_ops {
606 void (*pmu_elpg_statistics)(struct gk20a *g, 606 void (*pmu_elpg_statistics)(struct gk20a *g,
607 u32 *ingating_time, u32 *ungating_time, 607 u32 *ingating_time, u32 *ungating_time,
608 u32 *gating_cnt); 608 u32 *gating_cnt);
609 int (*pmu_pg_grinit_param)(struct gk20a *g, 609 int (*pmu_pg_init_param)(struct gk20a *g, u32 pg_engine_id);
610 u8 grfeaturemask); 610 u32 (*pmu_pg_supported_engines_list)(struct gk20a *g);
611 u32 (*pmu_pg_engines_feature_list)(struct gk20a *g,
612 u32 pg_engine_id);
611 int (*send_lrf_tex_ltc_dram_overide_en_dis_cmd) 613 int (*send_lrf_tex_ltc_dram_overide_en_dis_cmd)
612 (struct gk20a *g, u32 mask); 614 (struct gk20a *g, u32 mask);
613 void (*dump_secure_fuses)(struct gk20a *g); 615 void (*dump_secure_fuses)(struct gk20a *g);
diff --git a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
index 853011f2..c70f9876 100644
--- a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.c
@@ -3048,9 +3048,6 @@ skip_init:
3048 return err; 3048 return err;
3049} 3049}
3050 3050
3051static void pmu_handle_pg_elpg_msg(struct gk20a *g, struct pmu_msg *msg,
3052 void *param, u32 handle, u32 status);
3053
3054static void pmu_handle_pg_buf_config_msg(struct gk20a *g, struct pmu_msg *msg, 3051static void pmu_handle_pg_buf_config_msg(struct gk20a *g, struct pmu_msg *msg,
3055 void *param, u32 handle, u32 status) 3052 void *param, u32 handle, u32 status)
3056{ 3053{
@@ -3274,6 +3271,19 @@ static bool gk20a_is_pmu_supported(struct gk20a *g)
3274 return true; 3271 return true;
3275} 3272}
3276 3273
3274u32 gk20a_pmu_pg_engines_list(struct gk20a *g)
3275{
3276 return BIT(PMU_PG_ELPG_ENGINE_ID_GRAPHICS);
3277}
3278
3279u32 gk20a_pmu_pg_feature_list(struct gk20a *g, u32 pg_engine_id)
3280{
3281 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
3282 return PMU_PG_FEATURE_GR_POWER_GATING_ENABLED;
3283
3284 return 0;
3285}
3286
3277void gk20a_init_pmu_ops(struct gpu_ops *gops) 3287void gk20a_init_pmu_ops(struct gpu_ops *gops)
3278{ 3288{
3279 gops->pmu.is_pmu_supported = gk20a_is_pmu_supported; 3289 gops->pmu.is_pmu_supported = gk20a_is_pmu_supported;
@@ -3285,7 +3295,9 @@ void gk20a_init_pmu_ops(struct gpu_ops *gops)
3285 gops->pmu.load_lsfalcon_ucode = NULL; 3295 gops->pmu.load_lsfalcon_ucode = NULL;
3286 gops->pmu.write_dmatrfbase = gk20a_write_dmatrfbase; 3296 gops->pmu.write_dmatrfbase = gk20a_write_dmatrfbase;
3287 gops->pmu.pmu_elpg_statistics = gk20a_pmu_elpg_statistics; 3297 gops->pmu.pmu_elpg_statistics = gk20a_pmu_elpg_statistics;
3288 gops->pmu.pmu_pg_grinit_param = NULL; 3298 gops->pmu.pmu_pg_init_param = NULL;
3299 gops->pmu.pmu_pg_supported_engines_list = gk20a_pmu_pg_engines_list;
3300 gops->pmu.pmu_pg_engines_feature_list = gk20a_pmu_pg_feature_list;
3289 gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd = NULL; 3301 gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd = NULL;
3290 gops->pmu.dump_secure_fuses = NULL; 3302 gops->pmu.dump_secure_fuses = NULL;
3291 gops->pmu.is_lazy_bootstrap = NULL; 3303 gops->pmu.is_lazy_bootstrap = NULL;
@@ -3330,6 +3342,7 @@ static void pmu_handle_pg_elpg_msg(struct gk20a *g, struct pmu_msg *msg,
3330{ 3342{
3331 struct pmu_gk20a *pmu = param; 3343 struct pmu_gk20a *pmu = param;
3332 struct pmu_pg_msg_elpg_msg *elpg_msg = &msg->msg.pg.elpg_msg; 3344 struct pmu_pg_msg_elpg_msg *elpg_msg = &msg->msg.pg.elpg_msg;
3345 u32 *ack_status = param;
3333 3346
3334 gk20a_dbg_fn(""); 3347 gk20a_dbg_fn("");
3335 3348
@@ -3341,18 +3354,32 @@ static void pmu_handle_pg_elpg_msg(struct gk20a *g, struct pmu_msg *msg,
3341 3354
3342 switch (elpg_msg->msg) { 3355 switch (elpg_msg->msg) {
3343 case PMU_PG_ELPG_MSG_INIT_ACK: 3356 case PMU_PG_ELPG_MSG_INIT_ACK:
3344 gk20a_dbg_pmu("INIT_PG is acknowledged from PMU"); 3357 gk20a_dbg_pmu("INIT_PG is ack from PMU, eng - %d",
3358 elpg_msg->engine_id);
3345 break; 3359 break;
3346 case PMU_PG_ELPG_MSG_ALLOW_ACK: 3360 case PMU_PG_ELPG_MSG_ALLOW_ACK:
3347 gk20a_dbg_pmu("ALLOW is acknowledged from PMU"); 3361 gk20a_dbg_pmu("ALLOW is ack from PMU, eng - %d",
3348 pmu->elpg_stat = PMU_ELPG_STAT_ON; 3362 elpg_msg->engine_id);
3363 if (elpg_msg->engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
3364 pmu->elpg_stat = PMU_ELPG_STAT_ON;
3349 break; 3365 break;
3350 case PMU_PG_ELPG_MSG_DISALLOW_ACK: 3366 case PMU_PG_ELPG_MSG_DISALLOW_ACK:
3351 gk20a_dbg_pmu("DISALLOW is acknowledged from PMU"); 3367 gk20a_dbg_pmu("DISALLOW is ack from PMU, eng - %d",
3352 pmu->elpg_stat = PMU_ELPG_STAT_OFF; 3368 elpg_msg->engine_id);
3369 if (elpg_msg->engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
3370 pmu->elpg_stat = PMU_ELPG_STAT_OFF;
3371 else if (elpg_msg->engine_id == PMU_PG_ELPG_ENGINE_ID_MS)
3372 *ack_status = 1;
3353 if (pmu->pmu_state == PMU_STATE_ELPG_BOOTING) { 3373 if (pmu->pmu_state == PMU_STATE_ELPG_BOOTING) {
3354 pmu->pmu_state = PMU_STATE_ELPG_BOOTED; 3374 pmu->pmu_state = PMU_STATE_ELPG_BOOTED;
3355 schedule_work(&pmu->pg_init); 3375 if (g->ops.pmu.pmu_pg_engines_feature_list &&
3376 g->ops.pmu.pmu_pg_engines_feature_list(g,
3377 PMU_PG_ELPG_ENGINE_ID_GRAPHICS) !=
3378 PMU_PG_FEATURE_GR_POWER_GATING_ENABLED) {
3379 pmu->initialized = true;
3380 pmu->pmu_state = PMU_STATE_STARTED;
3381 } else
3382 schedule_work(&pmu->pg_init);
3356 } 3383 }
3357 break; 3384 break;
3358 default: 3385 default:
@@ -3386,43 +3413,37 @@ static void pmu_handle_pg_stat_msg(struct gk20a *g, struct pmu_msg *msg,
3386 } 3413 }
3387} 3414}
3388 3415
3389static int pmu_init_powergating(struct gk20a *g) 3416static int pmu_pg_init_send(struct gk20a *g, u32 pg_engine_id)
3390{ 3417{
3391 struct pmu_gk20a *pmu = &g->pmu; 3418 struct pmu_gk20a *pmu = &g->pmu;
3392 struct pmu_cmd cmd; 3419 struct pmu_cmd cmd;
3393 u32 seq; 3420 u32 seq;
3394 u32 gr_engine_id;
3395 3421
3396 gk20a_dbg_fn(""); 3422 gk20a_dbg_fn("");
3397 3423
3398 gr_engine_id = gk20a_fifo_get_gr_engine_id(g);
3399
3400 if (tegra_cpu_is_asim()) { 3424 if (tegra_cpu_is_asim()) {
3401 /* TBD: calculate threshold for silicon */ 3425 /* TBD: calculate threshold for silicon */
3402 gk20a_writel(g, pwr_pmu_pg_idlefilth_r(gr_engine_id), 3426 gk20a_writel(g, pwr_pmu_pg_idlefilth_r(pg_engine_id),
3403 PMU_PG_IDLE_THRESHOLD_SIM); 3427 PMU_PG_IDLE_THRESHOLD_SIM);
3404 gk20a_writel(g, pwr_pmu_pg_ppuidlefilth_r(gr_engine_id), 3428 gk20a_writel(g, pwr_pmu_pg_ppuidlefilth_r(pg_engine_id),
3405 PMU_PG_POST_POWERUP_IDLE_THRESHOLD_SIM); 3429 PMU_PG_POST_POWERUP_IDLE_THRESHOLD_SIM);
3406 } else { 3430 } else {
3407 /* TBD: calculate threshold for silicon */ 3431 /* TBD: calculate threshold for silicon */
3408 gk20a_writel(g, pwr_pmu_pg_idlefilth_r(gr_engine_id), 3432 gk20a_writel(g, pwr_pmu_pg_idlefilth_r(pg_engine_id),
3409 PMU_PG_IDLE_THRESHOLD); 3433 PMU_PG_IDLE_THRESHOLD);
3410 gk20a_writel(g, pwr_pmu_pg_ppuidlefilth_r(gr_engine_id), 3434 gk20a_writel(g, pwr_pmu_pg_ppuidlefilth_r(pg_engine_id),
3411 PMU_PG_POST_POWERUP_IDLE_THRESHOLD); 3435 PMU_PG_POST_POWERUP_IDLE_THRESHOLD);
3412 } 3436 }
3413 3437
3414 gk20a_gr_wait_initialized(g); 3438 if (g->ops.pmu.pmu_pg_init_param)
3415 3439 g->ops.pmu.pmu_pg_init_param(g, pg_engine_id);
3416 if (g->ops.pmu.pmu_pg_grinit_param)
3417 g->ops.pmu.pmu_pg_grinit_param(g,
3418 PMU_PG_FEATURE_GR_POWER_GATING_ENABLED);
3419 3440
3420 /* init ELPG */ 3441 /* init ELPG */
3421 memset(&cmd, 0, sizeof(struct pmu_cmd)); 3442 memset(&cmd, 0, sizeof(struct pmu_cmd));
3422 cmd.hdr.unit_id = PMU_UNIT_PG; 3443 cmd.hdr.unit_id = PMU_UNIT_PG;
3423 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_elpg_cmd); 3444 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_elpg_cmd);
3424 cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD; 3445 cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
3425 cmd.cmd.pg.elpg_cmd.engine_id = gr_engine_id; 3446 cmd.cmd.pg.elpg_cmd.engine_id = pg_engine_id;
3426 cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_INIT; 3447 cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_INIT;
3427 3448
3428 gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_INIT"); 3449 gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_INIT");
@@ -3435,7 +3456,7 @@ static int pmu_init_powergating(struct gk20a *g)
3435 cmd.hdr.unit_id = PMU_UNIT_PG; 3456 cmd.hdr.unit_id = PMU_UNIT_PG;
3436 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_stat); 3457 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_stat);
3437 cmd.cmd.pg.stat.cmd_type = PMU_PG_CMD_ID_PG_STAT; 3458 cmd.cmd.pg.stat.cmd_type = PMU_PG_CMD_ID_PG_STAT;
3438 cmd.cmd.pg.stat.engine_id = gr_engine_id; 3459 cmd.cmd.pg.stat.engine_id = pg_engine_id;
3439 cmd.cmd.pg.stat.sub_cmd_id = PMU_PG_STAT_CMD_ALLOC_DMEM; 3460 cmd.cmd.pg.stat.sub_cmd_id = PMU_PG_STAT_CMD_ALLOC_DMEM;
3440 cmd.cmd.pg.stat.data = 0; 3461 cmd.cmd.pg.stat.data = 0;
3441 3462
@@ -3445,20 +3466,45 @@ static int pmu_init_powergating(struct gk20a *g)
3445 3466
3446 /* disallow ELPG initially 3467 /* disallow ELPG initially
3447 PMU ucode requires a disallow cmd before allow cmd */ 3468 PMU ucode requires a disallow cmd before allow cmd */
3448 pmu->elpg_stat = PMU_ELPG_STAT_OFF; /* set for wait_event PMU_ELPG_STAT_OFF */ 3469 /* set for wait_event PMU_ELPG_STAT_OFF */
3470 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
3471 pmu->elpg_stat = PMU_ELPG_STAT_OFF;
3449 memset(&cmd, 0, sizeof(struct pmu_cmd)); 3472 memset(&cmd, 0, sizeof(struct pmu_cmd));
3450 cmd.hdr.unit_id = PMU_UNIT_PG; 3473 cmd.hdr.unit_id = PMU_UNIT_PG;
3451 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_elpg_cmd); 3474 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_elpg_cmd);
3452 cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD; 3475 cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
3453 cmd.cmd.pg.elpg_cmd.engine_id = gr_engine_id; 3476 cmd.cmd.pg.elpg_cmd.engine_id = pg_engine_id;
3454 cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_DISALLOW; 3477 cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_DISALLOW;
3455 3478
3456 gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_DISALLOW"); 3479 gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_DISALLOW");
3457 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ, 3480 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ,
3458 pmu_handle_pg_elpg_msg, pmu, &seq, ~0); 3481 pmu_handle_pg_elpg_msg, pmu, &seq, ~0);
3482
3483 return 0;
3484}
3485static int pmu_init_powergating(struct gk20a *g)
3486{
3487 struct pmu_gk20a *pmu = &g->pmu;
3488 u32 pg_engine_id;
3489 u32 pg_engine_id_list = 0;
3459 3490
3460 if (pmu->pmu_state == PMU_STATE_INIT_RECEIVED) 3491 gk20a_dbg_fn("");
3461 pmu->pmu_state = PMU_STATE_ELPG_BOOTING; 3492
3493 if (g->ops.pmu.pmu_pg_supported_engines_list)
3494 pg_engine_id_list = g->ops.pmu.pmu_pg_supported_engines_list(g);
3495
3496 gk20a_gr_wait_initialized(g);
3497
3498 for (pg_engine_id = PMU_PG_ELPG_ENGINE_ID_GRAPHICS;
3499 pg_engine_id < PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE;
3500 pg_engine_id++) {
3501
3502 if (BIT(pg_engine_id) & pg_engine_id_list) {
3503 pmu_pg_init_send(g, pg_engine_id);
3504 if (pmu->pmu_state == PMU_STATE_INIT_RECEIVED)
3505 pmu->pmu_state = PMU_STATE_ELPG_BOOTING;
3506 }
3507 }
3462 3508
3463 return 0; 3509 return 0;
3464} 3510}
@@ -4652,28 +4698,39 @@ static int gk20a_pmu_enable_elpg_locked(struct gk20a *g)
4652 struct pmu_gk20a *pmu = &g->pmu; 4698 struct pmu_gk20a *pmu = &g->pmu;
4653 struct pmu_cmd cmd; 4699 struct pmu_cmd cmd;
4654 u32 seq, status; 4700 u32 seq, status;
4655 u32 gr_engine_id; 4701 u32 pg_engine_id;
4702 u32 pg_engine_id_list = 0;
4656 4703
4657 gk20a_dbg_fn(""); 4704 gk20a_dbg_fn("");
4658 4705
4659 gr_engine_id = gk20a_fifo_get_gr_engine_id(g); 4706 if (g->ops.pmu.pmu_pg_supported_engines_list)
4660 4707 pg_engine_id_list = g->ops.pmu.pmu_pg_supported_engines_list(g);
4661 memset(&cmd, 0, sizeof(struct pmu_cmd)); 4708 for (pg_engine_id = PMU_PG_ELPG_ENGINE_ID_GRAPHICS;
4662 cmd.hdr.unit_id = PMU_UNIT_PG; 4709 pg_engine_id < PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE;
4663 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_elpg_cmd); 4710 pg_engine_id++) {
4664 cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD; 4711
4665 cmd.cmd.pg.elpg_cmd.engine_id = gr_engine_id; 4712 if (BIT(pg_engine_id) & pg_engine_id_list) {
4666 cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_ALLOW; 4713 memset(&cmd, 0, sizeof(struct pmu_cmd));
4667 4714 cmd.hdr.unit_id = PMU_UNIT_PG;
4668 /* no need to wait ack for ELPG enable but set pending to sync 4715 cmd.hdr.size = PMU_CMD_HDR_SIZE +
4669 with follow up ELPG disable */ 4716 sizeof(struct pmu_pg_cmd_elpg_cmd);
4670 pmu->elpg_stat = PMU_ELPG_STAT_ON_PENDING; 4717 cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
4671 4718 cmd.cmd.pg.elpg_cmd.engine_id = pg_engine_id;
4672 gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_ALLOW"); 4719 cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_ALLOW;
4673 status = gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ, 4720
4674 pmu_handle_pg_elpg_msg, pmu, &seq, ~0); 4721 /* no need to wait ack for ELPG enable but set
4675 4722 * pending to sync with follow up ELPG disable
4676 BUG_ON(status != 0); 4723 */
4724 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
4725 pmu->elpg_stat = PMU_ELPG_STAT_ON_PENDING;
4726
4727 gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_ALLOW");
4728 status = gk20a_pmu_cmd_post(g, &cmd, NULL, NULL,
4729 PMU_COMMAND_QUEUE_HPQ, pmu_handle_pg_elpg_msg,
4730 pmu, &seq, ~0);
4731 WARN_ON(status != 0);
4732 }
4733 }
4677 4734
4678 gk20a_dbg_fn("done"); 4735 gk20a_dbg_fn("done");
4679 return 0; 4736 return 0;
@@ -4729,11 +4786,17 @@ int gk20a_pmu_disable_elpg(struct gk20a *g)
4729 struct pmu_cmd cmd; 4786 struct pmu_cmd cmd;
4730 u32 seq; 4787 u32 seq;
4731 int ret = 0; 4788 int ret = 0;
4732 u32 gr_engine_id; 4789 u32 pg_engine_id;
4790 u32 pg_engine_id_list = 0;
4791 u32 ack_status = 0;
4792 u32 *wait_msg_cond_ptr = NULL;
4793 u32 wait_msg_cond = 0;
4794 void *cb_param = NULL;
4733 4795
4734 gk20a_dbg_fn(""); 4796 gk20a_dbg_fn("");
4735 4797
4736 gr_engine_id = gk20a_fifo_get_gr_engine_id(g); 4798 if (g->ops.pmu.pmu_pg_supported_engines_list)
4799 pg_engine_id_list = g->ops.pmu.pmu_pg_supported_engines_list(g);
4737 4800
4738 if (!support_gk20a_pmu(g->dev)) 4801 if (!support_gk20a_pmu(g->dev))
4739 return ret; 4802 return ret;
@@ -4778,28 +4841,49 @@ int gk20a_pmu_disable_elpg(struct gk20a *g)
4778 goto exit_reschedule; 4841 goto exit_reschedule;
4779 } 4842 }
4780 4843
4781 memset(&cmd, 0, sizeof(struct pmu_cmd)); 4844 for (pg_engine_id = PMU_PG_ELPG_ENGINE_ID_GRAPHICS;
4782 cmd.hdr.unit_id = PMU_UNIT_PG; 4845 pg_engine_id < PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE;
4783 cmd.hdr.size = PMU_CMD_HDR_SIZE + sizeof(struct pmu_pg_cmd_elpg_cmd); 4846 pg_engine_id++) {
4784 cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD; 4847
4785 cmd.cmd.pg.elpg_cmd.engine_id = gr_engine_id; 4848 if (BIT(pg_engine_id) & pg_engine_id_list) {
4786 cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_DISALLOW; 4849 memset(&cmd, 0, sizeof(struct pmu_cmd));
4787 4850 cmd.hdr.unit_id = PMU_UNIT_PG;
4788 pmu->elpg_stat = PMU_ELPG_STAT_OFF_PENDING; 4851 cmd.hdr.size = PMU_CMD_HDR_SIZE +
4852 sizeof(struct pmu_pg_cmd_elpg_cmd);
4853 cmd.cmd.pg.elpg_cmd.cmd_type = PMU_PG_CMD_ID_ELPG_CMD;
4854 cmd.cmd.pg.elpg_cmd.engine_id = pg_engine_id;
4855 cmd.cmd.pg.elpg_cmd.cmd = PMU_PG_ELPG_CMD_DISALLOW;
4856
4857 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS)
4858 pmu->elpg_stat = PMU_ELPG_STAT_OFF_PENDING;
4859
4860 if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_GRAPHICS) {
4861 wait_msg_cond_ptr = &pmu->elpg_stat;
4862 wait_msg_cond = PMU_ELPG_STAT_OFF;
4863 cb_param = pmu;
4864 } else if (pg_engine_id == PMU_PG_ELPG_ENGINE_ID_MS) {
4865 wait_msg_cond_ptr = &ack_status;
4866 wait_msg_cond = 0x1;
4867 cb_param = &ack_status;
4868 }
4789 4869
4790 gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_DISALLOW"); 4870 gk20a_dbg_pmu("cmd post PMU_PG_ELPG_CMD_DISALLOW");
4791 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL, PMU_COMMAND_QUEUE_HPQ, 4871 gk20a_pmu_cmd_post(g, &cmd, NULL, NULL,
4792 pmu_handle_pg_elpg_msg, pmu, &seq, ~0); 4872 PMU_COMMAND_QUEUE_HPQ, pmu_handle_pg_elpg_msg,
4873 cb_param, &seq, ~0);
4793 4874
4794 pmu_wait_message_cond(pmu, gk20a_get_gr_idle_timeout(g), 4875 pmu_wait_message_cond(pmu,
4795 &pmu->elpg_stat, PMU_ELPG_STAT_OFF); 4876 gk20a_get_gr_idle_timeout(g),
4796 if (pmu->elpg_stat != PMU_ELPG_STAT_OFF) { 4877 wait_msg_cond_ptr, wait_msg_cond);
4797 gk20a_err(dev_from_gk20a(g), 4878 if (*wait_msg_cond_ptr != wait_msg_cond) {
4798 "ELPG_DISALLOW_ACK failed"); 4879 gk20a_err(dev_from_gk20a(g),
4799 pmu_dump_elpg_stats(pmu); 4880 "ELPG_DISALLOW_ACK failed");
4800 pmu_dump_falcon_stats(pmu); 4881 pmu_dump_elpg_stats(pmu);
4801 ret = -EBUSY; 4882 pmu_dump_falcon_stats(pmu);
4802 goto exit_unlock; 4883 ret = -EBUSY;
4884 goto exit_unlock;
4885 }
4886 }
4803 } 4887 }
4804 4888
4805exit_reschedule: 4889exit_reschedule:
diff --git a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h
index bfb6f117..78652bcb 100644
--- a/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/pmu_gk20a.h
@@ -615,6 +615,10 @@ struct pmu_pg_stats {
615#define PMU_PG_IDLE_THRESHOLD 15000 615#define PMU_PG_IDLE_THRESHOLD 15000
616#define PMU_PG_POST_POWERUP_IDLE_THRESHOLD 1000000 616#define PMU_PG_POST_POWERUP_IDLE_THRESHOLD 1000000
617 617
618#define PMU_PG_ELPG_ENGINE_ID_GRAPHICS (0x00000000)
619#define PMU_PG_ELPG_ENGINE_ID_MS (0x00000004)
620#define PMU_PG_ELPG_ENGINE_ID_INVALID_ENGINE (0x00000005)
621
618/* state transition : 622/* state transition :
619 OFF => [OFF_ON_PENDING optional] => ON_PENDING => ON => OFF 623 OFF => [OFF_ON_PENDING optional] => ON_PENDING => ON => OFF
620 ON => OFF is always synchronized */ 624 ON => OFF is always synchronized */
@@ -771,6 +775,9 @@ int gk20a_pmu_cmd_post(struct gk20a *g, struct pmu_cmd *cmd, struct pmu_msg *msg
771int gk20a_pmu_enable_elpg(struct gk20a *g); 775int gk20a_pmu_enable_elpg(struct gk20a *g);
772int gk20a_pmu_disable_elpg(struct gk20a *g); 776int gk20a_pmu_disable_elpg(struct gk20a *g);
773 777
778u32 gk20a_pmu_pg_engines_list(struct gk20a *g);
779u32 gk20a_pmu_pg_feature_list(struct gk20a *g, u32 pg_engine_id);
780
774void gk20a_pmu_save_zbc(struct gk20a *g, u32 entries); 781void gk20a_pmu_save_zbc(struct gk20a *g, u32 entries);
775 782
776int gk20a_pmu_perfmon_enable(struct gk20a *g, bool enable); 783int gk20a_pmu_perfmon_enable(struct gk20a *g, bool enable);
diff --git a/drivers/gpu/nvgpu/gm206/pmu_gm206.c b/drivers/gpu/nvgpu/gm206/pmu_gm206.c
index a87ecc1d..d109be97 100644
--- a/drivers/gpu/nvgpu/gm206/pmu_gm206.c
+++ b/drivers/gpu/nvgpu/gm206/pmu_gm206.c
@@ -156,7 +156,9 @@ void gm206_init_pmu_ops(struct gpu_ops *gops)
156 gops->pmu.fecsbootstrapdone = false; 156 gops->pmu.fecsbootstrapdone = false;
157 gops->pmu.write_dmatrfbase = gm20b_write_dmatrfbase; 157 gops->pmu.write_dmatrfbase = gm20b_write_dmatrfbase;
158 gops->pmu.pmu_elpg_statistics = NULL; 158 gops->pmu.pmu_elpg_statistics = NULL;
159 gops->pmu.pmu_pg_grinit_param = NULL; 159 gops->pmu.pmu_pg_init_param = NULL;
160 gops->pmu.pmu_pg_supported_engines_list = NULL;
161 gops->pmu.pmu_pg_engines_feature_list = NULL;
160 gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd = NULL; 162 gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd = NULL;
161 gops->pmu.dump_secure_fuses = NULL; 163 gops->pmu.dump_secure_fuses = NULL;
162 gops->pmu.reset = gk20a_pmu_reset; 164 gops->pmu.reset = gk20a_pmu_reset;
diff --git a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c
index 5c5a889a..517c92a1 100644
--- a/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c
+++ b/drivers/gpu/nvgpu/gm20b/pmu_gm20b.c
@@ -285,7 +285,9 @@ void gm20b_init_pmu_ops(struct gpu_ops *gops)
285 gops->pmu.fecsbootstrapdone = false; 285 gops->pmu.fecsbootstrapdone = false;
286 gops->pmu.write_dmatrfbase = gm20b_write_dmatrfbase; 286 gops->pmu.write_dmatrfbase = gm20b_write_dmatrfbase;
287 gops->pmu.pmu_elpg_statistics = gk20a_pmu_elpg_statistics; 287 gops->pmu.pmu_elpg_statistics = gk20a_pmu_elpg_statistics;
288 gops->pmu.pmu_pg_grinit_param = NULL; 288 gops->pmu.pmu_pg_init_param = NULL;
289 gops->pmu.pmu_pg_supported_engines_list = gk20a_pmu_pg_engines_list;
290 gops->pmu.pmu_pg_engines_feature_list = gk20a_pmu_pg_feature_list;
289 gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd = NULL; 291 gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd = NULL;
290 gops->pmu.dump_secure_fuses = pmu_dump_security_fuses_gm20b; 292 gops->pmu.dump_secure_fuses = pmu_dump_security_fuses_gm20b;
291 gops->pmu.reset = gk20a_pmu_reset; 293 gops->pmu.reset = gk20a_pmu_reset;