Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/accel/amdxdna/aie2_smu.c
26428 views
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
138