blob: e1d34d5c3f9a7a6a44c4aecbea450ed96f007a2f [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>
Subhransu S. Prustya750ba52015-07-10 22:18:44 +053023#include "../common/sst-dsp.h"
24#include "../common/sst-dsp-priv.h"
25#include "../common/sst-ipc.h"
26#include "skl-sst-ipc.h"
27
28#define SKL_BASEFW_TIMEOUT 300
29#define SKL_INIT_TIMEOUT 1000
30
31/* Intel HD Audio SRAM Window 0*/
32#define SKL_ADSP_SRAM0_BASE 0x8000
33
34/* Firmware status window */
35#define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE
36#define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4)
37
38#define SKL_INSTANCE_ID 0
39#define SKL_BASE_FW_MODULE_ID 0
40
41static 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;
75 u32 reg;
76
Jeeja KP84c9e282015-10-09 09:01:50 +010077 skl->boot_complete = false;
78 init_waitqueue_head(&skl->boot_wait);
79
80 if (ctx->fw == NULL) {
Vinod Koulaecf6fd2015-11-05 21:34:15 +053081 ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev);
Jeeja KP84c9e282015-10-09 09:01:50 +010082 if (ret < 0) {
83 dev_err(ctx->dev, "Request firmware failed %d\n", ret);
84 skl_dsp_disable_core(ctx);
85 return -EIO;
86 }
87 }
88
89 ret = skl_dsp_boot(ctx);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +053090 if (ret < 0) {
Jeeja KP84c9e282015-10-09 09:01:50 +010091 dev_err(ctx->dev, "Boot dsp core failed ret: %d", ret);
92 goto skl_load_base_firmware_failed;
93 }
94
95 ret = skl_cldma_prepare(ctx);
96 if (ret < 0) {
97 dev_err(ctx->dev, "CL dma prepare failed : %d", ret);
98 goto skl_load_base_firmware_failed;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +053099 }
100
101 /* enable Interrupt */
102 skl_ipc_int_enable(ctx);
103 skl_ipc_op_int_enable(ctx);
104
105 /* check ROM Status */
106 for (i = SKL_INIT_TIMEOUT; i > 0; --i) {
107 if (skl_check_fw_status(ctx, SKL_FW_INIT)) {
108 dev_dbg(ctx->dev,
109 "ROM loaded, we can continue with FW loading\n");
110 break;
111 }
112 mdelay(1);
113 }
114 if (!i) {
115 reg = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS);
116 dev_err(ctx->dev,
117 "Timeout waiting for ROM init done, reg:0x%x\n", reg);
118 ret = -EIO;
Jeeja KPae395932015-11-13 19:22:08 +0530119 goto transfer_firmware_failed;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530120 }
121
Jeeja KP84c9e282015-10-09 09:01:50 +0100122 ret = skl_transfer_firmware(ctx, ctx->fw->data, ctx->fw->size);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530123 if (ret < 0) {
124 dev_err(ctx->dev, "Transfer firmware failed%d\n", ret);
Jeeja KPae395932015-11-13 19:22:08 +0530125 goto transfer_firmware_failed;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530126 } else {
127 ret = wait_event_timeout(skl->boot_wait, skl->boot_complete,
128 msecs_to_jiffies(SKL_IPC_BOOT_MSECS));
129 if (ret == 0) {
130 dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n");
131 ret = -EIO;
Jeeja KPae395932015-11-13 19:22:08 +0530132 goto transfer_firmware_failed;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530133 }
134
135 dev_dbg(ctx->dev, "Download firmware successful%d\n", ret);
136 skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
137 }
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530138 return 0;
Jeeja KPae395932015-11-13 19:22:08 +0530139transfer_firmware_failed:
140 ctx->cl_dev.ops.cl_cleanup_controller(ctx);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530141skl_load_base_firmware_failed:
142 skl_dsp_disable_core(ctx);
Jeeja KP84c9e282015-10-09 09:01:50 +0100143 release_firmware(ctx->fw);
144 ctx->fw = NULL;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530145 return ret;
146}
147
148static int skl_set_dsp_D0(struct sst_dsp *ctx)
149{
150 int ret;
151
152 ret = skl_load_base_firmware(ctx);
153 if (ret < 0) {
154 dev_err(ctx->dev, "unable to load firmware\n");
155 return ret;
156 }
157
158 skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING);
159
160 return ret;
161}
162
163static int skl_set_dsp_D3(struct sst_dsp *ctx)
164{
165 int ret;
166 struct skl_ipc_dxstate_info dx;
167 struct skl_sst *skl = ctx->thread_context;
168
169 dev_dbg(ctx->dev, "In %s:\n", __func__);
170 mutex_lock(&ctx->mutex);
171 if (!is_skl_dsp_running(ctx)) {
172 mutex_unlock(&ctx->mutex);
173 return 0;
174 }
175 mutex_unlock(&ctx->mutex);
176
177 dx.core_mask = SKL_DSP_CORE0_MASK;
178 dx.dx_mask = SKL_IPC_D3_MASK;
179 ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx);
Jeeja KP53afce22015-11-13 19:22:09 +0530180 if (ret < 0)
181 dev_err(ctx->dev,
182 "D3 request to FW failed, continuing reset: %d", ret);
183
184 /* disable Interrupt */
185 ctx->cl_dev.ops.cl_cleanup_controller(ctx);
186 skl_cldma_int_disable(ctx);
187 skl_ipc_op_int_disable(ctx);
188 skl_ipc_int_disable(ctx);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530189
190 ret = skl_dsp_disable_core(ctx);
191 if (ret < 0) {
192 dev_err(ctx->dev, "disable dsp core failed ret: %d\n", ret);
193 ret = -EIO;
194 }
195 skl_dsp_set_state_locked(ctx, SKL_DSP_RESET);
196
197 return ret;
198}
199
200static unsigned int skl_get_errorcode(struct sst_dsp *ctx)
201{
202 return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE);
203}
204
205static struct skl_dsp_fw_ops skl_fw_ops = {
206 .set_state_D0 = skl_set_dsp_D0,
207 .set_state_D3 = skl_set_dsp_D3,
208 .load_fw = skl_load_base_firmware,
209 .get_fw_errcode = skl_get_errorcode,
210};
211
212static struct sst_ops skl_ops = {
213 .irq_handler = skl_dsp_sst_interrupt,
214 .write = sst_shim32_write,
215 .read = sst_shim32_read,
216 .ram_read = sst_memcpy_fromio_32,
217 .ram_write = sst_memcpy_toio_32,
218 .free = skl_dsp_free,
219};
220
221static struct sst_dsp_device skl_dev = {
222 .thread = skl_dsp_irq_thread_handler,
223 .ops = &skl_ops,
224};
225
226int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq,
Vinod Koulaecf6fd2015-11-05 21:34:15 +0530227 const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp)
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530228{
229 struct skl_sst *skl;
230 struct sst_dsp *sst;
231 int ret;
232
233 skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL);
234 if (skl == NULL)
235 return -ENOMEM;
236
237 skl->dev = dev;
238 skl_dev.thread_context = skl;
239
240 skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq);
241 if (!skl->dsp) {
242 dev_err(skl->dev, "%s: no device\n", __func__);
243 return -ENODEV;
244 }
245
246 sst = skl->dsp;
247
Vinod Koulaecf6fd2015-11-05 21:34:15 +0530248 sst->fw_name = fw_name;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530249 sst->addr.lpe = mmio_base;
250 sst->addr.shim = mmio_base;
251 sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ),
252 SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ);
253
254 sst->dsp_ops = dsp_ops;
255 sst->fw_ops = skl_fw_ops;
256
257 ret = skl_ipc_init(dev, skl);
258 if (ret)
259 return ret;
260
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530261 ret = sst->fw_ops.load_fw(sst);
262 if (ret < 0) {
263 dev_err(dev, "Load base fw failed : %d", ret);
Subhransu S. Prustyb4fe9652015-10-30 20:34:19 +0530264 goto cleanup;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530265 }
266
267 if (dsp)
268 *dsp = skl;
269
Subhransu S. Prustyb4fe9652015-10-30 20:34:19 +0530270 return ret;
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530271
Subhransu S. Prustyb4fe9652015-10-30 20:34:19 +0530272cleanup:
273 skl_sst_dsp_cleanup(dev, skl);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530274 return ret;
275}
276EXPORT_SYMBOL_GPL(skl_sst_dsp_init);
277
278void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
279{
280 skl_ipc_free(&ctx->ipc);
Subhransu S. Prustya750ba52015-07-10 22:18:44 +0530281 ctx->dsp->ops->free(ctx->dsp);
282}
283EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup);
284
285MODULE_LICENSE("GPL v2");
286MODULE_DESCRIPTION("Intel Skylake IPC driver");