Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

firmware: cs_dsp: Add API to hibernate the DSP

For some parts, the DSP is kept running when in low power mode
(hibernation), leaving the firmware ALSA controls enabled, but the
registers are inaccessible. Attempts to access volatile firmware
controls whilst in this state would produce errors in the kernel log
due to a regmap_raw_read() into DSP registers whilst the regmap is in
cache_only.

To remove this error log, add a hibernating flag to indicate that the
controls are inaccessible, so we no longer try to read or write to the
registers whilst the regmap is in cache_only.

This would still produce an error when trying to read or write to these
controls, but this would be a different error (-EPERM instead of
-EBUSY), and would not produce a spurious error log in the kernel.

Upon wake from hibernation, the control caches are re-synced to the
hardware, if the DSP is running.

Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com>
Link: https://patch.msgid.link/20260224161821.93365-2-sbinding@opensource.cirrus.com
Reviewed-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Stefan Binding and committed by
Mark Brown
73942a6e 11439c46

+48 -4
+45 -4
drivers/firmware/cirrus/cs_dsp.c
··· 515 515 516 516 debugfs_create_bool("booted", 0444, root, &dsp->booted); 517 517 debugfs_create_bool("running", 0444, root, &dsp->running); 518 + debugfs_create_bool("hibernating", 0444, root, &dsp->hibernating); 518 519 debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id); 519 520 debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version); 520 521 ··· 704 703 705 704 lockdep_assert_held(&dsp->pwr_lock); 706 705 707 - if (!dsp->running) 706 + if (!dsp->running || dsp->hibernating) 708 707 return -EPERM; 709 708 710 709 ret = cs_dsp_coeff_base_reg(ctl, &reg, 0); ··· 828 827 } 829 828 830 829 ctl->set = 1; 831 - if (ctl->enabled && ctl->dsp->running) 830 + if (ctl->enabled && ctl->dsp->running && !ctl->dsp->hibernating) 832 831 ret = cs_dsp_coeff_write_ctrl_raw(ctl, off, buf, len); 833 832 834 833 if (ret < 0) ··· 921 920 return -EINVAL; 922 921 923 922 if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { 924 - if (ctl->enabled && ctl->dsp->running) 923 + if (ctl->enabled && ctl->dsp->running && !ctl->dsp->hibernating) 925 924 return cs_dsp_coeff_read_ctrl_raw(ctl, off, buf, len); 926 925 else 927 926 return -EPERM; 928 927 } else { 929 - if (!ctl->flags && ctl->enabled && ctl->dsp->running) 928 + if (!ctl->flags && ctl->enabled && ctl->dsp->running && !ctl->dsp->hibernating) 930 929 ret = cs_dsp_coeff_read_ctrl_raw(ctl, 0, ctl->cache, ctl->len); 931 930 932 931 if (buf != ctl->cache) ··· 1108 1107 1109 1108 return ret; 1110 1109 } 1110 + 1111 + 1112 + /** 1113 + * cs_dsp_hibernate() - Disable or enable all controls for a DSP 1114 + * @dsp: pointer to DSP structure 1115 + * @hibernate: whether to set controls to cache only mode 1116 + * 1117 + * When @hibernate is true, the DSP is entering hibernation mode where the 1118 + * regmap is inaccessible, and all controls become cache only. 1119 + * When @hibernate is false, the DSP has exited hibernation mode. If the DSP 1120 + * is running, all controls are re-synced to the DSP. 1121 + * 1122 + */ 1123 + void cs_dsp_hibernate(struct cs_dsp *dsp, bool hibernate) 1124 + { 1125 + mutex_lock(&dsp->pwr_lock); 1126 + 1127 + if (!dsp->running) { 1128 + cs_dsp_dbg(dsp, "Cannot hibernate, DSP not running\n"); 1129 + goto out; 1130 + } 1131 + 1132 + if (dsp->hibernating == hibernate) 1133 + goto out; 1134 + 1135 + cs_dsp_dbg(dsp, "Set hibernating to %d\n", hibernate); 1136 + dsp->hibernating = hibernate; 1137 + 1138 + if (!dsp->hibernating && dsp->running) { 1139 + int ret = cs_dsp_coeff_sync_controls(dsp); 1140 + 1141 + if (ret) 1142 + cs_dsp_err(dsp, "Error syncing controls: %d\n", ret); 1143 + } 1144 + out: 1145 + mutex_unlock(&dsp->pwr_lock); 1146 + } 1147 + EXPORT_SYMBOL_NS_GPL(cs_dsp_hibernate, "FW_CS_DSP"); 1111 1148 1112 1149 struct cs_dsp_coeff_parsed_alg { 1113 1150 int id; ··· 2537 2498 goto err_ena; 2538 2499 2539 2500 dsp->booted = true; 2501 + dsp->hibernating = false; 2540 2502 2541 2503 /* Start the core running */ 2542 2504 regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, ··· 2816 2776 dsp->ops->disable_core(dsp); 2817 2777 2818 2778 dsp->booted = true; 2779 + dsp->hibernating = false; 2819 2780 2820 2781 mutex_unlock(&dsp->pwr_lock); 2821 2782
+3
include/linux/firmware/cirrus/cs_dsp.h
··· 179 179 180 180 bool booted; 181 181 bool running; 182 + bool hibernating; 182 183 183 184 struct list_head ctl_list; 184 185 ··· 354 353 int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val); 355 354 int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch); 356 355 int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits); 356 + 357 + void cs_dsp_hibernate(struct cs_dsp *dsp, bool hibernating); 357 358 358 359 #endif