1 1.1 riastrad /* $NetBSD: radeon_kv_smc.c,v 1.2 2021/12/18 23:45:43 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright 2013 Advanced Micro Devices, Inc. 5 1.1 riastrad * 6 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 7 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 8 1.1 riastrad * to deal in the Software without restriction, including without limitation 9 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 11 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 12 1.1 riastrad * 13 1.1 riastrad * The above copyright notice and this permission notice shall be included in 14 1.1 riastrad * all copies or substantial portions of the Software. 15 1.1 riastrad * 16 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 1.1 riastrad * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 1.1 riastrad * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 1.1 riastrad * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 1.1 riastrad * OTHER DEALINGS IN THE SOFTWARE. 23 1.1 riastrad * 24 1.1 riastrad * Authors: Alex Deucher 25 1.1 riastrad */ 26 1.1 riastrad 27 1.1 riastrad #include <sys/cdefs.h> 28 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: radeon_kv_smc.c,v 1.2 2021/12/18 23:45:43 riastradh Exp $"); 29 1.1 riastrad 30 1.1 riastrad #include "radeon.h" 31 1.1 riastrad #include "cikd.h" 32 1.1 riastrad #include "kv_dpm.h" 33 1.1 riastrad 34 1.1 riastrad int kv_notify_message_to_smu(struct radeon_device *rdev, u32 id) 35 1.1 riastrad { 36 1.1 riastrad u32 i; 37 1.1 riastrad u32 tmp = 0; 38 1.1 riastrad 39 1.1 riastrad WREG32(SMC_MESSAGE_0, id & SMC_MSG_MASK); 40 1.1 riastrad 41 1.1 riastrad for (i = 0; i < rdev->usec_timeout; i++) { 42 1.1 riastrad if ((RREG32(SMC_RESP_0) & SMC_RESP_MASK) != 0) 43 1.1 riastrad break; 44 1.1 riastrad udelay(1); 45 1.1 riastrad } 46 1.1 riastrad tmp = RREG32(SMC_RESP_0) & SMC_RESP_MASK; 47 1.1 riastrad 48 1.1 riastrad if (tmp != 1) { 49 1.1 riastrad if (tmp == 0xFF) 50 1.1 riastrad return -EINVAL; 51 1.1 riastrad else if (tmp == 0xFE) 52 1.1 riastrad return -EINVAL; 53 1.1 riastrad } 54 1.1 riastrad 55 1.1 riastrad return 0; 56 1.1 riastrad } 57 1.1 riastrad 58 1.1 riastrad int kv_dpm_get_enable_mask(struct radeon_device *rdev, u32 *enable_mask) 59 1.1 riastrad { 60 1.1 riastrad int ret; 61 1.1 riastrad 62 1.1 riastrad ret = kv_notify_message_to_smu(rdev, PPSMC_MSG_SCLKDPM_GetEnabledMask); 63 1.1 riastrad 64 1.1 riastrad if (ret == 0) 65 1.1 riastrad *enable_mask = RREG32_SMC(SMC_SYSCON_MSG_ARG_0); 66 1.1 riastrad 67 1.1 riastrad return ret; 68 1.1 riastrad } 69 1.1 riastrad 70 1.1 riastrad int kv_send_msg_to_smc_with_parameter(struct radeon_device *rdev, 71 1.1 riastrad PPSMC_Msg msg, u32 parameter) 72 1.1 riastrad { 73 1.1 riastrad 74 1.1 riastrad WREG32(SMC_MSG_ARG_0, parameter); 75 1.1 riastrad 76 1.1 riastrad return kv_notify_message_to_smu(rdev, msg); 77 1.1 riastrad } 78 1.1 riastrad 79 1.1 riastrad static int kv_set_smc_sram_address(struct radeon_device *rdev, 80 1.1 riastrad u32 smc_address, u32 limit) 81 1.1 riastrad { 82 1.1 riastrad if (smc_address & 3) 83 1.1 riastrad return -EINVAL; 84 1.1 riastrad if ((smc_address + 3) > limit) 85 1.1 riastrad return -EINVAL; 86 1.1 riastrad 87 1.1 riastrad WREG32(SMC_IND_INDEX_0, smc_address); 88 1.1 riastrad WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0); 89 1.1 riastrad 90 1.1 riastrad return 0; 91 1.1 riastrad } 92 1.1 riastrad 93 1.1 riastrad int kv_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address, 94 1.1 riastrad u32 *value, u32 limit) 95 1.1 riastrad { 96 1.1 riastrad int ret; 97 1.1 riastrad 98 1.1 riastrad ret = kv_set_smc_sram_address(rdev, smc_address, limit); 99 1.1 riastrad if (ret) 100 1.1 riastrad return ret; 101 1.1 riastrad 102 1.1 riastrad *value = RREG32(SMC_IND_DATA_0); 103 1.1 riastrad return 0; 104 1.1 riastrad } 105 1.1 riastrad 106 1.1 riastrad int kv_smc_dpm_enable(struct radeon_device *rdev, bool enable) 107 1.1 riastrad { 108 1.1 riastrad if (enable) 109 1.1 riastrad return kv_notify_message_to_smu(rdev, PPSMC_MSG_DPM_Enable); 110 1.1 riastrad else 111 1.1 riastrad return kv_notify_message_to_smu(rdev, PPSMC_MSG_DPM_Disable); 112 1.1 riastrad } 113 1.1 riastrad 114 1.1 riastrad int kv_smc_bapm_enable(struct radeon_device *rdev, bool enable) 115 1.1 riastrad { 116 1.1 riastrad if (enable) 117 1.1 riastrad return kv_notify_message_to_smu(rdev, PPSMC_MSG_EnableBAPM); 118 1.1 riastrad else 119 1.1 riastrad return kv_notify_message_to_smu(rdev, PPSMC_MSG_DisableBAPM); 120 1.1 riastrad } 121 1.1 riastrad 122 1.1 riastrad int kv_copy_bytes_to_smc(struct radeon_device *rdev, 123 1.1 riastrad u32 smc_start_address, 124 1.1 riastrad const u8 *src, u32 byte_count, u32 limit) 125 1.1 riastrad { 126 1.1 riastrad int ret; 127 1.1 riastrad u32 data, original_data, addr, extra_shift, t_byte, count, mask; 128 1.1 riastrad 129 1.1 riastrad if ((smc_start_address + byte_count) > limit) 130 1.1 riastrad return -EINVAL; 131 1.1 riastrad 132 1.1 riastrad addr = smc_start_address; 133 1.1 riastrad t_byte = addr & 3; 134 1.1 riastrad 135 1.1 riastrad /* RMW for the initial bytes */ 136 1.1 riastrad if (t_byte != 0) { 137 1.1 riastrad addr -= t_byte; 138 1.1 riastrad 139 1.1 riastrad ret = kv_set_smc_sram_address(rdev, addr, limit); 140 1.1 riastrad if (ret) 141 1.1 riastrad return ret; 142 1.1 riastrad 143 1.1 riastrad original_data = RREG32(SMC_IND_DATA_0); 144 1.1 riastrad 145 1.1 riastrad data = 0; 146 1.1 riastrad mask = 0; 147 1.1 riastrad count = 4; 148 1.1 riastrad while (count > 0) { 149 1.1 riastrad if (t_byte > 0) { 150 1.1 riastrad mask = (mask << 8) | 0xff; 151 1.1 riastrad t_byte--; 152 1.1 riastrad } else if (byte_count > 0) { 153 1.1 riastrad data = (data << 8) + *src++; 154 1.1 riastrad byte_count--; 155 1.1 riastrad mask <<= 8; 156 1.1 riastrad } else { 157 1.1 riastrad data <<= 8; 158 1.1 riastrad mask = (mask << 8) | 0xff; 159 1.1 riastrad } 160 1.1 riastrad count--; 161 1.1 riastrad } 162 1.1 riastrad 163 1.1 riastrad data |= original_data & mask; 164 1.1 riastrad 165 1.1 riastrad ret = kv_set_smc_sram_address(rdev, addr, limit); 166 1.1 riastrad if (ret) 167 1.1 riastrad return ret; 168 1.1 riastrad 169 1.1 riastrad WREG32(SMC_IND_DATA_0, data); 170 1.1 riastrad 171 1.1 riastrad addr += 4; 172 1.1 riastrad } 173 1.1 riastrad 174 1.1 riastrad while (byte_count >= 4) { 175 1.1 riastrad /* SMC address space is BE */ 176 1.1 riastrad data = (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3]; 177 1.1 riastrad 178 1.1 riastrad ret = kv_set_smc_sram_address(rdev, addr, limit); 179 1.1 riastrad if (ret) 180 1.1 riastrad return ret; 181 1.1 riastrad 182 1.1 riastrad WREG32(SMC_IND_DATA_0, data); 183 1.1 riastrad 184 1.1 riastrad src += 4; 185 1.1 riastrad byte_count -= 4; 186 1.1 riastrad addr += 4; 187 1.1 riastrad } 188 1.1 riastrad 189 1.1 riastrad /* RMW for the final bytes */ 190 1.1 riastrad if (byte_count > 0) { 191 1.1 riastrad data = 0; 192 1.1 riastrad 193 1.1 riastrad ret = kv_set_smc_sram_address(rdev, addr, limit); 194 1.1 riastrad if (ret) 195 1.1 riastrad return ret; 196 1.1 riastrad 197 1.1 riastrad original_data= RREG32(SMC_IND_DATA_0); 198 1.1 riastrad 199 1.1 riastrad extra_shift = 8 * (4 - byte_count); 200 1.1 riastrad 201 1.1 riastrad while (byte_count > 0) { 202 1.1 riastrad /* SMC address space is BE */ 203 1.1 riastrad data = (data << 8) + *src++; 204 1.1 riastrad byte_count--; 205 1.1 riastrad } 206 1.1 riastrad 207 1.1 riastrad data <<= extra_shift; 208 1.1 riastrad 209 1.1 riastrad data |= (original_data & ~((~0UL) << extra_shift)); 210 1.1 riastrad 211 1.1 riastrad ret = kv_set_smc_sram_address(rdev, addr, limit); 212 1.1 riastrad if (ret) 213 1.1 riastrad return ret; 214 1.1 riastrad 215 1.1 riastrad WREG32(SMC_IND_DATA_0, data); 216 1.1 riastrad } 217 1.1 riastrad return 0; 218 1.1 riastrad } 219 1.1 riastrad 220