Home | History | Annotate | Line # | Download | only in dcn10
      1 /*	$NetBSD: amdgpu_rv1_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_rv1_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 #define MAX_INSTANCE	5
     36 #define MAX_SEGMENT		5
     37 
     38 struct IP_BASE_INSTANCE {
     39 	unsigned int segment[MAX_SEGMENT];
     40 };
     41 
     42 struct IP_BASE {
     43 	struct IP_BASE_INSTANCE instance[MAX_INSTANCE];
     44 };
     45 
     46 
     47 static const struct IP_BASE MP1_BASE  = { { { { 0x00016000, 0, 0, 0, 0 } },
     48 											 { { 0, 0, 0, 0, 0 } },
     49 											 { { 0, 0, 0, 0, 0 } },
     50 											 { { 0, 0, 0, 0, 0 } },
     51 											 { { 0, 0, 0, 0, 0 } } } };
     52 
     53 #define mmMP1_SMN_C2PMSG_91            0x29B
     54 #define mmMP1_SMN_C2PMSG_83            0x293
     55 #define mmMP1_SMN_C2PMSG_67            0x283
     56 #define mmMP1_SMN_C2PMSG_91_BASE_IDX   0
     57 #define mmMP1_SMN_C2PMSG_83_BASE_IDX   0
     58 #define mmMP1_SMN_C2PMSG_67_BASE_IDX   0
     59 
     60 #define MP1_SMN_C2PMSG_91__CONTENT_MASK                    0xffffffffL
     61 #define MP1_SMN_C2PMSG_83__CONTENT_MASK                    0xffffffffL
     62 #define MP1_SMN_C2PMSG_67__CONTENT_MASK                    0xffffffffL
     63 #define MP1_SMN_C2PMSG_91__CONTENT__SHIFT                  0x00000000
     64 #define MP1_SMN_C2PMSG_83__CONTENT__SHIFT                  0x00000000
     65 #define MP1_SMN_C2PMSG_67__CONTENT__SHIFT                  0x00000000
     66 
     67 #define REG(reg_name) \
     68 	(MP1_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name)
     69 
     70 #define FN(reg_name, field) \
     71 	FD(reg_name##__##field)
     72 
     73 #define VBIOSSMC_MSG_SetDispclkFreq           0x4
     74 #define VBIOSSMC_MSG_SetDprefclkFreq          0x5
     75 
     76 int rv1_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned int msg_id, unsigned int param)
     77 {
     78 	/* First clear response register */
     79 	REG_WRITE(MP1_SMN_C2PMSG_91, 0);
     80 
     81 	/* Set the parameter register for the SMU message, unit is Mhz */
     82 	REG_WRITE(MP1_SMN_C2PMSG_83, param);
     83 
     84 	/* Trigger the message transaction by writing the message ID */
     85 	REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
     86 
     87 	REG_WAIT(MP1_SMN_C2PMSG_91, CONTENT, 1, 10, 200000);
     88 
     89 	/* Actual dispclk set is returned in the parameter register */
     90 	return REG_READ(MP1_SMN_C2PMSG_83);
     91 }
     92 
     93 int rv1_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
     94 {
     95 	int actual_dispclk_set_mhz = -1;
     96 	struct dc *dc = clk_mgr->base.ctx->dc;
     97 	struct dmcu *dmcu = dc->res_pool->dmcu;
     98 
     99 	/*  Unit of SMU msg parameter is Mhz */
    100 	actual_dispclk_set_mhz = rv1_vbios_smu_send_msg_with_param(
    101 			clk_mgr,
    102 			VBIOSSMC_MSG_SetDispclkFreq,
    103 			requested_dispclk_khz / 1000);
    104 
    105 	/* Actual dispclk set is returned in the parameter register */
    106 	actual_dispclk_set_mhz = REG_READ(MP1_SMN_C2PMSG_83) * 1000;
    107 
    108 	if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
    109 		if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
    110 			if (clk_mgr->dfs_bypass_disp_clk != actual_dispclk_set_mhz)
    111 				dmcu->funcs->set_psr_wait_loop(dmcu,
    112 						actual_dispclk_set_mhz / 7);
    113 		}
    114 	}
    115 
    116 	return actual_dispclk_set_mhz * 1000;
    117 }
    118 
    119 int rv1_vbios_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr)
    120 {
    121 	int actual_dprefclk_set_mhz = -1;
    122 
    123 	actual_dprefclk_set_mhz = rv1_vbios_smu_send_msg_with_param(
    124 			clk_mgr,
    125 			VBIOSSMC_MSG_SetDprefclkFreq,
    126 			clk_mgr->base.dprefclk_khz / 1000);
    127 
    128 	/* TODO: add code for programing DP DTO, currently this is down by command table */
    129 
    130 	return actual_dprefclk_set_mhz * 1000;
    131 }
    132