diff options
-rw-r--r-- | sound/soc/intel/sst/sst.c | 128 | ||||
-rw-r--r-- | sound/soc/intel/sst/sst.h | 9 |
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 | ||
418 | static 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; | ||
484 | ddr: | ||
485 | kfree(fw_save->sram); | ||
486 | sram: | ||
487 | kfree(fw_save->dram); | ||
488 | dram: | ||
489 | kfree(fw_save->iram); | ||
490 | iram: | ||
491 | kfree(fw_save); | ||
492 | return ret; | ||
493 | } | ||
494 | |||
418 | static int intel_sst_runtime_resume(struct device *dev) | 495 | static 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 | ||
510 | static 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 | |||
433 | const struct dev_pm_ops intel_sst_pm = { | 559 | const 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 | ||
340 | struct 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 */ |