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

drm/amd/display: Refactor dcn401_update_clocks

[WHY & HOW]
Refactor complex code into manageable functions. This also cleans up
some updating logics.

Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Acked-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Dillon Varone <dillon.varone@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Dillon Varone and committed by
Alex Deucher
2eb7d4b9 61f88003

+718 -6
+7 -1
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dalsmc.h
··· 36 36 #define DALSMC_MSG_SetFclkSwitchAllow 0x11 37 37 #define DALSMC_MSG_SetCabForUclkPstate 0x12 38 38 #define DALSMC_MSG_SetWorstCaseUclkLatency 0x13 39 - #define DALSMC_Message_Count 0x14 39 + #define DALSMC_MSG_DcnExitReset 0x14 40 + #define DALSMC_MSG_ReturnHardMinStatus 0x15 41 + #define DALSMC_MSG_SetAlwaysWaitDmcubResp 0x16 42 + #define DALSMC_MSG_IndicateDrrStatus 0x17 // PMFW 15811 43 + #define DALSMC_MSG_ActiveUclkFclk 0x18 44 + #define DALSMC_MSG_IdleUclkFclk 0x19 45 + #define DALSMC_Message_Count 0x1A 40 46 41 47 typedef enum { 42 48 FCLK_SWITCH_DISALLOW,
+520 -3
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c
··· 67 67 CLK_COMMON_MASK_SH_LIST_DCN401(_MASK) 68 68 }; 69 69 70 + #define TO_DCN401_CLK_MGR(clk_mgr)\ 71 + container_of(clk_mgr, struct dcn401_clk_mgr, base) 72 + 70 73 static bool dcn401_is_ppclk_dpm_enabled(struct clk_mgr_internal *clk_mgr, PPCLK_e clk) 71 74 { 72 75 bool ppclk_dpm_enabled = false; ··· 113 110 ppclk_dpm_enabled &= clk_mgr->smu_present; 114 111 115 112 return ppclk_dpm_enabled; 113 + } 114 + 115 + static bool dcn401_is_ppclk_idle_dpm_enabled(struct clk_mgr_internal *clk_mgr, PPCLK_e clk) 116 + { 117 + bool ppclk_idle_dpm_enabled = false; 118 + 119 + switch (clk) { 120 + case PPCLK_UCLK: 121 + case PPCLK_FCLK: 122 + if (ASICREV_IS_GC_12_0_0_A0(clk_mgr->base.ctx->asic_id.hw_internal_rev) && 123 + clk_mgr->smu_ver >= 0x681800) { 124 + ppclk_idle_dpm_enabled = true; 125 + } else if (ASICREV_IS_GC_12_0_1_A0(clk_mgr->base.ctx->asic_id.hw_internal_rev) && 126 + clk_mgr->smu_ver >= 0x661300) { 127 + ppclk_idle_dpm_enabled = true; 128 + } 129 + break; 130 + default: 131 + ppclk_idle_dpm_enabled = false; 132 + } 133 + 134 + ppclk_idle_dpm_enabled &= clk_mgr->smu_present; 135 + 136 + return ppclk_idle_dpm_enabled; 116 137 } 117 138 118 139 /* Query SMU for all clock states for a particular clock */ ··· 497 470 498 471 } 499 472 500 - static void dcn401_update_clocks(struct clk_mgr *clk_mgr_base, 473 + static void dcn401_update_clocks_legacy(struct clk_mgr *clk_mgr_base, 501 474 struct dc_state *context, 502 475 bool safe_to_lower) 503 476 { ··· 539 512 540 513 if (clk_mgr->smu_present) { 541 514 if (enter_display_off == safe_to_lower) 542 - dcn30_smu_set_num_of_displays(clk_mgr, display_count); 515 + dcn401_smu_set_num_of_displays(clk_mgr, display_count); 543 516 544 517 clk_mgr_base->clks.fclk_prev_p_state_change_support = clk_mgr_base->clks.fclk_p_state_change_support; 545 518 ··· 569 542 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { 570 543 clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; 571 544 if (dcn401_is_ppclk_dpm_enabled(clk_mgr, PPCLK_DCFCLK)) 572 - dcn30_smu_set_min_deep_sleep_dcef_clk(clk_mgr, khz_to_mhz_ceil(clk_mgr_base->clks.dcfclk_deep_sleep_khz)); 545 + dcn401_smu_set_min_deep_sleep_dcef_clk(clk_mgr, khz_to_mhz_ceil(clk_mgr_base->clks.dcfclk_deep_sleep_khz)); 573 546 } 574 547 575 548 if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr_base->clks.socclk_khz)) ··· 693 666 /*update dmcu for wait_loop count*/ 694 667 dmcu->funcs->set_psr_wait_loop(dmcu, 695 668 clk_mgr_base->clks.dispclk_khz / 1000 / 7); 669 + } 670 + 671 + static void dcn401_build_update_clocks_sequence( 672 + struct clk_mgr *clk_mgr_base, 673 + struct dc_state *context, 674 + bool safe_to_lower, 675 + unsigned int *num_steps) 676 + { 677 + struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base); 678 + struct dcn401_clk_mgr *clk_mgr401 = TO_DCN401_CLK_MGR(clk_mgr_internal); 679 + struct dc *dc = clk_mgr_base->ctx->dc; 680 + struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu; 681 + struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; 682 + struct dcn401_clk_mgr_block_sequence *block_sequence = clk_mgr401->block_sequence; 683 + bool force_reset = false; 684 + bool enter_display_off = false; 685 + bool update_active_fclk = false; 686 + bool update_active_uclk = false; 687 + bool update_idle_fclk = false; 688 + bool update_idle_uclk = false; 689 + bool update_dispclk = false; 690 + bool update_dppclk = false; 691 + bool dppclk_lowered = false; 692 + bool is_idle_dpm_enabled = dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_UCLK) && 693 + dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_FCLK) && 694 + dcn401_is_ppclk_idle_dpm_enabled(clk_mgr_internal, PPCLK_UCLK) && 695 + dcn401_is_ppclk_idle_dpm_enabled(clk_mgr_internal, PPCLK_FCLK); 696 + int total_plane_count = clk_mgr_helper_get_active_plane_cnt(dc, context); 697 + int active_uclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz); 698 + int active_fclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.fclk_khz); 699 + int idle_uclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.idle_dramclk_khz); 700 + int idle_fclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.idle_fclk_khz); 701 + 702 + int display_count; 703 + bool fclk_p_state_change_support, uclk_p_state_change_support; 704 + 705 + *num_steps = 0; 706 + 707 + /* CLK_MGR401_READ_CLOCKS_FROM_DENTIST */ 708 + if (clk_mgr_base->clks.dispclk_khz == 0 || 709 + (dc->debug.force_clock_mode & 0x1)) { 710 + /* This is from resume or boot up, if forced_clock cfg option used, 711 + * we bypass program dispclk and DPPCLK, but need set them for S3. 712 + * Force_clock_mode 0x1: force reset the clock even it is the same clock 713 + * as long as it is in Passive level. 714 + */ 715 + force_reset = true; 716 + 717 + block_sequence[*num_steps].func = CLK_MGR401_READ_CLOCKS_FROM_DENTIST; 718 + (*num_steps)++; 719 + } 720 + 721 + /* CLK_MGR401_UPDATE_NUM_DISPLAYS */ 722 + if (clk_mgr_internal->smu_present) { 723 + display_count = clk_mgr_helper_get_active_display_cnt(dc, context); 724 + 725 + if (display_count == 0) 726 + enter_display_off = true; 727 + 728 + if (enter_display_off == safe_to_lower) { 729 + block_sequence[*num_steps].params.update_num_displays_params.num_displays = display_count; 730 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_NUM_DISPLAYS; 731 + (*num_steps)++; 732 + } 733 + } 734 + 735 + /* CLK_MGR401_UPDATE_FCLK_PSTATE_SUPPORT */ 736 + clk_mgr_base->clks.fclk_prev_p_state_change_support = clk_mgr_base->clks.fclk_p_state_change_support; 737 + fclk_p_state_change_support = new_clocks->fclk_p_state_change_support || (total_plane_count == 0); 738 + if (should_update_pstate_support(safe_to_lower, fclk_p_state_change_support, clk_mgr_base->clks.fclk_p_state_change_support)) { 739 + clk_mgr_base->clks.fclk_p_state_change_support = fclk_p_state_change_support; 740 + update_active_fclk = true; 741 + update_idle_fclk = true; 742 + 743 + /* To enable FCLK P-state switching, send FCLK_PSTATE_SUPPORTED message to PMFW */ 744 + if (clk_mgr_base->clks.fclk_p_state_change_support) { 745 + /* Handle the code for sending a message to PMFW that FCLK P-state change is supported */ 746 + if (dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_FCLK)) { 747 + block_sequence[*num_steps].params.update_fclk_pstate_support_params.support = FCLK_PSTATE_SUPPORTED; 748 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_FCLK_PSTATE_SUPPORT; 749 + (*num_steps)++; 750 + } 751 + } else { 752 + /* P-State is not supported so force max clocks */ 753 + idle_fclk_mhz = 754 + clk_mgr_base->bw_params->clk_table.entries[clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_fclk_levels - 1].fclk_mhz; 755 + active_fclk_mhz = idle_fclk_mhz; 756 + } 757 + } 758 + 759 + /* UPDATE DCFCLK */ 760 + if (dc->debug.force_min_dcfclk_mhz > 0) 761 + new_clocks->dcfclk_khz = (new_clocks->dcfclk_khz > (dc->debug.force_min_dcfclk_mhz * 1000)) ? 762 + new_clocks->dcfclk_khz : (dc->debug.force_min_dcfclk_mhz * 1000); 763 + 764 + if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { 765 + clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; 766 + if (dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DCFCLK)) { 767 + block_sequence[*num_steps].params.update_hardmin_params.ppclk = PPCLK_DCFCLK; 768 + block_sequence[*num_steps].params.update_hardmin_params.freq_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.dcfclk_khz); 769 + block_sequence[*num_steps].params.update_hardmin_params.response = NULL; 770 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_HARDMIN_PPCLK; 771 + (*num_steps)++; 772 + } 773 + } 774 + 775 + /* CLK_MGR401_UPDATE_DEEP_SLEEP_DCFCLK */ 776 + if (should_set_clock(safe_to_lower, new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { 777 + clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; 778 + if (dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DCFCLK)) { 779 + block_sequence[*num_steps].params.update_deep_sleep_dcfclk_params.freq_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.dcfclk_deep_sleep_khz); 780 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_DEEP_SLEEP_DCFCLK; 781 + (*num_steps)++; 782 + } 783 + } 784 + 785 + /* SOCCLK */ 786 + if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr_base->clks.socclk_khz)) 787 + /* We don't actually care about socclk, don't notify SMU of hard min */ 788 + clk_mgr_base->clks.socclk_khz = new_clocks->socclk_khz; 789 + 790 + /* CLK_MGR401_UPDATE_CAB_FOR_UCLK */ 791 + clk_mgr_base->clks.prev_p_state_change_support = clk_mgr_base->clks.p_state_change_support; 792 + clk_mgr_base->clks.prev_num_ways = clk_mgr_base->clks.num_ways; 793 + 794 + if (clk_mgr_base->clks.num_ways != new_clocks->num_ways && 795 + clk_mgr_base->clks.num_ways < new_clocks->num_ways) { 796 + clk_mgr_base->clks.num_ways = new_clocks->num_ways; 797 + if (dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_UCLK)) { 798 + block_sequence[*num_steps].params.update_cab_for_uclk_params.num_ways = clk_mgr_base->clks.num_ways; 799 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_CAB_FOR_UCLK; 800 + (*num_steps)++; 801 + } 802 + } 803 + 804 + /* UCLK */ 805 + uclk_p_state_change_support = new_clocks->p_state_change_support || (total_plane_count == 0); 806 + if (should_update_pstate_support(safe_to_lower, uclk_p_state_change_support, clk_mgr_base->clks.p_state_change_support)) { 807 + clk_mgr_base->clks.p_state_change_support = uclk_p_state_change_support; 808 + update_active_uclk = true; 809 + update_idle_uclk = true; 810 + 811 + /* to disable P-State switching, set UCLK min = max */ 812 + if (!clk_mgr_base->clks.p_state_change_support) { 813 + if (dc->clk_mgr->dc_mode_softmax_enabled) { 814 + /* will never have the functional UCLK min above the softmax 815 + * since we calculate mode support based on softmax being the max UCLK 816 + * frequency. 817 + */ 818 + active_uclk_mhz = clk_mgr_base->bw_params->dc_mode_softmax_memclk; 819 + } else { 820 + active_uclk_mhz = clk_mgr_base->bw_params->max_memclk_mhz; 821 + } 822 + idle_uclk_mhz = active_uclk_mhz; 823 + } 824 + } 825 + 826 + /* Always update saved value, even if new value not set due to P-State switching unsupported */ 827 + if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr_base->clks.dramclk_khz)) { 828 + clk_mgr_base->clks.dramclk_khz = new_clocks->dramclk_khz; 829 + 830 + if (clk_mgr_base->clks.p_state_change_support) { 831 + update_active_uclk = true; 832 + active_uclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz); 833 + } 834 + } 835 + if (should_set_clock(safe_to_lower, new_clocks->idle_dramclk_khz, clk_mgr_base->clks.idle_dramclk_khz)) { 836 + clk_mgr_base->clks.idle_dramclk_khz = new_clocks->idle_dramclk_khz; 837 + 838 + if (clk_mgr_base->clks.p_state_change_support) { 839 + update_idle_uclk = true; 840 + idle_uclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.idle_dramclk_khz); 841 + } 842 + } 843 + 844 + /* set UCLK to requested value */ 845 + if ((update_active_uclk || update_idle_uclk) && 846 + dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_UCLK) && 847 + !is_idle_dpm_enabled) { 848 + block_sequence[*num_steps].params.update_hardmin_params.ppclk = PPCLK_UCLK; 849 + block_sequence[*num_steps].params.update_hardmin_params.freq_mhz = active_uclk_mhz; 850 + block_sequence[*num_steps].params.update_hardmin_params.response = NULL; 851 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_HARDMIN_PPCLK; 852 + (*num_steps)++; 853 + } 854 + 855 + /* FCLK */ 856 + /* Always update saved value, even if new value not set due to P-State switching unsupported */ 857 + if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, clk_mgr_base->clks.fclk_khz)) { 858 + clk_mgr_base->clks.fclk_khz = new_clocks->fclk_khz; 859 + 860 + if (clk_mgr_base->clks.fclk_p_state_change_support) { 861 + update_active_fclk = true; 862 + active_fclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.fclk_khz); 863 + } 864 + } 865 + 866 + if (should_set_clock(safe_to_lower, new_clocks->idle_fclk_khz, clk_mgr_base->clks.idle_fclk_khz)) { 867 + clk_mgr_base->clks.idle_fclk_khz = new_clocks->idle_fclk_khz; 868 + 869 + if (clk_mgr_base->clks.fclk_p_state_change_support) { 870 + update_idle_fclk = true; 871 + idle_fclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.idle_fclk_khz); 872 + } 873 + } 874 + 875 + /* When idle DPM is enabled, need to send active and idle hardmins separately */ 876 + /* CLK_MGR401_UPDATE_ACTIVE_HARDMINS */ 877 + if ((update_active_uclk || update_active_fclk) && is_idle_dpm_enabled) { 878 + block_sequence[*num_steps].params.update_idle_hardmin_params.uclk_mhz = active_uclk_mhz; 879 + block_sequence[*num_steps].params.update_idle_hardmin_params.fclk_mhz = active_fclk_mhz; 880 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_ACTIVE_HARDMINS; 881 + (*num_steps)++; 882 + } 883 + 884 + /* CLK_MGR401_UPDATE_IDLE_HARDMINS */ 885 + if ((update_idle_uclk || update_idle_uclk) && is_idle_dpm_enabled) { 886 + block_sequence[*num_steps].params.update_idle_hardmin_params.uclk_mhz = idle_uclk_mhz; 887 + block_sequence[*num_steps].params.update_idle_hardmin_params.fclk_mhz = idle_fclk_mhz; 888 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_IDLE_HARDMINS; 889 + (*num_steps)++; 890 + } 891 + 892 + /* CLK_MGR401_UPDATE_WAIT_FOR_DMUB_ACK, CLK_MGR401_INDICATE_DRR_STATUS*/ 893 + if (clk_mgr_base->clks.fw_based_mclk_switching != new_clocks->fw_based_mclk_switching) { 894 + clk_mgr_base->clks.fw_based_mclk_switching = new_clocks->fw_based_mclk_switching; 895 + 896 + block_sequence[*num_steps].params.update_wait_for_dmub_ack_params.enable = clk_mgr_base->clks.fw_based_mclk_switching; 897 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_WAIT_FOR_DMUB_ACK; 898 + (*num_steps)++; 899 + 900 + block_sequence[*num_steps].params.indicate_drr_status_params.mod_drr_for_pstate = clk_mgr_base->clks.fw_based_mclk_switching; 901 + block_sequence[*num_steps].func = CLK_MGR401_INDICATE_DRR_STATUS; 902 + (*num_steps)++; 903 + } 904 + 905 + /* set FCLK to requested value if P-State switching is supported, or to re-enable P-State switching */ 906 + if ((update_active_fclk || update_idle_fclk)) { 907 + /* disable FCLK P-State support if needed */ 908 + if (clk_mgr_base->clks.fclk_p_state_change_support != clk_mgr_base->clks.fclk_prev_p_state_change_support && 909 + dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_FCLK)) { 910 + block_sequence[*num_steps].params.update_fclk_pstate_support_params.support = FCLK_PSTATE_NOTSUPPORTED; 911 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_FCLK_PSTATE_SUPPORT; 912 + (*num_steps)++; 913 + } 914 + 915 + /* No need to send active FCLK hardmin, automatically set based on DCFCLK */ 916 + // block_sequence[*num_steps].update_hardmin_params.clk_mgr = clk_mgr; 917 + // block_sequence[*num_steps].update_hardmin_params.ppclk = PPCLK_FCLK; 918 + // block_sequence[*num_steps].update_hardmin_params.freq_mhz = active_fclk_mhz; 919 + // block_sequence[*num_steps].update_hardmin_params.response = NULL; 920 + // block_sequence[*num_steps].func = CLK_MGR401_UPDATE_HARDMIN_PPCLK; 921 + // (*num_steps)++; 922 + } 923 + 924 + /* CLK_MGR401_UPDATE_CAB_FOR_UCLK */ 925 + if (clk_mgr_base->clks.num_ways != new_clocks->num_ways && 926 + clk_mgr_base->clks.num_ways > new_clocks->num_ways) { 927 + clk_mgr_base->clks.num_ways = new_clocks->num_ways; 928 + if (dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_UCLK)) { 929 + block_sequence[*num_steps].params.update_cab_for_uclk_params.num_ways = clk_mgr_base->clks.num_ways; 930 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_CAB_FOR_UCLK; 931 + (*num_steps)++; 932 + } 933 + } 934 + 935 + /* DTBCLK */ 936 + if (!new_clocks->dtbclk_en && dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DTBCLK)) 937 + new_clocks->ref_dtbclk_khz = clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz * 1000; 938 + 939 + /* clock limits are received with MHz precision, divide by 1000 to prevent setting clocks at every call */ 940 + if (!dc->debug.disable_dtb_ref_clk_switch && 941 + should_set_clock(safe_to_lower, new_clocks->ref_dtbclk_khz / 1000, clk_mgr_base->clks.ref_dtbclk_khz / 1000) && //TODO these should be ceiled 942 + dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DTBCLK)) { 943 + /* DCCG requires KHz precision for DTBCLK */ 944 + block_sequence[*num_steps].params.update_hardmin_params.ppclk = PPCLK_DTBCLK; 945 + block_sequence[*num_steps].params.update_hardmin_params.freq_mhz = khz_to_mhz_ceil(new_clocks->ref_dtbclk_khz); 946 + block_sequence[*num_steps].params.update_hardmin_params.response = &clk_mgr_base->clks.ref_dtbclk_khz; 947 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_HARDMIN_PPCLK; 948 + (*num_steps)++; 949 + 950 + /* Update DTO in DCCG */ 951 + block_sequence[*num_steps].params.update_dtbclk_dto_params.context = context; 952 + block_sequence[*num_steps].params.update_dtbclk_dto_params.ref_dtbclk_khz = clk_mgr_base->clks.ref_dtbclk_khz; 953 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_DTBCLK_DTO; 954 + (*num_steps)++; 955 + } 956 + 957 + if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr_base->clks.dppclk_khz)) { 958 + if (clk_mgr_base->clks.dppclk_khz > new_clocks->dppclk_khz) 959 + dppclk_lowered = true; 960 + 961 + clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz; 962 + clk_mgr_base->clks.actual_dppclk_khz = new_clocks->dppclk_khz; 963 + 964 + update_dppclk = true; 965 + } 966 + 967 + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { 968 + clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; 969 + 970 + update_dispclk = true; 971 + } 972 + 973 + if (dc->config.forced_clocks == false || (force_reset && safe_to_lower)) { 974 + if (dppclk_lowered) { 975 + /* if clock is being lowered, increase DTO before lowering refclk */ 976 + block_sequence[*num_steps].params.update_dppclk_dto_params.context = context; 977 + block_sequence[*num_steps].params.update_dppclk_dto_params.dppclk_khz = clk_mgr_base->clks.dppclk_khz; 978 + block_sequence[*num_steps].params.update_dppclk_dto_params.safe_to_lower = safe_to_lower; 979 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_DPPCLK_DTO; 980 + (*num_steps)++; 981 + 982 + block_sequence[*num_steps].params.update_dentist_params.context = context; 983 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_DENTIST; 984 + (*num_steps)++; 985 + 986 + if (dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DPPCLK)) { 987 + block_sequence[*num_steps].params.update_hardmin_optimized_params.ppclk = PPCLK_DPPCLK; 988 + block_sequence[*num_steps].params.update_hardmin_optimized_params.freq_khz = clk_mgr_base->clks.dppclk_khz; 989 + block_sequence[*num_steps].params.update_hardmin_optimized_params.response = &clk_mgr_base->clks.actual_dppclk_khz; 990 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_HARDMIN_PPCLK_OPTIMIZED; 991 + (*num_steps)++; 992 + 993 + block_sequence[*num_steps].params.update_dppclk_dto_params.context = context; 994 + block_sequence[*num_steps].params.update_dppclk_dto_params.dppclk_khz = clk_mgr_base->clks.actual_dppclk_khz; 995 + block_sequence[*num_steps].params.update_dppclk_dto_params.safe_to_lower = safe_to_lower; 996 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_DPPCLK_DTO; 997 + (*num_steps)++; 998 + } 999 + } else { 1000 + /* if clock is being raised, increase refclk before lowering DTO */ 1001 + if (update_dppclk && dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DPPCLK)) { 1002 + block_sequence[*num_steps].params.update_hardmin_optimized_params.ppclk = PPCLK_DPPCLK; 1003 + block_sequence[*num_steps].params.update_hardmin_optimized_params.freq_khz = clk_mgr_base->clks.dppclk_khz; 1004 + block_sequence[*num_steps].params.update_hardmin_optimized_params.response = &clk_mgr_base->clks.actual_dppclk_khz; 1005 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_HARDMIN_PPCLK_OPTIMIZED; 1006 + (*num_steps)++; 1007 + } 1008 + 1009 + if (update_dppclk || update_dispclk) { 1010 + block_sequence[*num_steps].params.update_dentist_params.context = context; 1011 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_DENTIST; 1012 + (*num_steps)++; 1013 + } 1014 + 1015 + block_sequence[*num_steps].params.update_dppclk_dto_params.context = context; 1016 + block_sequence[*num_steps].params.update_dppclk_dto_params.dppclk_khz = clk_mgr_base->clks.actual_dppclk_khz; 1017 + block_sequence[*num_steps].params.update_dppclk_dto_params.safe_to_lower = safe_to_lower; 1018 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_DPPCLK_DTO; 1019 + (*num_steps)++; 1020 + } 1021 + } 1022 + 1023 + if (update_dispclk && dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { 1024 + /*update dmcu for wait_loop count*/ 1025 + block_sequence[*num_steps].params.update_psr_wait_loop_params.dmcu = dmcu; 1026 + block_sequence[*num_steps].params.update_psr_wait_loop_params.wait = clk_mgr_base->clks.dispclk_khz / 1000 / 7; 1027 + block_sequence[*num_steps].func = CLK_MGR401_UPDATE_PSR_WAIT_LOOP; 1028 + (*num_steps)++; 1029 + } 1030 + } 1031 + 1032 + static void dcn401_update_clocks(struct clk_mgr *clk_mgr_base, 1033 + struct dc_state *context, 1034 + bool safe_to_lower) 1035 + { 1036 + struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base); 1037 + struct dcn401_clk_mgr *clk_mgr401 = TO_DCN401_CLK_MGR(clk_mgr_internal); 1038 + struct dc *dc = clk_mgr_base->ctx->dc; 1039 + 1040 + unsigned int num_steps = 0; 1041 + 1042 + unsigned int i; 1043 + union dcn401_clk_mgr_block_sequence_params *params; 1044 + 1045 + if (dc->work_arounds.skip_clock_update) 1046 + return; 1047 + 1048 + if (dc->debug.enable_legacy_clock_update) { 1049 + dcn401_update_clocks_legacy(clk_mgr_base, context, safe_to_lower); 1050 + return; 1051 + } 1052 + 1053 + /* build clock update sequence */ 1054 + dcn401_build_update_clocks_sequence(clk_mgr_base, 1055 + context, 1056 + safe_to_lower, 1057 + &num_steps); 1058 + 1059 + /* execute sequence */ 1060 + for (i = 0; i < num_steps; i++) { 1061 + params = &clk_mgr401->block_sequence[i].params; 1062 + 1063 + switch (clk_mgr401->block_sequence[i].func) { 1064 + case CLK_MGR401_READ_CLOCKS_FROM_DENTIST: 1065 + dcn2_read_clocks_from_hw_dentist(clk_mgr_base); 1066 + break; 1067 + case CLK_MGR401_UPDATE_NUM_DISPLAYS: 1068 + dcn401_smu_set_num_of_displays(clk_mgr_internal, 1069 + params->update_num_displays_params.num_displays); 1070 + break; 1071 + case CLK_MGR401_UPDATE_HARDMIN_PPCLK: 1072 + if (params->update_hardmin_params.response) 1073 + *params->update_hardmin_params.response = dcn401_smu_set_hard_min_by_freq( 1074 + clk_mgr_internal, 1075 + params->update_hardmin_params.ppclk, 1076 + params->update_hardmin_params.freq_mhz); 1077 + else 1078 + dcn401_smu_set_hard_min_by_freq(clk_mgr_internal, 1079 + params->update_hardmin_params.ppclk, 1080 + params->update_hardmin_params.freq_mhz); 1081 + break; 1082 + case CLK_MGR401_UPDATE_HARDMIN_PPCLK_OPTIMIZED: 1083 + if (params->update_hardmin_optimized_params.response) 1084 + *params->update_hardmin_optimized_params.response = dcn401_set_hard_min_by_freq_optimized( 1085 + clk_mgr_internal, 1086 + params->update_hardmin_optimized_params.ppclk, 1087 + params->update_hardmin_optimized_params.freq_khz); 1088 + else 1089 + dcn401_set_hard_min_by_freq_optimized(clk_mgr_internal, 1090 + params->update_hardmin_optimized_params.ppclk, 1091 + params->update_hardmin_optimized_params.freq_khz); 1092 + break; 1093 + case CLK_MGR401_UPDATE_ACTIVE_HARDMINS: 1094 + dcn401_smu_set_active_uclk_fclk_hardmin( 1095 + clk_mgr_internal, 1096 + params->update_idle_hardmin_params.uclk_mhz, 1097 + params->update_idle_hardmin_params.fclk_mhz); 1098 + break; 1099 + case CLK_MGR401_UPDATE_IDLE_HARDMINS: 1100 + dcn401_smu_set_idle_uclk_fclk_hardmin( 1101 + clk_mgr_internal, 1102 + params->update_idle_hardmin_params.uclk_mhz, 1103 + params->update_idle_hardmin_params.fclk_mhz); 1104 + break; 1105 + case CLK_MGR401_UPDATE_DEEP_SLEEP_DCFCLK: 1106 + dcn401_smu_set_min_deep_sleep_dcef_clk( 1107 + clk_mgr_internal, 1108 + params->update_deep_sleep_dcfclk_params.freq_mhz); 1109 + break; 1110 + case CLK_MGR401_UPDATE_FCLK_PSTATE_SUPPORT: 1111 + dcn401_smu_send_fclk_pstate_message( 1112 + clk_mgr_internal, 1113 + params->update_fclk_pstate_support_params.support); 1114 + break; 1115 + case CLK_MGR401_UPDATE_CAB_FOR_UCLK: 1116 + dcn401_smu_send_cab_for_uclk_message( 1117 + clk_mgr_internal, 1118 + params->update_cab_for_uclk_params.num_ways); 1119 + break; 1120 + case CLK_MGR401_UPDATE_WAIT_FOR_DMUB_ACK: 1121 + dcn401_smu_wait_for_dmub_ack_mclk( 1122 + clk_mgr_internal, 1123 + params->update_wait_for_dmub_ack_params.enable); 1124 + break; 1125 + case CLK_MGR401_INDICATE_DRR_STATUS: 1126 + dcn401_smu_indicate_drr_status( 1127 + clk_mgr_internal, 1128 + params->indicate_drr_status_params.mod_drr_for_pstate); 1129 + break; 1130 + case CLK_MGR401_UPDATE_DPPCLK_DTO: 1131 + dcn401_update_clocks_update_dpp_dto( 1132 + clk_mgr_internal, 1133 + params->update_dppclk_dto_params.context, 1134 + params->update_dppclk_dto_params.safe_to_lower, 1135 + params->update_dppclk_dto_params.dppclk_khz); 1136 + break; 1137 + case CLK_MGR401_UPDATE_DTBCLK_DTO: 1138 + dcn401_update_clocks_update_dtb_dto( 1139 + clk_mgr_internal, 1140 + params->update_dtbclk_dto_params.context, 1141 + params->update_dtbclk_dto_params.ref_dtbclk_khz); 1142 + break; 1143 + case CLK_MGR401_UPDATE_DENTIST: 1144 + dcn401_update_clocks_update_dentist( 1145 + clk_mgr_internal, 1146 + params->update_dentist_params.context); 1147 + break; 1148 + case CLK_MGR401_UPDATE_PSR_WAIT_LOOP: 1149 + params->update_psr_wait_loop_params.dmcu->funcs->set_psr_wait_loop( 1150 + params->update_psr_wait_loop_params.dmcu, 1151 + params->update_psr_wait_loop_params.wait); 1152 + break; 1153 + default: 1154 + /* this should never happen */ 1155 + BREAK_TO_DEBUGGER(); 1156 + break; 1157 + } 1158 + } 696 1159 } 697 1160 698 1161 static uint32_t dcn401_get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr)
+94
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.h
··· 5 5 #ifndef __DCN401_CLK_MGR_H_ 6 6 #define __DCN401_CLK_MGR_H_ 7 7 8 + #define DCN401_CLK_MGR_MAX_SEQUENCE_SIZE 30 9 + 10 + union dcn401_clk_mgr_block_sequence_params { 11 + struct { 12 + /* inputs */ 13 + uint32_t num_displays; 14 + } update_num_displays_params; 15 + struct { 16 + /* inputs */ 17 + uint32_t ppclk; 18 + uint16_t freq_mhz; 19 + /* outputs */ 20 + uint32_t *response; 21 + } update_hardmin_params; 22 + struct { 23 + /* inputs */ 24 + uint32_t ppclk; 25 + int freq_khz; 26 + /* outputs */ 27 + uint32_t *response; 28 + } update_hardmin_optimized_params; 29 + struct { 30 + /* inputs */ 31 + uint16_t uclk_mhz; 32 + uint16_t fclk_mhz; 33 + } update_idle_hardmin_params; 34 + struct { 35 + /* inputs */ 36 + uint16_t freq_mhz; 37 + } update_deep_sleep_dcfclk_params; 38 + struct { 39 + /* inputs */ 40 + bool support; 41 + } update_fclk_pstate_support_params; 42 + struct { 43 + /* inputs */ 44 + unsigned int num_ways; 45 + } update_cab_for_uclk_params; 46 + struct { 47 + /* inputs */ 48 + bool enable; 49 + } update_wait_for_dmub_ack_params; 50 + struct { 51 + /* inputs */ 52 + bool mod_drr_for_pstate; 53 + } indicate_drr_status_params; 54 + struct { 55 + /* inputs */ 56 + struct dc_state *context; 57 + int dppclk_khz; 58 + bool safe_to_lower; 59 + } update_dppclk_dto_params; 60 + struct { 61 + /* inputs */ 62 + struct dc_state *context; 63 + int ref_dtbclk_khz; 64 + } update_dtbclk_dto_params; 65 + struct { 66 + /* inputs */ 67 + struct dc_state *context; 68 + int ref_dtbclk_khz; 69 + } update_dentist_params; 70 + struct { 71 + /* inputs */ 72 + struct dmcu *dmcu; 73 + unsigned int wait; 74 + } update_psr_wait_loop_params; 75 + }; 76 + 77 + enum dcn401_clk_mgr_block_sequence_func { 78 + CLK_MGR401_READ_CLOCKS_FROM_DENTIST, 79 + CLK_MGR401_UPDATE_NUM_DISPLAYS, 80 + CLK_MGR401_UPDATE_HARDMIN_PPCLK, 81 + CLK_MGR401_UPDATE_HARDMIN_PPCLK_OPTIMIZED, 82 + CLK_MGR401_UPDATE_ACTIVE_HARDMINS, 83 + CLK_MGR401_UPDATE_IDLE_HARDMINS, 84 + CLK_MGR401_UPDATE_DEEP_SLEEP_DCFCLK, 85 + CLK_MGR401_UPDATE_FCLK_PSTATE_SUPPORT, 86 + CLK_MGR401_UPDATE_CAB_FOR_UCLK, 87 + CLK_MGR401_UPDATE_WAIT_FOR_DMUB_ACK, 88 + CLK_MGR401_INDICATE_DRR_STATUS, 89 + CLK_MGR401_UPDATE_DPPCLK_DTO, 90 + CLK_MGR401_UPDATE_DTBCLK_DTO, 91 + CLK_MGR401_UPDATE_DENTIST, 92 + CLK_MGR401_UPDATE_PSR_WAIT_LOOP, 93 + }; 94 + 95 + struct dcn401_clk_mgr_block_sequence { 96 + union dcn401_clk_mgr_block_sequence_params params; 97 + enum dcn401_clk_mgr_block_sequence_func func; 98 + }; 99 + 8 100 struct dcn401_clk_mgr { 9 101 struct clk_mgr_internal base; 102 + 103 + struct dcn401_clk_mgr_block_sequence block_sequence[DCN401_CLK_MGR_MAX_SEQUENCE_SIZE]; 10 104 }; 11 105 12 106 void dcn401_init_clocks(struct clk_mgr *clk_mgr_base);
+79 -1
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr_smu_msg.c
··· 105 105 unsigned int dcn401_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint16_t freq_mhz) 106 106 { 107 107 uint32_t response = 0; 108 + bool hard_min_done = false; 108 109 109 110 /* bits 23:16 for clock type, lower 16 bits for frequency in MHz */ 110 111 uint32_t param = (clk << 16) | freq_mhz; ··· 115 114 dcn401_smu_send_msg_with_param(clk_mgr, 116 115 DALSMC_MSG_SetHardMinByFreq, param, &response); 117 116 118 - smu_print("SMU Frequency set = %d KHz\n", response); 117 + /* wait until hardmin acknowledged */ 118 + //hard_min_done = dcn401_smu_wait_get_hard_min_status(clk_mgr, clk); 119 + smu_print("SMU Frequency set = %d KHz hard_min_done %d\n", response, hard_min_done); 119 120 120 121 return response; 122 + } 123 + 124 + void dcn401_smu_wait_for_dmub_ack_mclk(struct clk_mgr_internal *clk_mgr, bool enable) 125 + { 126 + smu_print("SMU to wait for DMCUB ack for MCLK : %d\n", enable); 127 + 128 + dcn401_smu_send_msg_with_param(clk_mgr, DALSMC_MSG_SetAlwaysWaitDmcubResp, enable ? 1 : 0, NULL); 129 + } 130 + 131 + void dcn401_smu_indicate_drr_status(struct clk_mgr_internal *clk_mgr, bool mod_drr_for_pstate) 132 + { 133 + smu_print("SMU Set indicate drr status = %d\n", mod_drr_for_pstate); 134 + 135 + dcn401_smu_send_msg_with_param(clk_mgr, 136 + DALSMC_MSG_IndicateDrrStatus, mod_drr_for_pstate ? 1 : 0, NULL); 137 + } 138 + 139 + bool dcn401_smu_set_idle_uclk_fclk_hardmin(struct clk_mgr_internal *clk_mgr, 140 + uint16_t uclk_freq_mhz, 141 + uint16_t fclk_freq_mhz) 142 + { 143 + uint32_t response = 0; 144 + bool success; 145 + 146 + /* 15:0 for uclk, 32:16 for fclk */ 147 + uint32_t param = (fclk_freq_mhz << 16) | uclk_freq_mhz; 148 + 149 + smu_print("SMU Set idle hardmin by freq: uclk_freq_mhz = %d MHz, fclk_freq_mhz = %d MHz\n", uclk_freq_mhz, fclk_freq_mhz); 150 + 151 + success = dcn401_smu_send_msg_with_param(clk_mgr, 152 + DALSMC_MSG_IdleUclkFclk, param, &response); 153 + 154 + /* wait until hardmin acknowledged */ 155 + //success &= dcn401_smu_wait_get_hard_min_status(clk_mgr, PPCLK_UCLK); 156 + smu_print("SMU hard_min_done %d\n", success); 157 + 158 + return success; 159 + } 160 + 161 + bool dcn401_smu_set_active_uclk_fclk_hardmin(struct clk_mgr_internal *clk_mgr, 162 + uint16_t uclk_freq_mhz, 163 + uint16_t fclk_freq_mhz) 164 + { 165 + uint32_t response = 0; 166 + bool success; 167 + 168 + /* 15:0 for uclk, 32:16 for fclk */ 169 + uint32_t param = (fclk_freq_mhz << 16) | uclk_freq_mhz; 170 + 171 + smu_print("SMU Set active hardmin by freq: uclk_freq_mhz = %d MHz, fclk_freq_mhz = %d MHz\n", uclk_freq_mhz, fclk_freq_mhz); 172 + 173 + success = dcn401_smu_send_msg_with_param(clk_mgr, 174 + DALSMC_MSG_ActiveUclkFclk, param, &response); 175 + 176 + /* wait until hardmin acknowledged */ 177 + //success &= dcn401_smu_wait_get_hard_min_status(clk_mgr, PPCLK_UCLK); 178 + smu_print("SMU hard_min_done %d\n", success); 179 + 180 + return success; 181 + } 182 + 183 + void dcn401_smu_set_min_deep_sleep_dcef_clk(struct clk_mgr_internal *clk_mgr, uint32_t freq_mhz) 184 + { 185 + smu_print("SMU Set min deep sleep dcef clk: freq_mhz = %d MHz\n", freq_mhz); 186 + 187 + dcn401_smu_send_msg_with_param(clk_mgr, 188 + DALSMC_MSG_SetMinDeepSleepDcfclk, freq_mhz, NULL); 189 + } 190 + 191 + void dcn401_smu_set_num_of_displays(struct clk_mgr_internal *clk_mgr, uint32_t num_displays) 192 + { 193 + smu_print("SMU Set num of displays: num_displays = %d\n", num_displays); 194 + 195 + dcn401_smu_send_msg_with_param(clk_mgr, 196 + DALSMC_MSG_NumOfDisplays, num_displays, NULL); 121 197 }
+10
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr_smu_msg.h
··· 17 17 void dcn401_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr); 18 18 void dcn401_smu_set_pme_workaround(struct clk_mgr_internal *clk_mgr); 19 19 unsigned int dcn401_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint16_t freq_mhz); 20 + void dcn401_smu_wait_for_dmub_ack_mclk(struct clk_mgr_internal *clk_mgr, bool enable); 21 + void dcn401_smu_indicate_drr_status(struct clk_mgr_internal *clk_mgr, bool mod_drr_for_pstate); 22 + bool dcn401_smu_set_idle_uclk_fclk_hardmin(struct clk_mgr_internal *clk_mgr, 23 + uint16_t uclk_freq_mhz, 24 + uint16_t fclk_freq_mhz); 25 + bool dcn401_smu_set_active_uclk_fclk_hardmin(struct clk_mgr_internal *clk_mgr, 26 + uint16_t uclk_freq_mhz, 27 + uint16_t fclk_freq_mhz); 28 + void dcn401_smu_set_min_deep_sleep_dcef_clk(struct clk_mgr_internal *clk_mgr, uint32_t freq_mhz); 29 + void dcn401_smu_set_num_of_displays(struct clk_mgr_internal *clk_mgr, uint32_t num_displays); 20 30 21 31 #endif /* __DCN401_CLK_MGR_SMU_MSG_H_ */
+2 -1
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
··· 204 204 dc_version = DCN_VERSION_3_51; 205 205 break; 206 206 case AMDGPU_FAMILY_GC_12_0_0: 207 - if (ASICREV_IS_DCN401(asic_id.hw_internal_rev)) 207 + if (ASICREV_IS_GC_12_0_1_A0(asic_id.hw_internal_rev) || 208 + ASICREV_IS_GC_12_0_0_A0(asic_id.hw_internal_rev)) 208 209 dc_version = DCN_VERSION_4_01; 209 210 break; 210 211 default:
+3
drivers/gpu/drm/amd/display/dc/dc.h
··· 610 610 int max_supported_dispclk_khz; 611 611 int bw_dppclk_khz; /*a copy of dppclk_khz*/ 612 612 int bw_dispclk_khz; 613 + int idle_dramclk_khz; 614 + int idle_fclk_khz; 613 615 }; 614 616 615 617 struct dc_bw_validation_profile { ··· 1037 1035 uint32_t dml21_force_pstate_method_value; 1038 1036 uint32_t dml21_disable_pstate_method_mask; 1039 1037 union dmub_fams2_global_feature_config fams2_config; 1038 + bool enable_legacy_clock_update; 1040 1039 unsigned int force_cositing; 1041 1040 }; 1042 1041
+3
drivers/gpu/drm/amd/display/include/dal_asic_id.h
··· 266 266 GC_12_UNKNOWN = 0xFF, 267 267 }; 268 268 269 + #define ASICREV_IS_GC_12_0_1_A0(eChipRev) (eChipRev >= GC_12_0_1_A0 && eChipRev < GC_12_0_0_A0) 270 + #define ASICREV_IS_GC_12_0_0_A0(eChipRev) (eChipRev >= GC_12_0_0_A0 && eChipRev < 0xFF) 271 + 269 272 #define ASICREV_IS_DCN4(eChipRev) (eChipRev >= GC_12_0_1_A0 && eChipRev < GC_12_0_0_A0) 270 273 #define ASICREV_IS_DCN401(eChipRev) (eChipRev >= GC_12_0_0_A0 && eChipRev < GC_12_UNKNOWN) 271 274