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