linux/drivers/gpu/drm/amd/amdgpu/mes_v10_1.c
<<
>>
Prefs
   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
  32MODULE_FIRMWARE("amdgpu/navi10_mes.bin");
  33
  34static int mes_v10_1_add_hw_queue(struct amdgpu_mes *mes,
  35                                  struct mes_add_queue_input *input)
  36{
  37        return 0;
  38}
  39
  40static int mes_v10_1_remove_hw_queue(struct amdgpu_mes *mes,
  41                                     struct mes_remove_queue_input *input)
  42{
  43        return 0;
  44}
  45
  46static int mes_v10_1_suspend_gang(struct amdgpu_mes *mes,
  47                                  struct mes_suspend_gang_input *input)
  48{
  49        return 0;
  50}
  51
  52static int mes_v10_1_resume_gang(struct amdgpu_mes *mes,
  53                                 struct mes_resume_gang_input *input)
  54{
  55        return 0;
  56}
  57
  58static 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
  65static 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
 106static void mes_v10_1_free_microcode(struct amdgpu_device *adev)
 107{
 108        release_firmware(adev->mes.fw);
 109        adev->mes.fw = NULL;
 110}
 111
 112static 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
 144static 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
 176static 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
 187static 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 */
 221static 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
 286static 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
 298static 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
 307static 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
 328static 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
 340static int mes_v10_1_suspend(void *handle)
 341{
 342        return 0;
 343}
 344
 345static int mes_v10_1_resume(void *handle)
 346{
 347        return 0;
 348}
 349
 350static 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
 360const 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