Home | History | Annotate | Line # | Download | only in dcn21
      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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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