xref: /linux/drivers/accel/amdxdna/aie2_smu.c (revision 815e260a18a3af4dab59025ee99a7156c0e8b5e0)
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