aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/intel/sst/sst.c128
-rw-r--r--sound/soc/intel/sst/sst.h9
2 files changed, 137 insertions, 0 deletions
diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c
index 8a8d56a146e7..8f938112a01f 100644
--- a/sound/soc/intel/sst/sst.c
+++ b/sound/soc/intel/sst/sst.c
@@ -415,6 +415,83 @@ static int intel_sst_runtime_suspend(struct device *dev)
415 return ret; 415 return ret;
416} 416}
417 417
418static int intel_sst_suspend(struct device *dev)
419{
420 struct intel_sst_drv *ctx = dev_get_drvdata(dev);
421 struct sst_fw_save *fw_save;
422 int i, ret = 0;
423
424 /* check first if we are already in SW reset */
425 if (ctx->sst_state == SST_RESET)
426 return 0;
427
428 /*
429 * check if any stream is active and running
430 * they should already by suspend by soc_suspend
431 */
432 for (i = 1; i <= ctx->info.max_streams; i++) {
433 struct stream_info *stream = &ctx->streams[i];
434
435 if (stream->status == STREAM_RUNNING) {
436 dev_err(dev, "stream %d is running, cant susupend, abort\n", i);
437 return -EBUSY;
438 }
439 }
440 synchronize_irq(ctx->irq_num);
441 flush_workqueue(ctx->post_msg_wq);
442
443 /* Move the SST state to Reset */
444 sst_set_fw_state_locked(ctx, SST_RESET);
445
446 /* tell DSP we are suspending */
447 if (ctx->ops->save_dsp_context(ctx))
448 return -EBUSY;
449
450 /* save the memories */
451 fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL);
452 if (!fw_save)
453 return -ENOMEM;
454 fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL);
455 if (!fw_save->iram) {
456 ret = -ENOMEM;
457 goto iram;
458 }
459 fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL);
460 if (!fw_save->dram) {
461 ret = -ENOMEM;
462 goto dram;
463 }
464 fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
465 if (!fw_save->sram) {
466 ret = -ENOMEM;
467 goto sram;
468 }
469
470 fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL);
471 if (!fw_save->ddr) {
472 ret = -ENOMEM;
473 goto ddr;
474 }
475
476 memcpy32_fromio(fw_save->iram, ctx->iram, ctx->iram_end - ctx->iram_base);
477 memcpy32_fromio(fw_save->dram, ctx->dram, ctx->dram_end - ctx->dram_base);
478 memcpy32_fromio(fw_save->sram, ctx->mailbox, SST_MAILBOX_SIZE);
479 memcpy32_fromio(fw_save->ddr, ctx->ddr, ctx->ddr_end - ctx->ddr_base);
480
481 ctx->fw_save = fw_save;
482 ctx->ops->reset(ctx);
483 return 0;
484ddr:
485 kfree(fw_save->sram);
486sram:
487 kfree(fw_save->dram);
488dram:
489 kfree(fw_save->iram);
490iram:
491 kfree(fw_save);
492 return ret;
493}
494
418static int intel_sst_runtime_resume(struct device *dev) 495static int intel_sst_runtime_resume(struct device *dev)
419{ 496{
420 int ret = 0; 497 int ret = 0;
@@ -430,7 +507,58 @@ static int intel_sst_runtime_resume(struct device *dev)
430 return ret; 507 return ret;
431} 508}
432 509
510static int intel_sst_resume(struct device *dev)
511{
512 struct intel_sst_drv *ctx = dev_get_drvdata(dev);
513 struct sst_fw_save *fw_save = ctx->fw_save;
514 int ret = 0;
515 struct sst_block *block;
516
517 if (!fw_save)
518 return intel_sst_runtime_resume(dev);
519
520 sst_set_fw_state_locked(ctx, SST_FW_LOADING);
521
522 /* we have to restore the memory saved */
523 ctx->ops->reset(ctx);
524
525 ctx->fw_save = NULL;
526
527 memcpy32_toio(ctx->iram, fw_save->iram, ctx->iram_end - ctx->iram_base);
528 memcpy32_toio(ctx->dram, fw_save->dram, ctx->dram_end - ctx->dram_base);
529 memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE);
530 memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base);
531
532 kfree(fw_save->sram);
533 kfree(fw_save->dram);
534 kfree(fw_save->iram);
535 kfree(fw_save->ddr);
536 kfree(fw_save);
537
538 block = sst_create_block(ctx, 0, FW_DWNL_ID);
539 if (block == NULL)
540 return -ENOMEM;
541
542
543 /* start and wait for ack */
544 ctx->ops->start(ctx);
545 ret = sst_wait_timeout(ctx, block);
546 if (ret) {
547 dev_err(ctx->dev, "fw download failed %d\n", ret);
548 /* FW download failed due to timeout */
549 ret = -EBUSY;
550
551 } else {
552 sst_set_fw_state_locked(ctx, SST_FW_RUNNING);
553 }
554
555 sst_free_block(ctx, block);
556 return ret;
557}
558
433const struct dev_pm_ops intel_sst_pm = { 559const struct dev_pm_ops intel_sst_pm = {
560 .suspend = intel_sst_suspend,
561 .resume = intel_sst_resume,
434 .runtime_suspend = intel_sst_runtime_suspend, 562 .runtime_suspend = intel_sst_runtime_suspend,
435 .runtime_resume = intel_sst_runtime_resume, 563 .runtime_resume = intel_sst_runtime_resume,
436}; 564};
diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h
index f793780a50a2..3f493862e98d 100644
--- a/sound/soc/intel/sst/sst.h
+++ b/sound/soc/intel/sst/sst.h
@@ -337,6 +337,13 @@ struct sst_shim_regs64 {
337 u64 csr2; 337 u64 csr2;
338}; 338};
339 339
340struct sst_fw_save {
341 void *iram;
342 void *dram;
343 void *sram;
344 void *ddr;
345};
346
340/** 347/**
341 * struct intel_sst_drv - driver ops 348 * struct intel_sst_drv - driver ops
342 * 349 *
@@ -428,6 +435,8 @@ struct intel_sst_drv {
428 * persistent till worker thread gets called 435 * persistent till worker thread gets called
429 */ 436 */
430 char firmware_name[FW_NAME_SIZE]; 437 char firmware_name[FW_NAME_SIZE];
438
439 struct sst_fw_save *fw_save;
431}; 440};
432 441
433/* misc definitions */ 442/* misc definitions */