diff options
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.h | 6 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/pmu_gk20a.c | 234 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/pmu_gk20a.h | 7 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gm206/pmu_gm206.c | 4 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gm20b/pmu_gm20b.c | 4 |
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 | ||
3051 | static void pmu_handle_pg_elpg_msg(struct gk20a *g, struct pmu_msg *msg, | ||
3052 | void *param, u32 handle, u32 status); | ||
3053 | |||
3054 | static void pmu_handle_pg_buf_config_msg(struct gk20a *g, struct pmu_msg *msg, | 3051 | static 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 | ||
3274 | u32 gk20a_pmu_pg_engines_list(struct gk20a *g) | ||
3275 | { | ||
3276 | return BIT(PMU_PG_ELPG_ENGINE_ID_GRAPHICS); | ||
3277 | } | ||
3278 | |||
3279 | u32 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 | |||
3277 | void gk20a_init_pmu_ops(struct gpu_ops *gops) | 3287 | void 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 | ||
3389 | static int pmu_init_powergating(struct gk20a *g) | 3416 | static 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 | } | ||
3485 | static 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 | ||
4805 | exit_reschedule: | 4889 | exit_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 | |||
771 | int gk20a_pmu_enable_elpg(struct gk20a *g); | 775 | int gk20a_pmu_enable_elpg(struct gk20a *g); |
772 | int gk20a_pmu_disable_elpg(struct gk20a *g); | 776 | int gk20a_pmu_disable_elpg(struct gk20a *g); |
773 | 777 | ||
778 | u32 gk20a_pmu_pg_engines_list(struct gk20a *g); | ||
779 | u32 gk20a_pmu_pg_feature_list(struct gk20a *g, u32 pg_engine_id); | ||
780 | |||
774 | void gk20a_pmu_save_zbc(struct gk20a *g, u32 entries); | 781 | void gk20a_pmu_save_zbc(struct gk20a *g, u32 entries); |
775 | 782 | ||
776 | int gk20a_pmu_perfmon_enable(struct gk20a *g, bool enable); | 783 | int 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; |