blob: fa3421706e4eff35867a471da9d8cdeb171c4d85 [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
155static struct intel_sst_ops mrfld_ops = {
156 .interrupt = intel_sst_interrupt_mrfld,
157 .irq_thread = intel_sst_irq_thread_mrfld,
158 .clear_interrupt = intel_sst_clear_intr_mrfld,
159 .start = sst_start_mrfld,
160 .reset = intel_sst_reset_dsp_mrfld,
161 .post_message = sst_post_message_mrfld,
162 .process_reply = sst_process_reply_mrfld,
163 .alloc_stream = sst_alloc_stream_mrfld,
164 .post_download = sst_post_download_mrfld,
165};
166
167int sst_driver_ops(struct intel_sst_drv *sst)
168{
169
Subhransu S. Prusty39581032014-10-24 13:49:46 +0530170 switch (sst->dev_id) {
Vinod Koul163d2082014-10-16 20:00:13 +0530171 case SST_MRFLD_PCI_ID:
172 sst->tstamp = SST_TIME_STAMP_MRFLD;
173 sst->ops = &mrfld_ops;
174 return 0;
175
176 default:
177 dev_err(sst->dev,
Subhransu S. Prusty39581032014-10-24 13:49:46 +0530178 "SST Driver capablities missing for dev_id: %x", sst->dev_id);
Vinod Koul163d2082014-10-16 20:00:13 +0530179 return -EINVAL;
180 };
181}
182
183void sst_process_pending_msg(struct work_struct *work)
184{
185 struct intel_sst_drv *ctx = container_of(work,
186 struct intel_sst_drv, ipc_post_msg_wq);
187
188 ctx->ops->post_message(ctx, NULL, false);
189}
190
191/*
192* intel_sst_probe - PCI probe function
193*
194* @pci: PCI device structure
195* @pci_id: PCI device ID structure
196*
197*/
198static int intel_sst_probe(struct pci_dev *pci,
199 const struct pci_device_id *pci_id)
200{
201 int i, ret = 0;
202 struct intel_sst_drv *sst_drv_ctx;
203 struct intel_sst_ops *ops;
204 struct sst_platform_info *sst_pdata = pci->dev.platform_data;
205 int ddr_base;
206
207 dev_dbg(&pci->dev, "Probe for DID %x\n", pci->device);
208 sst_drv_ctx = devm_kzalloc(&pci->dev, sizeof(*sst_drv_ctx), GFP_KERNEL);
209 if (!sst_drv_ctx)
210 return -ENOMEM;
211
212 sst_drv_ctx->dev = &pci->dev;
Subhransu S. Prusty39581032014-10-24 13:49:46 +0530213 sst_drv_ctx->dev_id = pci->device;
Vinod Koul163d2082014-10-16 20:00:13 +0530214 if (!sst_pdata)
215 return -EINVAL;
216
217 sst_drv_ctx->pdata = sst_pdata;
218 if (!sst_drv_ctx->pdata->probe_data)
219 return -EINVAL;
220
221 memcpy(&sst_drv_ctx->info, sst_drv_ctx->pdata->probe_data,
222 sizeof(sst_drv_ctx->info));
223
224 if (0 != sst_driver_ops(sst_drv_ctx))
225 return -EINVAL;
226
227 ops = sst_drv_ctx->ops;
228 mutex_init(&sst_drv_ctx->sst_lock);
229
230 /* pvt_id 0 reserved for async messages */
231 sst_drv_ctx->pvt_id = 1;
232 sst_drv_ctx->stream_cnt = 0;
233 sst_drv_ctx->fw_in_mem = NULL;
234
235 /* we use memcpy, so set to 0 */
236 sst_drv_ctx->use_dma = 0;
237 sst_drv_ctx->use_lli = 0;
238
239 INIT_LIST_HEAD(&sst_drv_ctx->memcpy_list);
240 INIT_LIST_HEAD(&sst_drv_ctx->ipc_dispatch_list);
241 INIT_LIST_HEAD(&sst_drv_ctx->block_list);
242 INIT_LIST_HEAD(&sst_drv_ctx->rx_list);
243
244 sst_drv_ctx->post_msg_wq =
245 create_singlethread_workqueue("sst_post_msg_wq");
246 if (!sst_drv_ctx->post_msg_wq) {
247 ret = -EINVAL;
248 goto do_free_drv_ctx;
249 }
250 INIT_WORK(&sst_drv_ctx->ipc_post_msg_wq, sst_process_pending_msg);
251 init_waitqueue_head(&sst_drv_ctx->wait_queue);
252
253 spin_lock_init(&sst_drv_ctx->ipc_spin_lock);
254 spin_lock_init(&sst_drv_ctx->block_lock);
255 spin_lock_init(&sst_drv_ctx->rx_msg_lock);
256
257 dev_info(sst_drv_ctx->dev, "Got drv data max stream %d\n",
258 sst_drv_ctx->info.max_streams);
259 for (i = 1; i <= sst_drv_ctx->info.max_streams; i++) {
260 struct stream_info *stream = &sst_drv_ctx->streams[i];
261
262 memset(stream, 0, sizeof(*stream));
263 stream->pipe_id = PIPE_RSVD;
264 mutex_init(&stream->lock);
265 }
266
267 /* Init the device */
268 ret = pcim_enable_device(pci);
269 if (ret) {
270 dev_err(sst_drv_ctx->dev,
271 "device can't be enabled. Returned err: %d\n", ret);
272 goto do_free_mem;
273 }
274 sst_drv_ctx->pci = pci_dev_get(pci);
275 ret = pci_request_regions(pci, SST_DRV_NAME);
276 if (ret)
277 goto do_free_mem;
278
279 /* map registers */
280 /* DDR base */
Subhransu S. Prusty39581032014-10-24 13:49:46 +0530281 if (sst_drv_ctx->dev_id == SST_MRFLD_PCI_ID) {
Vinod Koul163d2082014-10-16 20:00:13 +0530282 sst_drv_ctx->ddr_base = pci_resource_start(pci, 0);
283 /* check that the relocated IMR base matches with FW Binary */
284 ddr_base = relocate_imr_addr_mrfld(sst_drv_ctx->ddr_base);
285 if (!sst_drv_ctx->pdata->lib_info) {
286 dev_err(sst_drv_ctx->dev, "lib_info pointer NULL\n");
287 ret = -EINVAL;
288 goto do_release_regions;
289 }
290 if (ddr_base != sst_drv_ctx->pdata->lib_info->mod_base) {
291 dev_err(sst_drv_ctx->dev,
292 "FW LSP DDR BASE does not match with IFWI\n");
293 ret = -EINVAL;
294 goto do_release_regions;
295 }
296 sst_drv_ctx->ddr_end = pci_resource_end(pci, 0);
297
298 sst_drv_ctx->ddr = pcim_iomap(pci, 0,
299 pci_resource_len(pci, 0));
300 if (!sst_drv_ctx->ddr) {
301 ret = -EINVAL;
302 goto do_release_regions;
303 }
304 dev_dbg(sst_drv_ctx->dev, "sst: DDR Ptr %p\n", sst_drv_ctx->ddr);
305 } else {
306 sst_drv_ctx->ddr = NULL;
307 }
308
309 /* SHIM */
310 sst_drv_ctx->shim_phy_add = pci_resource_start(pci, 1);
311 sst_drv_ctx->shim = pcim_iomap(pci, 1, pci_resource_len(pci, 1));
312 if (!sst_drv_ctx->shim) {
313 ret = -EINVAL;
314 goto do_release_regions;
315 }
316 dev_dbg(sst_drv_ctx->dev, "SST Shim Ptr %p\n", sst_drv_ctx->shim);
317
318 /* Shared SRAM */
319 sst_drv_ctx->mailbox_add = pci_resource_start(pci, 2);
320 sst_drv_ctx->mailbox = pcim_iomap(pci, 2, pci_resource_len(pci, 2));
321 if (!sst_drv_ctx->mailbox) {
322 ret = -EINVAL;
323 goto do_release_regions;
324 }
325 dev_dbg(sst_drv_ctx->dev, "SRAM Ptr %p\n", sst_drv_ctx->mailbox);
326
327 /* IRAM */
328 sst_drv_ctx->iram_end = pci_resource_end(pci, 3);
329 sst_drv_ctx->iram_base = pci_resource_start(pci, 3);
330 sst_drv_ctx->iram = pcim_iomap(pci, 3, pci_resource_len(pci, 3));
331 if (!sst_drv_ctx->iram) {
332 ret = -EINVAL;
333 goto do_release_regions;
334 }
335 dev_dbg(sst_drv_ctx->dev, "IRAM Ptr %p\n", sst_drv_ctx->iram);
336
337 /* DRAM */
338 sst_drv_ctx->dram_end = pci_resource_end(pci, 4);
339 sst_drv_ctx->dram_base = pci_resource_start(pci, 4);
340 sst_drv_ctx->dram = pcim_iomap(pci, 4, pci_resource_len(pci, 4));
341 if (!sst_drv_ctx->dram) {
342 ret = -EINVAL;
343 goto do_release_regions;
344 }
345 dev_dbg(sst_drv_ctx->dev, "DRAM Ptr %p\n", sst_drv_ctx->dram);
346
347
348 sst_set_fw_state_locked(sst_drv_ctx, SST_RESET);
349 sst_drv_ctx->irq_num = pci->irq;
350 /* Register the ISR */
351 ret = devm_request_threaded_irq(&pci->dev, pci->irq,
352 sst_drv_ctx->ops->interrupt,
353 sst_drv_ctx->ops->irq_thread, 0, SST_DRV_NAME,
354 sst_drv_ctx);
355 if (ret)
356 goto do_release_regions;
357 dev_dbg(sst_drv_ctx->dev, "Registered IRQ 0x%x\n", pci->irq);
358
359 /* default intr are unmasked so set this as masked */
Subhransu S. Prusty39581032014-10-24 13:49:46 +0530360 if (sst_drv_ctx->dev_id == SST_MRFLD_PCI_ID)
Vinod Koul163d2082014-10-16 20:00:13 +0530361 sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, 0xFFFF0038);
362
363 pci_set_drvdata(pci, sst_drv_ctx);
364 pm_runtime_set_autosuspend_delay(sst_drv_ctx->dev, SST_SUSPEND_DELAY);
365 pm_runtime_use_autosuspend(sst_drv_ctx->dev);
366 pm_runtime_allow(sst_drv_ctx->dev);
367 pm_runtime_put_noidle(sst_drv_ctx->dev);
368 sst_register(sst_drv_ctx->dev);
369 sst_drv_ctx->qos = devm_kzalloc(&pci->dev,
370 sizeof(struct pm_qos_request), GFP_KERNEL);
371 if (!sst_drv_ctx->qos) {
372 ret = -ENOMEM;
373 goto do_release_regions;
374 }
375 pm_qos_add_request(sst_drv_ctx->qos, PM_QOS_CPU_DMA_LATENCY,
376 PM_QOS_DEFAULT_VALUE);
377
378 return ret;
379
380do_release_regions:
381 pci_release_regions(pci);
382do_free_mem:
383 destroy_workqueue(sst_drv_ctx->post_msg_wq);
384do_free_drv_ctx:
385 dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret);
386 return ret;
387}
388
389/**
390* intel_sst_remove - PCI remove function
391*
392* @pci: PCI device structure
393*
394* This function is called by OS when a device is unloaded
395* This frees the interrupt etc
396*/
397static void intel_sst_remove(struct pci_dev *pci)
398{
399 struct intel_sst_drv *sst_drv_ctx = pci_get_drvdata(pci);
400
401 pm_runtime_get_noresume(sst_drv_ctx->dev);
402 pm_runtime_forbid(sst_drv_ctx->dev);
403 sst_unregister(sst_drv_ctx->dev);
404 pci_dev_put(sst_drv_ctx->pci);
405 sst_set_fw_state_locked(sst_drv_ctx, SST_SHUTDOWN);
406
407 flush_scheduled_work();
408 destroy_workqueue(sst_drv_ctx->post_msg_wq);
409 pm_qos_remove_request(sst_drv_ctx->qos);
410 kfree(sst_drv_ctx->fw_sg_list.src);
411 kfree(sst_drv_ctx->fw_sg_list.dst);
412 sst_drv_ctx->fw_sg_list.list_len = 0;
413 kfree(sst_drv_ctx->fw_in_mem);
414 sst_drv_ctx->fw_in_mem = NULL;
415 sst_memcpy_free_resources(sst_drv_ctx);
416 sst_drv_ctx = NULL;
417 pci_release_regions(pci);
418 pci_set_drvdata(pci, NULL);
419}
420
421/* PCI Routines */
422static struct pci_device_id intel_sst_ids[] = {
423 { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
424 { 0, }
425};
426
427static struct pci_driver sst_driver = {
428 .name = SST_DRV_NAME,
429 .id_table = intel_sst_ids,
430 .probe = intel_sst_probe,
431 .remove = intel_sst_remove,
432};
433
434module_pci_driver(sst_driver);