OSDN Git Service

ASoC: SOF: Intel: hda: make DSPless mode work with DSP disabled in BIOS
authorPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Tue, 4 Apr 2023 09:21:09 +0000 (12:21 +0300)
committerMark Brown <broonie@kernel.org>
Tue, 4 Apr 2023 11:42:37 +0000 (12:42 +0100)
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>
sound/soc/sof/intel/hda-dsp.c
sound/soc/sof/intel/hda-ipc.c
sound/soc/sof/intel/hda-stream.c
sound/soc/sof/intel/hda.c

index c9231ae..23c05e6 100644 (file)
@@ -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 */
index df541b2..a838ddd 100644 (file)
@@ -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);
index 87e31a6..79d818e 100644 (file)
@@ -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;
 
index a14733a..483ec80 100644 (file)
@@ -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);