xref: /openbmc/linux/sound/soc/intel/atom/sst/sst_loader.c (revision 29c37341)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  sst_dsp.c - Intel SST Driver for audio engine
4  *
5  *  Copyright (C) 2008-14	Intel Corp
6  *  Authors:	Vinod Koul <vinod.koul@intel.com>
7  *		Harsha Priya <priya.harsha@intel.com>
8  *		Dharageswari R <dharageswari.r@intel.com>
9  *		KP Jeeja <jeeja.kp@intel.com>
10  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11  *
12  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13  *
14  *  This file contains all dsp controlling functions like firmware download,
15  * setting/resetting dsp cores, etc
16  */
17 #include <linux/pci.h>
18 #include <linux/delay.h>
19 #include <linux/fs.h>
20 #include <linux/sched.h>
21 #include <linux/firmware.h>
22 #include <linux/dmaengine.h>
23 #include <linux/pm_runtime.h>
24 #include <linux/pm_qos.h>
25 #include <sound/core.h>
26 #include <sound/pcm.h>
27 #include <sound/soc.h>
28 #include <sound/compress_driver.h>
29 #include <asm/platform_sst_audio.h>
30 #include "../sst-mfld-platform.h"
31 #include "sst.h"
32 #include "../../common/sst-dsp.h"
33 
34 void memcpy32_toio(void __iomem *dst, const void *src, int count)
35 {
36 	/* __iowrite32_copy uses 32-bit count values so divide by 4 for
37 	 * right count in words
38 	 */
39 	__iowrite32_copy(dst, src, count / 4);
40 }
41 
42 void memcpy32_fromio(void *dst, const void __iomem *src, int count)
43 {
44 	/* __ioread32_copy uses 32-bit count values so divide by 4 for
45 	 * right count in words
46 	 */
47 	__ioread32_copy(dst, src, count / 4);
48 }
49 
50 /**
51  * intel_sst_reset_dsp_mrfld - Resetting SST DSP
52  * @sst_drv_ctx: intel_sst_drv context pointer
53  *
54  * This resets DSP in case of MRFLD platfroms
55  */
56 int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx)
57 {
58 	union config_status_reg_mrfld csr;
59 
60 	dev_dbg(sst_drv_ctx->dev, "sst: Resetting the DSP in mrfld\n");
61 	csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
62 
63 	dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
64 
65 	csr.full |= 0x7;
66 	sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
67 	csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
68 
69 	dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
70 
71 	csr.full &= ~(0x1);
72 	sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
73 
74 	csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
75 	dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
76 	return 0;
77 }
78 
79 /**
80  * sst_start_merrifield - Start the SST DSP processor
81  * @sst_drv_ctx: intel_sst_drv context pointer
82  *
83  * This starts the DSP in MERRIFIELD platfroms
84  */
85 int sst_start_mrfld(struct intel_sst_drv *sst_drv_ctx)
86 {
87 	union config_status_reg_mrfld csr;
88 
89 	dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP in mrfld LALALALA\n");
90 	csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
91 	dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
92 
93 	csr.full |= 0x7;
94 	sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
95 
96 	csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
97 	dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
98 
99 	csr.part.xt_snoop = 1;
100 	csr.full &= ~(0x5);
101 	sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
102 
103 	csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
104 	dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP_merrifield:%llx\n",
105 			csr.full);
106 	return 0;
107 }
108 
109 static int sst_validate_fw_image(struct intel_sst_drv *ctx, unsigned long size,
110 		struct fw_module_header **module, u32 *num_modules)
111 {
112 	struct sst_fw_header *header;
113 	const void *sst_fw_in_mem = ctx->fw_in_mem;
114 
115 	dev_dbg(ctx->dev, "Enter\n");
116 
117 	/* Read the header information from the data pointer */
118 	header = (struct sst_fw_header *)sst_fw_in_mem;
119 	dev_dbg(ctx->dev,
120 		"header sign=%s size=%x modules=%x fmt=%x size=%zx\n",
121 		header->signature, header->file_size, header->modules,
122 		header->file_format, sizeof(*header));
123 
124 	/* verify FW */
125 	if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) ||
126 		(size != header->file_size + sizeof(*header))) {
127 		/* Invalid FW signature */
128 		dev_err(ctx->dev, "InvalidFW sign/filesize mismatch\n");
129 		return -EINVAL;
130 	}
131 	*num_modules = header->modules;
132 	*module = (void *)sst_fw_in_mem + sizeof(*header);
133 
134 	return 0;
135 }
136 
137 /*
138  * sst_fill_memcpy_list - Fill the memcpy list
139  *
140  * @memcpy_list: List to be filled
141  * @destn: Destination addr to be filled in the list
142  * @src: Source addr to be filled in the list
143  * @size: Size to be filled in the list
144  *
145  * Adds the node to the list after required fields
146  * are populated in the node
147  */
148 static int sst_fill_memcpy_list(struct list_head *memcpy_list,
149 			void *destn, const void *src, u32 size, bool is_io)
150 {
151 	struct sst_memcpy_list *listnode;
152 
153 	listnode = kzalloc(sizeof(*listnode), GFP_KERNEL);
154 	if (listnode == NULL)
155 		return -ENOMEM;
156 	listnode->dstn = destn;
157 	listnode->src = src;
158 	listnode->size = size;
159 	listnode->is_io = is_io;
160 	list_add_tail(&listnode->memcpylist, memcpy_list);
161 
162 	return 0;
163 }
164 
165 /**
166  * sst_parse_module_memcpy - Parse audio FW modules and populate the memcpy list
167  *
168  * @sst_drv_ctx		: driver context
169  * @module		: FW module header
170  * @memcpy_list	: Pointer to the list to be populated
171  * Create the memcpy list as the number of block to be copied
172  * returns error or 0 if module sizes are proper
173  */
174 static int sst_parse_module_memcpy(struct intel_sst_drv *sst_drv_ctx,
175 		struct fw_module_header *module, struct list_head *memcpy_list)
176 {
177 	struct fw_block_info *block;
178 	u32 count;
179 	int ret_val = 0;
180 	void __iomem *ram_iomem;
181 
182 	dev_dbg(sst_drv_ctx->dev, "module sign %s size %x blocks %x type %x\n",
183 			module->signature, module->mod_size,
184 			module->blocks, module->type);
185 	dev_dbg(sst_drv_ctx->dev, "module entrypoint 0x%x\n", module->entry_point);
186 
187 	block = (void *)module + sizeof(*module);
188 
189 	for (count = 0; count < module->blocks; count++) {
190 		if (block->size <= 0) {
191 			dev_err(sst_drv_ctx->dev, "block size invalid\n");
192 			return -EINVAL;
193 		}
194 		switch (block->type) {
195 		case SST_IRAM:
196 			ram_iomem = sst_drv_ctx->iram;
197 			break;
198 		case SST_DRAM:
199 			ram_iomem = sst_drv_ctx->dram;
200 			break;
201 		case SST_DDR:
202 			ram_iomem = sst_drv_ctx->ddr;
203 			break;
204 		case SST_CUSTOM_INFO:
205 			block = (void *)block + sizeof(*block) + block->size;
206 			continue;
207 		default:
208 			dev_err(sst_drv_ctx->dev, "wrong ram type0x%x in block0x%x\n",
209 					block->type, count);
210 			return -EINVAL;
211 		}
212 
213 		ret_val = sst_fill_memcpy_list(memcpy_list,
214 				ram_iomem + block->ram_offset,
215 				(void *)block + sizeof(*block), block->size, 1);
216 		if (ret_val)
217 			return ret_val;
218 
219 		block = (void *)block + sizeof(*block) + block->size;
220 	}
221 	return 0;
222 }
223 
224 /**
225  * sst_parse_fw_memcpy - parse the firmware image & populate the list for memcpy
226  *
227  * @ctx			: pointer to drv context
228  * @size		: size of the firmware
229  * @fw_list		: pointer to list_head to be populated
230  * This function parses the FW image and saves the parsed image in the list
231  * for memcpy
232  */
233 static int sst_parse_fw_memcpy(struct intel_sst_drv *ctx, unsigned long size,
234 				struct list_head *fw_list)
235 {
236 	struct fw_module_header *module;
237 	u32 count, num_modules;
238 	int ret_val;
239 
240 	ret_val = sst_validate_fw_image(ctx, size, &module, &num_modules);
241 	if (ret_val)
242 		return ret_val;
243 
244 	for (count = 0; count < num_modules; count++) {
245 		ret_val = sst_parse_module_memcpy(ctx, module, fw_list);
246 		if (ret_val)
247 			return ret_val;
248 		module = (void *)module + sizeof(*module) + module->mod_size;
249 	}
250 
251 	return 0;
252 }
253 
254 /**
255  * sst_do_memcpy - function initiates the memcpy
256  *
257  * @memcpy_list: Pter to memcpy list on which the memcpy needs to be initiated
258  *
259  * Triggers the memcpy
260  */
261 static void sst_do_memcpy(struct list_head *memcpy_list)
262 {
263 	struct sst_memcpy_list *listnode;
264 
265 	list_for_each_entry(listnode, memcpy_list, memcpylist) {
266 		if (listnode->is_io)
267 			memcpy32_toio((void __iomem *)listnode->dstn,
268 					listnode->src, listnode->size);
269 		else
270 			memcpy(listnode->dstn, listnode->src, listnode->size);
271 	}
272 }
273 
274 void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx)
275 {
276 	struct sst_memcpy_list *listnode, *tmplistnode;
277 
278 	/* Free the list */
279 	list_for_each_entry_safe(listnode, tmplistnode,
280 				 &sst_drv_ctx->memcpy_list, memcpylist) {
281 		list_del(&listnode->memcpylist);
282 		kfree(listnode);
283 	}
284 }
285 
286 static int sst_cache_and_parse_fw(struct intel_sst_drv *sst,
287 		const struct firmware *fw)
288 {
289 	int retval = 0;
290 
291 	sst->fw_in_mem = kzalloc(fw->size, GFP_KERNEL);
292 	if (!sst->fw_in_mem) {
293 		retval = -ENOMEM;
294 		goto end_release;
295 	}
296 	dev_dbg(sst->dev, "copied fw to %p", sst->fw_in_mem);
297 	dev_dbg(sst->dev, "phys: %lx", (unsigned long)virt_to_phys(sst->fw_in_mem));
298 	memcpy(sst->fw_in_mem, fw->data, fw->size);
299 	retval = sst_parse_fw_memcpy(sst, fw->size, &sst->memcpy_list);
300 	if (retval) {
301 		dev_err(sst->dev, "Failed to parse fw\n");
302 		kfree(sst->fw_in_mem);
303 		sst->fw_in_mem = NULL;
304 	}
305 
306 end_release:
307 	release_firmware(fw);
308 	return retval;
309 
310 }
311 
312 void sst_firmware_load_cb(const struct firmware *fw, void *context)
313 {
314 	struct intel_sst_drv *ctx = context;
315 
316 	dev_dbg(ctx->dev, "Enter\n");
317 
318 	if (fw == NULL) {
319 		dev_err(ctx->dev, "request fw failed\n");
320 		return;
321 	}
322 
323 	mutex_lock(&ctx->sst_lock);
324 
325 	if (ctx->sst_state != SST_RESET ||
326 			ctx->fw_in_mem != NULL) {
327 		release_firmware(fw);
328 		mutex_unlock(&ctx->sst_lock);
329 		return;
330 	}
331 
332 	dev_dbg(ctx->dev, "Request Fw completed\n");
333 	sst_cache_and_parse_fw(ctx, fw);
334 	mutex_unlock(&ctx->sst_lock);
335 }
336 
337 /*
338  * sst_request_fw - requests audio fw from kernel and saves a copy
339  *
340  * This function requests the SST FW from the kernel, parses it and
341  * saves a copy in the driver context
342  */
343 static int sst_request_fw(struct intel_sst_drv *sst)
344 {
345 	int retval = 0;
346 	const struct firmware *fw;
347 
348 	retval = request_firmware(&fw, sst->firmware_name, sst->dev);
349 	if (retval) {
350 		dev_err(sst->dev, "request fw failed %d\n", retval);
351 		return retval;
352 	}
353 	if (fw == NULL) {
354 		dev_err(sst->dev, "fw is returning as null\n");
355 		return -EINVAL;
356 	}
357 	mutex_lock(&sst->sst_lock);
358 	retval = sst_cache_and_parse_fw(sst, fw);
359 	mutex_unlock(&sst->sst_lock);
360 
361 	return retval;
362 }
363 
364 /*
365  * Writing the DDR physical base to DCCM offset
366  * so that FW can use it to setup TLB
367  */
368 static void sst_dccm_config_write(void __iomem *dram_base,
369 		unsigned int ddr_base)
370 {
371 	void __iomem *addr;
372 	u32 bss_reset = 0;
373 
374 	addr = (void __iomem *)(dram_base + MRFLD_FW_DDR_BASE_OFFSET);
375 	memcpy32_toio(addr, (void *)&ddr_base, sizeof(u32));
376 	bss_reset |= (1 << MRFLD_FW_BSS_RESET_BIT);
377 	addr = (void __iomem *)(dram_base + MRFLD_FW_FEATURE_BASE_OFFSET);
378 	memcpy32_toio(addr, &bss_reset, sizeof(u32));
379 
380 }
381 
382 void sst_post_download_mrfld(struct intel_sst_drv *ctx)
383 {
384 	sst_dccm_config_write(ctx->dram, ctx->ddr_base);
385 	dev_dbg(ctx->dev, "config written to DCCM\n");
386 }
387 
388 /**
389  * sst_load_fw - function to load FW into DSP
390  * @sst_drv_ctx: intel_sst_drv context pointer
391  *
392  * Transfers the FW to DSP using dma/memcpy
393  */
394 int sst_load_fw(struct intel_sst_drv *sst_drv_ctx)
395 {
396 	int ret_val = 0;
397 	struct sst_block *block;
398 
399 	dev_dbg(sst_drv_ctx->dev, "sst_load_fw\n");
400 
401 	if (sst_drv_ctx->sst_state !=  SST_RESET ||
402 			sst_drv_ctx->sst_state == SST_SHUTDOWN)
403 		return -EAGAIN;
404 
405 	if (!sst_drv_ctx->fw_in_mem) {
406 		dev_dbg(sst_drv_ctx->dev, "sst: FW not in memory retry to download\n");
407 		ret_val = sst_request_fw(sst_drv_ctx);
408 		if (ret_val)
409 			return ret_val;
410 	}
411 
412 	block = sst_create_block(sst_drv_ctx, 0, FW_DWNL_ID);
413 	if (block == NULL)
414 		return -ENOMEM;
415 
416 	/* Prevent C-states beyond C6 */
417 	cpu_latency_qos_update_request(sst_drv_ctx->qos, 0);
418 
419 	sst_drv_ctx->sst_state = SST_FW_LOADING;
420 
421 	ret_val = sst_drv_ctx->ops->reset(sst_drv_ctx);
422 	if (ret_val)
423 		goto restore;
424 
425 	sst_do_memcpy(&sst_drv_ctx->memcpy_list);
426 
427 	/* Write the DRAM/DCCM config before enabling FW */
428 	if (sst_drv_ctx->ops->post_download)
429 		sst_drv_ctx->ops->post_download(sst_drv_ctx);
430 
431 	/* bring sst out of reset */
432 	ret_val = sst_drv_ctx->ops->start(sst_drv_ctx);
433 	if (ret_val)
434 		goto restore;
435 
436 	ret_val = sst_wait_timeout(sst_drv_ctx, block);
437 	if (ret_val) {
438 		dev_err(sst_drv_ctx->dev, "fw download failed %d\n" , ret_val);
439 		/* FW download failed due to timeout */
440 		ret_val = -EBUSY;
441 
442 	}
443 
444 
445 restore:
446 	/* Re-enable Deeper C-states beyond C6 */
447 	cpu_latency_qos_update_request(sst_drv_ctx->qos, PM_QOS_DEFAULT_VALUE);
448 	sst_free_block(sst_drv_ctx, block);
449 	dev_dbg(sst_drv_ctx->dev, "fw load successful!!!\n");
450 
451 	if (sst_drv_ctx->ops->restore_dsp_context)
452 		sst_drv_ctx->ops->restore_dsp_context();
453 	sst_drv_ctx->sst_state = SST_FW_RUNNING;
454 	return ret_val;
455 }
456 
457