Ranjani Sridharan 6c26b5054c
ASoC: SOF: Intel: add .ack support for HDaudio platforms
When we disable rewinds, then the .ack can be used to program SPIB
with the application pointer, which allows the HDaudio DMA to save
power by opportunistically bursting data transfers when the path to
memory is enabled (and conversely to shut it down when there are no
transfer requests).

The SPIB register can only be programmed with incremental values with
wrap-around after the DMA RUN bits are set. For simplicity, we set the
INFO_NO_REWINDS flag in the .open callback when we already need to
program the SNDRV_PCM_INFO_SYNC_APPLPTR flag.

Rewinds are not used by many applications. One notable application
using rewinds is PulseAudio. Practical experiments with
Ubuntu/PulseAudio default settings did not show any audible issues,
but the user may hear volume changes and notification with a delay,
depending on the size of the ring buffer and latency constraints.

The choice of disabling rewinds is exposed as a kernel parameter and
not a Kconfig option to avoid any undesirable side-effects.

Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Co-developed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Link: https://lore.kernel.org/r/20211119230852.206310-5-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2021-11-24 12:57:21 +00:00

248 lines
7.1 KiB
C

// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// Copyright(c) 2020 Intel Corporation. All rights reserved.
//
// Authors: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
//
/*
* Hardware interface for audio DSP on Tigerlake.
*/
#include "../ops.h"
#include "hda.h"
#include "hda-ipc.h"
#include "../sof-audio.h"
static const struct snd_sof_debugfs_map tgl_dsp_debugfs[] = {
{"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
{"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
{"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
};
static int tgl_dsp_core_get(struct snd_sof_dev *sdev, int core)
{
struct sof_ipc_pm_core_config pm_core_config = {
.hdr = {
.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
.size = sizeof(pm_core_config),
},
.enable_mask = sdev->enabled_cores_mask | BIT(core),
};
/* power up primary core if not already powered up and return */
if (core == SOF_DSP_PRIMARY_CORE)
return hda_dsp_enable_core(sdev, BIT(core));
/* notify DSP for secondary cores */
return sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd,
&pm_core_config, sizeof(pm_core_config),
&pm_core_config, sizeof(pm_core_config));
}
static int tgl_dsp_core_put(struct snd_sof_dev *sdev, int core)
{
struct sof_ipc_pm_core_config pm_core_config = {
.hdr = {
.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
.size = sizeof(pm_core_config),
},
.enable_mask = sdev->enabled_cores_mask & ~BIT(core),
};
/* power down primary core and return */
if (core == SOF_DSP_PRIMARY_CORE)
return hda_dsp_core_reset_power_down(sdev, BIT(core));
/* notify DSP for secondary cores */
return sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd,
&pm_core_config, sizeof(pm_core_config),
&pm_core_config, sizeof(pm_core_config));
}
/* Tigerlake ops */
const struct snd_sof_dsp_ops sof_tgl_ops = {
/* probe/remove/shutdown */
.probe = hda_dsp_probe,
.remove = hda_dsp_remove,
.shutdown = hda_dsp_shutdown,
/* Register IO */
.write = sof_io_write,
.read = sof_io_read,
.write64 = sof_io_write64,
.read64 = sof_io_read64,
/* Block IO */
.block_read = sof_block_read,
.block_write = sof_block_write,
/* Mailbox IO */
.mailbox_read = sof_mailbox_read,
.mailbox_write = sof_mailbox_write,
/* doorbell */
.irq_thread = cnl_ipc_irq_thread,
/* ipc */
.send_msg = cnl_ipc_send_msg,
.fw_ready = sof_fw_ready,
.get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset,
.get_window_offset = hda_dsp_ipc_get_window_offset,
.ipc_msg_data = hda_ipc_msg_data,
.ipc_pcm_params = hda_ipc_pcm_params,
/* machine driver */
.machine_select = hda_machine_select,
.machine_register = sof_machine_register,
.machine_unregister = sof_machine_unregister,
.set_mach_params = hda_set_mach_params,
/* debug */
.debug_map = tgl_dsp_debugfs,
.debug_map_count = ARRAY_SIZE(tgl_dsp_debugfs),
.dbg_dump = hda_dsp_dump,
.ipc_dump = cnl_ipc_dump,
.debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
/* stream callbacks */
.pcm_open = hda_dsp_pcm_open,
.pcm_close = hda_dsp_pcm_close,
.pcm_hw_params = hda_dsp_pcm_hw_params,
.pcm_hw_free = hda_dsp_stream_hw_free,
.pcm_trigger = hda_dsp_pcm_trigger,
.pcm_pointer = hda_dsp_pcm_pointer,
.pcm_ack = hda_dsp_pcm_ack,
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
/* probe callbacks */
.probe_assign = hda_probe_compr_assign,
.probe_free = hda_probe_compr_free,
.probe_set_params = hda_probe_compr_set_params,
.probe_trigger = hda_probe_compr_trigger,
.probe_pointer = hda_probe_compr_pointer,
#endif
/* firmware loading */
.load_firmware = snd_sof_load_firmware_raw,
/* pre/post fw run */
.pre_fw_run = hda_dsp_pre_fw_run,
.post_fw_run = hda_dsp_post_fw_run,
/* parse platform specific extended manifest */
.parse_platform_ext_manifest = hda_dsp_ext_man_get_cavs_config_data,
/* dsp core get/put */
.core_get = tgl_dsp_core_get,
.core_put = tgl_dsp_core_put,
/* firmware run */
.run = hda_dsp_cl_boot_firmware_iccmax,
/* trace callback */
.trace_init = hda_dsp_trace_init,
.trace_release = hda_dsp_trace_release,
.trace_trigger = hda_dsp_trace_trigger,
/* DAI drivers */
.drv = skl_dai,
.num_drv = SOF_SKL_NUM_DAIS,
/* PM */
.suspend = hda_dsp_suspend,
.resume = hda_dsp_resume,
.runtime_suspend = hda_dsp_runtime_suspend,
.runtime_resume = hda_dsp_runtime_resume,
.runtime_idle = hda_dsp_runtime_idle,
.set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume,
.set_power_state = hda_dsp_set_power_state,
/* ALSA HW info flags */
.hw_info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
.dsp_arch_ops = &sof_xtensa_arch_ops,
};
EXPORT_SYMBOL_NS(sof_tgl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc tgl_chip_info = {
/* Tigerlake , Alderlake */
.cores_num = 4,
.init_core_mask = 1,
.host_managed_cores_mask = BIT(0),
.ipc_req = CNL_DSP_REG_HIPCIDR,
.ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
.ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq,
};
EXPORT_SYMBOL_NS(tgl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc tglh_chip_info = {
/* Tigerlake-H */
.cores_num = 2,
.init_core_mask = 1,
.host_managed_cores_mask = BIT(0),
.ipc_req = CNL_DSP_REG_HIPCIDR,
.ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
.ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq,
};
EXPORT_SYMBOL_NS(tglh_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc ehl_chip_info = {
/* Elkhartlake */
.cores_num = 4,
.init_core_mask = 1,
.host_managed_cores_mask = BIT(0),
.ipc_req = CNL_DSP_REG_HIPCIDR,
.ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
.ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq,
};
EXPORT_SYMBOL_NS(ehl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
const struct sof_intel_dsp_desc adls_chip_info = {
/* Alderlake-S */
.cores_num = 2,
.init_core_mask = BIT(0),
.host_managed_cores_mask = BIT(0),
.ipc_req = CNL_DSP_REG_HIPCIDR,
.ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY,
.ipc_ack = CNL_DSP_REG_HIPCIDA,
.ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE,
.ipc_ctl = CNL_DSP_REG_HIPCCTL,
.rom_init_timeout = 300,
.ssp_count = ICL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
.sdw_shim_base = SDW_SHIM_BASE,
.sdw_alh_base = SDW_ALH_BASE,
.check_sdw_irq = hda_common_check_sdw_irq,
};
EXPORT_SYMBOL_NS(adls_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);