xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/amd/display/dc/clk_mgr/dcn21/amdgpu_rn_clk_mgr_vbios_smu.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
1 /*	$NetBSD: amdgpu_rn_clk_mgr_vbios_smu.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $	*/
2 
3 /*
4  * Copyright 2012-16 Advanced Micro Devices, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Authors: AMD
25  *
26  */
27 
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: amdgpu_rn_clk_mgr_vbios_smu.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $");
30 
31 #include "core_types.h"
32 #include "clk_mgr_internal.h"
33 #include "reg_helper.h"
34 
35 #include "renoir_ip_offset.h"
36 
37 #include "mp/mp_12_0_0_offset.h"
38 #include "mp/mp_12_0_0_sh_mask.h"
39 
40 #define REG(reg_name) \
41 	(MP0_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name)
42 
43 #define FN(reg_name, field) \
44 	FD(reg_name##__##field)
45 
46 #define VBIOSSMC_MSG_TestMessage                  0x1
47 #define VBIOSSMC_MSG_GetSmuVersion                0x2
48 #define VBIOSSMC_MSG_PowerUpGfx                   0x3
49 #define VBIOSSMC_MSG_SetDispclkFreq               0x4
50 #define VBIOSSMC_MSG_SetDprefclkFreq              0x5
51 #define VBIOSSMC_MSG_PowerDownGfx                 0x6
52 #define VBIOSSMC_MSG_SetDppclkFreq                0x7
53 #define VBIOSSMC_MSG_SetHardMinDcfclkByFreq       0x8
54 #define VBIOSSMC_MSG_SetMinDeepSleepDcfclk        0x9
55 #define VBIOSSMC_MSG_SetPhyclkVoltageByFreq       0xA
56 #define VBIOSSMC_MSG_GetFclkFrequency             0xB
57 #define VBIOSSMC_MSG_SetDisplayCount              0xC
58 #define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xD
59 #define VBIOSSMC_MSG_UpdatePmeRestore			  0xE
60 
rn_vbios_smu_send_msg_with_param(struct clk_mgr_internal * clk_mgr,unsigned int msg_id,unsigned int param)61 int rn_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned int msg_id, unsigned int param)
62 {
63 	/* First clear response register */
64 	REG_WRITE(MP1_SMN_C2PMSG_91, 0);
65 
66 	/* Set the parameter register for the SMU message, unit is Mhz */
67 	REG_WRITE(MP1_SMN_C2PMSG_83, param);
68 
69 	/* Trigger the message transaction by writing the message ID */
70 	REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
71 
72 	REG_WAIT(MP1_SMN_C2PMSG_91, CONTENT, 1, 10, 200000);
73 
74 	/* Actual dispclk set is returned in the parameter register */
75 	return REG_READ(MP1_SMN_C2PMSG_83);
76 }
77 
rn_vbios_smu_get_smu_version(struct clk_mgr_internal * clk_mgr)78 int rn_vbios_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
79 {
80 	return rn_vbios_smu_send_msg_with_param(
81 			clk_mgr,
82 			VBIOSSMC_MSG_GetSmuVersion,
83 			0);
84 }
85 
86 
rn_vbios_smu_set_dispclk(struct clk_mgr_internal * clk_mgr,int requested_dispclk_khz)87 int rn_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
88 {
89 	int actual_dispclk_set_mhz = -1;
90 	struct dc *dc = clk_mgr->base.ctx->dc;
91 	struct dmcu *dmcu = dc->res_pool->dmcu;
92 
93 	/*  Unit of SMU msg parameter is Mhz */
94 	actual_dispclk_set_mhz = rn_vbios_smu_send_msg_with_param(
95 			clk_mgr,
96 			VBIOSSMC_MSG_SetDispclkFreq,
97 			requested_dispclk_khz / 1000);
98 
99 	if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
100 		if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
101 			if (clk_mgr->dfs_bypass_disp_clk != actual_dispclk_set_mhz)
102 				dmcu->funcs->set_psr_wait_loop(dmcu,
103 						actual_dispclk_set_mhz / 7);
104 		}
105 	}
106 
107 	return actual_dispclk_set_mhz * 1000;
108 }
109 
rn_vbios_smu_set_dprefclk(struct clk_mgr_internal * clk_mgr)110 int rn_vbios_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr)
111 {
112 	int actual_dprefclk_set_mhz = -1;
113 
114 	actual_dprefclk_set_mhz = rn_vbios_smu_send_msg_with_param(
115 			clk_mgr,
116 			VBIOSSMC_MSG_SetDprefclkFreq,
117 			clk_mgr->base.dprefclk_khz / 1000);
118 
119 	/* TODO: add code for programing DP DTO, currently this is down by command table */
120 
121 	return actual_dprefclk_set_mhz * 1000;
122 }
123 
rn_vbios_smu_set_hard_min_dcfclk(struct clk_mgr_internal * clk_mgr,int requested_dcfclk_khz)124 int rn_vbios_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
125 {
126 	int actual_dcfclk_set_mhz = -1;
127 
128 	if (clk_mgr->smu_ver < 0x370c00)
129 		return actual_dcfclk_set_mhz;
130 
131 	actual_dcfclk_set_mhz = rn_vbios_smu_send_msg_with_param(
132 			clk_mgr,
133 			VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
134 			requested_dcfclk_khz / 1000);
135 
136 	return actual_dcfclk_set_mhz * 1000;
137 }
138 
rn_vbios_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal * clk_mgr,int requested_min_ds_dcfclk_khz)139 int rn_vbios_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
140 {
141 	int actual_min_ds_dcfclk_mhz = -1;
142 
143 	if (clk_mgr->smu_ver < 0x370c00)
144 		return actual_min_ds_dcfclk_mhz;
145 
146 	actual_min_ds_dcfclk_mhz = rn_vbios_smu_send_msg_with_param(
147 			clk_mgr,
148 			VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
149 			requested_min_ds_dcfclk_khz / 1000);
150 
151 	return actual_min_ds_dcfclk_mhz * 1000;
152 }
153 
rn_vbios_smu_set_phyclk(struct clk_mgr_internal * clk_mgr,int requested_phyclk_khz)154 void rn_vbios_smu_set_phyclk(struct clk_mgr_internal *clk_mgr, int requested_phyclk_khz)
155 {
156 	rn_vbios_smu_send_msg_with_param(
157 			clk_mgr,
158 			VBIOSSMC_MSG_SetPhyclkVoltageByFreq,
159 			requested_phyclk_khz / 1000);
160 }
161 
rn_vbios_smu_set_dppclk(struct clk_mgr_internal * clk_mgr,int requested_dpp_khz)162 int rn_vbios_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
163 {
164 	int actual_dppclk_set_mhz = -1;
165 
166 	actual_dppclk_set_mhz = rn_vbios_smu_send_msg_with_param(
167 			clk_mgr,
168 			VBIOSSMC_MSG_SetDppclkFreq,
169 			requested_dpp_khz / 1000);
170 
171 	return actual_dppclk_set_mhz * 1000;
172 }
173 
rn_vbios_smu_set_dcn_low_power_state(struct clk_mgr_internal * clk_mgr,enum dcn_pwr_state state)174 void rn_vbios_smu_set_dcn_low_power_state(struct clk_mgr_internal *clk_mgr, enum dcn_pwr_state state)
175 {
176 	int disp_count;
177 
178 	if (state == DCN_PWR_STATE_LOW_POWER)
179 		disp_count = 0;
180 	else
181 		disp_count = 1;
182 
183 	rn_vbios_smu_send_msg_with_param(
184 		clk_mgr,
185 		VBIOSSMC_MSG_SetDisplayCount,
186 		disp_count);
187 }
188 
rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal * clk_mgr,bool enable)189 void rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
190 {
191 	rn_vbios_smu_send_msg_with_param(
192 			clk_mgr,
193 			VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown,
194 			enable);
195 }
196 
rn_vbios_smu_enable_pme_wa(struct clk_mgr_internal * clk_mgr)197 void rn_vbios_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
198 {
199 	rn_vbios_smu_send_msg_with_param(
200 			clk_mgr,
201 			VBIOSSMC_MSG_UpdatePmeRestore,
202 			0);
203 }
204