1 /* 2 * Copyright 2019 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 */ 23 24 #include <linux/firmware.h> 25 #include "amdgpu.h" 26 #include "soc15_common.h" 27 #include "nv.h" 28 #include "gc/gc_10_1_0_offset.h" 29 #include "gc/gc_10_1_0_sh_mask.h" 30 31 MODULE_FIRMWARE("amdgpu/navi10_mes.bin"); 32 33 static int mes_v10_1_add_hw_queue(struct amdgpu_mes *mes, 34 struct mes_add_queue_input *input) 35 { 36 return 0; 37 } 38 39 static int mes_v10_1_remove_hw_queue(struct amdgpu_mes *mes, 40 struct mes_remove_queue_input *input) 41 { 42 return 0; 43 } 44 45 static int mes_v10_1_suspend_gang(struct amdgpu_mes *mes, 46 struct mes_suspend_gang_input *input) 47 { 48 return 0; 49 } 50 51 static int mes_v10_1_resume_gang(struct amdgpu_mes *mes, 52 struct mes_resume_gang_input *input) 53 { 54 return 0; 55 } 56 57 static const struct amdgpu_mes_funcs mes_v10_1_funcs = { 58 .add_hw_queue = mes_v10_1_add_hw_queue, 59 .remove_hw_queue = mes_v10_1_remove_hw_queue, 60 .suspend_gang = mes_v10_1_suspend_gang, 61 .resume_gang = mes_v10_1_resume_gang, 62 }; 63 64 static int mes_v10_1_init_microcode(struct amdgpu_device *adev) 65 { 66 const char *chip_name; 67 char fw_name[30]; 68 int err; 69 const struct mes_firmware_header_v1_0 *mes_hdr; 70 71 switch (adev->asic_type) { 72 case CHIP_NAVI10: 73 chip_name = "navi10"; 74 break; 75 default: 76 BUG(); 77 } 78 79 snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes.bin", chip_name); 80 err = request_firmware(&adev->mes.fw, fw_name, adev->dev); 81 if (err) 82 return err; 83 84 err = amdgpu_ucode_validate(adev->mes.fw); 85 if (err) { 86 release_firmware(adev->mes.fw); 87 adev->mes.fw = NULL; 88 return err; 89 } 90 91 mes_hdr = (const struct mes_firmware_header_v1_0 *)adev->mes.fw->data; 92 adev->mes.ucode_fw_version = le32_to_cpu(mes_hdr->mes_ucode_version); 93 adev->mes.ucode_fw_version = 94 le32_to_cpu(mes_hdr->mes_ucode_data_version); 95 adev->mes.uc_start_addr = 96 le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) | 97 ((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32); 98 adev->mes.data_start_addr = 99 le32_to_cpu(mes_hdr->mes_data_start_addr_lo) | 100 ((uint64_t)(le32_to_cpu(mes_hdr->mes_data_start_addr_hi)) << 32); 101 102 return 0; 103 } 104 105 static void mes_v10_1_free_microcode(struct amdgpu_device *adev) 106 { 107 release_firmware(adev->mes.fw); 108 adev->mes.fw = NULL; 109 } 110 111 static int mes_v10_1_allocate_ucode_buffer(struct amdgpu_device *adev) 112 { 113 int r; 114 const struct mes_firmware_header_v1_0 *mes_hdr; 115 const __le32 *fw_data; 116 unsigned fw_size; 117 118 mes_hdr = (const struct mes_firmware_header_v1_0 *) 119 adev->mes.fw->data; 120 121 fw_data = (const __le32 *)(adev->mes.fw->data + 122 le32_to_cpu(mes_hdr->mes_ucode_offset_bytes)); 123 fw_size = le32_to_cpu(mes_hdr->mes_ucode_size_bytes); 124 125 r = amdgpu_bo_create_reserved(adev, fw_size, 126 PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, 127 &adev->mes.ucode_fw_obj, 128 &adev->mes.ucode_fw_gpu_addr, 129 (void **)&adev->mes.ucode_fw_ptr); 130 if (r) { 131 dev_err(adev->dev, "(%d) failed to create mes fw bo\n", r); 132 return r; 133 } 134 135 memcpy(adev->mes.ucode_fw_ptr, fw_data, fw_size); 136 137 amdgpu_bo_kunmap(adev->mes.ucode_fw_obj); 138 amdgpu_bo_unreserve(adev->mes.ucode_fw_obj); 139 140 return 0; 141 } 142 143 static int mes_v10_1_allocate_ucode_data_buffer(struct amdgpu_device *adev) 144 { 145 int r; 146 const struct mes_firmware_header_v1_0 *mes_hdr; 147 const __le32 *fw_data; 148 unsigned fw_size; 149 150 mes_hdr = (const struct mes_firmware_header_v1_0 *) 151 adev->mes.fw->data; 152 153 fw_data = (const __le32 *)(adev->mes.fw->data + 154 le32_to_cpu(mes_hdr->mes_ucode_data_offset_bytes)); 155 fw_size = le32_to_cpu(mes_hdr->mes_ucode_data_size_bytes); 156 157 r = amdgpu_bo_create_reserved(adev, fw_size, 158 64 * 1024, AMDGPU_GEM_DOMAIN_GTT, 159 &adev->mes.data_fw_obj, 160 &adev->mes.data_fw_gpu_addr, 161 (void **)&adev->mes.data_fw_ptr); 162 if (r) { 163 dev_err(adev->dev, "(%d) failed to create mes data fw bo\n", r); 164 return r; 165 } 166 167 memcpy(adev->mes.data_fw_ptr, fw_data, fw_size); 168 169 amdgpu_bo_kunmap(adev->mes.data_fw_obj); 170 amdgpu_bo_unreserve(adev->mes.data_fw_obj); 171 172 return 0; 173 } 174 175 static void mes_v10_1_free_ucode_buffers(struct amdgpu_device *adev) 176 { 177 amdgpu_bo_free_kernel(&adev->mes.data_fw_obj, 178 &adev->mes.data_fw_gpu_addr, 179 (void **)&adev->mes.data_fw_ptr); 180 181 amdgpu_bo_free_kernel(&adev->mes.ucode_fw_obj, 182 &adev->mes.ucode_fw_gpu_addr, 183 (void **)&adev->mes.ucode_fw_ptr); 184 } 185 186 static void mes_v10_1_enable(struct amdgpu_device *adev, bool enable) 187 { 188 uint32_t data = 0; 189 190 if (enable) { 191 data = RREG32_SOC15(GC, 0, mmCP_MES_CNTL); 192 data = REG_SET_FIELD(data, CP_MES_CNTL, MES_PIPE0_RESET, 1); 193 WREG32_SOC15(GC, 0, mmCP_MES_CNTL, data); 194 195 /* set ucode start address */ 196 WREG32_SOC15(GC, 0, mmCP_MES_PRGRM_CNTR_START, 197 (uint32_t)(adev->mes.uc_start_addr) >> 2); 198 199 /* clear BYPASS_UNCACHED to avoid hangs after interrupt. */ 200 data = RREG32_SOC15(GC, 0, mmCP_MES_DC_OP_CNTL); 201 data = REG_SET_FIELD(data, CP_MES_DC_OP_CNTL, 202 BYPASS_UNCACHED, 0); 203 WREG32_SOC15(GC, 0, mmCP_MES_DC_OP_CNTL, data); 204 205 /* unhalt MES and activate pipe0 */ 206 data = REG_SET_FIELD(0, CP_MES_CNTL, MES_PIPE0_ACTIVE, 1); 207 WREG32_SOC15(GC, 0, mmCP_MES_CNTL, data); 208 } else { 209 data = RREG32_SOC15(GC, 0, mmCP_MES_CNTL); 210 data = REG_SET_FIELD(data, CP_MES_CNTL, MES_PIPE0_ACTIVE, 0); 211 data = REG_SET_FIELD(data, CP_MES_CNTL, 212 MES_INVALIDATE_ICACHE, 1); 213 data = REG_SET_FIELD(data, CP_MES_CNTL, MES_PIPE0_RESET, 1); 214 data = REG_SET_FIELD(data, CP_MES_CNTL, MES_HALT, 1); 215 WREG32_SOC15(GC, 0, mmCP_MES_CNTL, data); 216 } 217 } 218 219 /* This function is for backdoor MES firmware */ 220 static int mes_v10_1_load_microcode(struct amdgpu_device *adev) 221 { 222 int r; 223 uint32_t data; 224 225 if (!adev->mes.fw) 226 return -EINVAL; 227 228 r = mes_v10_1_allocate_ucode_buffer(adev); 229 if (r) 230 return r; 231 232 r = mes_v10_1_allocate_ucode_data_buffer(adev); 233 if (r) { 234 mes_v10_1_free_ucode_buffers(adev); 235 return r; 236 } 237 238 mes_v10_1_enable(adev, false); 239 240 WREG32_SOC15(GC, 0, mmCP_MES_IC_BASE_CNTL, 0); 241 242 mutex_lock(&adev->srbm_mutex); 243 /* me=3, pipe=0, queue=0 */ 244 nv_grbm_select(adev, 3, 0, 0, 0); 245 246 /* set ucode start address */ 247 WREG32_SOC15(GC, 0, mmCP_MES_PRGRM_CNTR_START, 248 (uint32_t)(adev->mes.uc_start_addr) >> 2); 249 250 /* set ucode fimrware address */ 251 WREG32_SOC15(GC, 0, mmCP_MES_IC_BASE_LO, 252 lower_32_bits(adev->mes.ucode_fw_gpu_addr)); 253 WREG32_SOC15(GC, 0, mmCP_MES_IC_BASE_HI, 254 upper_32_bits(adev->mes.ucode_fw_gpu_addr)); 255 256 /* set ucode instruction cache boundary to 2M-1 */ 257 WREG32_SOC15(GC, 0, mmCP_MES_MIBOUND_LO, 0x1FFFFF); 258 259 /* set ucode data firmware address */ 260 WREG32_SOC15(GC, 0, mmCP_MES_MDBASE_LO, 261 lower_32_bits(adev->mes.data_fw_gpu_addr)); 262 WREG32_SOC15(GC, 0, mmCP_MES_MDBASE_HI, 263 upper_32_bits(adev->mes.data_fw_gpu_addr)); 264 265 /* Set 0x3FFFF (256K-1) to CP_MES_MDBOUND_LO */ 266 WREG32_SOC15(GC, 0, mmCP_MES_MDBOUND_LO, 0x3FFFF); 267 268 /* invalidate ICACHE */ 269 data = RREG32_SOC15(GC, 0, mmCP_MES_IC_OP_CNTL); 270 data = REG_SET_FIELD(data, CP_MES_IC_OP_CNTL, PRIME_ICACHE, 0); 271 data = REG_SET_FIELD(data, CP_MES_IC_OP_CNTL, INVALIDATE_CACHE, 1); 272 WREG32_SOC15(GC, 0, mmCP_MES_IC_OP_CNTL, data); 273 274 /* prime the ICACHE. */ 275 data = RREG32_SOC15(GC, 0, mmCP_MES_IC_OP_CNTL); 276 data = REG_SET_FIELD(data, CP_MES_IC_OP_CNTL, PRIME_ICACHE, 1); 277 WREG32_SOC15(GC, 0, mmCP_MES_IC_OP_CNTL, data); 278 279 nv_grbm_select(adev, 0, 0, 0, 0); 280 mutex_unlock(&adev->srbm_mutex); 281 282 return 0; 283 } 284 285 static int mes_v10_1_sw_init(void *handle) 286 { 287 int r; 288 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 289 290 r = mes_v10_1_init_microcode(adev); 291 if (r) 292 return r; 293 294 return 0; 295 } 296 297 static int mes_v10_1_sw_fini(void *handle) 298 { 299 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 300 301 mes_v10_1_free_microcode(adev); 302 303 return 0; 304 } 305 306 static int mes_v10_1_hw_init(void *handle) 307 { 308 int r; 309 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 310 311 if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) { 312 r = mes_v10_1_load_microcode(adev); 313 if (r) { 314 DRM_ERROR("failed to MES fw, r=%d\n", r); 315 return r; 316 } 317 } else { 318 DRM_ERROR("only support direct fw loading on MES\n"); 319 return -EINVAL; 320 } 321 322 mes_v10_1_enable(adev, true); 323 324 return 0; 325 } 326 327 static int mes_v10_1_hw_fini(void *handle) 328 { 329 struct amdgpu_device *adev = (struct amdgpu_device *)handle; 330 331 mes_v10_1_enable(adev, false); 332 333 if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) 334 mes_v10_1_free_ucode_buffers(adev); 335 336 return 0; 337 } 338 339 static int mes_v10_1_suspend(void *handle) 340 { 341 return 0; 342 } 343 344 static int mes_v10_1_resume(void *handle) 345 { 346 return 0; 347 } 348 349 static const struct amd_ip_funcs mes_v10_1_ip_funcs = { 350 .name = "mes_v10_1", 351 .sw_init = mes_v10_1_sw_init, 352 .sw_fini = mes_v10_1_sw_fini, 353 .hw_init = mes_v10_1_hw_init, 354 .hw_fini = mes_v10_1_hw_fini, 355 .suspend = mes_v10_1_suspend, 356 .resume = mes_v10_1_resume, 357 }; 358 359 const struct amdgpu_ip_block_version mes_v10_1_ip_block = { 360 .type = AMD_IP_BLOCK_TYPE_MES, 361 .major = 10, 362 .minor = 1, 363 .rev = 0, 364 .funcs = &mes_v10_1_ip_funcs, 365 }; 366