Unverified Commit 9fc6786f authored by Pierre-Louis Bossart's avatar Pierre-Louis Bossart Committed by Mark Brown
Browse files

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: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: default avatarPéter Ujfalusi <peter.ujfalusi@linux.intel.com>
Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://lore.kernel.org/r/20230404092115.27949-7-peter.ujfalusi@linux.intel.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 1f7b5d52
Loading
Loading
Loading
Loading
+23 −7
Original line number Diff line number Diff line
@@ -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);
	}

	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;

	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;

	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 */
+3 −0
Original line number Diff line number Diff line
@@ -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);
+14 −11
Original line number Diff line number Diff line
@@ -874,12 +874,14 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)

		hext_stream = &hda_stream->hext_stream;

		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;
		}

		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 */
		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;
		}

		hstream = &hext_stream->hstream;

+67 −27
Original line number Diff line number Diff line
@@ -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 @@ bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)

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,6 +1030,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
	const struct sof_intel_dsp_desc *chip;
	int ret = 0;

	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
@@ -1018,13 +1039,16 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
		 * 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");
			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, "error: unknown PCI class/subclass/prog-if 0x%06x found, aborting probe\n", pci->class);
			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,6 +1172,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
	if (ret < 0)
		goto free_ipc_irq;

	if (!sdev->dspless_mode_selected) {
		/* enable ppcap interrupt */
		hda_dsp_ctrl_ppcap_enable(sdev, true);
		hda_dsp_ctrl_ppcap_int_enable(sdev, true);
@@ -1152,6 +1181,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
		sdev->dsp_box.offset = HDA_DSP_MBOX_UPLINK_OFFSET;

		INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work);
	}

	init_waitqueue_head(&hdev->waitq);

@@ -1167,6 +1197,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
free_streams:
	hda_dsp_stream_free(sdev);
/* dsp_unmap: not currently used */
	if (!sdev->dspless_mode_selected)
		iounmap(sdev->bar[HDA_DSP_BAR]);
hdac_bus_unmap:
	platform_device_unregister(hdev->dmic_dev);
@@ -1187,6 +1218,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
	if (nhlt)
		intel_nhlt_free(nhlt);

	if (!sdev->dspless_mode_selected)
		/* cancel any attempt for DSP D0I3 */
		cancel_delayed_work_sync(&hda->d0i3_work);

@@ -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);

	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));

	if (!sdev->dspless_mode_selected)
		iounmap(sdev->bar[HDA_DSP_BAR]);

	iounmap(bus->remap_addr);

	sof_hda_bus_exit(sdev);