blob: 04af2460f9cce7824ff43e6887267bbaea35c1c5 [file] [log] [blame]
Vinod Koul163d2082014-10-16 20:00:13 +05301/*
2 * sst.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#include <linux/module.h>
23#include <linux/pci.h>
24#include <linux/fs.h>
25#include <linux/interrupt.h>
26#include <linux/firmware.h>
27#include <linux/pm_runtime.h>
28#include <linux/pm_qos.h>
29#include <linux/async.h>
30#include <linux/delay.h>
31#include <linux/acpi.h>
32#include <sound/core.h>
33#include <sound/pcm.h>
34#include <sound/soc.h>
35#include <sound/compress_driver.h>
36#include <asm/intel-mid.h>
37#include <asm/platform_sst_audio.h>
38#include "../sst-mfld-platform.h"
39#include "sst.h"
40#include "../sst-dsp.h"
41
42MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
43MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
44MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine Driver");
45MODULE_LICENSE("GPL v2");
46
47static inline bool sst_is_process_reply(u32 msg_id)
48{
49 return ((msg_id & PROCESS_MSG) ? true : false);
50}
51
52static inline bool sst_validate_mailbox_size(unsigned int size)
53{
54 return ((size <= SST_MAILBOX_SIZE) ? true : false);
55}
56
57static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context)
58{
59 union interrupt_reg_mrfld isr;
60 union ipc_header_mrfld header;
61 union sst_imr_reg_mrfld imr;
62 struct ipc_post *msg = NULL;
63 unsigned int size = 0;
64 struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
65 irqreturn_t retval = IRQ_HANDLED;
66
67 /* Interrupt arrived, check src */
68 isr.full = sst_shim_read64(drv->shim, SST_ISRX);
69
70 if (isr.part.done_interrupt) {
71 /* Clear done bit */
72 spin_lock(&drv->ipc_spin_lock);
73 header.full = sst_shim_read64(drv->shim,
74 drv->ipc_reg.ipcx);
75 header.p.header_high.part.done = 0;
76 sst_shim_write64(drv->shim, drv->ipc_reg.ipcx, header.full);
77
78 /* write 1 to clear status register */;
79 isr.part.done_interrupt = 1;
80 sst_shim_write64(drv->shim, SST_ISRX, isr.full);
81 spin_unlock(&drv->ipc_spin_lock);
82
83 /* we can send more messages to DSP so trigger work */
84 queue_work(drv->post_msg_wq, &drv->ipc_post_msg_wq);
85 retval = IRQ_HANDLED;
86 }
87
88 if (isr.part.busy_interrupt) {
89 /* message from dsp so copy that */
90 spin_lock(&drv->ipc_spin_lock);
91 imr.full = sst_shim_read64(drv->shim, SST_IMRX);
92 imr.part.busy_interrupt = 1;
93 sst_shim_write64(drv->shim, SST_IMRX, imr.full);
94 spin_unlock(&drv->ipc_spin_lock);
95 header.full = sst_shim_read64(drv->shim, drv->ipc_reg.ipcd);
96
97 if (sst_create_ipc_msg(&msg, header.p.header_high.part.large)) {
98 drv->ops->clear_interrupt(drv);
99 return IRQ_HANDLED;
100 }
101
102 if (header.p.header_high.part.large) {
103 size = header.p.header_low_payload;
104 if (sst_validate_mailbox_size(size)) {
105 memcpy_fromio(msg->mailbox_data,
106 drv->mailbox + drv->mailbox_recv_offset, size);
107 } else {
108 dev_err(drv->dev,
109 "Mailbox not copied, payload size is: %u\n", size);
110 header.p.header_low_payload = 0;
111 }
112 }
113
114 msg->mrfld_header = header;
115 msg->is_process_reply =
116 sst_is_process_reply(header.p.header_high.part.msg_id);
117 spin_lock(&drv->rx_msg_lock);
118 list_add_tail(&msg->node, &drv->rx_list);
119 spin_unlock(&drv->rx_msg_lock);
120 drv->ops->clear_interrupt(drv);
121 retval = IRQ_WAKE_THREAD;
122 }
123 return retval;
124}
125
126static irqreturn_t intel_sst_irq_thread_mrfld(int irq, void *context)
127{
128 struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
129 struct ipc_post *__msg, *msg = NULL;
130 unsigned long irq_flags;
131
132 spin_lock_irqsave(&drv->rx_msg_lock, irq_flags);
133 if (list_empty(&drv->rx_list)) {
134 spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags);
135 return IRQ_HANDLED;
136 }
137
138 list_for_each_entry_safe(msg, __msg, &drv->rx_list, node) {
139 list_del(&msg->node);
140 spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags);
141 if (msg->is_process_reply)
142 drv->ops->process_message(msg);
143 else
144 drv->ops->process_reply(drv, msg);
145
146 if (msg->is_large)
147 kfree(msg->mailbox_data);
148 kfree(msg);
149 spin_lock_irqsave(&drv->rx_msg_lock, irq_flags);
150 }
151 spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags);
152 return IRQ_HANDLED;
153}
154
Vinod Kould62f2a02014-10-31 12:38:20 +0530155static int sst_save_dsp_context_v2(struct intel_sst_drv *sst)
156{
157 int ret = 0;
158
159 ret = sst_prepare_and_post_msg(sst, SST_TASK_ID_MEDIA, IPC_CMD,
160 IPC_PREP_D3, PIPE_RSVD, 0, NULL, NULL,
161 true, true, false, true);
162
163 if (ret < 0) {
164 dev_err(sst->dev, "not suspending FW!!, Err: %d\n", ret);
165 return -EIO;
166 }
167
168 return 0;
169}
170
171
Vinod Koul163d2082014-10-16 20:00:13 +0530172static struct intel_sst_ops mrfld_ops = {
173 .interrupt = intel_sst_interrupt_mrfld,
174 .irq_thread = intel_sst_irq_thread_mrfld,
175 .clear_interrupt = intel_sst_clear_intr_mrfld,
176 .start = sst_start_mrfld,
177 .reset = intel_sst_reset_dsp_mrfld,
178 .post_message = sst_post_message_mrfld,
179 .process_reply = sst_process_reply_mrfld,
Vinod Kould62f2a02014-10-31 12:38:20 +0530180 .save_dsp_context = sst_save_dsp_context_v2,
Vinod Koul163d2082014-10-16 20:00:13 +0530181 .alloc_stream = sst_alloc_stream_mrfld,
182 .post_download = sst_post_download_mrfld,
183};
184
185int sst_driver_ops(struct intel_sst_drv *sst)
186{
187
Subhransu S. Prusty39581032014-10-24 13:49:46 +0530188 switch (sst->dev_id) {
Vinod Koul163d2082014-10-16 20:00:13 +0530189 case SST_MRFLD_PCI_ID:
190 sst->tstamp = SST_TIME_STAMP_MRFLD;
191 sst->ops = &mrfld_ops;
192 return 0;
193
194 default:
195 dev_err(sst->dev,
Subhransu S. Prusty39581032014-10-24 13:49:46 +0530196 "SST Driver capablities missing for dev_id: %x", sst->dev_id);
Vinod Koul163d2082014-10-16 20:00:13 +0530197 return -EINVAL;
198 };
199}
200
201void sst_process_pending_msg(struct work_struct *work)
202{
203 struct intel_sst_drv *ctx = container_of(work,
204 struct intel_sst_drv, ipc_post_msg_wq);
205
206 ctx->ops->post_message(ctx, NULL, false);
207}
208
209/*
210* intel_sst_probe - PCI probe function
211*
212* @pci: PCI device structure
213* @pci_id: PCI device ID structure
214*
215*/
216static int intel_sst_probe(struct pci_dev *pci,
217 const struct pci_device_id *pci_id)
218{
219 int i, ret = 0;
220 struct intel_sst_drv *sst_drv_ctx;
221 struct intel_sst_ops *ops;
222 struct sst_platform_info *sst_pdata = pci->dev.platform_data;
223 int ddr_base;
224
225 dev_dbg(&pci->dev, "Probe for DID %x\n", pci->device);
226 sst_drv_ctx = devm_kzalloc(&pci->dev, sizeof(*sst_drv_ctx), GFP_KERNEL);
227 if (!sst_drv_ctx)
228 return -ENOMEM;
229
230 sst_drv_ctx->dev = &pci->dev;
Subhransu S. Prusty39581032014-10-24 13:49:46 +0530231 sst_drv_ctx->dev_id = pci->device;
Vinod Koul163d2082014-10-16 20:00:13 +0530232 if (!sst_pdata)
233 return -EINVAL;
234
235 sst_drv_ctx->pdata = sst_pdata;
236 if (!sst_drv_ctx->pdata->probe_data)
237 return -EINVAL;
238
239 memcpy(&sst_drv_ctx->info, sst_drv_ctx->pdata->probe_data,
240 sizeof(sst_drv_ctx->info));
241
242 if (0 != sst_driver_ops(sst_drv_ctx))
243 return -EINVAL;
244
245 ops = sst_drv_ctx->ops;
246 mutex_init(&sst_drv_ctx->sst_lock);
247
248 /* pvt_id 0 reserved for async messages */
249 sst_drv_ctx->pvt_id = 1;
250 sst_drv_ctx->stream_cnt = 0;
251 sst_drv_ctx->fw_in_mem = NULL;
252
253 /* we use memcpy, so set to 0 */
254 sst_drv_ctx->use_dma = 0;
255 sst_drv_ctx->use_lli = 0;
256
257 INIT_LIST_HEAD(&sst_drv_ctx->memcpy_list);
258 INIT_LIST_HEAD(&sst_drv_ctx->ipc_dispatch_list);
259 INIT_LIST_HEAD(&sst_drv_ctx->block_list);
260 INIT_LIST_HEAD(&sst_drv_ctx->rx_list);
261
262 sst_drv_ctx->post_msg_wq =
263 create_singlethread_workqueue("sst_post_msg_wq");
264 if (!sst_drv_ctx->post_msg_wq) {
265 ret = -EINVAL;
266 goto do_free_drv_ctx;
267 }
268 INIT_WORK(&sst_drv_ctx->ipc_post_msg_wq, sst_process_pending_msg);
269 init_waitqueue_head(&sst_drv_ctx->wait_queue);
270
271 spin_lock_init(&sst_drv_ctx->ipc_spin_lock);
272 spin_lock_init(&sst_drv_ctx->block_lock);
273 spin_lock_init(&sst_drv_ctx->rx_msg_lock);
274
275 dev_info(sst_drv_ctx->dev, "Got drv data max stream %d\n",
276 sst_drv_ctx->info.max_streams);
277 for (i = 1; i <= sst_drv_ctx->info.max_streams; i++) {
278 struct stream_info *stream = &sst_drv_ctx->streams[i];
279
280 memset(stream, 0, sizeof(*stream));
281 stream->pipe_id = PIPE_RSVD;
282 mutex_init(&stream->lock);
283 }
284
285 /* Init the device */
286 ret = pcim_enable_device(pci);
287 if (ret) {
288 dev_err(sst_drv_ctx->dev,
289 "device can't be enabled. Returned err: %d\n", ret);
290 goto do_free_mem;
291 }
292 sst_drv_ctx->pci = pci_dev_get(pci);
293 ret = pci_request_regions(pci, SST_DRV_NAME);
294 if (ret)
295 goto do_free_mem;
296
297 /* map registers */
298 /* DDR base */
Subhransu S. Prusty39581032014-10-24 13:49:46 +0530299 if (sst_drv_ctx->dev_id == SST_MRFLD_PCI_ID) {
Vinod Koul163d2082014-10-16 20:00:13 +0530300 sst_drv_ctx->ddr_base = pci_resource_start(pci, 0);
301 /* check that the relocated IMR base matches with FW Binary */
302 ddr_base = relocate_imr_addr_mrfld(sst_drv_ctx->ddr_base);
303 if (!sst_drv_ctx->pdata->lib_info) {
304 dev_err(sst_drv_ctx->dev, "lib_info pointer NULL\n");
305 ret = -EINVAL;
306 goto do_release_regions;
307 }
308 if (ddr_base != sst_drv_ctx->pdata->lib_info->mod_base) {
309 dev_err(sst_drv_ctx->dev,
310 "FW LSP DDR BASE does not match with IFWI\n");
311 ret = -EINVAL;
312 goto do_release_regions;
313 }
314 sst_drv_ctx->ddr_end = pci_resource_end(pci, 0);
315
316 sst_drv_ctx->ddr = pcim_iomap(pci, 0,
317 pci_resource_len(pci, 0));
318 if (!sst_drv_ctx->ddr) {
319 ret = -EINVAL;
320 goto do_release_regions;
321 }
322 dev_dbg(sst_drv_ctx->dev, "sst: DDR Ptr %p\n", sst_drv_ctx->ddr);
323 } else {
324 sst_drv_ctx->ddr = NULL;
325 }
326
327 /* SHIM */
328 sst_drv_ctx->shim_phy_add = pci_resource_start(pci, 1);
329 sst_drv_ctx->shim = pcim_iomap(pci, 1, pci_resource_len(pci, 1));
330 if (!sst_drv_ctx->shim) {
331 ret = -EINVAL;
332 goto do_release_regions;
333 }
334 dev_dbg(sst_drv_ctx->dev, "SST Shim Ptr %p\n", sst_drv_ctx->shim);
335
336 /* Shared SRAM */
337 sst_drv_ctx->mailbox_add = pci_resource_start(pci, 2);
338 sst_drv_ctx->mailbox = pcim_iomap(pci, 2, pci_resource_len(pci, 2));
339 if (!sst_drv_ctx->mailbox) {
340 ret = -EINVAL;
341 goto do_release_regions;
342 }
343 dev_dbg(sst_drv_ctx->dev, "SRAM Ptr %p\n", sst_drv_ctx->mailbox);
344
345 /* IRAM */
346 sst_drv_ctx->iram_end = pci_resource_end(pci, 3);
347 sst_drv_ctx->iram_base = pci_resource_start(pci, 3);
348 sst_drv_ctx->iram = pcim_iomap(pci, 3, pci_resource_len(pci, 3));
349 if (!sst_drv_ctx->iram) {
350 ret = -EINVAL;
351 goto do_release_regions;
352 }
353 dev_dbg(sst_drv_ctx->dev, "IRAM Ptr %p\n", sst_drv_ctx->iram);
354
355 /* DRAM */
356 sst_drv_ctx->dram_end = pci_resource_end(pci, 4);
357 sst_drv_ctx->dram_base = pci_resource_start(pci, 4);
358 sst_drv_ctx->dram = pcim_iomap(pci, 4, pci_resource_len(pci, 4));
359 if (!sst_drv_ctx->dram) {
360 ret = -EINVAL;
361 goto do_release_regions;
362 }
363 dev_dbg(sst_drv_ctx->dev, "DRAM Ptr %p\n", sst_drv_ctx->dram);
364
365
366 sst_set_fw_state_locked(sst_drv_ctx, SST_RESET);
367 sst_drv_ctx->irq_num = pci->irq;
368 /* Register the ISR */
369 ret = devm_request_threaded_irq(&pci->dev, pci->irq,
370 sst_drv_ctx->ops->interrupt,
371 sst_drv_ctx->ops->irq_thread, 0, SST_DRV_NAME,
372 sst_drv_ctx);
373 if (ret)
374 goto do_release_regions;
375 dev_dbg(sst_drv_ctx->dev, "Registered IRQ 0x%x\n", pci->irq);
376
377 /* default intr are unmasked so set this as masked */
Subhransu S. Prusty39581032014-10-24 13:49:46 +0530378 if (sst_drv_ctx->dev_id == SST_MRFLD_PCI_ID)
Vinod Koul163d2082014-10-16 20:00:13 +0530379 sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, 0xFFFF0038);
380
381 pci_set_drvdata(pci, sst_drv_ctx);
382 pm_runtime_set_autosuspend_delay(sst_drv_ctx->dev, SST_SUSPEND_DELAY);
383 pm_runtime_use_autosuspend(sst_drv_ctx->dev);
384 pm_runtime_allow(sst_drv_ctx->dev);
385 pm_runtime_put_noidle(sst_drv_ctx->dev);
386 sst_register(sst_drv_ctx->dev);
387 sst_drv_ctx->qos = devm_kzalloc(&pci->dev,
388 sizeof(struct pm_qos_request), GFP_KERNEL);
389 if (!sst_drv_ctx->qos) {
390 ret = -ENOMEM;
391 goto do_release_regions;
392 }
393 pm_qos_add_request(sst_drv_ctx->qos, PM_QOS_CPU_DMA_LATENCY,
394 PM_QOS_DEFAULT_VALUE);
395
396 return ret;
397
398do_release_regions:
399 pci_release_regions(pci);
400do_free_mem:
401 destroy_workqueue(sst_drv_ctx->post_msg_wq);
402do_free_drv_ctx:
403 dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret);
404 return ret;
405}
406
407/**
408* intel_sst_remove - PCI remove function
409*
410* @pci: PCI device structure
411*
412* This function is called by OS when a device is unloaded
413* This frees the interrupt etc
414*/
415static void intel_sst_remove(struct pci_dev *pci)
416{
417 struct intel_sst_drv *sst_drv_ctx = pci_get_drvdata(pci);
418
419 pm_runtime_get_noresume(sst_drv_ctx->dev);
420 pm_runtime_forbid(sst_drv_ctx->dev);
421 sst_unregister(sst_drv_ctx->dev);
422 pci_dev_put(sst_drv_ctx->pci);
423 sst_set_fw_state_locked(sst_drv_ctx, SST_SHUTDOWN);
424
425 flush_scheduled_work();
426 destroy_workqueue(sst_drv_ctx->post_msg_wq);
427 pm_qos_remove_request(sst_drv_ctx->qos);
428 kfree(sst_drv_ctx->fw_sg_list.src);
429 kfree(sst_drv_ctx->fw_sg_list.dst);
430 sst_drv_ctx->fw_sg_list.list_len = 0;
431 kfree(sst_drv_ctx->fw_in_mem);
432 sst_drv_ctx->fw_in_mem = NULL;
433 sst_memcpy_free_resources(sst_drv_ctx);
434 sst_drv_ctx = NULL;
435 pci_release_regions(pci);
436 pci_set_drvdata(pci, NULL);
437}
438
Vinod Kould62f2a02014-10-31 12:38:20 +0530439static int intel_sst_runtime_suspend(struct device *dev)
440{
441 int ret = 0;
442 struct intel_sst_drv *ctx = dev_get_drvdata(dev);
443
444 if (ctx->sst_state == SST_RESET) {
445 dev_dbg(dev, "LPE is already in RESET state, No action\n");
446 return 0;
447 }
448 /* save fw context */
449 if (ctx->ops->save_dsp_context(ctx))
450 return -EBUSY;
451
452 /* Move the SST state to Reset */
453 sst_set_fw_state_locked(ctx, SST_RESET);
454
455 synchronize_irq(ctx->irq_num);
456 flush_workqueue(ctx->post_msg_wq);
457
458 return ret;
459}
460
461static int intel_sst_runtime_resume(struct device *dev)
462{
463 int ret = 0;
464 struct intel_sst_drv *ctx = dev_get_drvdata(dev);
465
Vinod Kould62f2a02014-10-31 12:38:20 +0530466 if (ctx->sst_state == SST_RESET) {
467 ret = sst_load_fw(ctx);
468 if (ret) {
469 dev_err(dev, "FW download fail %d\n", ret);
Mythri P K45f31bf2014-10-31 12:38:21 +0530470 sst_set_fw_state_locked(ctx, SST_RESET);
Vinod Kould62f2a02014-10-31 12:38:20 +0530471 }
472 }
Vinod Kould62f2a02014-10-31 12:38:20 +0530473 return ret;
474}
475
476static const struct dev_pm_ops intel_sst_pm = {
477 .runtime_suspend = intel_sst_runtime_suspend,
478 .runtime_resume = intel_sst_runtime_resume,
479};
480
Vinod Koul163d2082014-10-16 20:00:13 +0530481/* PCI Routines */
482static struct pci_device_id intel_sst_ids[] = {
483 { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
484 { 0, }
485};
486
487static struct pci_driver sst_driver = {
488 .name = SST_DRV_NAME,
489 .id_table = intel_sst_ids,
490 .probe = intel_sst_probe,
491 .remove = intel_sst_remove,
Vinod Kould62f2a02014-10-31 12:38:20 +0530492#ifdef CONFIG_PM
493 .driver = {
494 .pm = &intel_sst_pm,
495 },
496#endif
Vinod Koul163d2082014-10-16 20:00:13 +0530497};
498
499module_pci_driver(sst_driver);