Linux Audio

Check our new training course

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