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