aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/intel_sst/intel_sst_dsp.c
diff options
context:
space:
mode:
authorVinod Koul <vinod.koul@intel.com>2010-10-05 11:25:17 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-10-05 16:24:04 -0400
commitfffa1cca3db6ac0ce612bc52f5cbd23b6672566f (patch)
treee9591609cd452d21d1bfa26f578e931131efbd07 /drivers/staging/intel_sst/intel_sst_dsp.c
parenta747d4b817daf95c64ac6396e27fddc66c83a811 (diff)
Staging: sst: Intel SST audio driver
This is the Intel SST audio driver. As compared to the previous versions it has all the printks and other stuff noted cleaned up and more hardware support. The Aava support is disabled in this patch (is_aava resolves to 0) because the Aava board detection logic is not yet upstream. The driver itself is a combination of a traditional ALSA driver and a hardware assisted offload driver which can play audio while the processor is asleep but which can't do all the more interactive stuff. In the general case most software would use the ALSA interface, but the other interface is needed for certain classes of use such as music playback on highly power consumption sensitive devices. This is going to staging primarily because it depends upon the staging memrar driver. Signed-off-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Harsha Priya <priya.harsha@intel.com> [Merged together and tweaked for -next] Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/intel_sst/intel_sst_dsp.c')
-rw-r--r--drivers/staging/intel_sst/intel_sst_dsp.c486
1 files changed, 486 insertions, 0 deletions
diff --git a/drivers/staging/intel_sst/intel_sst_dsp.c b/drivers/staging/intel_sst/intel_sst_dsp.c
new file mode 100644
index 00000000000..d80a6ee2deb
--- /dev/null
+++ b/drivers/staging/intel_sst/intel_sst_dsp.c
@@ -0,0 +1,486 @@
1/*
2 * intel_sst_dsp.c - Intel SST Driver for audio engine
3 *
4 * Copyright (C) 2008-10 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 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23 *
24 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25 *
26 * This driver exposes the audio engine functionalities to the ALSA
27 * and middleware.
28 *
29 * This file contains all dsp controlling functions like firmware download,
30 * setting/resetting dsp cores, etc
31 */
32#include <linux/pci.h>
33#include <linux/fs.h>
34#include <linux/firmware.h>
35#include "intel_sst.h"
36#include "intel_sst_ioctl.h"
37#include "intel_sst_fw_ipc.h"
38#include "intel_sst_common.h"
39
40
41/**
42 * intel_sst_reset_dsp_mrst - Resetting SST DSP
43 *
44 * This resets DSP in case of MRST platfroms
45 */
46static int intel_sst_reset_dsp_mrst(void)
47{
48 union config_status_reg csr;
49
50 pr_debug("sst: Resetting the DSP in mrst\n");
51 csr.full = 0x3a2;
52 sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
53 csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
54 csr.part.strb_cntr_rst = 0;
55 csr.part.run_stall = 0x1;
56 csr.part.bypass = 0x7;
57 csr.part.sst_reset = 0x1;
58 sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
59 return 0;
60}
61
62/**
63 * intel_sst_reset_dsp_medfield - Resetting SST DSP
64 *
65 * This resets DSP in case of Medfield platfroms
66 */
67static int intel_sst_reset_dsp_medfield(void)
68{
69 union config_status_reg csr;
70
71 pr_debug("sst: Resetting the DSP in medfield\n");
72 csr.full = 0x048303E2;
73 sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
74
75 return 0;
76}
77
78/**
79 * sst_start_mrst - Start the SST DSP processor
80 *
81 * This starts the DSP in MRST platfroms
82 */
83static int sst_start_mrst(void)
84{
85 union config_status_reg csr;
86
87 csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
88 csr.part.bypass = 0;
89 sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
90 csr.part.run_stall = 0;
91 csr.part.sst_reset = 0;
92 csr.part.strb_cntr_rst = 1;
93 pr_debug("sst: Setting SST to execute_mrst 0x%x\n", csr.full);
94 sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
95
96 return 0;
97}
98
99/**
100 * sst_start_medfield - Start the SST DSP processor
101 *
102 * This starts the DSP in MRST platfroms
103 */
104static int sst_start_medfield(void)
105{
106 union config_status_reg csr;
107
108 csr.full = 0x04830062;
109 sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
110 csr.full = 0x04830063;
111 sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
112 csr.full = 0x04830061;
113 sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
114 pr_debug("sst: Starting the DSP_medfld\n");
115
116 return 0;
117}
118
119/**
120 * sst_parse_module - Parse audio FW modules
121 *
122 * @module: FW module header
123 *
124 * Parses modules that need to be placed in SST IRAM and DRAM
125 * returns error or 0 if module sizes are proper
126 */
127static int sst_parse_module(struct fw_module_header *module)
128{
129 struct dma_block_info *block;
130 u32 count;
131 void __iomem *ram;
132
133 pr_debug("sst: module sign %s size %x blocks %x type %x\n",
134 module->signature, module->mod_size,
135 module->blocks, module->type);
136 pr_debug("sst: module entrypoint 0x%x\n", module->entry_point);
137
138 block = (void *)module + sizeof(*module);
139
140 for (count = 0; count < module->blocks; count++) {
141 if (block->size <= 0) {
142 pr_err("sst: block size invalid\n");
143 return -EINVAL;
144 }
145 switch (block->type) {
146 case SST_IRAM:
147 ram = sst_drv_ctx->iram;
148 break;
149 case SST_DRAM:
150 ram = sst_drv_ctx->dram;
151 break;
152 default:
153 pr_err("sst: wrong ram type0x%x in block0x%x\n",
154 block->type, count);
155 return -EINVAL;
156 }
157 memcpy_toio(ram + block->ram_offset,
158 (void *)block + sizeof(*block), block->size);
159 block = (void *)block + sizeof(*block) + block->size;
160 }
161 return 0;
162}
163
164/**
165 * sst_parse_fw_image - parse and load FW
166 *
167 * @sst_fw: pointer to audio fw
168 *
169 * This function is called to parse and download the FW image
170 */
171static int sst_parse_fw_image(const struct firmware *sst_fw)
172{
173 struct fw_header *header;
174 u32 count;
175 int ret_val;
176 struct fw_module_header *module;
177
178 BUG_ON(!sst_fw);
179
180 /* Read the header information from the data pointer */
181 header = (struct fw_header *)sst_fw->data;
182
183 /* verify FW */
184 if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) ||
185 (sst_fw->size != header->file_size + sizeof(*header))) {
186 /* Invalid FW signature */
187 pr_err("sst: InvalidFW sign/filesize mismatch\n");
188 return -EINVAL;
189 }
190 pr_debug("sst: header sign=%s size=%x modules=%x fmt=%x size=%x\n",
191 header->signature, header->file_size, header->modules,
192 header->file_format, sizeof(*header));
193 module = (void *)sst_fw->data + sizeof(*header);
194 for (count = 0; count < header->modules; count++) {
195 /* module */
196 ret_val = sst_parse_module(module);
197 if (ret_val)
198 return ret_val;
199 module = (void *)module + sizeof(*module) + module->mod_size ;
200 }
201
202 return 0;
203}
204
205/**
206 * sst_load_fw - function to load FW into DSP
207 *
208 * @fw: Pointer to driver loaded FW
209 * @context: driver context
210 *
211 * This function is called by OS when the FW is loaded into kernel
212 */
213int sst_load_fw(const struct firmware *fw, void *context)
214{
215 int ret_val;
216
217 pr_debug("sst: load_fw called\n");
218 BUG_ON(!fw);
219
220 if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
221 ret_val = intel_sst_reset_dsp_mrst();
222 else if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID)
223 ret_val = intel_sst_reset_dsp_medfield();
224 if (ret_val)
225 return ret_val;
226
227 ret_val = sst_parse_fw_image(fw);
228 if (ret_val)
229 return ret_val;
230 mutex_lock(&sst_drv_ctx->sst_lock);
231 sst_drv_ctx->sst_state = SST_FW_LOADED;
232 mutex_unlock(&sst_drv_ctx->sst_lock);
233 /* 7. ask scu to reset the bypass bits */
234 /* 8.bring sst out of reset */
235 if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
236 ret_val = sst_start_mrst();
237 else if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID)
238 ret_val = sst_start_medfield();
239 if (ret_val)
240 return ret_val;
241
242 pr_debug("sst: fw loaded successful!!!\n");
243 return ret_val;
244}
245
246/*This function is called when any codec/post processing library
247 needs to be downloaded*/
248static int sst_download_library(const struct firmware *fw_lib,
249 struct snd_sst_lib_download_info *lib)
250{
251 /* send IPC message and wait */
252 int i;
253 u8 pvt_id;
254 struct ipc_post *msg = NULL;
255 union config_status_reg csr;
256 struct snd_sst_str_type str_type = {0};
257 int retval = 0;
258
259 if (sst_create_large_msg(&msg))
260 return -ENOMEM;
261
262 pvt_id = sst_assign_pvt_id(sst_drv_ctx);
263 i = sst_get_block_stream(sst_drv_ctx);
264 pr_debug("sst: alloc block allocated = %d, pvt_id %d\n", i, pvt_id);
265 if (i < 0) {
266 kfree(msg);
267 return -ENOMEM;
268 }
269 sst_drv_ctx->alloc_block[i].sst_id = pvt_id;
270 sst_fill_header(&msg->header, IPC_IA_PREP_LIB_DNLD, 1, pvt_id);
271 msg->header.part.data = sizeof(u32) + sizeof(str_type);
272 str_type.codec_type = lib->dload_lib.lib_info.lib_type;
273 /*str_type.pvt_id = pvt_id;*/
274 memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
275 memcpy(msg->mailbox_data + sizeof(u32), &str_type, sizeof(str_type));
276 spin_lock(&sst_drv_ctx->list_spin_lock);
277 list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
278 spin_unlock(&sst_drv_ctx->list_spin_lock);
279 sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
280 retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]);
281 if (retval) {
282 /* error */
283 sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
284 pr_err("sst: Prep codec downloaded failed %d\n",
285 retval);
286 return -EIO;
287 }
288 pr_debug("sst: FW responded, ready for download now...\n");
289 /* downloading on success */
290 mutex_lock(&sst_drv_ctx->sst_lock);
291 sst_drv_ctx->sst_state = SST_FW_LOADED;
292 mutex_unlock(&sst_drv_ctx->sst_lock);
293 csr.full = readl(sst_drv_ctx->shim + SST_CSR);
294 csr.part.run_stall = 1;
295 sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
296
297 csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
298 csr.part.bypass = 0x7;
299 sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
300
301 sst_parse_fw_image(fw_lib);
302
303 /* set the FW to running again */
304 csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
305 csr.part.bypass = 0x0;
306 sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
307
308 csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
309 csr.part.run_stall = 0;
310 sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
311
312 /* send download complete and wait */
313 if (sst_create_large_msg(&msg)) {
314 sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
315 return -ENOMEM;
316 }
317
318 sst_fill_header(&msg->header, IPC_IA_LIB_DNLD_CMPLT, 1, pvt_id);
319 sst_drv_ctx->alloc_block[i].sst_id = pvt_id;
320 msg->header.part.data = sizeof(u32) + sizeof(*lib);
321 lib->pvt_id = pvt_id;
322 memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
323 memcpy(msg->mailbox_data + sizeof(u32), lib, sizeof(*lib));
324 spin_lock(&sst_drv_ctx->list_spin_lock);
325 list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
326 spin_unlock(&sst_drv_ctx->list_spin_lock);
327 sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
328 pr_debug("sst: Waiting for FW response Download complete\n");
329 sst_drv_ctx->alloc_block[i].ops_block.condition = false;
330 retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]);
331 if (retval) {
332 /* error */
333 mutex_lock(&sst_drv_ctx->sst_lock);
334 sst_drv_ctx->sst_state = SST_UN_INIT;
335 mutex_unlock(&sst_drv_ctx->sst_lock);
336 sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
337 return -EIO;
338 }
339
340 pr_debug("sst: FW sucess on Download complete\n");
341 sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
342 mutex_lock(&sst_drv_ctx->sst_lock);
343 sst_drv_ctx->sst_state = SST_FW_RUNNING;
344 mutex_unlock(&sst_drv_ctx->sst_lock);
345 return 0;
346
347}
348
349/* This function is called befoer downloading the codec/postprocessing
350library is set for download to SST DSP*/
351static int sst_validate_library(const struct firmware *fw_lib,
352 struct lib_slot_info *slot,
353 u32 *entry_point)
354{
355 struct fw_header *header;
356 struct fw_module_header *module;
357 struct dma_block_info *block;
358 unsigned int n_blk, isize = 0, dsize = 0;
359 int err = 0;
360
361 header = (struct fw_header *)fw_lib->data;
362 if (header->modules != 1) {
363 pr_err("sst: Module no mismatch found\n ");
364 err = -EINVAL;
365 goto exit;
366 }
367 module = (void *)fw_lib->data + sizeof(*header);
368 *entry_point = module->entry_point;
369 pr_debug("sst: Module entry point 0x%x\n", *entry_point);
370 pr_debug("sst: Module Sign %s, Size 0x%x, Blocks 0x%x Type 0x%x\n",
371 module->signature, module->mod_size,
372 module->blocks, module->type);
373
374 block = (void *)module + sizeof(*module);
375 for (n_blk = 0; n_blk < module->blocks; n_blk++) {
376 switch (block->type) {
377 case SST_IRAM:
378 isize += block->size;
379 break;
380 case SST_DRAM:
381 dsize += block->size;
382 break;
383 default:
384 pr_err("sst: Invalid block type for 0x%x\n", n_blk);
385 err = -EINVAL;
386 goto exit;
387 }
388 block = (void *)block + sizeof(*block) + block->size;
389 }
390 if (isize > slot->iram_size || dsize > slot->dram_size) {
391 pr_err("sst: library exceeds size allocated\n");
392 err = -EINVAL;
393 goto exit;
394 } else
395 pr_debug("sst: Library is safe for download...\n");
396
397 pr_debug("sst: iram 0x%x, dram 0x%x, iram 0x%x, dram 0x%x\n",
398 isize, dsize, slot->iram_size, slot->dram_size);
399exit:
400 return err;
401
402}
403
404/* This function is called when FW requests for a particular libary download
405This function prepares the library to download*/
406int sst_load_library(struct snd_sst_lib_download *lib, u8 ops)
407{
408 char buf[20];
409 const char *type, *dir;
410 int len = 0, error = 0;
411 u32 entry_point;
412 const struct firmware *fw_lib;
413 struct snd_sst_lib_download_info dload_info = {{{0},},};
414
415 memset(buf, 0, sizeof(buf));
416
417 pr_debug("sst: Lib Type 0x%x, Slot 0x%x, ops 0x%x\n",
418 lib->lib_info.lib_type, lib->slot_info.slot_num, ops);
419 pr_debug("sst: Version 0x%x, name %s, caps 0x%x media type 0x%x\n",
420 lib->lib_info.lib_version, lib->lib_info.lib_name,
421 lib->lib_info.lib_caps, lib->lib_info.media_type);
422
423 pr_debug("sst: IRAM Size 0x%x, offset 0x%x\n",
424 lib->slot_info.iram_size, lib->slot_info.iram_offset);
425 pr_debug("sst: DRAM Size 0x%x, offset 0x%x\n",
426 lib->slot_info.dram_size, lib->slot_info.dram_offset);
427
428 switch (lib->lib_info.lib_type) {
429 case SST_CODEC_TYPE_MP3:
430 type = "mp3_";
431 break;
432 case SST_CODEC_TYPE_AAC:
433 type = "aac_";
434 break;
435 case SST_CODEC_TYPE_AACP:
436 type = "aac_v1_";
437 break;
438 case SST_CODEC_TYPE_eAACP:
439 type = "aac_v2_";
440 break;
441 case SST_CODEC_TYPE_WMA9:
442 type = "wma9_";
443 break;
444 default:
445 pr_err("sst: Invalid codec type\n");
446 error = -EINVAL;
447 goto wake;
448 }
449
450 if (ops == STREAM_OPS_CAPTURE)
451 dir = "enc_";
452 else
453 dir = "dec_";
454 len = strlen(type) + strlen(dir);
455 strncpy(buf, type, sizeof(buf)-1);
456 strncpy(buf + strlen(type), dir, sizeof(buf)-strlen(type)-1);
457 len += snprintf(buf + len, sizeof(buf) - len, "%d",
458 lib->slot_info.slot_num);
459 len += snprintf(buf + len, sizeof(buf) - len, ".bin");
460
461 pr_debug("sst: Requesting %s\n", buf);
462
463 error = request_firmware(&fw_lib, buf, &sst_drv_ctx->pci->dev);
464 if (error) {
465 pr_err("sst: library load failed %d\n", error);
466 goto wake;
467 }
468 error = sst_validate_library(fw_lib, &lib->slot_info, &entry_point);
469 if (error)
470 goto wake_free;
471
472 lib->mod_entry_pt = entry_point;
473 memcpy(&dload_info.dload_lib, lib, sizeof(*lib));
474 error = sst_download_library(fw_lib, &dload_info);
475 if (error)
476 goto wake_free;
477
478 /* lib is downloaded and init send alloc again */
479 pr_debug("sst: Library is downloaded now...\n");
480wake_free:
481 /* sst_wake_up_alloc_block(sst_drv_ctx, pvt_id, error, NULL); */
482 release_firmware(fw_lib);
483wake:
484 return error;
485}
486