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