xref: /linux/drivers/accel/amdxdna/aie_smu.c (revision 0eaed89c18aeedf0898baf2dbf5ff027c6795152)
1*81673325SDavid Zhang // SPDX-License-Identifier: GPL-2.0
2*81673325SDavid Zhang /*
3*81673325SDavid Zhang  * Copyright (C) 2026, Advanced Micro Devices, Inc.
4*81673325SDavid Zhang  */
5*81673325SDavid Zhang 
6*81673325SDavid Zhang #include "drm/amdxdna_accel.h"
7*81673325SDavid Zhang #include <drm/drm_device.h>
8*81673325SDavid Zhang #include <drm/drm_managed.h>
9*81673325SDavid Zhang #include <drm/drm_print.h>
10*81673325SDavid Zhang #include <drm/gpu_scheduler.h>
11*81673325SDavid Zhang #include <linux/iopoll.h>
12*81673325SDavid Zhang 
13*81673325SDavid Zhang #include "aie.h"
14*81673325SDavid Zhang 
15*81673325SDavid Zhang #define SMU_RESULT_OK   1
16*81673325SDavid Zhang 
17*81673325SDavid Zhang /* SMU commands */
18*81673325SDavid Zhang #define AIE_SMU_POWER_ON                0x3
19*81673325SDavid Zhang #define AIE_SMU_POWER_OFF               0x4
20*81673325SDavid Zhang #define AIE_SMU_SET_MPNPUCLK_FREQ       0x5
21*81673325SDavid Zhang #define AIE_SMU_SET_HCLK_FREQ           0x6
22*81673325SDavid Zhang #define AIE_SMU_SET_SOFT_DPMLEVEL       0x7
23*81673325SDavid Zhang #define AIE_SMU_SET_HARD_DPMLEVEL       0x8
24*81673325SDavid Zhang 
25*81673325SDavid Zhang #define SMU_REG(s, reg) ((s)->smu_regs[reg])
26*81673325SDavid Zhang 
27*81673325SDavid Zhang struct smu_device {
28*81673325SDavid Zhang 	struct drm_device	*ddev;
29*81673325SDavid Zhang 	struct smu_config	conf;
30*81673325SDavid Zhang 	void __iomem		*smu_regs[SMU_MAX_REGS];
31*81673325SDavid Zhang };
32*81673325SDavid Zhang 
33*81673325SDavid Zhang static int aie_smu_exec(struct smu_device *smu, u32 reg_cmd, u32 reg_arg, u32 *out)
34*81673325SDavid Zhang {
35*81673325SDavid Zhang 	u32 resp;
36*81673325SDavid Zhang 	int ret;
37*81673325SDavid Zhang 
38*81673325SDavid Zhang 	writel(0, SMU_REG(smu, SMU_RESP_REG));
39*81673325SDavid Zhang 	writel(reg_arg, SMU_REG(smu, SMU_ARG_REG));
40*81673325SDavid Zhang 	writel(reg_cmd, SMU_REG(smu, SMU_CMD_REG));
41*81673325SDavid Zhang 
42*81673325SDavid Zhang 	/* Clear and set SMU_INTR_REG to kick off */
43*81673325SDavid Zhang 	writel(0, SMU_REG(smu, SMU_INTR_REG));
44*81673325SDavid Zhang 	writel(1, SMU_REG(smu, SMU_INTR_REG));
45*81673325SDavid Zhang 
46*81673325SDavid Zhang 	ret = readx_poll_timeout(readl, SMU_REG(smu, SMU_RESP_REG), resp,
47*81673325SDavid Zhang 				 resp, AIE_INTERVAL, AIE_TIMEOUT);
48*81673325SDavid Zhang 	if (ret) {
49*81673325SDavid Zhang 		drm_err(smu->ddev, "smu cmd %d timed out", reg_cmd);
50*81673325SDavid Zhang 		return ret;
51*81673325SDavid Zhang 	}
52*81673325SDavid Zhang 
53*81673325SDavid Zhang 	if (out)
54*81673325SDavid Zhang 		*out = readl(SMU_REG(smu, SMU_OUT_REG));
55*81673325SDavid Zhang 
56*81673325SDavid Zhang 	if (resp != SMU_RESULT_OK) {
57*81673325SDavid Zhang 		drm_err(smu->ddev, "smu cmd %d failed, 0x%x", reg_cmd, resp);
58*81673325SDavid Zhang 		return -EINVAL;
59*81673325SDavid Zhang 	}
60*81673325SDavid Zhang 
61*81673325SDavid Zhang 	return 0;
62*81673325SDavid Zhang }
63*81673325SDavid Zhang 
64*81673325SDavid Zhang int aie_smu_init(struct smu_device *smu)
65*81673325SDavid Zhang {
66*81673325SDavid Zhang 	int ret;
67*81673325SDavid Zhang 
68*81673325SDavid Zhang 	/*
69*81673325SDavid Zhang 	 * Failing to set power off indicates an unrecoverable hardware or
70*81673325SDavid Zhang 	 * firmware error.
71*81673325SDavid Zhang 	 */
72*81673325SDavid Zhang 	ret = aie_smu_exec(smu, AIE_SMU_POWER_OFF, 0, NULL);
73*81673325SDavid Zhang 	if (ret) {
74*81673325SDavid Zhang 		drm_err(smu->ddev, "Access power failed, ret %d", ret);
75*81673325SDavid Zhang 		return ret;
76*81673325SDavid Zhang 	}
77*81673325SDavid Zhang 
78*81673325SDavid Zhang 	ret = aie_smu_exec(smu, AIE_SMU_POWER_ON, 0, NULL);
79*81673325SDavid Zhang 	if (ret) {
80*81673325SDavid Zhang 		drm_err(smu->ddev, "Power on failed, ret %d", ret);
81*81673325SDavid Zhang 		return ret;
82*81673325SDavid Zhang 	}
83*81673325SDavid Zhang 
84*81673325SDavid Zhang 	return 0;
85*81673325SDavid Zhang }
86*81673325SDavid Zhang 
87*81673325SDavid Zhang void aie_smu_fini(struct smu_device *smu)
88*81673325SDavid Zhang {
89*81673325SDavid Zhang 	int ret;
90*81673325SDavid Zhang 
91*81673325SDavid Zhang 	ret = aie_smu_exec(smu, AIE_SMU_POWER_OFF, 0, NULL);
92*81673325SDavid Zhang 	if (ret)
93*81673325SDavid Zhang 		drm_err(smu->ddev, "Power off failed, ret %d", ret);
94*81673325SDavid Zhang }
95*81673325SDavid Zhang 
96*81673325SDavid Zhang int aie_smu_set_clocks(struct smu_device *smu, u32 *npuclk, u32 *hclk)
97*81673325SDavid Zhang {
98*81673325SDavid Zhang 	int ret;
99*81673325SDavid Zhang 
100*81673325SDavid Zhang 	if (npuclk) {
101*81673325SDavid Zhang 		ret = aie_smu_exec(smu, AIE_SMU_SET_MPNPUCLK_FREQ, *npuclk, npuclk);
102*81673325SDavid Zhang 		if (ret) {
103*81673325SDavid Zhang 			drm_err(smu->ddev, "Set mpnpu clock to %d failed, ret %d", *npuclk, ret);
104*81673325SDavid Zhang 			return ret;
105*81673325SDavid Zhang 		}
106*81673325SDavid Zhang 	}
107*81673325SDavid Zhang 
108*81673325SDavid Zhang 	if (hclk) {
109*81673325SDavid Zhang 		ret = aie_smu_exec(smu, AIE_SMU_SET_HCLK_FREQ, *hclk, hclk);
110*81673325SDavid Zhang 		if (ret) {
111*81673325SDavid Zhang 			drm_err(smu->ddev, "Set hclock to %d failed, ret %d",
112*81673325SDavid Zhang 				*hclk, ret);
113*81673325SDavid Zhang 			return ret;
114*81673325SDavid Zhang 		}
115*81673325SDavid Zhang 	}
116*81673325SDavid Zhang 
117*81673325SDavid Zhang 	return 0;
118*81673325SDavid Zhang }
119*81673325SDavid Zhang 
120*81673325SDavid Zhang int aie_smu_set_dpm(struct smu_device *smu, u32 dpm_level)
121*81673325SDavid Zhang {
122*81673325SDavid Zhang 	int ret;
123*81673325SDavid Zhang 
124*81673325SDavid Zhang 	ret = aie_smu_exec(smu, AIE_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL);
125*81673325SDavid Zhang 	if (ret) {
126*81673325SDavid Zhang 		drm_err(smu->ddev, "Set hard dpm level %d failed, ret %d",
127*81673325SDavid Zhang 			dpm_level, ret);
128*81673325SDavid Zhang 		return ret;
129*81673325SDavid Zhang 	}
130*81673325SDavid Zhang 
131*81673325SDavid Zhang 	ret = aie_smu_exec(smu, AIE_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL);
132*81673325SDavid Zhang 	if (ret) {
133*81673325SDavid Zhang 		drm_err(smu->ddev, "Set soft dpm level %d failed, ret %d",
134*81673325SDavid Zhang 			dpm_level, ret);
135*81673325SDavid Zhang 		return ret;
136*81673325SDavid Zhang 	}
137*81673325SDavid Zhang 
138*81673325SDavid Zhang 	return 0;
139*81673325SDavid Zhang }
140*81673325SDavid Zhang 
141*81673325SDavid Zhang struct smu_device *aiem_smu_create(struct drm_device *ddev, struct smu_config *conf)
142*81673325SDavid Zhang {
143*81673325SDavid Zhang 	struct smu_device *smu;
144*81673325SDavid Zhang 
145*81673325SDavid Zhang 	smu = drmm_kzalloc(ddev, sizeof(*smu), GFP_KERNEL);
146*81673325SDavid Zhang 	if (!smu)
147*81673325SDavid Zhang 		return NULL;
148*81673325SDavid Zhang 
149*81673325SDavid Zhang 	smu->ddev = ddev;
150*81673325SDavid Zhang 	memcpy(smu->smu_regs, conf->smu_regs, sizeof(smu->smu_regs));
151*81673325SDavid Zhang 
152*81673325SDavid Zhang 	return smu;
153*81673325SDavid Zhang }
154