blob: be2c42b815b7dd821c36ca01e0ecd4e3e26de0f7 [file] [log] [blame]
Subhransu S. Prustya750ba52015-07-10 22:18:44 +05301/*
2 * skl-sst.c - HDA DSP library functions for SKL platform
3 *
4 * Copyright (C) 2014-15, Intel Corporation.
5 * Author:Rafal Redzimski <rafal.f.redzimski@intel.com>
6 * Jeeja KP <jeeja.kp@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 */
18
19#include <linux/module.h>
20#include <linux/delay.h>
21#include <linux/device.h>
Jeeja KP53afce22015-11-13 19:22:09 +053022#include <linux/err.h>
Shreyas NC09305da2016-04-21 11:45:22 +053023#include <linux/uuid.h>
Subhransu S. Prustya750ba52015-07-10 22:18:44 +053024#include "../common/sst-dsp.h"
25#include "../common/sst-dsp-priv.h"
26#include "../common/sst-ipc.h"
27#include "skl-sst-ipc.h"
28
29#define SKL_BASEFW_TIMEOUT 300
30#define SKL_INIT_TIMEOUT 1000
31
32/* Intel HD Audio SRAM Window 0*/
33#define SKL_ADSP_SRAM0_BASE 0x8000
34
35/* Firmware status window */
36#define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE
37#define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4)
38
Dharageswari R6c5768b2015-12-03 23:29:50 +053039#define SKL_NUM_MODULES 1
40
Subhransu S. Prustya750ba52015-07-10 22:18:44 +053041static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status)
42{
43 u32 cur_sts;
44
45 cur_sts = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS) & SKL_FW_STS_MASK;
46
47 return (cur_sts == status);
48}
49
50static int skl_transfer_firmware(struct sst_dsp *ctx,
51 const void *basefw, u32 base_fw_size)
52{
53 int ret = 0;
54
55 ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size);
56 if (ret < 0)
57 return ret;
58
59 ret = sst_dsp_register_poll(ctx,
60 SKL_ADSP_FW_STATUS,
61 SKL_FW_STS_MASK,
62 SKL_FW_RFW_START,
63 SKL_BASEFW_TIMEOUT,
64 "Firmware boot");
65
66 ctx->cl_dev.ops.cl_stop_dma(ctx);
67
68 return ret;
69}
70
71static int skl_load_base_firmware(struct sst_dsp *ctx)
72{
73 int ret = 0, i;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +053074 struct skl_sst *skl = ctx->thread_context;
Vinod Koulcd636552016-05-30 17:42:57 +053075 struct firmware stripped_fw;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +053076 u32 reg;
77
Jeeja KP84c9e282015-10-09 09:01:50 +010078 skl->boot_complete = false;
79 init_waitqueue_head(&skl->boot_wait);
80
81 if (ctx->fw == NULL) {
Vinod Koulaecf6fd2015-11-05 21:34:15 +053082 ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
Jeeja KP84c9e282015-10-09 09:01:50 +010083 if (ret < 0) {
84 dev_err(ctx->dev, "Request firmware failed %d\n", ret);
85 skl_dsp_disable_core(ctx);
86 return -EIO;
87 }
88 }
89
Vinod Koulcd636552016-05-30 17:42:57 +053090 /* check for extended manifest */
91 stripped_fw.data = ctx->fw->data;
92 stripped_fw.size = ctx->fw->size;
93
94 skl_dsp_strip_extended_manifest(&stripped_fw);
95
Jeeja KP84c9e282015-10-09 09:01:50 +010096 ret = skl_dsp_boot(ctx);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +053097 if (ret < 0) {
Jeeja KP84c9e282015-10-09 09:01:50 +010098 dev_err(ctx->dev, "Boot dsp core failed ret: %d", ret);
99 goto skl_load_base_firmware_failed;
100 }
101
102 ret = skl_cldma_prepare(ctx);
103 if (ret < 0) {
104 dev_err(ctx->dev, "CL dma prepare failed : %d", ret);
105 goto skl_load_base_firmware_failed;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530106 }
107
108 /* enable Interrupt */
109 skl_ipc_int_enable(ctx);
110 skl_ipc_op_int_enable(ctx);
111
112 /* check ROM Status */
113 for (i = SKL_INIT_TIMEOUT; i > 0; --i) {
114 if (skl_check_fw_status(ctx, SKL_FW_INIT)) {
115 dev_dbg(ctx->dev,
116 "ROM loaded, we can continue with FW loading\n");
117 break;
118 }
119 mdelay(1);
120 }
121 if (!i) {
122 reg = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS);
123 dev_err(ctx->dev,
124 "Timeout waiting for ROM init done, reg:0x%x\n", reg);
125 ret = -EIO;
Jeeja KPae395932015-11-13 19:22:08 +0530126 goto transfer_firmware_failed;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530127 }
128
Vinod Koulcd636552016-05-30 17:42:57 +0530129 ret = skl_transfer_firmware(ctx, stripped_fw.data, stripped_fw.size);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530130 if (ret < 0) {
131 dev_err(ctx->dev, "Transfer firmware failed%d\n", ret);
Jeeja KPae395932015-11-13 19:22:08 +0530132 goto transfer_firmware_failed;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530133 } else {
134 ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
135 msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
136 if (ret == 0) {
137 dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n");
138 ret = -EIO;
Jeeja KPae395932015-11-13 19:22:08 +0530139 goto transfer_firmware_failed;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530140 }
141
142 dev_dbg(ctx->dev, "Download firmware successful%d\n", ret);
143 skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
144 }
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530145 return 0;
Jeeja KPae395932015-11-13 19:22:08 +0530146transfer_firmware_failed:
147 ctx->cl_dev.ops.cl_cleanup_controller(ctx);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530148skl_load_base_firmware_failed:
149 skl_dsp_disable_core(ctx);
Jeeja KP84c9e282015-10-09 09:01:50 +0100150 release_firmware(ctx->fw);
151 ctx->fw = NULL;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530152 return ret;
153}
154
155static int skl_set_dsp_D0(struct sst_dsp *ctx)
156{
157 int ret;
158
159 ret = skl_load_base_firmware(ctx);
160 if (ret < 0) {
161 dev_err(ctx->dev, "unable to load firmware\n");
162 return ret;
163 }
164
165 skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
166
167 return ret;
168}
169
170static int skl_set_dsp_D3(struct sst_dsp *ctx)
171{
172 int ret;
173 struct skl_ipc_dxstate_info dx;
174 struct skl_sst *skl = ctx->thread_context;
175
176 dev_dbg(ctx->dev, "In %s:\n", __func__);
177 mutex_lock(&ctx->mutex);
178 if (!is_skl_dsp_running(ctx)) {
179 mutex_unlock(&ctx->mutex);
180 return 0;
181 }
182 mutex_unlock(&ctx->mutex);
183
184 dx.core_mask = SKL_DSP_CORE0_MASK;
185 dx.dx_mask = SKL_IPC_D3_MASK;
186 ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx);
Jeeja KP53afce22015-11-13 19:22:09 +0530187 if (ret < 0)
188 dev_err(ctx->dev,
189 "D3 request to FW failed, continuing reset: %d", ret);
190
191 /* disable Interrupt */
192 ctx->cl_dev.ops.cl_cleanup_controller(ctx);
193 skl_cldma_int_disable(ctx);
194 skl_ipc_op_int_disable(ctx);
195 skl_ipc_int_disable(ctx);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530196
197 ret = skl_dsp_disable_core(ctx);
198 if (ret < 0) {
199 dev_err(ctx->dev, "disable dsp core failed ret: %d\n", ret);
200 ret = -EIO;
201 }
202 skl_dsp_set_state_locked(ctx, SKL_DSP_RESET);
203
204 return ret;
205}
206
207static unsigned int skl_get_errorcode(struct sst_dsp *ctx)
208{
209 return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE);
210}
211
Dharageswari R6c5768b2015-12-03 23:29:50 +0530212/*
213 * since get/set_module are called from DAPM context,
214 * we don't need lock for usage count
215 */
Dan Carpenterdb4e5612015-12-15 12:20:14 +0300216static int skl_get_module(struct sst_dsp *ctx, u16 mod_id)
Dharageswari R6c5768b2015-12-03 23:29:50 +0530217{
218 struct skl_module_table *module;
219
220 list_for_each_entry(module, &ctx->module_list, list) {
221 if (module->mod_info->mod_id == mod_id)
222 return ++module->usage_cnt;
223 }
224
225 return -EINVAL;
226}
227
Dan Carpenterdb4e5612015-12-15 12:20:14 +0300228static int skl_put_module(struct sst_dsp *ctx, u16 mod_id)
Dharageswari R6c5768b2015-12-03 23:29:50 +0530229{
230 struct skl_module_table *module;
231
232 list_for_each_entry(module, &ctx->module_list, list) {
233 if (module->mod_info->mod_id == mod_id)
234 return --module->usage_cnt;
235 }
236
237 return -EINVAL;
238}
239
240static struct skl_module_table *skl_fill_module_table(struct sst_dsp *ctx,
241 char *mod_name, int mod_id)
242{
243 const struct firmware *fw;
244 struct skl_module_table *skl_module;
245 unsigned int size;
246 int ret;
247
248 ret = request_firmware(&fw, mod_name, ctx->dev);
249 if (ret < 0) {
250 dev_err(ctx->dev, "Request Module %s failed :%d\n",
251 mod_name, ret);
252 return NULL;
253 }
254
255 skl_module = devm_kzalloc(ctx->dev, sizeof(*skl_module), GFP_KERNEL);
256 if (skl_module == NULL) {
257 release_firmware(fw);
258 return NULL;
259 }
260
261 size = sizeof(*skl_module->mod_info);
262 skl_module->mod_info = devm_kzalloc(ctx->dev, size, GFP_KERNEL);
263 if (skl_module->mod_info == NULL) {
264 release_firmware(fw);
265 return NULL;
266 }
267
268 skl_module->mod_info->mod_id = mod_id;
269 skl_module->mod_info->fw = fw;
270 list_add(&skl_module->list, &ctx->module_list);
271
272 return skl_module;
273}
274
275/* get a module from it's unique ID */
276static struct skl_module_table *skl_module_get_from_id(
277 struct sst_dsp *ctx, u16 mod_id)
278{
279 struct skl_module_table *module;
280
281 if (list_empty(&ctx->module_list)) {
282 dev_err(ctx->dev, "Module list is empty\n");
283 return NULL;
284 }
285
286 list_for_each_entry(module, &ctx->module_list, list) {
287 if (module->mod_info->mod_id == mod_id)
288 return module;
289 }
290
291 return NULL;
292}
293
294static int skl_transfer_module(struct sst_dsp *ctx,
295 struct skl_load_module_info *module)
296{
297 int ret;
298 struct skl_sst *skl = ctx->thread_context;
299
300 ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, module->fw->data,
301 module->fw->size);
302 if (ret < 0)
303 return ret;
304
305 ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES,
306 (void *)&module->mod_id);
307 if (ret < 0)
308 dev_err(ctx->dev, "Failed to Load module: %d\n", ret);
309
310 ctx->cl_dev.ops.cl_stop_dma(ctx);
311
312 return ret;
313}
314
Shreyas NC09305da2016-04-21 11:45:22 +0530315static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid)
Dharageswari R6c5768b2015-12-03 23:29:50 +0530316{
317 struct skl_module_table *module_entry = NULL;
318 int ret = 0;
319 char mod_name[64]; /* guid str = 32 chars + 4 hyphens */
Shreyas NC09305da2016-04-21 11:45:22 +0530320 uuid_le *uuid_mod;
Dharageswari R6c5768b2015-12-03 23:29:50 +0530321
Shreyas NC09305da2016-04-21 11:45:22 +0530322 uuid_mod = (uuid_le *)guid;
323 snprintf(mod_name, sizeof(mod_name), "%s%pUL%s",
324 "intel/dsp_fw_", uuid_mod, ".bin");
Dharageswari R6c5768b2015-12-03 23:29:50 +0530325
326 module_entry = skl_module_get_from_id(ctx, mod_id);
327 if (module_entry == NULL) {
328 module_entry = skl_fill_module_table(ctx, mod_name, mod_id);
329 if (module_entry == NULL) {
330 dev_err(ctx->dev, "Failed to Load module\n");
331 return -EINVAL;
332 }
333 }
334
335 if (!module_entry->usage_cnt) {
336 ret = skl_transfer_module(ctx, module_entry->mod_info);
337 if (ret < 0) {
338 dev_err(ctx->dev, "Failed to Load module\n");
339 return ret;
340 }
341 }
342
343 ret = skl_get_module(ctx, mod_id);
344
345 return ret;
346}
347
348static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id)
349{
Dan Carpenterdb4e5612015-12-15 12:20:14 +0300350 int usage_cnt;
Dharageswari R6c5768b2015-12-03 23:29:50 +0530351 struct skl_sst *skl = ctx->thread_context;
352 int ret = 0;
353
354 usage_cnt = skl_put_module(ctx, mod_id);
355 if (usage_cnt < 0) {
356 dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt);
357 return -EIO;
358 }
359 ret = skl_ipc_unload_modules(&skl->ipc,
360 SKL_NUM_MODULES, &mod_id);
361 if (ret < 0) {
362 dev_err(ctx->dev, "Failed to UnLoad module\n");
363 skl_get_module(ctx, mod_id);
364 return ret;
365 }
366
367 return ret;
368}
369
370static void skl_clear_module_table(struct sst_dsp *ctx)
371{
372 struct skl_module_table *module, *tmp;
373
374 if (list_empty(&ctx->module_list))
375 return;
376
377 list_for_each_entry_safe(module, tmp, &ctx->module_list, list) {
378 list_del(&module->list);
379 release_firmware(module->mod_info->fw);
380 }
381}
382
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530383static struct skl_dsp_fw_ops skl_fw_ops = {
384 .set_state_D0 = skl_set_dsp_D0,
385 .set_state_D3 = skl_set_dsp_D3,
386 .load_fw = skl_load_base_firmware,
387 .get_fw_errcode = skl_get_errorcode,
Dharageswari R6c5768b2015-12-03 23:29:50 +0530388 .load_mod = skl_load_module,
389 .unload_mod = skl_unload_module,
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530390};
391
392static struct sst_ops skl_ops = {
393 .irq_handler = skl_dsp_sst_interrupt,
394 .write = sst_shim32_write,
395 .read = sst_shim32_read,
396 .ram_read = sst_memcpy_fromio_32,
397 .ram_write = sst_memcpy_toio_32,
398 .free = skl_dsp_free,
399};
400
401static struct sst_dsp_device skl_dev = {
402 .thread = skl_dsp_irq_thread_handler,
403 .ops = &skl_ops,
404};
405
406int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
Vinod Koulaecf6fd2015-11-05 21:34:15 +0530407 const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp)
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530408{
409 struct skl_sst *skl;
410 struct sst_dsp *sst;
411 int ret;
412
413 skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
414 if (skl == NULL)
415 return -ENOMEM;
416
417 skl->dev = dev;
418 skl_dev.thread_context = skl;
419
420 skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq);
421 if (!skl->dsp) {
422 dev_err(skl->dev, "%s: no device\n", __func__);
423 return -ENODEV;
424 }
425
426 sst = skl->dsp;
427
Vinod Koulaecf6fd2015-11-05 21:34:15 +0530428 sst->fw_name = fw_name;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530429 sst->addr.lpe = mmio_base;
430 sst->addr.shim = mmio_base;
431 sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
432 SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
433
Dharageswari R6c5768b2015-12-03 23:29:50 +0530434 INIT_LIST_HEAD(&sst->module_list);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530435 sst->dsp_ops = dsp_ops;
436 sst->fw_ops = skl_fw_ops;
437
438 ret = skl_ipc_init(dev, skl);
439 if (ret)
440 return ret;
441
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530442 ret = sst->fw_ops.load_fw(sst);
443 if (ret < 0) {
444 dev_err(dev, "Load base fw failed : %d", ret);
Subhransu S. Prustyb4fe9652015-10-30 20:34:19 +0530445 goto cleanup;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530446 }
447
448 if (dsp)
449 *dsp = skl;
450
Subhransu S. Prustyb4fe9652015-10-30 20:34:19 +0530451 return ret;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530452
Subhransu S. Prustyb4fe9652015-10-30 20:34:19 +0530453cleanup:
454 skl_sst_dsp_cleanup(dev, skl);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530455 return ret;
456}
457EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
458
459void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
460{
Dharageswari R6c5768b2015-12-03 23:29:50 +0530461 skl_clear_module_table(ctx->dsp);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530462 skl_ipc_free(&ctx->ipc);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530463 ctx->dsp->ops->free(ctx->dsp);
Dharageswari.R95536d82016-04-28 18:45:25 +0530464 if (ctx->boot_complete) {
465 ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp);
466 skl_cldma_int_disable(ctx->dsp);
467 }
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530468}
469EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup);
470
471MODULE_LICENSE("GPL v2");
472MODULE_DESCRIPTION("Intel Skylake IPC driver");