if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
ret = misc_register(&lpe_dev);
if (ret) {
- pr_err("couldn't register misc driver\n");
+ pr_err("couldn't register LPE device\n");
goto do_free_misc;
}
+ } else if (sst_drv_ctx->pci_id == SST_MFLD_PCI_ID) {
+ u32 csr;
+
+ /*allocate mem for fw context save during suspend*/
+ sst_drv_ctx->fw_cntx = kzalloc(FW_CONTEXT_MEM, GFP_KERNEL);
+ if (!sst_drv_ctx->fw_cntx) {
+ ret = -ENOMEM;
+ goto do_free_misc;
+ }
+ /*setting zero as that is valid mem to restore*/
+ sst_drv_ctx->fw_cntx_size = 0;
+
+ /*set lpe start clock and ram size*/
+ csr = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr |= 0x30060; /*remove the clock ratio after fw fix*/
+ sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr);
}
sst_drv_ctx->lpe_stalled = 0;
pm_runtime_set_active(&pci->dev);
sst_drv_ctx->sst_state = SST_UN_INIT;
mutex_unlock(&sst_drv_ctx->sst_lock);
misc_deregister(&lpe_ctrl);
- if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
- misc_deregister(&lpe_dev);
free_irq(pci->irq, sst_drv_ctx);
iounmap(sst_drv_ctx->dram);
iounmap(sst_drv_ctx->iram);
iounmap(sst_drv_ctx->mailbox);
iounmap(sst_drv_ctx->shim);
sst_drv_ctx->pmic_state = SND_MAD_UN_INIT;
- if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
+ if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
+ misc_deregister(&lpe_dev);
kfree(sst_drv_ctx->mmap_mem);
+ } else
+ kfree(sst_drv_ctx->fw_cntx);
flush_scheduled_work();
destroy_workqueue(sst_drv_ctx->process_reply_wq);
destroy_workqueue(sst_drv_ctx->process_msg_wq);
pci_set_drvdata(pci, NULL);
}
+void sst_save_dsp_context(void)
+{
+ struct snd_sst_ctxt_params fw_context;
+ unsigned int pvt_id, i;
+ struct ipc_post *msg = NULL;
+
+ /*check cpu type*/
+ if (sst_drv_ctx->pci_id != SST_MFLD_PCI_ID)
+ return;
+ /*not supported for rest*/
+ if (sst_drv_ctx->sst_state != SST_FW_RUNNING) {
+ pr_debug("fw not running no context save ...\n");
+ return;
+ }
+
+ /*send msg to fw*/
+ if (sst_create_large_msg(&msg))
+ return;
+ pvt_id = sst_assign_pvt_id(sst_drv_ctx);
+ i = sst_get_block_stream(sst_drv_ctx);
+ sst_drv_ctx->alloc_block[i].sst_id = pvt_id;
+ sst_fill_header(&msg->header, IPC_IA_GET_FW_CTXT, 1, pvt_id);
+ msg->header.part.data = sizeof(fw_context) + sizeof(u32);
+ fw_context.address = virt_to_phys((void *)sst_drv_ctx->fw_cntx);
+ fw_context.size = FW_CONTEXT_MEM;
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32),
+ &fw_context, sizeof(fw_context));
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ /*wait for reply*/
+ if (sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]))
+ pr_debug("err fw context save timeout ...\n");
+ sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
+ pr_debug("fw context saved ...\n");
+ return;
+}
+
/* Power Management */
/*
* intel_sst_suspend - PCI suspend function
pr_err("active streams,not able to suspend\n");
return -EBUSY;
}
+ /*save fw context*/
+ sst_save_dsp_context();
/*Assert RESET on LPE Processor*/
csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
csr.full = csr.full | 0x2;
* Common private declarations for SST
*/
-#define SST_DRIVER_VERSION "1.2.09"
-#define SST_VERSION_NUM 0x1209
+#define SST_DRIVER_VERSION "1.2.11"
+#define SST_VERSION_NUM 0x1211
/* driver names */
#define SST_DRV_NAME "intel_sst_driver"
#define SST_MFLD_PCI_ID 0x082F
#define PCI_ID_LENGTH 4
#define SST_SUSPEND_DELAY 2000
+#define FW_CONTEXT_MEM (64*1024)
enum sst_states {
SST_FW_LOADED = 1,
/* SST shim registers to structure mapping */
union config_status_reg {
struct {
- u32 rsvd0:1;
+ u32 mfld_strb:1;
u32 sst_reset:1;
u32 hw_rsvd:3;
u32 sst_clk:2;
unsigned int audio_start;
dev_t devt_d, devt_c;
unsigned int max_streams;
+ unsigned int *fw_cntx;
+ unsigned int fw_cntx_size;
};
extern struct intel_sst_drv *sst_drv_ctx;
sst_drv_ctx->pmic_state = SND_MAD_INIT_DONE;
sst_drv_ctx->rx_time_slot_status = 0; /*default AMIC*/
card->pcm_control = sst_pmic_ops.pcm_control;
+ sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
return 0;
} else {
pr_err("strcmp fail %s\n", card->module_name);
pr_err("Repeat for registration..denied\n");
return -EBADRQC;
}
+ sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
return 0;
}
EXPORT_SYMBOL_GPL(register_sst_card);
union config_status_reg csr;
pr_debug("Resetting the DSP in medfield\n");
- csr.full = 0x048303E2;
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.full |= 0x382;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
return 0;
{
union config_status_reg csr;
- csr.full = 0x04830062;
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.part.bypass = 0;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
- csr.full = 0x04830063;
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.part.mfld_strb = 1;
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
- csr.full = 0x04830061;
+ csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
+ csr.part.run_stall = 0;
+ csr.part.sst_reset = 0;
+ pr_debug("Starting the DSP_medfld %x\n", csr.full);
sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
pr_debug("Starting the DSP_medfld\n");
#define IPC_IA_GET_FW_VERSION 0x04
#define IPC_IA_GET_FW_BUILD_INF 0x05
#define IPC_IA_GET_FW_INFO 0x06
+#define IPC_IA_GET_FW_CTXT 0x07
+#define IPC_IA_SET_FW_CTXT 0x08
/* I2L Codec Config/control msgs */
#define IPC_IA_SET_CODEC_PARAMS 0x10
char *mailbox_data;
};
+struct snd_sst_ctxt_params {
+ u32 address; /* Physical Address in DDR where the context is stored */
+ u32 size; /* size of the context */
+};
#endif /* __INTEL_SST_FW_IPC_H__ */
sst_shim_write(sst_drv_ctx->shim, SST_IMRX, imr.full);
}
+void sst_restore_fw_context(void)
+{
+ struct snd_sst_ctxt_params fw_context;
+ struct ipc_post *msg = NULL;
+
+ pr_debug("restore_fw_context\n");
+ /*check cpu type*/
+ if (sst_drv_ctx->pci_id != SST_MFLD_PCI_ID)
+ return;
+ /*not supported for rest*/
+ if (!sst_drv_ctx->fw_cntx_size)
+ return;
+ /*nothing to restore*/
+ pr_debug("restoring context......\n");
+ /*send msg to fw*/
+ if (sst_create_large_msg(&msg))
+ return;
+
+ sst_fill_header(&msg->header, IPC_IA_SET_FW_CTXT, 1, 0);
+ msg->header.part.data = sizeof(fw_context) + sizeof(u32);
+ fw_context.address = virt_to_phys((void *)sst_drv_ctx->fw_cntx);
+ fw_context.size = sst_drv_ctx->fw_cntx_size;
+ memcpy(msg->mailbox_data, &msg->header, sizeof(u32));
+ memcpy(msg->mailbox_data + sizeof(u32),
+ &fw_context, sizeof(fw_context));
+ spin_lock(&sst_drv_ctx->list_spin_lock);
+ list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
+ spin_unlock(&sst_drv_ctx->list_spin_lock);
+ sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
+ return;
+}
/*
* process_fw_init - process the FW init msg
*
sst_drv_ctx->sst_state = SST_FW_RUNNING;
sst_drv_ctx->lpe_stalled = 0;
mutex_unlock(&sst_drv_ctx->sst_lock);
- pr_debug("FW Version %x.%x\n",
- init->fw_version.major, init->fw_version.minor);
- pr_debug("Build No %x Type %x\n",
- init->fw_version.build, init->fw_version.type);
+ pr_debug("FW Version %02x.%02x.%02x\n", init->fw_version.major,
+ init->fw_version.minor, init->fw_version.build);
+ pr_debug("Build Type %x\n", init->fw_version.type);
pr_debug(" Build date %s Time %s\n",
init->build_info.date, init->build_info.time);
sst_wake_up_alloc_block(sst_drv_ctx, FW_DWNL_ID, retval, NULL);
+ sst_restore_fw_context();
return retval;
}
/**
break;
case IPC_IA_FREE_STREAM:
+ str_info = &sst_drv_ctx->streams[str_id];
if (!msg->header.part.data) {
pr_debug("Stream %d freed\n", str_id);
} else {
pr_err("Free for %d ret error %x\n",
str_id, msg->header.part.data);
}
+ if (str_info->ctrl_blk.on == true) {
+ str_info->ctrl_blk.on = false;
+ str_info->ctrl_blk.condition = true;
+ wake_up(&sst_drv_ctx->wait_queue);
+ }
break;
case IPC_IA_ALLOC_STREAM: {
/* map to stream, call play */
case IPC_IA_START_STREAM:
pr_debug("reply for START STREAM %x\n", msg->header.full);
break;
+
+ case IPC_IA_GET_FW_CTXT:
+ pr_debug("reply for get fw ctxt %x\n", msg->header.full);
+ if (msg->header.part.data)
+ sst_drv_ctx->fw_cntx_size = 0;
+ else
+ sst_drv_ctx->fw_cntx_size = *sst_drv_ctx->fw_cntx;
+ pr_debug("fw copied data %x\n", sst_drv_ctx->fw_cntx_size);
+ sst_wake_up_alloc_block(
+ sst_drv_ctx, str_id, msg->header.part.data, NULL);
+ break;
default:
/* Illegal case */
pr_err("process reply:default = %x\n", msg->header.full);
#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/sched.h>
+#include <linux/delay.h>
#include "intel_sst_ioctl.h"
#include "intel_sst.h"
#include "intel_sst_fw_ipc.h"
str_info->data_blk.on = true;
retval = sst_wait_interruptible(sst_drv_ctx, &str_info->data_blk);
str_info->need_draining = false;
- if (retval == -SST_ERR_INVALID_STREAM_ID) {
- retval = -EINVAL;
- sst_clean_stream(str_info);
- }
return retval;
}
str_info->data_blk.ret_code = 0;
wake_up(&sst_drv_ctx->wait_queue);
}
+ str_info->data_blk.on = true;
+ str_info->data_blk.condition = false;
+ retval = sst_wait_interruptible_timeout(sst_drv_ctx,
+ &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
+ pr_debug("wait for free returned %d\n", retval);
+ msleep(100);
mutex_lock(&sst_drv_ctx->stream_lock);
sst_clean_stream(str_info);
mutex_unlock(&sst_drv_ctx->stream_lock);
pr_err("SST_Activate_target_fail\n");
else
pr_err("SST_Activate_target_pass\n");
- return retval;
} else if (slot->action == SND_SST_PORT_PREPARE &&
slot->device_type == SND_SST_DEVICE_PCM) {
retval = sst_prepare_target(slot);
pr_err("SST_prepare_target_fail\n");
else
pr_err("SST_prepare_target_pass\n");
- return retval;
} else {
pr_err("slot_action : %d, device_type: %d\n",
slot->action, slot->device_type);
- return retval;
}
+ return retval;
}
int sst_send_target(struct snd_sst_target_device *target)
int *input_index, int *in_copied,
int *input_index_valid_size, int *new_entry_flag)
{
- int retval = 0;
- int i;
+ int retval = 0, i;
if (str_info->ops == STREAM_OPS_PLAYBACK_DRM) {
struct RAR_buffer rar_buffers;
return retval;
}
#endif
-
/*This function is used to prepare the kernel input buffers with contents
before sending for decode*/
static int sst_prepare_input_buffers(struct stream_info *str_info,
pr_err("sst card registration failed\n");
return ret_val;
}
- sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
-
sst_card_vendor_id = intelmaddata->sstdrv_ops->vendor_id;
intelmaddata->pmic_status = PMIC_UNINIT;
return ret_val;