xref: /linux/drivers/accel/amdxdna/aie_psp.c (revision 0eaed89c18aeedf0898baf2dbf5ff027c6795152)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2026, Advanced Micro Devices, Inc.
4  */
5 
6 #include <drm/drm_device.h>
7 #include <drm/drm_managed.h>
8 #include <drm/drm_print.h>
9 #include <linux/bitfield.h>
10 #include <linux/iopoll.h>
11 #include <linux/slab.h>
12 
13 #include "aie.h"
14 
15 #define PSP_STATUS_READY	BIT(31)
16 
17 /* PSP commands */
18 #define PSP_VALIDATE		1
19 #define PSP_START		2
20 #define PSP_RELEASE_TMR		3
21 #define PSP_VALIDATE_CERT       4
22 
23 /* PSP special arguments */
24 #define PSP_START_COPY_FW	1
25 
26 /* PSP response error code */
27 #define PSP_ERROR_CANCEL	0xFFFF0002
28 #define PSP_ERROR_BAD_STATE	0xFFFF0007
29 
30 #define PSP_FW_ALIGN		0x10000
31 #define PSP_CFW_ALIGN           0x8000
32 #define PSP_POLL_INTERVAL	20000	/* us */
33 #define PSP_POLL_TIMEOUT	1000000	/* us */
34 
35 #define PSP_REG(p, reg) ((p)->conf.psp_regs[reg])
36 #define PSP_SET_CMD(psp, reg_vals, cmd, arg0, arg1, arg2)		\
37 ({									\
38 	u32 *_regs = reg_vals;						\
39 	u32 _cmd = cmd;							\
40 	_regs[0] = _cmd;						\
41 	_regs[1] = arg0;						\
42 	_regs[2] = arg1;						\
43 	_regs[3] = ((arg2) | ((_cmd) << 24)) & (psp)->conf.arg2_mask;	\
44 })
45 
46 struct psp_device {
47 	struct drm_device	*ddev;
48 	struct psp_config	conf;
49 	u32			fw_buf_sz;
50 	u64			fw_paddr;
51 	void			*fw_buffer;
52 	u32                     certfw_buf_sz;
53 	u64                     certfw_paddr;
54 	void                    *certfw_buffer;
55 };
56 
57 static int psp_exec(struct psp_device *psp, u32 *reg_vals)
58 {
59 	u32 resp_code;
60 	int ret, i;
61 	u32 ready;
62 
63 	/* Check for PSP ready before any write */
64 	ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_STATUS_REG), ready,
65 				 FIELD_GET(PSP_STATUS_READY, ready),
66 				 PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT);
67 	if (ret) {
68 		drm_err(psp->ddev, "PSP is not ready, ret 0x%x", ret);
69 		return ret;
70 	}
71 
72 	/* Write command and argument registers */
73 	for (i = 0; i < PSP_NUM_IN_REGS; i++)
74 		writel(reg_vals[i], PSP_REG(psp, i));
75 
76 	/* clear and set PSP INTR register to kick off */
77 	writel(0, PSP_REG(psp, PSP_INTR_REG));
78 	writel(psp->conf.notify_val, PSP_REG(psp, PSP_INTR_REG));
79 
80 	/* PSP should be busy. Wait for ready, so we know task is done. */
81 	ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_STATUS_REG), ready,
82 				 FIELD_GET(PSP_STATUS_READY, ready),
83 				 PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT);
84 	if (ret) {
85 		drm_err(psp->ddev, "PSP is not ready, ret 0x%x", ret);
86 		return ret;
87 	}
88 
89 	resp_code = readl(PSP_REG(psp, PSP_RESP_REG));
90 	if (resp_code) {
91 		drm_err(psp->ddev, "fw return error 0x%x", resp_code);
92 		return -EIO;
93 	}
94 
95 	return 0;
96 }
97 
98 int aie_psp_waitmode_poll(struct psp_device *psp)
99 {
100 	struct amdxdna_dev *xdna = to_xdna_dev(psp->ddev);
101 	u32 mode_reg;
102 	int ret;
103 
104 	ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_PWAITMODE_REG), mode_reg,
105 				 (mode_reg & 0x1) == 1,
106 				 PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT);
107 	if (ret)
108 		XDNA_ERR(xdna, "fw waitmode reg error, ret %d", ret);
109 
110 	return ret;
111 }
112 
113 void aie_psp_stop(struct psp_device *psp)
114 {
115 	u32 reg_vals[PSP_NUM_IN_REGS];
116 	int ret;
117 
118 	PSP_SET_CMD(psp, reg_vals, PSP_RELEASE_TMR, 0, 0, 0);
119 
120 	ret = psp_exec(psp, reg_vals);
121 	if (ret)
122 		drm_err(psp->ddev, "release tmr failed, ret %d", ret);
123 }
124 
125 static int psp_validate_fw(struct psp_device *psp, u8 cmd, u64 paddr, u32 buf_sz)
126 {
127 	u32 reg_vals[PSP_NUM_IN_REGS];
128 	int ret;
129 
130 	PSP_SET_CMD(psp, reg_vals, cmd, lower_32_bits(paddr),
131 		    upper_32_bits(paddr), buf_sz);
132 
133 	ret = psp_exec(psp, reg_vals);
134 	if (ret)
135 		drm_err(psp->ddev, "failed to validate fw, ret %d", ret);
136 
137 	return ret;
138 }
139 
140 static int psp_start(struct psp_device *psp)
141 {
142 	u32 reg_vals[PSP_NUM_IN_REGS];
143 	int ret;
144 
145 	PSP_SET_CMD(psp, reg_vals, PSP_START, PSP_START_COPY_FW, 0, 0);
146 
147 	ret = psp_exec(psp, reg_vals);
148 	if (ret)
149 		drm_err(psp->ddev, "failed to start fw, ret %d", ret);
150 
151 	return ret;
152 }
153 
154 int aie_psp_start(struct psp_device *psp)
155 {
156 	int ret;
157 
158 	ret = psp_validate_fw(psp, PSP_VALIDATE,
159 			      psp->fw_paddr, psp->fw_buf_sz);
160 	if (ret)
161 		return ret;
162 
163 	if (!psp->certfw_buf_sz)
164 		goto psp_start;
165 
166 	ret = psp_validate_fw(psp, PSP_VALIDATE_CERT,
167 			      psp->certfw_paddr, psp->certfw_buf_sz);
168 	if (ret)
169 		return ret;
170 psp_start:
171 	return psp_start(psp);
172 }
173 
174 /*
175  * PSP requires host physical address to load firmware.
176  * Allocate a buffer, obtain its physical address, align, and copy data in.
177  */
178 static void *psp_alloc_fw_buf(struct psp_device *psp, const void *fw_data,
179 			      u32 fw_size, u32 align, u32 *buf_sz,
180 			      u64 *paddr)
181 {
182 	u32 alloc_sz;
183 	void *buffer;
184 	u64 offset;
185 
186 	*buf_sz = ALIGN(fw_size, align);
187 	alloc_sz = *buf_sz + align;
188 
189 	buffer = drmm_kmalloc(psp->ddev, alloc_sz, GFP_KERNEL);
190 	if (!buffer)
191 		return NULL;
192 
193 	*paddr = virt_to_phys(buffer);
194 	offset = ALIGN(*paddr, align) - *paddr;
195 	*paddr += offset;
196 	memcpy(buffer + offset, fw_data, fw_size);
197 
198 	return buffer;
199 }
200 
201 struct psp_device *aiem_psp_create(struct drm_device *ddev, struct psp_config *conf)
202 {
203 	struct psp_device *psp;
204 
205 	psp = drmm_kzalloc(ddev, sizeof(*psp), GFP_KERNEL);
206 	if (!psp)
207 		return NULL;
208 
209 	psp->ddev = ddev;
210 	psp->fw_buffer = psp_alloc_fw_buf(psp, conf->fw_buf, conf->fw_size,
211 					  PSP_FW_ALIGN, &psp->fw_buf_sz,
212 					  &psp->fw_paddr);
213 	if (!psp->fw_buffer)
214 		return NULL;
215 
216 	if (!conf->certfw_size) {
217 		drm_dbg(ddev, "no cert fw");
218 		goto done;
219 	}
220 
221 	/* CERT firmware */
222 	psp->certfw_buffer = psp_alloc_fw_buf(psp, conf->certfw_buf,
223 					      conf->certfw_size, PSP_CFW_ALIGN,
224 					      &psp->certfw_buf_sz,
225 					      &psp->certfw_paddr);
226 	if (!psp->certfw_buffer) {
227 		drm_err(ddev, "no memory for cert fw buffer");
228 		return NULL;
229 	}
230 
231 done:
232 	memcpy(&psp->conf, conf, sizeof(psp->conf));
233 
234 	return psp;
235 }
236