xref: /linux/drivers/accel/amdxdna/aie2_smu.c (revision f96a974170b749e3a56844e25b31d46a7233b6f6)
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 	}
68 	ndev->npuclk_freq = freq;
69 
70 	ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HCLK_FREQ,
71 			    ndev->priv->dpm_clk_tbl[dpm_level].hclk, &freq);
72 	if (ret) {
73 		XDNA_ERR(ndev->xdna, "Set h clock to %d failed, ret %d\n",
74 			 ndev->priv->dpm_clk_tbl[dpm_level].hclk, ret);
75 	}
76 	ndev->hclk_freq = freq;
77 	ndev->dpm_level = dpm_level;
78 
79 	XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n",
80 		 ndev->npuclk_freq, ndev->hclk_freq);
81 
82 	return 0;
83 }
84 
85 int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
86 {
87 	int ret;
88 
89 	ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL);
90 	if (ret) {
91 		XDNA_ERR(ndev->xdna, "Set hard dpm level %d failed, ret %d ",
92 			 dpm_level, ret);
93 		return ret;
94 	}
95 
96 	ret = aie2_smu_exec(ndev, AIE2_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL);
97 	if (ret) {
98 		XDNA_ERR(ndev->xdna, "Set soft dpm level %d failed, ret %d",
99 			 dpm_level, ret);
100 		return ret;
101 	}
102 
103 	ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk;
104 	ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk;
105 	ndev->dpm_level = dpm_level;
106 
107 	XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n",
108 		 ndev->npuclk_freq, ndev->hclk_freq);
109 
110 	return 0;
111 }
112 
113 int aie2_smu_init(struct amdxdna_dev_hdl *ndev)
114 {
115 	int ret;
116 
117 	ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_ON, 0, NULL);
118 	if (ret) {
119 		XDNA_ERR(ndev->xdna, "Power on failed, ret %d", ret);
120 		return ret;
121 	}
122 
123 	return 0;
124 }
125 
126 void aie2_smu_fini(struct amdxdna_dev_hdl *ndev)
127 {
128 	int ret;
129 
130 	ndev->priv->hw_ops.set_dpm(ndev, 0);
131 	ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_OFF, 0, NULL);
132 	if (ret)
133 		XDNA_ERR(ndev->xdna, "Power off failed, ret %d", ret);
134 }
135