Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/display: Init DCN35 clocks from pre-os HW values

[Why]
We did not initialize dc clocks with boot-time hw values during init.
This lead to incorrect clock values in dc, causing `dcn35_update_clocks`
to make incorrect updates.

[How]
Correctly initialize DC with pre-os clk values from HW.
s/dump/save/ as that accurately reflects the purpose of the functions.

Fixes: 8774029f76b9 ("drm/amd/display: Add DCN35 CLK_MGR")
Reviewed-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Signed-off-by: Ivan Lipski <ivan.lipski@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Leo Li and committed by
Alex Deucher
d43cc4ea 550038ed

+119 -2
+119 -2
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
··· 587 587 return true; 588 588 } 589 589 590 - static void dcn35_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, 590 + static void dcn35_save_clk_registers_internal(struct dcn35_clk_internal *internal, struct clk_mgr *clk_mgr_base) 591 + { 592 + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 593 + 594 + // read dtbclk 595 + internal->CLK1_CLK4_CURRENT_CNT = REG_READ(CLK1_CLK4_CURRENT_CNT); 596 + internal->CLK1_CLK4_BYPASS_CNTL = REG_READ(CLK1_CLK4_BYPASS_CNTL); 597 + 598 + // read dcfclk 599 + internal->CLK1_CLK3_CURRENT_CNT = REG_READ(CLK1_CLK3_CURRENT_CNT); 600 + internal->CLK1_CLK3_BYPASS_CNTL = REG_READ(CLK1_CLK3_BYPASS_CNTL); 601 + 602 + // read dcf deep sleep divider 603 + internal->CLK1_CLK3_DS_CNTL = REG_READ(CLK1_CLK3_DS_CNTL); 604 + internal->CLK1_CLK3_ALLOW_DS = REG_READ(CLK1_CLK3_ALLOW_DS); 605 + 606 + // read dppclk 607 + internal->CLK1_CLK1_CURRENT_CNT = REG_READ(CLK1_CLK1_CURRENT_CNT); 608 + internal->CLK1_CLK1_BYPASS_CNTL = REG_READ(CLK1_CLK1_BYPASS_CNTL); 609 + 610 + // read dprefclk 611 + internal->CLK1_CLK2_CURRENT_CNT = REG_READ(CLK1_CLK2_CURRENT_CNT); 612 + internal->CLK1_CLK2_BYPASS_CNTL = REG_READ(CLK1_CLK2_BYPASS_CNTL); 613 + 614 + // read dispclk 615 + internal->CLK1_CLK0_CURRENT_CNT = REG_READ(CLK1_CLK0_CURRENT_CNT); 616 + internal->CLK1_CLK0_BYPASS_CNTL = REG_READ(CLK1_CLK0_BYPASS_CNTL); 617 + } 618 + 619 + static void dcn35_save_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, 591 620 struct clk_mgr_dcn35 *clk_mgr) 592 621 { 622 + struct dcn35_clk_internal internal = {0}; 623 + char *bypass_clks[5] = {"0x0 DFS", "0x1 REFCLK", "0x2 ERROR", "0x3 400 FCH", "0x4 600 FCH"}; 624 + 625 + dcn35_save_clk_registers_internal(&internal, &clk_mgr->base.base); 626 + 627 + regs_and_bypass->dcfclk = internal.CLK1_CLK3_CURRENT_CNT / 10; 628 + regs_and_bypass->dcf_deep_sleep_divider = internal.CLK1_CLK3_DS_CNTL / 10; 629 + regs_and_bypass->dcf_deep_sleep_allow = internal.CLK1_CLK3_ALLOW_DS; 630 + regs_and_bypass->dprefclk = internal.CLK1_CLK2_CURRENT_CNT / 10; 631 + regs_and_bypass->dispclk = internal.CLK1_CLK0_CURRENT_CNT / 10; 632 + regs_and_bypass->dppclk = internal.CLK1_CLK1_CURRENT_CNT / 10; 633 + regs_and_bypass->dtbclk = internal.CLK1_CLK4_CURRENT_CNT / 10; 634 + 635 + regs_and_bypass->dppclk_bypass = internal.CLK1_CLK1_BYPASS_CNTL & 0x0007; 636 + if (regs_and_bypass->dppclk_bypass < 0 || regs_and_bypass->dppclk_bypass > 4) 637 + regs_and_bypass->dppclk_bypass = 0; 638 + regs_and_bypass->dcfclk_bypass = internal.CLK1_CLK3_BYPASS_CNTL & 0x0007; 639 + if (regs_and_bypass->dcfclk_bypass < 0 || regs_and_bypass->dcfclk_bypass > 4) 640 + regs_and_bypass->dcfclk_bypass = 0; 641 + regs_and_bypass->dispclk_bypass = internal.CLK1_CLK0_BYPASS_CNTL & 0x0007; 642 + if (regs_and_bypass->dispclk_bypass < 0 || regs_and_bypass->dispclk_bypass > 4) 643 + regs_and_bypass->dispclk_bypass = 0; 644 + regs_and_bypass->dprefclk_bypass = internal.CLK1_CLK2_BYPASS_CNTL & 0x0007; 645 + if (regs_and_bypass->dprefclk_bypass < 0 || regs_and_bypass->dprefclk_bypass > 4) 646 + regs_and_bypass->dprefclk_bypass = 0; 647 + 648 + if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) { 649 + DC_LOG_SMU("clk_type,clk_value,deepsleep_cntl,deepsleep_allow,bypass\n"); 650 + 651 + DC_LOG_SMU("dcfclk,%d,%d,%d,%s\n", 652 + regs_and_bypass->dcfclk, 653 + regs_and_bypass->dcf_deep_sleep_divider, 654 + regs_and_bypass->dcf_deep_sleep_allow, 655 + bypass_clks[(int) regs_and_bypass->dcfclk_bypass]); 656 + 657 + DC_LOG_SMU("dprefclk,%d,N/A,N/A,%s\n", 658 + regs_and_bypass->dprefclk, 659 + bypass_clks[(int) regs_and_bypass->dprefclk_bypass]); 660 + 661 + DC_LOG_SMU("dispclk,%d,N/A,N/A,%s\n", 662 + regs_and_bypass->dispclk, 663 + bypass_clks[(int) regs_and_bypass->dispclk_bypass]); 664 + 665 + // REGISTER VALUES 666 + DC_LOG_SMU("reg_name,value,clk_type"); 667 + 668 + DC_LOG_SMU("CLK1_CLK3_CURRENT_CNT,%d,dcfclk", 669 + internal.CLK1_CLK3_CURRENT_CNT); 670 + 671 + DC_LOG_SMU("CLK1_CLK4_CURRENT_CNT,%d,dtbclk", 672 + internal.CLK1_CLK4_CURRENT_CNT); 673 + 674 + DC_LOG_SMU("CLK1_CLK3_DS_CNTL,%d,dcf_deep_sleep_divider", 675 + internal.CLK1_CLK3_DS_CNTL); 676 + 677 + DC_LOG_SMU("CLK1_CLK3_ALLOW_DS,%d,dcf_deep_sleep_allow", 678 + internal.CLK1_CLK3_ALLOW_DS); 679 + 680 + DC_LOG_SMU("CLK1_CLK2_CURRENT_CNT,%d,dprefclk", 681 + internal.CLK1_CLK2_CURRENT_CNT); 682 + 683 + DC_LOG_SMU("CLK1_CLK0_CURRENT_CNT,%d,dispclk", 684 + internal.CLK1_CLK0_CURRENT_CNT); 685 + 686 + DC_LOG_SMU("CLK1_CLK1_CURRENT_CNT,%d,dppclk", 687 + internal.CLK1_CLK1_CURRENT_CNT); 688 + 689 + DC_LOG_SMU("CLK1_CLK3_BYPASS_CNTL,%d,dcfclk_bypass", 690 + internal.CLK1_CLK3_BYPASS_CNTL); 691 + 692 + DC_LOG_SMU("CLK1_CLK2_BYPASS_CNTL,%d,dprefclk_bypass", 693 + internal.CLK1_CLK2_BYPASS_CNTL); 694 + 695 + DC_LOG_SMU("CLK1_CLK0_BYPASS_CNTL,%d,dispclk_bypass", 696 + internal.CLK1_CLK0_BYPASS_CNTL); 697 + 698 + DC_LOG_SMU("CLK1_CLK1_BYPASS_CNTL,%d,dppclk_bypass", 699 + internal.CLK1_CLK1_BYPASS_CNTL); 700 + 701 + } 593 702 } 594 703 595 704 static bool dcn35_is_spll_ssc_enabled(struct clk_mgr *clk_mgr_base) ··· 732 623 void dcn35_init_clocks(struct clk_mgr *clk_mgr) 733 624 { 734 625 struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr); 626 + struct clk_mgr_dcn35 *clk_mgr_dcn35 = TO_CLK_MGR_DCN35(clk_mgr_int); 735 627 736 628 init_clk_states(clk_mgr); 737 629 ··· 743 633 else 744 634 clk_mgr->dp_dto_source_clock_in_khz = clk_mgr->dprefclk_khz; 745 635 636 + dcn35_save_clk_registers(&clk_mgr->boot_snapshot, clk_mgr_dcn35); 637 + 638 + clk_mgr->clks.ref_dtbclk_khz = clk_mgr->boot_snapshot.dtbclk * 10; 639 + if (clk_mgr->boot_snapshot.dtbclk > 59000) { 640 + /*dtbclk enabled based on */ 641 + clk_mgr->clks.dtbclk_en = true; 642 + } 746 643 } 747 644 static struct clk_bw_params dcn35_bw_params = { 748 645 .vram_type = Ddr4MemType, ··· 1440 1323 dcn35_bw_params.wm_table = ddr5_wm_table; 1441 1324 } 1442 1325 /* Saved clocks configured at boot for debug purposes */ 1443 - dcn35_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, clk_mgr); 1326 + dcn35_save_clk_registers(&clk_mgr->base.base.boot_snapshot, clk_mgr); 1444 1327 1445 1328 clk_mgr->base.base.dprefclk_khz = dcn35_smu_get_dprefclk(&clk_mgr->base); 1446 1329 clk_mgr->base.base.clks.ref_dtbclk_khz = 600000;