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