1
0
Fork 0

ASoC: Intel: add pm support in sst ipc driver

This adds support for system pm support. We need to save the dsp memory
which gets lost on suspend and restore that on resume

Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
hifive-unleashed-5.1
Vinod Koul 2015-02-24 11:39:44 +05:30 committed by Mark Brown
parent 5c88b4e91d
commit 4a8448d428
2 changed files with 137 additions and 0 deletions

View File

@ -415,6 +415,83 @@ static int intel_sst_runtime_suspend(struct device *dev)
return ret;
}
static int intel_sst_suspend(struct device *dev)
{
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
struct sst_fw_save *fw_save;
int i, ret = 0;
/* check first if we are already in SW reset */
if (ctx->sst_state == SST_RESET)
return 0;
/*
* check if any stream is active and running
* they should already by suspend by soc_suspend
*/
for (i = 1; i <= ctx->info.max_streams; i++) {
struct stream_info *stream = &ctx->streams[i];
if (stream->status == STREAM_RUNNING) {
dev_err(dev, "stream %d is running, cant susupend, abort\n", i);
return -EBUSY;
}
}
synchronize_irq(ctx->irq_num);
flush_workqueue(ctx->post_msg_wq);
/* Move the SST state to Reset */
sst_set_fw_state_locked(ctx, SST_RESET);
/* tell DSP we are suspending */
if (ctx->ops->save_dsp_context(ctx))
return -EBUSY;
/* save the memories */
fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL);
if (!fw_save)
return -ENOMEM;
fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL);
if (!fw_save->iram) {
ret = -ENOMEM;
goto iram;
}
fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL);
if (!fw_save->dram) {
ret = -ENOMEM;
goto dram;
}
fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
if (!fw_save->sram) {
ret = -ENOMEM;
goto sram;
}
fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL);
if (!fw_save->ddr) {
ret = -ENOMEM;
goto ddr;
}
memcpy32_fromio(fw_save->iram, ctx->iram, ctx->iram_end - ctx->iram_base);
memcpy32_fromio(fw_save->dram, ctx->dram, ctx->dram_end - ctx->dram_base);
memcpy32_fromio(fw_save->sram, ctx->mailbox, SST_MAILBOX_SIZE);
memcpy32_fromio(fw_save->ddr, ctx->ddr, ctx->ddr_end - ctx->ddr_base);
ctx->fw_save = fw_save;
ctx->ops->reset(ctx);
return 0;
ddr:
kfree(fw_save->sram);
sram:
kfree(fw_save->dram);
dram:
kfree(fw_save->iram);
iram:
kfree(fw_save);
return ret;
}
static int intel_sst_runtime_resume(struct device *dev)
{
int ret = 0;
@ -430,7 +507,58 @@ static int intel_sst_runtime_resume(struct device *dev)
return ret;
}
static int intel_sst_resume(struct device *dev)
{
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
struct sst_fw_save *fw_save = ctx->fw_save;
int ret = 0;
struct sst_block *block;
if (!fw_save)
return intel_sst_runtime_resume(dev);
sst_set_fw_state_locked(ctx, SST_FW_LOADING);
/* we have to restore the memory saved */
ctx->ops->reset(ctx);
ctx->fw_save = NULL;
memcpy32_toio(ctx->iram, fw_save->iram, ctx->iram_end - ctx->iram_base);
memcpy32_toio(ctx->dram, fw_save->dram, ctx->dram_end - ctx->dram_base);
memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE);
memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base);
kfree(fw_save->sram);
kfree(fw_save->dram);
kfree(fw_save->iram);
kfree(fw_save->ddr);
kfree(fw_save);
block = sst_create_block(ctx, 0, FW_DWNL_ID);
if (block == NULL)
return -ENOMEM;
/* start and wait for ack */
ctx->ops->start(ctx);
ret = sst_wait_timeout(ctx, block);
if (ret) {
dev_err(ctx->dev, "fw download failed %d\n", ret);
/* FW download failed due to timeout */
ret = -EBUSY;
} else {
sst_set_fw_state_locked(ctx, SST_FW_RUNNING);
}
sst_free_block(ctx, block);
return ret;
}
const struct dev_pm_ops intel_sst_pm = {
.suspend = intel_sst_suspend,
.resume = intel_sst_resume,
.runtime_suspend = intel_sst_runtime_suspend,
.runtime_resume = intel_sst_runtime_resume,
};

View File

@ -337,6 +337,13 @@ struct sst_shim_regs64 {
u64 csr2;
};
struct sst_fw_save {
void *iram;
void *dram;
void *sram;
void *ddr;
};
/**
* struct intel_sst_drv - driver ops
*
@ -428,6 +435,8 @@ struct intel_sst_drv {
* persistent till worker thread gets called
*/
char firmware_name[FW_NAME_SIZE];
struct sst_fw_save *fw_save;
};
/* misc definitions */