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