2 * intel_sst_ipc.c - Intel SST Driver for audio engine
4 * Copyright (C) 2008-10 Intel Corporation
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 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
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.
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.
24 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26 * This file defines all ipc functions
29 #include <linux/pci.h>
30 #include <linux/firmware.h>
31 #include <linux/sched.h>
32 #include "intel_sst.h"
33 #include "intel_sst_ioctl.h"
34 #include "intel_sst_fw_ipc.h"
35 #include "intel_sst_common.h"
38 * sst_send_sound_card_type - send sound card type
40 * this function sends the sound card type to sst dsp engine
42 static void sst_send_sound_card_type(void)
44 struct ipc_post *msg = NULL;
46 if (sst_create_short_msg(&msg))
49 sst_fill_header(&msg->header, IPC_IA_SET_PMIC_TYPE, 0, 0);
50 msg->header.part.data = sst_drv_ctx->pmic_vendor;
51 spin_lock(&sst_drv_ctx->list_spin_lock);
52 list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
53 spin_unlock(&sst_drv_ctx->list_spin_lock);
54 sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
59 * sst_post_message - Posts message to SST
61 * @work: Pointer to work structure
63 * This function is called by any component in driver which
64 * wants to send an IPC message. This will post message only if
67 void sst_post_message(struct work_struct *work)
70 union ipc_header header;
71 union interrupt_reg imr;
75 /*To check if LPE is in stalled state.*/
76 retval = sst_stalled();
78 pr_err("sst: in stalled state\n");
81 pr_debug("sst: post message called\n");
82 spin_lock(&sst_drv_ctx->list_spin_lock);
85 if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) {
86 /* list is empty, mask imr */
87 pr_debug("sst: Empty msg queue... masking\n");
88 imr.full = readl(sst_drv_ctx->shim + SST_IMRX);
89 imr.part.done_interrupt = 1;
90 /* dummy register for shim workaround */
91 sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full);
92 spin_unlock(&sst_drv_ctx->list_spin_lock);
97 header.full = sst_shim_read(sst_drv_ctx->shim, SST_IPCX);
98 if (header.part.busy) {
100 pr_debug("sst: Busy not free... unmasking\n");
101 imr.full = readl(sst_drv_ctx->shim + SST_IMRX);
102 imr.part.done_interrupt = 0;
103 /* dummy register for shim workaround */
104 sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full);
105 spin_unlock(&sst_drv_ctx->list_spin_lock);
108 /* copy msg from list */
109 msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next,
110 struct ipc_post, node);
111 list_del(&msg->node);
112 pr_debug("sst: Post message: header = %x\n", msg->header.full);
113 pr_debug("sst: size: = %x\n", msg->header.part.data);
114 if (msg->header.part.large)
115 memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND,
116 msg->mailbox_data, msg->header.part.data);
117 /* dummy register for shim workaround */
119 sst_shim_write(sst_drv_ctx->shim, SST_IPCX, msg->header.full);
120 spin_unlock(&sst_drv_ctx->list_spin_lock);
122 kfree(msg->mailbox_data);
128 * sst_clear_interrupt - clear the SST FW interrupt
130 * This function clears the interrupt register after the interrupt
131 * bottom half is complete allowing next interrupt to arrive
133 void sst_clear_interrupt(void)
135 union interrupt_reg isr;
136 union interrupt_reg imr;
137 union ipc_header clear_ipc;
139 imr.full = sst_shim_read(sst_drv_ctx->shim, SST_IMRX);
140 isr.full = sst_shim_read(sst_drv_ctx->shim, SST_ISRX);
141 /* write 1 to clear */;
142 isr.part.busy_interrupt = 1;
143 sst_shim_write(sst_drv_ctx->shim, SST_ISRX, isr.full);
144 /* Set IA done bit */
145 clear_ipc.full = sst_shim_read(sst_drv_ctx->shim, SST_IPCD);
146 clear_ipc.part.busy = 0;
147 clear_ipc.part.done = 1;
148 clear_ipc.part.data = IPC_ACK_SUCCESS;
149 sst_shim_write(sst_drv_ctx->shim, SST_IPCD, clear_ipc.full);
150 /* un mask busy interrupt */
151 imr.part.busy_interrupt = 0;
152 sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full);
156 * process_fw_init - process the FW init msg
158 * @msg: IPC message from FW
160 * This function processes the FW init msg from FW
161 * marks FW state and prints debug info of loaded FW
163 int process_fw_init(struct sst_ipc_msg_wq *msg)
165 struct ipc_header_fw_init *init =
166 (struct ipc_header_fw_init *)msg->mailbox;
169 pr_debug("sst: *** FW Init msg came***\n");
171 mutex_lock(&sst_drv_ctx->sst_lock);
172 sst_drv_ctx->sst_state = SST_ERROR;
173 mutex_unlock(&sst_drv_ctx->sst_lock);
174 pr_debug("sst: FW Init failed, Error %x\n", init->result);
175 pr_err("sst: FW Init failed, Error %x\n", init->result);
176 retval = -init->result;
179 if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
180 sst_send_sound_card_type();
181 mutex_lock(&sst_drv_ctx->sst_lock);
182 sst_drv_ctx->sst_state = SST_FW_RUNNING;
183 mutex_unlock(&sst_drv_ctx->sst_lock);
184 pr_debug("sst: FW Version %x.%x\n",
185 init->fw_version.major, init->fw_version.minor);
186 pr_debug("sst: Build No %x Type %x\n",
187 init->fw_version.build, init->fw_version.type);
188 pr_debug("sst: Build date %s Time %s\n",
189 init->build_info.date, init->build_info.time);
190 sst_wake_up_alloc_block(sst_drv_ctx, FW_DWNL_ID, retval, NULL);
194 * sst_process_message - Processes message from SST
196 * @work: Pointer to work structure
198 * This function is scheduled by ISR
199 * It take a msg from process_queue and does action based on msg
201 void sst_process_message(struct work_struct *work)
203 struct sst_ipc_msg_wq *msg =
204 container_of(work, struct sst_ipc_msg_wq, wq);
205 int str_id = msg->header.part.str_id;
207 pr_debug("sst: IPC process for %x\n", msg->header.full);
209 /* based on msg in list call respective handler */
210 switch (msg->header.part.msg_id) {
211 case IPC_SST_BUF_UNDER_RUN:
212 case IPC_SST_BUF_OVER_RUN:
213 if (sst_validate_strid(str_id)) {
214 pr_err("sst: stream id %d invalid\n", str_id);
217 pr_err("sst: Buffer under/overrun for%d\n",
218 msg->header.part.str_id);
219 pr_err("sst: Got Underrun & not to send data...ignore\n");
222 case IPC_SST_GET_PLAY_FRAMES:
223 if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
224 struct stream_info *stream ;
226 if (sst_validate_strid(str_id)) {
227 pr_err("sst: strid %d invalid\n", str_id);
230 /* call sst_play_frame */
231 stream = &sst_drv_ctx->streams[str_id];
232 pr_debug("sst: sst_play_frames for %d\n",
233 msg->header.part.str_id);
234 mutex_lock(&sst_drv_ctx->streams[str_id].lock);
235 sst_play_frame(msg->header.part.str_id);
236 mutex_unlock(&sst_drv_ctx->streams[str_id].lock);
239 pr_err("sst: sst_play_frames for Penwell!!\n");
241 case IPC_SST_GET_CAPT_FRAMES:
242 if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
243 struct stream_info *stream;
244 /* call sst_capture_frame */
245 if (sst_validate_strid(str_id)) {
246 pr_err("sst: str id %d invalid\n", str_id);
249 stream = &sst_drv_ctx->streams[str_id];
250 pr_debug("sst: sst_capture_frames for %d\n",
251 msg->header.part.str_id);
252 mutex_lock(&stream->lock);
253 if (stream->mmapped == false &&
254 stream->src == SST_DRV) {
255 pr_debug("sst: waking up block for copy.\n");
256 stream->data_blk.ret_code = 0;
257 stream->data_blk.condition = true;
258 stream->data_blk.on = false;
259 wake_up(&sst_drv_ctx->wait_queue);
261 sst_capture_frame(msg->header.part.str_id);
262 mutex_unlock(&stream->lock);
264 pr_err("sst: sst_play_frames for Penwell!!\n");
267 case IPC_IA_PRINT_STRING:
268 pr_debug("sst: been asked to print something by fw\n");
272 case IPC_IA_FW_INIT_CMPLT: {
273 /* send next data to FW */
274 process_fw_init(msg);
278 case IPC_SST_STREAM_PROCESS_FATAL_ERR:
279 if (sst_validate_strid(str_id)) {
280 pr_err("sst: stream id %d invalid\n", str_id);
283 pr_err("sst: codec fatal error %x stream %d...\n",
284 msg->header.full, msg->header.part.str_id);
285 pr_err("sst: Dropping the stream\n");
286 sst_drop_stream(msg->header.part.str_id);
288 case IPC_IA_LPE_GETTING_STALLED:
289 sst_drv_ctx->lpe_stalled = 1;
291 case IPC_IA_LPE_UNSTALLED:
292 sst_drv_ctx->lpe_stalled = 0;
296 pr_err("sst: Unhandled msg %x header %x\n",
297 msg->header.part.msg_id, msg->header.full);
299 sst_clear_interrupt();
304 * sst_process_reply - Processes reply message from SST
306 * @work: Pointer to work structure
308 * This function is scheduled by ISR
309 * It take a reply msg from response_queue and
310 * does action based on msg
312 void sst_process_reply(struct work_struct *work)
314 struct sst_ipc_msg_wq *msg =
315 container_of(work, struct sst_ipc_msg_wq, wq);
317 int str_id = msg->header.part.str_id;
318 struct stream_info *str_info;
320 switch (msg->header.part.msg_id) {
321 case IPC_IA_TARGET_DEV_SELECT:
322 if (!msg->header.part.data) {
323 sst_drv_ctx->tgt_dev_blk.ret_code = 0;
325 pr_err("sst: Msg %x reply error %x\n",
326 msg->header.part.msg_id, msg->header.part.data);
327 sst_drv_ctx->tgt_dev_blk.ret_code =
328 -msg->header.part.data;
331 if (sst_drv_ctx->tgt_dev_blk.on == true) {
332 sst_drv_ctx->tgt_dev_blk.condition = true;
333 wake_up(&sst_drv_ctx->wait_queue);
336 case IPC_IA_GET_FW_INFO: {
337 struct snd_sst_fw_info *fw_info =
338 (struct snd_sst_fw_info *)msg->mailbox;
339 if (msg->header.part.large) {
340 int major = fw_info->fw_version.major;
341 int minor = fw_info->fw_version.minor;
342 int build = fw_info->fw_version.build;
343 pr_debug("sst: Msg succedded %x\n",
344 msg->header.part.msg_id);
345 pr_debug("INFO: ***FW*** = %02d.%02d.%02d\n",
346 major, minor, build);
347 memcpy_fromio(sst_drv_ctx->fw_info_blk.data,
348 ((struct snd_sst_fw_info *)(msg->mailbox)),
349 sizeof(struct snd_sst_fw_info));
350 sst_drv_ctx->fw_info_blk.ret_code = 0;
352 pr_err("sst: Msg %x reply error %x\n",
353 msg->header.part.msg_id, msg->header.part.data);
354 sst_drv_ctx->fw_info_blk.ret_code =
355 -msg->header.part.data;
357 if (sst_drv_ctx->fw_info_blk.on == true) {
358 pr_debug("sst: Memcopy succedded\n");
359 sst_drv_ctx->fw_info_blk.on = false;
360 sst_drv_ctx->fw_info_blk.condition = true;
361 wake_up(&sst_drv_ctx->wait_queue);
365 case IPC_IA_SET_STREAM_MUTE:
366 if (!msg->header.part.data) {
367 pr_debug("sst: Msg succedded %x\n",
368 msg->header.part.msg_id);
369 sst_drv_ctx->mute_info_blk.ret_code = 0;
371 pr_err("sst: Msg %x reply error %x\n",
372 msg->header.part.msg_id, msg->header.part.data);
373 sst_drv_ctx->mute_info_blk.ret_code =
374 -msg->header.part.data;
377 if (sst_drv_ctx->mute_info_blk.on == true) {
378 sst_drv_ctx->mute_info_blk.on = false;
379 sst_drv_ctx->mute_info_blk.condition = true;
380 wake_up(&sst_drv_ctx->wait_queue);
383 case IPC_IA_SET_STREAM_VOL:
384 if (!msg->header.part.data) {
385 pr_debug("sst: Msg succedded %x\n",
386 msg->header.part.msg_id);
387 sst_drv_ctx->vol_info_blk.ret_code = 0;
389 pr_err("sst: Msg %x reply error %x\n",
390 msg->header.part.msg_id,
391 msg->header.part.data);
392 sst_drv_ctx->vol_info_blk.ret_code =
393 -msg->header.part.data;
397 if (sst_drv_ctx->vol_info_blk.on == true) {
398 sst_drv_ctx->vol_info_blk.on = false;
399 sst_drv_ctx->vol_info_blk.condition = true;
400 wake_up(&sst_drv_ctx->wait_queue);
403 case IPC_IA_GET_STREAM_VOL:
404 if (msg->header.part.large) {
405 pr_debug("sst: Large Msg Received Successfully\n");
406 pr_debug("sst: Msg succedded %x\n",
407 msg->header.part.msg_id);
408 memcpy_fromio(sst_drv_ctx->vol_info_blk.data,
409 (void *) msg->mailbox,
410 sizeof(struct snd_sst_vol));
411 sst_drv_ctx->vol_info_blk.ret_code = 0;
413 pr_err("sst: Msg %x reply error %x\n",
414 msg->header.part.msg_id, msg->header.part.data);
415 sst_drv_ctx->vol_info_blk.ret_code =
416 -msg->header.part.data;
418 if (sst_drv_ctx->vol_info_blk.on == true) {
419 sst_drv_ctx->vol_info_blk.on = false;
420 sst_drv_ctx->vol_info_blk.condition = true;
421 wake_up(&sst_drv_ctx->wait_queue);
425 case IPC_IA_GET_STREAM_PARAMS:
426 if (sst_validate_strid(str_id)) {
427 pr_err("sst: stream id %d invalid\n", str_id);
430 str_info = &sst_drv_ctx->streams[str_id];
431 if (msg->header.part.large) {
432 pr_debug("sst: Get stream large success\n");
433 memcpy_fromio(str_info->ctrl_blk.data,
434 ((void *)(msg->mailbox)),
435 sizeof(struct snd_sst_fw_get_stream_params));
436 str_info->ctrl_blk.ret_code = 0;
438 pr_err("sst: Msg %x reply error %x\n",
439 msg->header.part.msg_id, msg->header.part.data);
440 str_info->ctrl_blk.ret_code = -msg->header.part.data;
442 if (str_info->ctrl_blk.on == true) {
443 str_info->ctrl_blk.on = false;
444 str_info->ctrl_blk.condition = true;
445 wake_up(&sst_drv_ctx->wait_queue);
448 case IPC_IA_DECODE_FRAMES:
449 if (sst_validate_strid(str_id)) {
450 pr_err("sst: stream id %d invalid\n", str_id);
453 str_info = &sst_drv_ctx->streams[str_id];
454 if (msg->header.part.large) {
455 pr_debug("sst: Msg succedded %x\n",
456 msg->header.part.msg_id);
457 memcpy_fromio(str_info->data_blk.data,
458 ((void *)(msg->mailbox)),
459 sizeof(struct snd_sst_decode_info));
460 str_info->data_blk.ret_code = 0;
462 pr_err("sst: Msg %x reply error %x\n",
463 msg->header.part.msg_id, msg->header.part.data);
464 str_info->data_blk.ret_code = -msg->header.part.data;
466 if (str_info->data_blk.on == true) {
467 str_info->data_blk.on = false;
468 str_info->data_blk.condition = true;
469 wake_up(&sst_drv_ctx->wait_queue);
472 case IPC_IA_DRAIN_STREAM:
473 if (sst_validate_strid(str_id)) {
474 pr_err("sst: stream id %d invalid\n", str_id);
477 str_info = &sst_drv_ctx->streams[str_id];
478 if (!msg->header.part.data) {
479 pr_debug("sst: Msg succedded %x\n",
480 msg->header.part.msg_id);
481 str_info->ctrl_blk.ret_code = 0;
484 pr_err("sst: Msg %x reply error %x\n",
485 msg->header.part.msg_id, msg->header.part.data);
486 str_info->ctrl_blk.ret_code = -msg->header.part.data;
489 str_info = &sst_drv_ctx->streams[str_id];
490 if (str_info->data_blk.on == true) {
491 str_info->data_blk.on = false;
492 str_info->data_blk.condition = true;
493 wake_up(&sst_drv_ctx->wait_queue);
497 case IPC_IA_DROP_STREAM:
498 if (sst_validate_strid(str_id)) {
499 pr_err("sst: str id %d invalid\n", str_id);
502 str_info = &sst_drv_ctx->streams[str_id];
503 if (msg->header.part.large) {
504 struct snd_sst_drop_response *drop_resp =
505 (struct snd_sst_drop_response *)msg->mailbox;
507 pr_debug("sst: Drop ret bytes %x\n", drop_resp->bytes);
509 str_info->curr_bytes = drop_resp->bytes;
510 str_info->ctrl_blk.ret_code = 0;
512 pr_err("sst: Msg %x reply error %x\n",
513 msg->header.part.msg_id, msg->header.part.data);
514 str_info->ctrl_blk.ret_code = -msg->header.part.data;
516 if (str_info->ctrl_blk.on == true) {
517 str_info->ctrl_blk.on = false;
518 str_info->ctrl_blk.condition = true;
519 wake_up(&sst_drv_ctx->wait_queue);
522 case IPC_IA_ENABLE_RX_TIME_SLOT:
523 if (!msg->header.part.data) {
524 pr_debug("sst: RX_TIME_SLOT success\n");
525 sst_drv_ctx->hs_info_blk.ret_code = 0;
527 pr_err("sst: Msg %x reply error %x\n",
528 msg->header.part.msg_id,
529 msg->header.part.data);
530 sst_drv_ctx->hs_info_blk.ret_code =
531 -msg->header.part.data;
533 if (sst_drv_ctx->hs_info_blk.on == true) {
534 sst_drv_ctx->hs_info_blk.on = false;
535 sst_drv_ctx->hs_info_blk.condition = true;
536 wake_up(&sst_drv_ctx->wait_queue);
539 case IPC_IA_PAUSE_STREAM:
540 case IPC_IA_RESUME_STREAM:
541 case IPC_IA_SET_STREAM_PARAMS:
542 str_info = &sst_drv_ctx->streams[str_id];
543 if (!msg->header.part.data) {
544 pr_debug("sst: Msg succedded %x\n",
545 msg->header.part.msg_id);
546 str_info->ctrl_blk.ret_code = 0;
548 pr_err("sst: Msg %x reply error %x\n",
549 msg->header.part.msg_id,
550 msg->header.part.data);
551 str_info->ctrl_blk.ret_code = -msg->header.part.data;
553 if (sst_validate_strid(str_id)) {
554 pr_err("sst: stream id %d invalid\n", str_id);
558 if (str_info->ctrl_blk.on == true) {
559 str_info->ctrl_blk.on = false;
560 str_info->ctrl_blk.condition = true;
561 wake_up(&sst_drv_ctx->wait_queue);
565 case IPC_IA_FREE_STREAM:
566 if (!msg->header.part.data) {
567 pr_debug("sst: Stream %d freed\n", str_id);
569 pr_err("sst: Free for %d ret error %x\n",
570 str_id, msg->header.part.data);
573 case IPC_IA_ALLOC_STREAM: {
574 /* map to stream, call play */
575 struct snd_sst_alloc_response *resp =
576 (struct snd_sst_alloc_response *)msg->mailbox;
577 if (resp->str_type.result)
578 pr_err("sst: error alloc stream = %x\n",
579 resp->str_type.result);
580 sst_alloc_stream_response(str_id, resp);
584 case IPC_IA_PLAY_FRAMES:
585 case IPC_IA_CAPT_FRAMES:
586 if (sst_validate_strid(str_id)) {
587 pr_err("sst: stream id %d invalid\n" , str_id);
590 pr_debug("sst: Ack for play/capt frames recived\n");
593 case IPC_IA_PREP_LIB_DNLD: {
594 struct snd_sst_str_type *str_type =
595 (struct snd_sst_str_type *)msg->mailbox;
596 pr_debug("sst: Prep Lib download %x\n",
597 msg->header.part.msg_id);
598 if (str_type->result)
599 pr_err("sst: Prep lib download %x\n", str_type->result);
601 pr_debug("sst: Can download codec now...\n");
602 sst_wake_up_alloc_block(sst_drv_ctx, str_id,
603 str_type->result, NULL);
607 case IPC_IA_LIB_DNLD_CMPLT: {
608 struct snd_sst_lib_download_info *resp =
609 (struct snd_sst_lib_download_info *)msg->mailbox;
610 int retval = resp->result;
612 pr_debug("sst: Lib downloaded %x\n", msg->header.part.msg_id);
614 pr_err("sst: err in lib dload %x\n", resp->result);
616 pr_debug("sst: Codec download complete...\n");
617 pr_debug("sst: codec Type %d Ver %d Built %s: %s\n",
618 resp->dload_lib.lib_info.lib_type,
619 resp->dload_lib.lib_info.lib_version,
620 resp->dload_lib.lib_info.b_date,
621 resp->dload_lib.lib_info.b_time);
623 sst_wake_up_alloc_block(sst_drv_ctx, str_id,
628 case IPC_IA_GET_FW_VERSION: {
629 struct ipc_header_fw_init *version =
630 (struct ipc_header_fw_init *)msg->mailbox;
631 int major = version->fw_version.major;
632 int minor = version->fw_version.minor;
633 int build = version->fw_version.build;
634 dev_info(&sst_drv_ctx->pci->dev,
635 "INFO: ***LOADED SST FW VERSION*** = %02d.%02d.%02d\n",
636 major, minor, build);
639 case IPC_IA_GET_FW_BUILD_INF: {
640 struct sst_fw_build_info *build =
641 (struct sst_fw_build_info *)msg->mailbox;
642 pr_debug("sst: Build date:%sTime:%s", build->date, build->time);
645 case IPC_IA_SET_PMIC_TYPE:
647 case IPC_IA_START_STREAM:
648 pr_debug("sst: reply for START STREAM %x\n", msg->header.full);
652 pr_err("sst: process reply:default = %x\n", msg->header.full);
654 sst_clear_interrupt();