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
42void 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
50void 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 */
63int 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 */
91int 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
115static 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 */
154static 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 */
180static 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 */
239static 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 */
267static 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
280void 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
294static 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
314end_release:
315	release_firmware(fw);
316	return retval;
317
318}
319
320void 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 */
351static 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 */
376static 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
390void 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 */
400int 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
452restore:
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