Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/accel/amdxdna/aie2_smu.c
51668 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
#define NPU4_DPM_TOPS(ndev, dpm_level) \
26
({ \
27
typeof(ndev) _ndev = ndev; \
28
(4096 * (_ndev)->total_col * \
29
(_ndev)->priv->dpm_clk_tbl[dpm_level].hclk / 1000000); \
30
})
31
32
static int aie2_smu_exec(struct amdxdna_dev_hdl *ndev, u32 reg_cmd,
33
u32 reg_arg, u32 *out)
34
{
35
u32 resp;
36
int ret;
37
38
writel(0, SMU_REG(ndev, SMU_RESP_REG));
39
writel(reg_arg, SMU_REG(ndev, SMU_ARG_REG));
40
writel(reg_cmd, SMU_REG(ndev, SMU_CMD_REG));
41
42
/* Clear and set SMU_INTR_REG to kick off */
43
writel(0, SMU_REG(ndev, SMU_INTR_REG));
44
writel(1, SMU_REG(ndev, SMU_INTR_REG));
45
46
ret = readx_poll_timeout(readl, SMU_REG(ndev, SMU_RESP_REG), resp,
47
resp, AIE2_INTERVAL, AIE2_TIMEOUT);
48
if (ret) {
49
XDNA_ERR(ndev->xdna, "smu cmd %d timed out", reg_cmd);
50
return ret;
51
}
52
53
if (out)
54
*out = readl(SMU_REG(ndev, SMU_OUT_REG));
55
56
if (resp != SMU_RESULT_OK) {
57
XDNA_ERR(ndev->xdna, "smu cmd %d failed, 0x%x", reg_cmd, resp);
58
return -EINVAL;
59
}
60
61
return 0;
62
}
63
64
int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
65
{
66
u32 freq;
67
int ret;
68
69
ret = aie2_smu_exec(ndev, AIE2_SMU_SET_MPNPUCLK_FREQ,
70
ndev->priv->dpm_clk_tbl[dpm_level].npuclk, &freq);
71
if (ret) {
72
XDNA_ERR(ndev->xdna, "Set npu clock to %d failed, ret %d\n",
73
ndev->priv->dpm_clk_tbl[dpm_level].npuclk, ret);
74
return ret;
75
}
76
ndev->npuclk_freq = freq;
77
78
ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HCLK_FREQ,
79
ndev->priv->dpm_clk_tbl[dpm_level].hclk, &freq);
80
if (ret) {
81
XDNA_ERR(ndev->xdna, "Set h clock to %d failed, ret %d\n",
82
ndev->priv->dpm_clk_tbl[dpm_level].hclk, ret);
83
return ret;
84
}
85
86
ndev->hclk_freq = freq;
87
ndev->max_tops = 2 * ndev->total_col;
88
ndev->curr_tops = ndev->max_tops * freq / 1028;
89
90
XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n",
91
ndev->npuclk_freq, ndev->hclk_freq);
92
93
return 0;
94
}
95
96
int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
97
{
98
int ret;
99
100
ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL);
101
if (ret) {
102
XDNA_ERR(ndev->xdna, "Set hard dpm level %d failed, ret %d ",
103
dpm_level, ret);
104
return ret;
105
}
106
107
ret = aie2_smu_exec(ndev, AIE2_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL);
108
if (ret) {
109
XDNA_ERR(ndev->xdna, "Set soft dpm level %d failed, ret %d",
110
dpm_level, ret);
111
return ret;
112
}
113
114
ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk;
115
ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk;
116
ndev->max_tops = NPU4_DPM_TOPS(ndev, ndev->max_dpm_level);
117
ndev->curr_tops = NPU4_DPM_TOPS(ndev, dpm_level);
118
119
XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n",
120
ndev->npuclk_freq, ndev->hclk_freq);
121
122
return 0;
123
}
124
125
int aie2_smu_init(struct amdxdna_dev_hdl *ndev)
126
{
127
int ret;
128
129
/*
130
* Failing to set power off indicates an unrecoverable hardware or
131
* firmware error.
132
*/
133
ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_OFF, 0, NULL);
134
if (ret) {
135
XDNA_ERR(ndev->xdna, "Access power failed, ret %d", ret);
136
return ret;
137
}
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
158