1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2022-2024, Advanced Micro Devices, Inc. 4 */ 5 6 #include <drm/drm_device.h> 7 #include <drm/drm_gem_shmem_helper.h> 8 #include <drm/drm_print.h> 9 #include <drm/gpu_scheduler.h> 10 #include <linux/iopoll.h> 11 12 #include "aie2_pci.h" 13 #include "amdxdna_pci_drv.h" 14 15 #define SMU_RESULT_OK 1 16 17 /* SMU commands */ 18 #define AIE2_SMU_POWER_ON 0x3 19 #define AIE2_SMU_POWER_OFF 0x4 20 #define AIE2_SMU_SET_MPNPUCLK_FREQ 0x5 21 #define AIE2_SMU_SET_HCLK_FREQ 0x6 22 #define AIE2_SMU_SET_SOFT_DPMLEVEL 0x7 23 #define AIE2_SMU_SET_HARD_DPMLEVEL 0x8 24 25 static int aie2_smu_exec(struct amdxdna_dev_hdl *ndev, u32 reg_cmd, 26 u32 reg_arg, u32 *out) 27 { 28 u32 resp; 29 int ret; 30 31 writel(0, SMU_REG(ndev, SMU_RESP_REG)); 32 writel(reg_arg, SMU_REG(ndev, SMU_ARG_REG)); 33 writel(reg_cmd, SMU_REG(ndev, SMU_CMD_REG)); 34 35 /* Clear and set SMU_INTR_REG to kick off */ 36 writel(0, SMU_REG(ndev, SMU_INTR_REG)); 37 writel(1, SMU_REG(ndev, SMU_INTR_REG)); 38 39 ret = readx_poll_timeout(readl, SMU_REG(ndev, SMU_RESP_REG), resp, 40 resp, AIE2_INTERVAL, AIE2_TIMEOUT); 41 if (ret) { 42 XDNA_ERR(ndev->xdna, "smu cmd %d timed out", reg_cmd); 43 return ret; 44 } 45 46 if (out) 47 *out = readl(SMU_REG(ndev, SMU_OUT_REG)); 48 49 if (resp != SMU_RESULT_OK) { 50 XDNA_ERR(ndev->xdna, "smu cmd %d failed, 0x%x", reg_cmd, resp); 51 return -EINVAL; 52 } 53 54 return 0; 55 } 56 57 int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) 58 { 59 u32 freq; 60 int ret; 61 62 ret = aie2_smu_exec(ndev, AIE2_SMU_SET_MPNPUCLK_FREQ, 63 ndev->priv->dpm_clk_tbl[dpm_level].npuclk, &freq); 64 if (ret) { 65 XDNA_ERR(ndev->xdna, "Set npu clock to %d failed, ret %d\n", 66 ndev->priv->dpm_clk_tbl[dpm_level].npuclk, ret); 67 return ret; 68 } 69 ndev->npuclk_freq = freq; 70 71 ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HCLK_FREQ, 72 ndev->priv->dpm_clk_tbl[dpm_level].hclk, &freq); 73 if (ret) { 74 XDNA_ERR(ndev->xdna, "Set h clock to %d failed, ret %d\n", 75 ndev->priv->dpm_clk_tbl[dpm_level].hclk, ret); 76 return ret; 77 } 78 ndev->hclk_freq = freq; 79 ndev->dpm_level = dpm_level; 80 81 XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n", 82 ndev->npuclk_freq, ndev->hclk_freq); 83 84 return 0; 85 } 86 87 int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) 88 { 89 int ret; 90 91 ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL); 92 if (ret) { 93 XDNA_ERR(ndev->xdna, "Set hard dpm level %d failed, ret %d ", 94 dpm_level, ret); 95 return ret; 96 } 97 98 ret = aie2_smu_exec(ndev, AIE2_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL); 99 if (ret) { 100 XDNA_ERR(ndev->xdna, "Set soft dpm level %d failed, ret %d", 101 dpm_level, ret); 102 return ret; 103 } 104 105 ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk; 106 ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk; 107 ndev->dpm_level = dpm_level; 108 109 XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n", 110 ndev->npuclk_freq, ndev->hclk_freq); 111 112 return 0; 113 } 114 115 int aie2_smu_init(struct amdxdna_dev_hdl *ndev) 116 { 117 int ret; 118 119 ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_ON, 0, NULL); 120 if (ret) { 121 XDNA_ERR(ndev->xdna, "Power on failed, ret %d", ret); 122 return ret; 123 } 124 125 return 0; 126 } 127 128 void aie2_smu_fini(struct amdxdna_dev_hdl *ndev) 129 { 130 int ret; 131 132 ndev->priv->hw_ops.set_dpm(ndev, 0); 133 ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_OFF, 0, NULL); 134 if (ret) 135 XDNA_ERR(ndev->xdna, "Power off failed, ret %d", ret); 136 } 137