1 /* 2 * Copyright 2025 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 "amdgpu_imu.h" 27 #include "amdgpu_dpm.h" 28 29 #include "imu_v12_1.h" 30 31 #include "gc/gc_12_1_0_offset.h" 32 #include "gc/gc_12_1_0_sh_mask.h" 33 #include "mmhub/mmhub_4_2_0_offset.h" 34 35 MODULE_FIRMWARE("amdgpu/gc_12_1_0_imu.bin"); 36 37 #define TRANSFER_RAM_MASK 0x001c0000 38 39 static int imu_v12_1_init_microcode(struct amdgpu_device *adev) 40 { 41 char ucode_prefix[15]; 42 int err; 43 const struct imu_firmware_header_v1_0 *imu_hdr; 44 struct amdgpu_firmware_info *info = NULL; 45 46 DRM_DEBUG("\n"); 47 48 amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, sizeof(ucode_prefix)); 49 err = amdgpu_ucode_request(adev, &adev->gfx.imu_fw, AMDGPU_UCODE_REQUIRED, 50 "amdgpu/%s_imu.bin", ucode_prefix); 51 if (err) 52 goto out; 53 54 imu_hdr = (const struct imu_firmware_header_v1_0 *)adev->gfx.imu_fw->data; 55 adev->gfx.imu_fw_version = le32_to_cpu(imu_hdr->header.ucode_version); 56 57 if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { 58 info = &adev->firmware.ucode[AMDGPU_UCODE_ID_IMU_I]; 59 info->ucode_id = AMDGPU_UCODE_ID_IMU_I; 60 info->fw = adev->gfx.imu_fw; 61 adev->firmware.fw_size += 62 ALIGN(le32_to_cpu(imu_hdr->imu_iram_ucode_size_bytes), PAGE_SIZE); 63 info = &adev->firmware.ucode[AMDGPU_UCODE_ID_IMU_D]; 64 info->ucode_id = AMDGPU_UCODE_ID_IMU_D; 65 info->fw = adev->gfx.imu_fw; 66 adev->firmware.fw_size += 67 ALIGN(le32_to_cpu(imu_hdr->imu_dram_ucode_size_bytes), PAGE_SIZE); 68 } 69 70 out: 71 if (err) { 72 dev_err(adev->dev, 73 "gfx12: Failed to load firmware \"%s_imu.bin\"\n", 74 ucode_prefix); 75 amdgpu_ucode_release(&adev->gfx.imu_fw); 76 } 77 78 return err; 79 } 80 81 static void imu_v12_1_xcc_load_microcode(struct amdgpu_device *adev, 82 int xcc_id) 83 { 84 const struct imu_firmware_header_v1_0 *hdr; 85 const __le32 *fw_data; 86 unsigned i, fw_size; 87 88 hdr = (const struct imu_firmware_header_v1_0 *)adev->gfx.imu_fw->data; 89 fw_data = (const __le32 *)(adev->gfx.imu_fw->data + 90 le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 91 fw_size = le32_to_cpu(hdr->imu_iram_ucode_size_bytes) / 4; 92 93 WREG32_SOC15(GC, GET_INST(GC, xcc_id), regGFX_IMU_I_RAM_ADDR, 0); 94 95 for (i = 0; i < fw_size; i++) 96 WREG32_SOC15(GC, GET_INST(GC, xcc_id), 97 regGFX_IMU_I_RAM_DATA, 98 le32_to_cpup(fw_data++)); 99 100 WREG32_SOC15(GC, GET_INST(GC, xcc_id), 101 regGFX_IMU_I_RAM_ADDR, 102 adev->gfx.imu_fw_version); 103 104 fw_data = (const __le32 *)(adev->gfx.imu_fw->data + 105 le32_to_cpu(hdr->header.ucode_array_offset_bytes) + 106 le32_to_cpu(hdr->imu_iram_ucode_size_bytes)); 107 fw_size = le32_to_cpu(hdr->imu_dram_ucode_size_bytes) / 4; 108 109 WREG32_SOC15(GC, GET_INST(GC, xcc_id), regGFX_IMU_D_RAM_ADDR, 0); 110 111 for (i = 0; i < fw_size; i++) 112 WREG32_SOC15(GC, GET_INST(GC, xcc_id), 113 regGFX_IMU_D_RAM_DATA, 114 le32_to_cpup(fw_data++)); 115 116 WREG32_SOC15(GC, GET_INST(GC, xcc_id), 117 regGFX_IMU_D_RAM_ADDR, 118 adev->gfx.imu_fw_version); 119 } 120 121 static int imu_v12_1_load_microcode(struct amdgpu_device *adev) 122 { 123 int i, num_xcc; 124 125 if (!adev->gfx.imu_fw) 126 return -EINVAL; 127 128 num_xcc = NUM_XCC(adev->gfx.xcc_mask); 129 for (i = 0; i < num_xcc; i++) { 130 imu_v12_1_xcc_load_microcode(adev, i); 131 } 132 133 return 0; 134 } 135 136 static int imu_v12_1_switch_compute_partition(struct amdgpu_device *adev, 137 int num_xccs_per_xcp, 138 int compute_partition_mode) 139 { 140 int ret; 141 142 if (adev->psp.funcs) { 143 /*TODO: revisit asp interface once it's avaialble */ 144 ret = psp_spatial_partition(&adev->psp, 145 NUM_XCC(adev->gfx.xcc_mask) / 146 num_xccs_per_xcp); 147 if (ret) 148 return ret; 149 } 150 151 adev->gfx.num_xcc_per_xcp = num_xccs_per_xcp; 152 153 return 0; 154 } 155 156 static void imu_v12_1_init_mcm_addr_lut(struct amdgpu_device *adev) 157 { 158 /* todo: fill in when interface is ready */ 159 } 160 161 const struct amdgpu_imu_funcs gfx_v12_1_imu_funcs = { 162 .init_microcode = imu_v12_1_init_microcode, 163 .load_microcode = imu_v12_1_load_microcode, 164 .switch_compute_partition = imu_v12_1_switch_compute_partition, 165 .init_mcm_addr_lut = imu_v12_1_init_mcm_addr_lut, 166 }; 167