mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 08:31:55 +00:00
ASoC: SOF: Intel: hda: make DSPless mode work with DSP disabled in BIOS
When the DSP is disabled in the BIOS, the DSP_BAR and PP_BAR cannot be accessed. One possible objection noted in initial reviews is that this patch adds a number of branches. However the number of branches is actually limited in probe/suspend/resume routines mostly, so there isn't really a degradation in terms of readability and maintainability. Adding yet another level of abstraction/ops/callbacks would increase complexity and not really help in terms of code reuse or readability and maintainability. A split between controller and DSP driver would be even more invasive. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Link: https://lore.kernel.org/r/20230404092115.27949-7-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
1f7b5d52be
commit
9fc6786f54
@ -321,6 +321,9 @@ void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev)
|
||||
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
|
||||
const struct sof_intel_dsp_desc *chip = hda->desc;
|
||||
|
||||
if (sdev->dspless_mode_selected)
|
||||
return;
|
||||
|
||||
/* enable IPC DONE and BUSY interrupts */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
|
||||
HDA_DSP_REG_HIPCCTL_DONE | HDA_DSP_REG_HIPCCTL_BUSY,
|
||||
@ -336,6 +339,9 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev)
|
||||
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
|
||||
const struct sof_intel_dsp_desc *chip = hda->desc;
|
||||
|
||||
if (sdev->dspless_mode_selected)
|
||||
return;
|
||||
|
||||
/* disable IPC interrupt */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
|
||||
HDA_DSP_ADSPIC_IPC, 0);
|
||||
@ -681,6 +687,9 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
|
||||
/* power down all hda links */
|
||||
hda_bus_ml_suspend(bus);
|
||||
|
||||
if (sdev->dspless_mode_selected)
|
||||
goto skip_dsp;
|
||||
|
||||
ret = chip->power_down_dsp(sdev);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "failed to power down DSP during suspend\n");
|
||||
@ -694,6 +703,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
|
||||
/* disable ppcap interrupt */
|
||||
hda_dsp_ctrl_ppcap_enable(sdev, false);
|
||||
hda_dsp_ctrl_ppcap_int_enable(sdev, false);
|
||||
skip_dsp:
|
||||
|
||||
/* disable hda bus irq and streams */
|
||||
hda_dsp_ctrl_stop_chip(sdev);
|
||||
@ -744,9 +754,11 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
|
||||
hda_codec_jack_check(sdev);
|
||||
}
|
||||
|
||||
/* enable ppcap interrupt */
|
||||
hda_dsp_ctrl_ppcap_enable(sdev, true);
|
||||
hda_dsp_ctrl_ppcap_int_enable(sdev, true);
|
||||
if (!sdev->dspless_mode_selected) {
|
||||
/* enable ppcap interrupt */
|
||||
hda_dsp_ctrl_ppcap_enable(sdev, true);
|
||||
hda_dsp_ctrl_ppcap_int_enable(sdev, true);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* display codec can powered off after controller init */
|
||||
@ -843,8 +855,10 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev)
|
||||
};
|
||||
int ret;
|
||||
|
||||
/* cancel any attempt for DSP D0I3 */
|
||||
cancel_delayed_work_sync(&hda->d0i3_work);
|
||||
if (!sdev->dspless_mode_selected) {
|
||||
/* cancel any attempt for DSP D0I3 */
|
||||
cancel_delayed_work_sync(&hda->d0i3_work);
|
||||
}
|
||||
|
||||
/* stop hda controller and power dsp off */
|
||||
ret = hda_suspend(sdev, true);
|
||||
@ -866,8 +880,10 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
|
||||
};
|
||||
int ret;
|
||||
|
||||
/* cancel any attempt for DSP D0I3 */
|
||||
cancel_delayed_work_sync(&hda->d0i3_work);
|
||||
if (!sdev->dspless_mode_selected) {
|
||||
/* cancel any attempt for DSP D0I3 */
|
||||
cancel_delayed_work_sync(&hda->d0i3_work);
|
||||
}
|
||||
|
||||
if (target_state == SOF_DSP_PM_D0) {
|
||||
/* Set DSP power state */
|
||||
|
@ -355,6 +355,9 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
|
||||
bool ret = false;
|
||||
u32 irq_status;
|
||||
|
||||
if (sdev->dspless_mode_selected)
|
||||
return false;
|
||||
|
||||
/* store status */
|
||||
irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS);
|
||||
trace_sof_intel_hda_irq_ipc_check(sdev, irq_status);
|
||||
|
@ -874,12 +874,14 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
|
||||
|
||||
hext_stream = &hda_stream->hext_stream;
|
||||
|
||||
hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
|
||||
SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i;
|
||||
if (sdev->bar[HDA_DSP_PP_BAR]) {
|
||||
hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
|
||||
SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i;
|
||||
|
||||
hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
|
||||
SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
|
||||
SOF_HDA_PPLC_INTERVAL * i;
|
||||
hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
|
||||
SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
|
||||
SOF_HDA_PPLC_INTERVAL * i;
|
||||
}
|
||||
|
||||
hstream = &hext_stream->hstream;
|
||||
|
||||
@ -930,13 +932,14 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
|
||||
|
||||
hext_stream = &hda_stream->hext_stream;
|
||||
|
||||
/* we always have DSP support */
|
||||
hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
|
||||
SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i;
|
||||
if (sdev->bar[HDA_DSP_PP_BAR]) {
|
||||
hext_stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
|
||||
SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i;
|
||||
|
||||
hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
|
||||
SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
|
||||
SOF_HDA_PPLC_INTERVAL * i;
|
||||
hext_stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
|
||||
SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total +
|
||||
SOF_HDA_PPLC_INTERVAL * i;
|
||||
}
|
||||
|
||||
hstream = &hext_stream->hstream;
|
||||
|
||||
|
@ -122,8 +122,12 @@ void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
|
||||
|
||||
void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
|
||||
{
|
||||
u32 interface_mask = hda_get_interface_mask(sdev);
|
||||
const struct sof_intel_dsp_desc *chip;
|
||||
|
||||
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
|
||||
return;
|
||||
|
||||
chip = get_chip_info(sdev->pdata);
|
||||
if (chip && chip->enable_sdw_irq)
|
||||
chip->enable_sdw_irq(sdev, enable);
|
||||
@ -131,10 +135,14 @@ void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
|
||||
|
||||
static int hda_sdw_acpi_scan(struct snd_sof_dev *sdev)
|
||||
{
|
||||
u32 interface_mask = hda_get_interface_mask(sdev);
|
||||
struct sof_intel_hda_dev *hdev;
|
||||
acpi_handle handle;
|
||||
int ret;
|
||||
|
||||
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
|
||||
return -EINVAL;
|
||||
|
||||
handle = ACPI_HANDLE(sdev->dev);
|
||||
|
||||
/* save ACPI info for the probe step */
|
||||
@ -288,8 +296,12 @@ out:
|
||||
|
||||
static bool hda_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
|
||||
{
|
||||
u32 interface_mask = hda_get_interface_mask(sdev);
|
||||
const struct sof_intel_dsp_desc *chip;
|
||||
|
||||
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
|
||||
return false;
|
||||
|
||||
chip = get_chip_info(sdev->pdata);
|
||||
if (chip && chip->check_sdw_irq)
|
||||
return chip->check_sdw_irq(sdev);
|
||||
@ -304,8 +316,12 @@ static irqreturn_t hda_dsp_sdw_thread(int irq, void *context)
|
||||
|
||||
static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
|
||||
{
|
||||
u32 interface_mask = hda_get_interface_mask(sdev);
|
||||
struct sof_intel_hda_dev *hdev;
|
||||
|
||||
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
|
||||
return false;
|
||||
|
||||
hdev = sdev->pdata->hw_pdata;
|
||||
if (hdev->sdw &&
|
||||
snd_sof_dsp_read(sdev, HDA_DSP_BAR,
|
||||
@ -317,8 +333,12 @@ static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
|
||||
|
||||
void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
|
||||
{
|
||||
u32 interface_mask = hda_get_interface_mask(sdev);
|
||||
struct sof_intel_hda_dev *hdev;
|
||||
|
||||
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
|
||||
return;
|
||||
|
||||
hdev = sdev->pdata->hw_pdata;
|
||||
if (!hdev->sdw)
|
||||
return;
|
||||
@ -1010,21 +1030,25 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
|
||||
const struct sof_intel_dsp_desc *chip;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* detect DSP by checking class/subclass/prog-id information
|
||||
* class=04 subclass 03 prog-if 00: no DSP, legacy driver is required
|
||||
* class=04 subclass 01 prog-if 00: DSP is present
|
||||
* (and may be required e.g. for DMIC or SSP support)
|
||||
* class=04 subclass 03 prog-if 80: either of DSP or legacy mode works
|
||||
*/
|
||||
if (pci->class == 0x040300) {
|
||||
dev_err(sdev->dev, "error: the DSP is not enabled on this platform, aborting probe\n");
|
||||
return -ENODEV;
|
||||
} else if (pci->class != 0x040100 && pci->class != 0x040380) {
|
||||
dev_err(sdev->dev, "error: unknown PCI class/subclass/prog-if 0x%06x found, aborting probe\n", pci->class);
|
||||
return -ENODEV;
|
||||
if (!sdev->dspless_mode_selected) {
|
||||
/*
|
||||
* detect DSP by checking class/subclass/prog-id information
|
||||
* class=04 subclass 03 prog-if 00: no DSP, legacy driver is required
|
||||
* class=04 subclass 01 prog-if 00: DSP is present
|
||||
* (and may be required e.g. for DMIC or SSP support)
|
||||
* class=04 subclass 03 prog-if 80: either of DSP or legacy mode works
|
||||
*/
|
||||
if (pci->class == 0x040300) {
|
||||
dev_err(sdev->dev, "the DSP is not enabled on this platform, aborting probe\n");
|
||||
return -ENODEV;
|
||||
} else if (pci->class != 0x040100 && pci->class != 0x040380) {
|
||||
dev_err(sdev->dev, "unknown PCI class/subclass/prog-if 0x%06x found, aborting probe\n",
|
||||
pci->class);
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n",
|
||||
pci->class);
|
||||
}
|
||||
dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n", pci->class);
|
||||
|
||||
chip = get_chip_info(sdev->pdata);
|
||||
if (!chip) {
|
||||
@ -1069,6 +1093,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
|
||||
if (ret < 0)
|
||||
goto hdac_bus_unmap;
|
||||
|
||||
if (sdev->dspless_mode_selected)
|
||||
goto skip_dsp_setup;
|
||||
|
||||
/* DSP base */
|
||||
sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR);
|
||||
if (!sdev->bar[HDA_DSP_BAR]) {
|
||||
@ -1079,6 +1106,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
|
||||
|
||||
sdev->mmio_bar = HDA_DSP_BAR;
|
||||
sdev->mailbox_bar = HDA_DSP_BAR;
|
||||
skip_dsp_setup:
|
||||
|
||||
/* allow 64bit DMA address if supported by H/W */
|
||||
if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(64))) {
|
||||
@ -1144,14 +1172,16 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
|
||||
if (ret < 0)
|
||||
goto free_ipc_irq;
|
||||
|
||||
/* enable ppcap interrupt */
|
||||
hda_dsp_ctrl_ppcap_enable(sdev, true);
|
||||
hda_dsp_ctrl_ppcap_int_enable(sdev, true);
|
||||
if (!sdev->dspless_mode_selected) {
|
||||
/* enable ppcap interrupt */
|
||||
hda_dsp_ctrl_ppcap_enable(sdev, true);
|
||||
hda_dsp_ctrl_ppcap_int_enable(sdev, true);
|
||||
|
||||
/* set default mailbox offset for FW ready message */
|
||||
sdev->dsp_box.offset = HDA_DSP_MBOX_UPLINK_OFFSET;
|
||||
/* set default mailbox offset for FW ready message */
|
||||
sdev->dsp_box.offset = HDA_DSP_MBOX_UPLINK_OFFSET;
|
||||
|
||||
INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work);
|
||||
INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work);
|
||||
}
|
||||
|
||||
init_waitqueue_head(&hdev->waitq);
|
||||
|
||||
@ -1167,7 +1197,8 @@ free_irq_vector:
|
||||
free_streams:
|
||||
hda_dsp_stream_free(sdev);
|
||||
/* dsp_unmap: not currently used */
|
||||
iounmap(sdev->bar[HDA_DSP_BAR]);
|
||||
if (!sdev->dspless_mode_selected)
|
||||
iounmap(sdev->bar[HDA_DSP_BAR]);
|
||||
hdac_bus_unmap:
|
||||
platform_device_unregister(hdev->dmic_dev);
|
||||
iounmap(bus->remap_addr);
|
||||
@ -1187,8 +1218,9 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
|
||||
if (nhlt)
|
||||
intel_nhlt_free(nhlt);
|
||||
|
||||
/* cancel any attempt for DSP D0I3 */
|
||||
cancel_delayed_work_sync(&hda->d0i3_work);
|
||||
if (!sdev->dspless_mode_selected)
|
||||
/* cancel any attempt for DSP D0I3 */
|
||||
cancel_delayed_work_sync(&hda->d0i3_work);
|
||||
|
||||
hda_codec_device_remove(sdev);
|
||||
|
||||
@ -1197,14 +1229,19 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
|
||||
if (!IS_ERR_OR_NULL(hda->dmic_dev))
|
||||
platform_device_unregister(hda->dmic_dev);
|
||||
|
||||
/* disable DSP IRQ */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
|
||||
SOF_HDA_PPCTL_PIE, 0);
|
||||
if (!sdev->dspless_mode_selected) {
|
||||
/* disable DSP IRQ */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
|
||||
SOF_HDA_PPCTL_PIE, 0);
|
||||
}
|
||||
|
||||
/* disable CIE and GIE interrupts */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
|
||||
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, 0);
|
||||
|
||||
if (sdev->dspless_mode_selected)
|
||||
goto skip_disable_dsp;
|
||||
|
||||
/* no need to check for error as the DSP will be disabled anyway */
|
||||
if (chip && chip->power_down_dsp)
|
||||
chip->power_down_dsp(sdev);
|
||||
@ -1213,6 +1250,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
|
||||
SOF_HDA_PPCTL_GPROCEN, 0);
|
||||
|
||||
skip_disable_dsp:
|
||||
free_irq(sdev->ipc_irq, sdev);
|
||||
if (sdev->msi_enabled)
|
||||
pci_free_irq_vectors(pci);
|
||||
@ -1221,7 +1259,9 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
|
||||
|
||||
hda_bus_ml_free(sof_to_bus(sdev));
|
||||
|
||||
iounmap(sdev->bar[HDA_DSP_BAR]);
|
||||
if (!sdev->dspless_mode_selected)
|
||||
iounmap(sdev->bar[HDA_DSP_BAR]);
|
||||
|
||||
iounmap(bus->remap_addr);
|
||||
|
||||
sof_hda_bus_exit(sdev);
|
||||
|
Loading…
Reference in New Issue
Block a user