xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_mes_v10_1.c (revision 0caae2224fa2e443b0194fe793325afc8e00f306)
1 /*	$NetBSD: amdgpu_mes_v10_1.c,v 1.3 2021/12/19 12:02:39 riastradh Exp $	*/
2 
3 /*
4  * Copyright 2019 Advanced Micro Devices, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  *
24  */
25 
26 #include <sys/cdefs.h>
27 __KERNEL_RCSID(0, "$NetBSD: amdgpu_mes_v10_1.c,v 1.3 2021/12/19 12:02:39 riastradh Exp $");
28 
29 #include <linux/firmware.h>
30 #include <linux/module.h>
31 #include "amdgpu.h"
32 #include "soc15_common.h"
33 #include "nv.h"
34 #include "gc/gc_10_1_0_offset.h"
35 #include "gc/gc_10_1_0_sh_mask.h"
36 
37 MODULE_FIRMWARE("amdgpu/navi10_mes.bin");
38 
mes_v10_1_add_hw_queue(struct amdgpu_mes * mes,struct mes_add_queue_input * input)39 static int mes_v10_1_add_hw_queue(struct amdgpu_mes *mes,
40 				  struct mes_add_queue_input *input)
41 {
42 	return 0;
43 }
44 
mes_v10_1_remove_hw_queue(struct amdgpu_mes * mes,struct mes_remove_queue_input * input)45 static int mes_v10_1_remove_hw_queue(struct amdgpu_mes *mes,
46 				     struct mes_remove_queue_input *input)
47 {
48 	return 0;
49 }
50 
mes_v10_1_suspend_gang(struct amdgpu_mes * mes,struct mes_suspend_gang_input * input)51 static int mes_v10_1_suspend_gang(struct amdgpu_mes *mes,
52 				  struct mes_suspend_gang_input *input)
53 {
54 	return 0;
55 }
56 
mes_v10_1_resume_gang(struct amdgpu_mes * mes,struct mes_resume_gang_input * input)57 static int mes_v10_1_resume_gang(struct amdgpu_mes *mes,
58 				 struct mes_resume_gang_input *input)
59 {
60 	return 0;
61 }
62 
63 static const struct amdgpu_mes_funcs mes_v10_1_funcs __unused = {
64 	.add_hw_queue = mes_v10_1_add_hw_queue,
65 	.remove_hw_queue = mes_v10_1_remove_hw_queue,
66 	.suspend_gang = mes_v10_1_suspend_gang,
67 	.resume_gang = mes_v10_1_resume_gang,
68 };
69 
mes_v10_1_init_microcode(struct amdgpu_device * adev)70 static int mes_v10_1_init_microcode(struct amdgpu_device *adev)
71 {
72 	const char *chip_name;
73 	char fw_name[30];
74 	int err;
75 	const struct mes_firmware_header_v1_0 *mes_hdr;
76 
77 	switch (adev->asic_type) {
78 	case CHIP_NAVI10:
79 		chip_name = "navi10";
80 		break;
81 	default:
82 		BUG();
83 	}
84 
85 	snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mes.bin", chip_name);
86 	err = request_firmware(&adev->mes.fw, fw_name, adev->dev);
87 	if (err)
88 		return err;
89 
90 	err = amdgpu_ucode_validate(adev->mes.fw);
91 	if (err) {
92 		release_firmware(adev->mes.fw);
93 		adev->mes.fw = NULL;
94 		return err;
95 	}
96 
97 	mes_hdr = (const struct mes_firmware_header_v1_0 *)adev->mes.fw->data;
98 	adev->mes.ucode_fw_version = le32_to_cpu(mes_hdr->mes_ucode_version);
99 	adev->mes.ucode_fw_version =
100 		le32_to_cpu(mes_hdr->mes_ucode_data_version);
101 	adev->mes.uc_start_addr =
102 		le32_to_cpu(mes_hdr->mes_uc_start_addr_lo) |
103 		((uint64_t)(le32_to_cpu(mes_hdr->mes_uc_start_addr_hi)) << 32);
104 	adev->mes.data_start_addr =
105 		le32_to_cpu(mes_hdr->mes_data_start_addr_lo) |
106 		((uint64_t)(le32_to_cpu(mes_hdr->mes_data_start_addr_hi)) << 32);
107 
108 	return 0;
109 }
110 
mes_v10_1_free_microcode(struct amdgpu_device * adev)111 static void mes_v10_1_free_microcode(struct amdgpu_device *adev)
112 {
113 	release_firmware(adev->mes.fw);
114 	adev->mes.fw = NULL;
115 }
116 
mes_v10_1_allocate_ucode_buffer(struct amdgpu_device * adev)117 static int mes_v10_1_allocate_ucode_buffer(struct amdgpu_device *adev)
118 {
119 	int r;
120 	const struct mes_firmware_header_v1_0 *mes_hdr;
121 	const __le32 *fw_data;
122 	unsigned fw_size;
123 
124 	mes_hdr = (const struct mes_firmware_header_v1_0 *)
125 		adev->mes.fw->data;
126 
127 	fw_data = (const __le32 *)(adev->mes.fw->data +
128 		   le32_to_cpu(mes_hdr->mes_ucode_offset_bytes));
129 	fw_size = le32_to_cpu(mes_hdr->mes_ucode_size_bytes);
130 
131 	r = amdgpu_bo_create_reserved(adev, fw_size,
132 				      PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT,
133 				      &adev->mes.ucode_fw_obj,
134 				      &adev->mes.ucode_fw_gpu_addr,
135 				      (void **)&adev->mes.ucode_fw_ptr);
136 	if (r) {
137 		dev_err(adev->dev, "(%d) failed to create mes fw bo\n", r);
138 		return r;
139 	}
140 
141 	memcpy(adev->mes.ucode_fw_ptr, fw_data, fw_size);
142 
143 	amdgpu_bo_kunmap(adev->mes.ucode_fw_obj);
144 	amdgpu_bo_unreserve(adev->mes.ucode_fw_obj);
145 
146 	return 0;
147 }
148 
mes_v10_1_allocate_ucode_data_buffer(struct amdgpu_device * adev)149 static int mes_v10_1_allocate_ucode_data_buffer(struct amdgpu_device *adev)
150 {
151 	int r;
152 	const struct mes_firmware_header_v1_0 *mes_hdr;
153 	const __le32 *fw_data;
154 	unsigned fw_size;
155 
156 	mes_hdr = (const struct mes_firmware_header_v1_0 *)
157 		adev->mes.fw->data;
158 
159 	fw_data = (const __le32 *)(adev->mes.fw->data +
160 		   le32_to_cpu(mes_hdr->mes_ucode_data_offset_bytes));
161 	fw_size = le32_to_cpu(mes_hdr->mes_ucode_data_size_bytes);
162 
163 	r = amdgpu_bo_create_reserved(adev, fw_size,
164 				      64 * 1024, AMDGPU_GEM_DOMAIN_GTT,
165 				      &adev->mes.data_fw_obj,
166 				      &adev->mes.data_fw_gpu_addr,
167 				      (void **)&adev->mes.data_fw_ptr);
168 	if (r) {
169 		dev_err(adev->dev, "(%d) failed to create mes data fw bo\n", r);
170 		return r;
171 	}
172 
173 	memcpy(adev->mes.data_fw_ptr, fw_data, fw_size);
174 
175 	amdgpu_bo_kunmap(adev->mes.data_fw_obj);
176 	amdgpu_bo_unreserve(adev->mes.data_fw_obj);
177 
178 	return 0;
179 }
180 
mes_v10_1_free_ucode_buffers(struct amdgpu_device * adev)181 static void mes_v10_1_free_ucode_buffers(struct amdgpu_device *adev)
182 {
183 	amdgpu_bo_free_kernel(&adev->mes.data_fw_obj,
184 			      &adev->mes.data_fw_gpu_addr,
185 			      (void **)&adev->mes.data_fw_ptr);
186 
187 	amdgpu_bo_free_kernel(&adev->mes.ucode_fw_obj,
188 			      &adev->mes.ucode_fw_gpu_addr,
189 			      (void **)&adev->mes.ucode_fw_ptr);
190 }
191 
mes_v10_1_enable(struct amdgpu_device * adev,bool enable)192 static void mes_v10_1_enable(struct amdgpu_device *adev, bool enable)
193 {
194 	uint32_t data = 0;
195 
196 	if (enable) {
197 		data = RREG32_SOC15(GC, 0, mmCP_MES_CNTL);
198 		data = REG_SET_FIELD(data, CP_MES_CNTL, MES_PIPE0_RESET, 1);
199 		WREG32_SOC15(GC, 0, mmCP_MES_CNTL, data);
200 
201 		/* set ucode start address */
202 		WREG32_SOC15(GC, 0, mmCP_MES_PRGRM_CNTR_START,
203 			     (uint32_t)(adev->mes.uc_start_addr) >> 2);
204 
205 		/* clear BYPASS_UNCACHED to avoid hangs after interrupt. */
206 		data = RREG32_SOC15(GC, 0, mmCP_MES_DC_OP_CNTL);
207 		data = REG_SET_FIELD(data, CP_MES_DC_OP_CNTL,
208 				     BYPASS_UNCACHED, 0);
209 		WREG32_SOC15(GC, 0, mmCP_MES_DC_OP_CNTL, data);
210 
211 		/* unhalt MES and activate pipe0 */
212 		data = REG_SET_FIELD(0, CP_MES_CNTL, MES_PIPE0_ACTIVE, 1);
213 		WREG32_SOC15(GC, 0, mmCP_MES_CNTL, data);
214 	} else {
215 		data = RREG32_SOC15(GC, 0, mmCP_MES_CNTL);
216 		data = REG_SET_FIELD(data, CP_MES_CNTL, MES_PIPE0_ACTIVE, 0);
217 		data = REG_SET_FIELD(data, CP_MES_CNTL,
218 				     MES_INVALIDATE_ICACHE, 1);
219 		data = REG_SET_FIELD(data, CP_MES_CNTL, MES_PIPE0_RESET, 1);
220 		data = REG_SET_FIELD(data, CP_MES_CNTL, MES_HALT, 1);
221 		WREG32_SOC15(GC, 0, mmCP_MES_CNTL, data);
222 	}
223 }
224 
225 /* This function is for backdoor MES firmware */
mes_v10_1_load_microcode(struct amdgpu_device * adev)226 static int mes_v10_1_load_microcode(struct amdgpu_device *adev)
227 {
228 	int r;
229 	uint32_t data;
230 
231 	if (!adev->mes.fw)
232 		return -EINVAL;
233 
234 	r = mes_v10_1_allocate_ucode_buffer(adev);
235 	if (r)
236 		return r;
237 
238 	r = mes_v10_1_allocate_ucode_data_buffer(adev);
239 	if (r) {
240 		mes_v10_1_free_ucode_buffers(adev);
241 		return r;
242 	}
243 
244 	mes_v10_1_enable(adev, false);
245 
246 	WREG32_SOC15(GC, 0, mmCP_MES_IC_BASE_CNTL, 0);
247 
248 	mutex_lock(&adev->srbm_mutex);
249 	/* me=3, pipe=0, queue=0 */
250 	nv_grbm_select(adev, 3, 0, 0, 0);
251 
252 	/* set ucode start address */
253 	WREG32_SOC15(GC, 0, mmCP_MES_PRGRM_CNTR_START,
254 		     (uint32_t)(adev->mes.uc_start_addr) >> 2);
255 
256 	/* set ucode fimrware address */
257 	WREG32_SOC15(GC, 0, mmCP_MES_IC_BASE_LO,
258 		     lower_32_bits(adev->mes.ucode_fw_gpu_addr));
259 	WREG32_SOC15(GC, 0, mmCP_MES_IC_BASE_HI,
260 		     upper_32_bits(adev->mes.ucode_fw_gpu_addr));
261 
262 	/* set ucode instruction cache boundary to 2M-1 */
263 	WREG32_SOC15(GC, 0, mmCP_MES_MIBOUND_LO, 0x1FFFFF);
264 
265 	/* set ucode data firmware address */
266 	WREG32_SOC15(GC, 0, mmCP_MES_MDBASE_LO,
267 		     lower_32_bits(adev->mes.data_fw_gpu_addr));
268 	WREG32_SOC15(GC, 0, mmCP_MES_MDBASE_HI,
269 		     upper_32_bits(adev->mes.data_fw_gpu_addr));
270 
271 	/* Set 0x3FFFF (256K-1) to CP_MES_MDBOUND_LO */
272 	WREG32_SOC15(GC, 0, mmCP_MES_MDBOUND_LO, 0x3FFFF);
273 
274 	/* invalidate ICACHE */
275 	data = RREG32_SOC15(GC, 0, mmCP_MES_IC_OP_CNTL);
276 	data = REG_SET_FIELD(data, CP_MES_IC_OP_CNTL, PRIME_ICACHE, 0);
277 	data = REG_SET_FIELD(data, CP_MES_IC_OP_CNTL, INVALIDATE_CACHE, 1);
278 	WREG32_SOC15(GC, 0, mmCP_MES_IC_OP_CNTL, data);
279 
280 	/* prime the ICACHE. */
281 	data = RREG32_SOC15(GC, 0, mmCP_MES_IC_OP_CNTL);
282 	data = REG_SET_FIELD(data, CP_MES_IC_OP_CNTL, PRIME_ICACHE, 1);
283 	WREG32_SOC15(GC, 0, mmCP_MES_IC_OP_CNTL, data);
284 
285 	nv_grbm_select(adev, 0, 0, 0, 0);
286 	mutex_unlock(&adev->srbm_mutex);
287 
288 	return 0;
289 }
290 
mes_v10_1_sw_init(void * handle)291 static int mes_v10_1_sw_init(void *handle)
292 {
293 	int r;
294 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
295 
296 	r = mes_v10_1_init_microcode(adev);
297 	if (r)
298 		return r;
299 
300 	return 0;
301 }
302 
mes_v10_1_sw_fini(void * handle)303 static int mes_v10_1_sw_fini(void *handle)
304 {
305 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
306 
307 	mes_v10_1_free_microcode(adev);
308 
309 	return 0;
310 }
311 
mes_v10_1_hw_init(void * handle)312 static int mes_v10_1_hw_init(void *handle)
313 {
314 	int r;
315 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
316 
317 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) {
318 		r = mes_v10_1_load_microcode(adev);
319 		if (r) {
320 			DRM_ERROR("failed to MES fw, r=%d\n", r);
321 			return r;
322 		}
323 	} else {
324 		DRM_ERROR("only support direct fw loading on MES\n");
325 		return -EINVAL;
326 	}
327 
328 	mes_v10_1_enable(adev, true);
329 
330 	return 0;
331 }
332 
mes_v10_1_hw_fini(void * handle)333 static int mes_v10_1_hw_fini(void *handle)
334 {
335 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
336 
337 	mes_v10_1_enable(adev, false);
338 
339 	if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT)
340 		mes_v10_1_free_ucode_buffers(adev);
341 
342 	return 0;
343 }
344 
mes_v10_1_suspend(void * handle)345 static int mes_v10_1_suspend(void *handle)
346 {
347 	return 0;
348 }
349 
mes_v10_1_resume(void * handle)350 static int mes_v10_1_resume(void *handle)
351 {
352 	return 0;
353 }
354 
355 static const struct amd_ip_funcs mes_v10_1_ip_funcs = {
356 	.name = "mes_v10_1",
357 	.sw_init = mes_v10_1_sw_init,
358 	.sw_fini = mes_v10_1_sw_fini,
359 	.hw_init = mes_v10_1_hw_init,
360 	.hw_fini = mes_v10_1_hw_fini,
361 	.suspend = mes_v10_1_suspend,
362 	.resume = mes_v10_1_resume,
363 };
364 
365 const struct amdgpu_ip_block_version mes_v10_1_ip_block = {
366 	.type = AMD_IP_BLOCK_TYPE_MES,
367 	.major = 10,
368 	.minor = 1,
369 	.rev = 0,
370 	.funcs = &mes_v10_1_ip_funcs,
371 };
372