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 #include "amdxdna_pm.h" 15 16 #define SMU_RESULT_OK 1 17 18 /* SMU commands */ 19 #define AIE2_SMU_POWER_ON 0x3 20 #define AIE2_SMU_POWER_OFF 0x4 21 #define AIE2_SMU_SET_MPNPUCLK_FREQ 0x5 22 #define AIE2_SMU_SET_HCLK_FREQ 0x6 23 #define AIE2_SMU_SET_SOFT_DPMLEVEL 0x7 24 #define AIE2_SMU_SET_HARD_DPMLEVEL 0x8 25 26 #define NPU4_DPM_TOPS(ndev, dpm_level) \ 27 ({ \ 28 typeof(ndev) _ndev = ndev; \ 29 (4096 * (_ndev)->total_col * \ 30 (_ndev)->priv->dpm_clk_tbl[dpm_level].hclk / 1000000); \ 31 }) 32 33 static int aie2_smu_exec(struct amdxdna_dev_hdl *ndev, u32 reg_cmd, 34 u32 reg_arg, u32 *out) 35 { 36 u32 resp; 37 int ret; 38 39 writel(0, SMU_REG(ndev, SMU_RESP_REG)); 40 writel(reg_arg, SMU_REG(ndev, SMU_ARG_REG)); 41 writel(reg_cmd, SMU_REG(ndev, SMU_CMD_REG)); 42 43 /* Clear and set SMU_INTR_REG to kick off */ 44 writel(0, SMU_REG(ndev, SMU_INTR_REG)); 45 writel(1, SMU_REG(ndev, SMU_INTR_REG)); 46 47 ret = readx_poll_timeout(readl, SMU_REG(ndev, SMU_RESP_REG), resp, 48 resp, AIE2_INTERVAL, AIE2_TIMEOUT); 49 if (ret) { 50 XDNA_ERR(ndev->xdna, "smu cmd %d timed out", reg_cmd); 51 return ret; 52 } 53 54 if (out) 55 *out = readl(SMU_REG(ndev, SMU_OUT_REG)); 56 57 if (resp != SMU_RESULT_OK) { 58 XDNA_ERR(ndev->xdna, "smu cmd %d failed, 0x%x", reg_cmd, resp); 59 return -EINVAL; 60 } 61 62 return 0; 63 } 64 65 int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) 66 { 67 u32 freq; 68 int ret; 69 70 ret = amdxdna_pm_resume_get(ndev->xdna); 71 if (ret) 72 return ret; 73 74 ret = aie2_smu_exec(ndev, AIE2_SMU_SET_MPNPUCLK_FREQ, 75 ndev->priv->dpm_clk_tbl[dpm_level].npuclk, &freq); 76 if (ret) { 77 XDNA_ERR(ndev->xdna, "Set npu clock to %d failed, ret %d\n", 78 ndev->priv->dpm_clk_tbl[dpm_level].npuclk, ret); 79 goto suspend_put; 80 } 81 ndev->npuclk_freq = freq; 82 83 ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HCLK_FREQ, 84 ndev->priv->dpm_clk_tbl[dpm_level].hclk, &freq); 85 if (ret) { 86 XDNA_ERR(ndev->xdna, "Set h clock to %d failed, ret %d\n", 87 ndev->priv->dpm_clk_tbl[dpm_level].hclk, ret); 88 goto suspend_put; 89 } 90 91 amdxdna_pm_suspend_put(ndev->xdna); 92 ndev->hclk_freq = freq; 93 ndev->dpm_level = dpm_level; 94 ndev->max_tops = 2 * ndev->total_col; 95 ndev->curr_tops = ndev->max_tops * freq / 1028; 96 97 XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n", 98 ndev->npuclk_freq, ndev->hclk_freq); 99 100 return 0; 101 102 suspend_put: 103 amdxdna_pm_suspend_put(ndev->xdna); 104 return ret; 105 } 106 107 int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level) 108 { 109 int ret; 110 111 ret = amdxdna_pm_resume_get(ndev->xdna); 112 if (ret) 113 return ret; 114 115 ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL); 116 if (ret) { 117 XDNA_ERR(ndev->xdna, "Set hard dpm level %d failed, ret %d ", 118 dpm_level, ret); 119 goto suspend_put; 120 } 121 122 ret = aie2_smu_exec(ndev, AIE2_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL); 123 if (ret) { 124 XDNA_ERR(ndev->xdna, "Set soft dpm level %d failed, ret %d", 125 dpm_level, ret); 126 goto suspend_put; 127 } 128 129 amdxdna_pm_suspend_put(ndev->xdna); 130 ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk; 131 ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk; 132 ndev->dpm_level = dpm_level; 133 ndev->max_tops = NPU4_DPM_TOPS(ndev, ndev->max_dpm_level); 134 ndev->curr_tops = NPU4_DPM_TOPS(ndev, dpm_level); 135 136 XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n", 137 ndev->npuclk_freq, ndev->hclk_freq); 138 139 return 0; 140 141 suspend_put: 142 amdxdna_pm_suspend_put(ndev->xdna); 143 return ret; 144 } 145 146 int aie2_smu_init(struct amdxdna_dev_hdl *ndev) 147 { 148 int ret; 149 150 ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_ON, 0, NULL); 151 if (ret) { 152 XDNA_ERR(ndev->xdna, "Power on failed, ret %d", ret); 153 return ret; 154 } 155 156 return 0; 157 } 158 159 void aie2_smu_fini(struct amdxdna_dev_hdl *ndev) 160 { 161 int ret; 162 163 ndev->priv->hw_ops.set_dpm(ndev, 0); 164 ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_OFF, 0, NULL); 165 if (ret) 166 XDNA_ERR(ndev->xdna, "Power off failed, ret %d", ret); 167 } 168