162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license.  When using or
462306a36Sopenharmony_ci// redistributing this file, you may do so under either license.
562306a36Sopenharmony_ci//
662306a36Sopenharmony_ci// Copyright(c) 2018 Intel Corporation. All rights reserved.
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
962306a36Sopenharmony_ci//	    Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
1062306a36Sopenharmony_ci//	    Rander Wang <rander.wang@intel.com>
1162306a36Sopenharmony_ci//          Keyon Jie <yang.jie@linux.intel.com>
1262306a36Sopenharmony_ci//
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/*
1562306a36Sopenharmony_ci * Hardware interface for generic Intel audio DSP HDA IP
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <sound/hdaudio_ext.h>
1962306a36Sopenharmony_ci#include <sound/hda_register.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/acpi.h>
2262306a36Sopenharmony_ci#include <linux/module.h>
2362306a36Sopenharmony_ci#include <linux/soundwire/sdw.h>
2462306a36Sopenharmony_ci#include <linux/soundwire/sdw_intel.h>
2562306a36Sopenharmony_ci#include <sound/intel-dsp-config.h>
2662306a36Sopenharmony_ci#include <sound/intel-nhlt.h>
2762306a36Sopenharmony_ci#include <sound/sof.h>
2862306a36Sopenharmony_ci#include <sound/sof/xtensa.h>
2962306a36Sopenharmony_ci#include <sound/hda-mlink.h>
3062306a36Sopenharmony_ci#include "../sof-audio.h"
3162306a36Sopenharmony_ci#include "../sof-pci-dev.h"
3262306a36Sopenharmony_ci#include "../ops.h"
3362306a36Sopenharmony_ci#include "hda.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
3662306a36Sopenharmony_ci#include <trace/events/sof_intel.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
3962306a36Sopenharmony_ci#include <sound/soc-acpi-intel-match.h>
4062306a36Sopenharmony_ci#endif
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* platform specific devices */
4362306a36Sopenharmony_ci#include "shim.h"
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define EXCEPT_MAX_HDR_SIZE	0x400
4662306a36Sopenharmony_ci#define HDA_EXT_ROM_STATUS_SIZE 8
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic u32 hda_get_interface_mask(struct snd_sof_dev *sdev)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip;
5162306a36Sopenharmony_ci	u32 interface_mask[2] = { 0 };
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	chip = get_chip_info(sdev->pdata);
5462306a36Sopenharmony_ci	switch (chip->hw_ip_version) {
5562306a36Sopenharmony_ci	case SOF_INTEL_TANGIER:
5662306a36Sopenharmony_ci	case SOF_INTEL_BAYTRAIL:
5762306a36Sopenharmony_ci	case SOF_INTEL_BROADWELL:
5862306a36Sopenharmony_ci		interface_mask[0] =  BIT(SOF_DAI_INTEL_SSP);
5962306a36Sopenharmony_ci		break;
6062306a36Sopenharmony_ci	case SOF_INTEL_CAVS_1_5:
6162306a36Sopenharmony_ci	case SOF_INTEL_CAVS_1_5_PLUS:
6262306a36Sopenharmony_ci		interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
6362306a36Sopenharmony_ci				    BIT(SOF_DAI_INTEL_HDA);
6462306a36Sopenharmony_ci		interface_mask[1] = BIT(SOF_DAI_INTEL_HDA);
6562306a36Sopenharmony_ci		break;
6662306a36Sopenharmony_ci	case SOF_INTEL_CAVS_1_8:
6762306a36Sopenharmony_ci	case SOF_INTEL_CAVS_2_0:
6862306a36Sopenharmony_ci	case SOF_INTEL_CAVS_2_5:
6962306a36Sopenharmony_ci	case SOF_INTEL_ACE_1_0:
7062306a36Sopenharmony_ci		interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
7162306a36Sopenharmony_ci				    BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
7262306a36Sopenharmony_ci		interface_mask[1] = BIT(SOF_DAI_INTEL_HDA);
7362306a36Sopenharmony_ci		break;
7462306a36Sopenharmony_ci	case SOF_INTEL_ACE_2_0:
7562306a36Sopenharmony_ci		interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
7662306a36Sopenharmony_ci				    BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
7762306a36Sopenharmony_ci		interface_mask[1] = interface_mask[0]; /* all interfaces accessible without DSP */
7862306a36Sopenharmony_ci		break;
7962306a36Sopenharmony_ci	default:
8062306a36Sopenharmony_ci		break;
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	return interface_mask[sdev->dspless_mode_selected];
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/*
8962306a36Sopenharmony_ci * The default for SoundWire clock stop quirks is to power gate the IP
9062306a36Sopenharmony_ci * and do a Bus Reset, this will need to be modified when the DSP
9162306a36Sopenharmony_ci * needs to remain in D0i3 so that the Master does not lose context
9262306a36Sopenharmony_ci * and enumeration is not required on clock restart
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_cistatic int sdw_clock_stop_quirks = SDW_INTEL_CLK_STOP_BUS_RESET;
9562306a36Sopenharmony_cimodule_param(sdw_clock_stop_quirks, int, 0444);
9662306a36Sopenharmony_ciMODULE_PARM_DESC(sdw_clock_stop_quirks, "SOF SoundWire clock stop quirks");
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic int sdw_params_stream(struct device *dev,
9962306a36Sopenharmony_ci			     struct sdw_intel_stream_params_data *params_data)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	struct snd_soc_dai *d = params_data->dai;
10262306a36Sopenharmony_ci	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(d, params_data->substream->stream);
10362306a36Sopenharmony_ci	struct snd_sof_dai_config_data data = { 0 };
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	data.dai_index = (params_data->link_id << 8) | d->id;
10662306a36Sopenharmony_ci	data.dai_data = params_data->alh_stream_id;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	return hda_dai_config(w, SOF_DAI_CONFIG_FLAGS_HW_PARAMS, &data);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct sdw_intel_ops sdw_callback = {
11262306a36Sopenharmony_ci	.params_stream = sdw_params_stream,
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic int sdw_ace2x_params_stream(struct device *dev,
11662306a36Sopenharmony_ci				   struct sdw_intel_stream_params_data *params_data)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	return sdw_hda_dai_hw_params(params_data->substream,
11962306a36Sopenharmony_ci				     params_data->hw_params,
12062306a36Sopenharmony_ci				     params_data->dai,
12162306a36Sopenharmony_ci				     params_data->link_id);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic int sdw_ace2x_free_stream(struct device *dev,
12562306a36Sopenharmony_ci				 struct sdw_intel_stream_free_data *free_data)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	return sdw_hda_dai_hw_free(free_data->substream,
12862306a36Sopenharmony_ci				   free_data->dai,
12962306a36Sopenharmony_ci				   free_data->link_id);
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic int sdw_ace2x_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	return sdw_hda_dai_trigger(substream, cmd, dai);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic struct sdw_intel_ops sdw_ace2x_callback = {
13862306a36Sopenharmony_ci	.params_stream = sdw_ace2x_params_stream,
13962306a36Sopenharmony_ci	.free_stream = sdw_ace2x_free_stream,
14062306a36Sopenharmony_ci	.trigger = sdw_ace2x_trigger,
14162306a36Sopenharmony_ci};
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_civoid hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	hdev = sdev->pdata->hw_pdata;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (!hdev->sdw)
15062306a36Sopenharmony_ci		return;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC2,
15362306a36Sopenharmony_ci				HDA_DSP_REG_ADSPIC2_SNDW,
15462306a36Sopenharmony_ci				enable ? HDA_DSP_REG_ADSPIC2_SNDW : 0);
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_civoid hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	u32 interface_mask = hda_get_interface_mask(sdev);
16062306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
16362306a36Sopenharmony_ci		return;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	chip = get_chip_info(sdev->pdata);
16662306a36Sopenharmony_ci	if (chip && chip->enable_sdw_irq)
16762306a36Sopenharmony_ci		chip->enable_sdw_irq(sdev, enable);
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int hda_sdw_acpi_scan(struct snd_sof_dev *sdev)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	u32 interface_mask = hda_get_interface_mask(sdev);
17362306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev;
17462306a36Sopenharmony_ci	acpi_handle handle;
17562306a36Sopenharmony_ci	int ret;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
17862306a36Sopenharmony_ci		return -EINVAL;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	handle = ACPI_HANDLE(sdev->dev);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/* save ACPI info for the probe step */
18362306a36Sopenharmony_ci	hdev = sdev->pdata->hw_pdata;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	ret = sdw_intel_acpi_scan(handle, &hdev->info);
18662306a36Sopenharmony_ci	if (ret < 0)
18762306a36Sopenharmony_ci		return -EINVAL;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return 0;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic int hda_sdw_probe(struct snd_sof_dev *sdev)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip;
19562306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev;
19662306a36Sopenharmony_ci	struct sdw_intel_res res;
19762306a36Sopenharmony_ci	void *sdw;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	hdev = sdev->pdata->hw_pdata;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	memset(&res, 0, sizeof(res));
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	chip = get_chip_info(sdev->pdata);
20462306a36Sopenharmony_ci	if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) {
20562306a36Sopenharmony_ci		res.mmio_base = sdev->bar[HDA_DSP_BAR];
20662306a36Sopenharmony_ci		res.hw_ops = &sdw_intel_cnl_hw_ops;
20762306a36Sopenharmony_ci		res.shim_base = hdev->desc->sdw_shim_base;
20862306a36Sopenharmony_ci		res.alh_base = hdev->desc->sdw_alh_base;
20962306a36Sopenharmony_ci		res.ext = false;
21062306a36Sopenharmony_ci		res.ops = &sdw_callback;
21162306a36Sopenharmony_ci	} else {
21262306a36Sopenharmony_ci		/*
21362306a36Sopenharmony_ci		 * retrieve eml_lock needed to protect shared registers
21462306a36Sopenharmony_ci		 * in the HDaudio multi-link areas
21562306a36Sopenharmony_ci		 */
21662306a36Sopenharmony_ci		res.eml_lock = hdac_bus_eml_get_mutex(sof_to_bus(sdev), true,
21762306a36Sopenharmony_ci						      AZX_REG_ML_LEPTR_ID_SDW);
21862306a36Sopenharmony_ci		if (!res.eml_lock)
21962306a36Sopenharmony_ci			return -ENODEV;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci		res.mmio_base = sdev->bar[HDA_DSP_HDA_BAR];
22262306a36Sopenharmony_ci		/*
22362306a36Sopenharmony_ci		 * the SHIM and SoundWire register offsets are link-specific
22462306a36Sopenharmony_ci		 * and will be determined when adding auxiliary devices
22562306a36Sopenharmony_ci		 */
22662306a36Sopenharmony_ci		res.hw_ops = &sdw_intel_lnl_hw_ops;
22762306a36Sopenharmony_ci		res.ext = true;
22862306a36Sopenharmony_ci		res.ops = &sdw_ace2x_callback;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci	res.irq = sdev->ipc_irq;
23262306a36Sopenharmony_ci	res.handle = hdev->info.handle;
23362306a36Sopenharmony_ci	res.parent = sdev->dev;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	res.dev = sdev->dev;
23662306a36Sopenharmony_ci	res.clock_stop_quirks = sdw_clock_stop_quirks;
23762306a36Sopenharmony_ci	res.hbus = sof_to_bus(sdev);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/*
24062306a36Sopenharmony_ci	 * ops and arg fields are not populated for now,
24162306a36Sopenharmony_ci	 * they will be needed when the DAI callbacks are
24262306a36Sopenharmony_ci	 * provided
24362306a36Sopenharmony_ci	 */
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* we could filter links here if needed, e.g for quirks */
24662306a36Sopenharmony_ci	res.count = hdev->info.count;
24762306a36Sopenharmony_ci	res.link_mask = hdev->info.link_mask;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	sdw = sdw_intel_probe(&res);
25062306a36Sopenharmony_ci	if (!sdw) {
25162306a36Sopenharmony_ci		dev_err(sdev->dev, "error: SoundWire probe failed\n");
25262306a36Sopenharmony_ci		return -EINVAL;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	/* save context */
25662306a36Sopenharmony_ci	hdev->sdw = sdw;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	return 0;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ciint hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev;
26462306a36Sopenharmony_ci	struct sdw_intel_ctx *ctx;
26562306a36Sopenharmony_ci	u32 caps;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	hdev = sdev->pdata->hw_pdata;
26862306a36Sopenharmony_ci	ctx = hdev->sdw;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	caps = snd_sof_dsp_read(sdev, HDA_DSP_BAR, ctx->shim_base + SDW_SHIM_LCAP);
27162306a36Sopenharmony_ci	caps &= SDW_SHIM_LCAP_LCOUNT_MASK;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* Check HW supported vs property value */
27462306a36Sopenharmony_ci	if (caps < ctx->count) {
27562306a36Sopenharmony_ci		dev_err(sdev->dev,
27662306a36Sopenharmony_ci			"%s: BIOS master count %d is larger than hardware capabilities %d\n",
27762306a36Sopenharmony_ci			__func__, ctx->count, caps);
27862306a36Sopenharmony_ci		return -EINVAL;
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	return 0;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ciint hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev;
28762306a36Sopenharmony_ci	struct sdw_intel_ctx *ctx;
28862306a36Sopenharmony_ci	struct hdac_bus *bus;
28962306a36Sopenharmony_ci	u32 slcount;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	bus = sof_to_bus(sdev);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	hdev = sdev->pdata->hw_pdata;
29462306a36Sopenharmony_ci	ctx = hdev->sdw;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	slcount = hdac_bus_eml_get_count(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	/* Check HW supported vs property value */
29962306a36Sopenharmony_ci	if (slcount < ctx->count) {
30062306a36Sopenharmony_ci		dev_err(sdev->dev,
30162306a36Sopenharmony_ci			"%s: BIOS master count %d is larger than hardware capabilities %d\n",
30262306a36Sopenharmony_ci			__func__, ctx->count, slcount);
30362306a36Sopenharmony_ci		return -EINVAL;
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	return 0;
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic int hda_sdw_check_lcount(struct snd_sof_dev *sdev)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	chip = get_chip_info(sdev->pdata);
31462306a36Sopenharmony_ci	if (chip && chip->read_sdw_lcount)
31562306a36Sopenharmony_ci		return chip->read_sdw_lcount(sdev);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	return 0;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ciint hda_sdw_startup(struct snd_sof_dev *sdev)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev;
32362306a36Sopenharmony_ci	struct snd_sof_pdata *pdata = sdev->pdata;
32462306a36Sopenharmony_ci	int ret;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	hdev = sdev->pdata->hw_pdata;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (!hdev->sdw)
32962306a36Sopenharmony_ci		return 0;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	if (pdata->machine && !pdata->machine->mach_params.link_mask)
33262306a36Sopenharmony_ci		return 0;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	ret = hda_sdw_check_lcount(sdev);
33562306a36Sopenharmony_ci	if (ret < 0)
33662306a36Sopenharmony_ci		return ret;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	return sdw_intel_startup(hdev->sdw);
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic int hda_sdw_exit(struct snd_sof_dev *sdev)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	hdev = sdev->pdata->hw_pdata;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	hda_sdw_int_enable(sdev, false);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (hdev->sdw)
35062306a36Sopenharmony_ci		sdw_intel_exit(hdev->sdw);
35162306a36Sopenharmony_ci	hdev->sdw = NULL;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return 0;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cibool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev;
35962306a36Sopenharmony_ci	bool ret = false;
36062306a36Sopenharmony_ci	u32 irq_status;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	hdev = sdev->pdata->hw_pdata;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (!hdev->sdw)
36562306a36Sopenharmony_ci		return ret;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* store status */
36862306a36Sopenharmony_ci	irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS2);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/* invalid message ? */
37162306a36Sopenharmony_ci	if (irq_status == 0xffffffff)
37262306a36Sopenharmony_ci		goto out;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	/* SDW message ? */
37562306a36Sopenharmony_ci	if (irq_status & HDA_DSP_REG_ADSPIS2_SNDW)
37662306a36Sopenharmony_ci		ret = true;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ciout:
37962306a36Sopenharmony_ci	return ret;
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic bool hda_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	u32 interface_mask = hda_get_interface_mask(sdev);
38562306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
38862306a36Sopenharmony_ci		return false;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	chip = get_chip_info(sdev->pdata);
39162306a36Sopenharmony_ci	if (chip && chip->check_sdw_irq)
39262306a36Sopenharmony_ci		return chip->check_sdw_irq(sdev);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	return false;
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic irqreturn_t hda_dsp_sdw_thread(int irq, void *context)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	return sdw_intel_thread(irq, context);
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cibool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	hdev = sdev->pdata->hw_pdata;
40762306a36Sopenharmony_ci	if (hdev->sdw &&
40862306a36Sopenharmony_ci	    snd_sof_dsp_read(sdev, HDA_DSP_BAR,
40962306a36Sopenharmony_ci			     hdev->desc->sdw_shim_base + SDW_SHIM_WAKESTS))
41062306a36Sopenharmony_ci		return true;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	return false;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	u32 interface_mask = hda_get_interface_mask(sdev);
41862306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
42162306a36Sopenharmony_ci		return false;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	chip = get_chip_info(sdev->pdata);
42462306a36Sopenharmony_ci	if (chip && chip->check_sdw_wakeen_irq)
42562306a36Sopenharmony_ci		return chip->check_sdw_wakeen_irq(sdev);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	return false;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_civoid hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	u32 interface_mask = hda_get_interface_mask(sdev);
43362306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
43662306a36Sopenharmony_ci		return;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	hdev = sdev->pdata->hw_pdata;
43962306a36Sopenharmony_ci	if (!hdev->sdw)
44062306a36Sopenharmony_ci		return;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	sdw_intel_process_wakeen_event(hdev->sdw);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci#else /* IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) */
44662306a36Sopenharmony_cistatic inline int hda_sdw_acpi_scan(struct snd_sof_dev *sdev)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	return 0;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic inline int hda_sdw_probe(struct snd_sof_dev *sdev)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	return 0;
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic inline int hda_sdw_exit(struct snd_sof_dev *sdev)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	return 0;
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic inline bool hda_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	return false;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic inline irqreturn_t hda_dsp_sdw_thread(int irq, void *context)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	return IRQ_HANDLED;
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic inline bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	return false;
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci#endif /* IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) */
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/*
47962306a36Sopenharmony_ci * Debug
48062306a36Sopenharmony_ci */
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistruct hda_dsp_msg_code {
48362306a36Sopenharmony_ci	u32 code;
48462306a36Sopenharmony_ci	const char *text;
48562306a36Sopenharmony_ci};
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG)
48862306a36Sopenharmony_cistatic bool hda_use_msi = true;
48962306a36Sopenharmony_cimodule_param_named(use_msi, hda_use_msi, bool, 0444);
49062306a36Sopenharmony_ciMODULE_PARM_DESC(use_msi, "SOF HDA use PCI MSI mode");
49162306a36Sopenharmony_ci#else
49262306a36Sopenharmony_ci#define hda_use_msi	(1)
49362306a36Sopenharmony_ci#endif
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ciint sof_hda_position_quirk = SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS;
49662306a36Sopenharmony_cimodule_param_named(position_quirk, sof_hda_position_quirk, int, 0444);
49762306a36Sopenharmony_ciMODULE_PARM_DESC(position_quirk, "SOF HDaudio position quirk");
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic char *hda_model;
50062306a36Sopenharmony_cimodule_param(hda_model, charp, 0444);
50162306a36Sopenharmony_ciMODULE_PARM_DESC(hda_model, "Use the given HDA board model.");
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic int dmic_num_override = -1;
50462306a36Sopenharmony_cimodule_param_named(dmic_num, dmic_num_override, int, 0444);
50562306a36Sopenharmony_ciMODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number");
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic int mclk_id_override = -1;
50862306a36Sopenharmony_cimodule_param_named(mclk_id, mclk_id_override, int, 0444);
50962306a36Sopenharmony_ciMODULE_PARM_DESC(mclk_id, "SOF SSP mclk_id");
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic const struct hda_dsp_msg_code hda_dsp_rom_fw_error_texts[] = {
51262306a36Sopenharmony_ci	{HDA_DSP_ROM_CSE_ERROR, "error: cse error"},
51362306a36Sopenharmony_ci	{HDA_DSP_ROM_CSE_WRONG_RESPONSE, "error: cse wrong response"},
51462306a36Sopenharmony_ci	{HDA_DSP_ROM_IMR_TO_SMALL, "error: IMR too small"},
51562306a36Sopenharmony_ci	{HDA_DSP_ROM_BASE_FW_NOT_FOUND, "error: base fw not found"},
51662306a36Sopenharmony_ci	{HDA_DSP_ROM_CSE_VALIDATION_FAILED, "error: signature verification failed"},
51762306a36Sopenharmony_ci	{HDA_DSP_ROM_IPC_FATAL_ERROR, "error: ipc fatal error"},
51862306a36Sopenharmony_ci	{HDA_DSP_ROM_L2_CACHE_ERROR, "error: L2 cache error"},
51962306a36Sopenharmony_ci	{HDA_DSP_ROM_LOAD_OFFSET_TO_SMALL, "error: load offset too small"},
52062306a36Sopenharmony_ci	{HDA_DSP_ROM_API_PTR_INVALID, "error: API ptr invalid"},
52162306a36Sopenharmony_ci	{HDA_DSP_ROM_BASEFW_INCOMPAT, "error: base fw incompatible"},
52262306a36Sopenharmony_ci	{HDA_DSP_ROM_UNHANDLED_INTERRUPT, "error: unhandled interrupt"},
52362306a36Sopenharmony_ci	{HDA_DSP_ROM_MEMORY_HOLE_ECC, "error: ECC memory hole"},
52462306a36Sopenharmony_ci	{HDA_DSP_ROM_KERNEL_EXCEPTION, "error: kernel exception"},
52562306a36Sopenharmony_ci	{HDA_DSP_ROM_USER_EXCEPTION, "error: user exception"},
52662306a36Sopenharmony_ci	{HDA_DSP_ROM_UNEXPECTED_RESET, "error: unexpected reset"},
52762306a36Sopenharmony_ci	{HDA_DSP_ROM_NULL_FW_ENTRY,	"error: null FW entry point"},
52862306a36Sopenharmony_ci};
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci#define FSR_ROM_STATE_ENTRY(state)	{FSR_STATE_ROM_##state, #state}
53162306a36Sopenharmony_cistatic const struct hda_dsp_msg_code fsr_rom_state_names[] = {
53262306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(INIT),
53362306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(INIT_DONE),
53462306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(CSE_MANIFEST_LOADED),
53562306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(FW_MANIFEST_LOADED),
53662306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(FW_FW_LOADED),
53762306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(FW_ENTERED),
53862306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(VERIFY_FEATURE_MASK),
53962306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(GET_LOAD_OFFSET),
54062306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(FETCH_ROM_EXT),
54162306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(FETCH_ROM_EXT_DONE),
54262306a36Sopenharmony_ci	/* CSE states */
54362306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(CSE_IMR_REQUEST),
54462306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(CSE_IMR_GRANTED),
54562306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(CSE_VALIDATE_IMAGE_REQUEST),
54662306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(CSE_IMAGE_VALIDATED),
54762306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(CSE_IPC_IFACE_INIT),
54862306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(CSE_IPC_RESET_PHASE_1),
54962306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(CSE_IPC_OPERATIONAL_ENTRY),
55062306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(CSE_IPC_OPERATIONAL),
55162306a36Sopenharmony_ci	FSR_ROM_STATE_ENTRY(CSE_IPC_DOWN),
55262306a36Sopenharmony_ci};
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci#define FSR_BRINGUP_STATE_ENTRY(state)	{FSR_STATE_BRINGUP_##state, #state}
55562306a36Sopenharmony_cistatic const struct hda_dsp_msg_code fsr_bringup_state_names[] = {
55662306a36Sopenharmony_ci	FSR_BRINGUP_STATE_ENTRY(INIT),
55762306a36Sopenharmony_ci	FSR_BRINGUP_STATE_ENTRY(INIT_DONE),
55862306a36Sopenharmony_ci	FSR_BRINGUP_STATE_ENTRY(HPSRAM_LOAD),
55962306a36Sopenharmony_ci	FSR_BRINGUP_STATE_ENTRY(UNPACK_START),
56062306a36Sopenharmony_ci	FSR_BRINGUP_STATE_ENTRY(IMR_RESTORE),
56162306a36Sopenharmony_ci	FSR_BRINGUP_STATE_ENTRY(FW_ENTERED),
56262306a36Sopenharmony_ci};
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci#define FSR_WAIT_STATE_ENTRY(state)	{FSR_WAIT_FOR_##state, #state}
56562306a36Sopenharmony_cistatic const struct hda_dsp_msg_code fsr_wait_state_names[] = {
56662306a36Sopenharmony_ci	FSR_WAIT_STATE_ENTRY(IPC_BUSY),
56762306a36Sopenharmony_ci	FSR_WAIT_STATE_ENTRY(IPC_DONE),
56862306a36Sopenharmony_ci	FSR_WAIT_STATE_ENTRY(CACHE_INVALIDATION),
56962306a36Sopenharmony_ci	FSR_WAIT_STATE_ENTRY(LP_SRAM_OFF),
57062306a36Sopenharmony_ci	FSR_WAIT_STATE_ENTRY(DMA_BUFFER_FULL),
57162306a36Sopenharmony_ci	FSR_WAIT_STATE_ENTRY(CSE_CSR),
57262306a36Sopenharmony_ci};
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci#define FSR_MODULE_NAME_ENTRY(mod)	[FSR_MOD_##mod] = #mod
57562306a36Sopenharmony_cistatic const char * const fsr_module_names[] = {
57662306a36Sopenharmony_ci	FSR_MODULE_NAME_ENTRY(ROM),
57762306a36Sopenharmony_ci	FSR_MODULE_NAME_ENTRY(ROM_BYP),
57862306a36Sopenharmony_ci	FSR_MODULE_NAME_ENTRY(BASE_FW),
57962306a36Sopenharmony_ci	FSR_MODULE_NAME_ENTRY(LP_BOOT),
58062306a36Sopenharmony_ci	FSR_MODULE_NAME_ENTRY(BRNGUP),
58162306a36Sopenharmony_ci	FSR_MODULE_NAME_ENTRY(ROM_EXT),
58262306a36Sopenharmony_ci};
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_cistatic const char *
58562306a36Sopenharmony_cihda_dsp_get_state_text(u32 code, const struct hda_dsp_msg_code *msg_code,
58662306a36Sopenharmony_ci		       size_t array_size)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	int i;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	for (i = 0; i < array_size; i++) {
59162306a36Sopenharmony_ci		if (code == msg_code[i].code)
59262306a36Sopenharmony_ci			return msg_code[i].text;
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	return NULL;
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic void hda_dsp_get_state(struct snd_sof_dev *sdev, const char *level)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
60162306a36Sopenharmony_ci	const char *state_text, *error_text, *module_text;
60262306a36Sopenharmony_ci	u32 fsr, state, wait_state, module, error_code;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	fsr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg);
60562306a36Sopenharmony_ci	state = FSR_TO_STATE_CODE(fsr);
60662306a36Sopenharmony_ci	wait_state = FSR_TO_WAIT_STATE_CODE(fsr);
60762306a36Sopenharmony_ci	module = FSR_TO_MODULE_CODE(fsr);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	if (module > FSR_MOD_ROM_EXT)
61062306a36Sopenharmony_ci		module_text = "unknown";
61162306a36Sopenharmony_ci	else
61262306a36Sopenharmony_ci		module_text = fsr_module_names[module];
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	if (module == FSR_MOD_BRNGUP)
61562306a36Sopenharmony_ci		state_text = hda_dsp_get_state_text(state, fsr_bringup_state_names,
61662306a36Sopenharmony_ci						    ARRAY_SIZE(fsr_bringup_state_names));
61762306a36Sopenharmony_ci	else
61862306a36Sopenharmony_ci		state_text = hda_dsp_get_state_text(state, fsr_rom_state_names,
61962306a36Sopenharmony_ci						    ARRAY_SIZE(fsr_rom_state_names));
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/* not for us, must be generic sof message */
62262306a36Sopenharmony_ci	if (!state_text) {
62362306a36Sopenharmony_ci		dev_printk(level, sdev->dev, "%#010x: unknown ROM status value\n", fsr);
62462306a36Sopenharmony_ci		return;
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	if (wait_state) {
62862306a36Sopenharmony_ci		const char *wait_state_text;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci		wait_state_text = hda_dsp_get_state_text(wait_state, fsr_wait_state_names,
63162306a36Sopenharmony_ci							 ARRAY_SIZE(fsr_wait_state_names));
63262306a36Sopenharmony_ci		if (!wait_state_text)
63362306a36Sopenharmony_ci			wait_state_text = "unknown";
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		dev_printk(level, sdev->dev,
63662306a36Sopenharmony_ci			   "%#010x: module: %s, state: %s, waiting for: %s, %s\n",
63762306a36Sopenharmony_ci			   fsr, module_text, state_text, wait_state_text,
63862306a36Sopenharmony_ci			   fsr & FSR_HALTED ? "not running" : "running");
63962306a36Sopenharmony_ci	} else {
64062306a36Sopenharmony_ci		dev_printk(level, sdev->dev, "%#010x: module: %s, state: %s, %s\n",
64162306a36Sopenharmony_ci			   fsr, module_text, state_text,
64262306a36Sopenharmony_ci			   fsr & FSR_HALTED ? "not running" : "running");
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	error_code = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg + 4);
64662306a36Sopenharmony_ci	if (!error_code)
64762306a36Sopenharmony_ci		return;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	error_text = hda_dsp_get_state_text(error_code, hda_dsp_rom_fw_error_texts,
65062306a36Sopenharmony_ci					    ARRAY_SIZE(hda_dsp_rom_fw_error_texts));
65162306a36Sopenharmony_ci	if (!error_text)
65262306a36Sopenharmony_ci		error_text = "unknown";
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	if (state == FSR_STATE_FW_ENTERED)
65562306a36Sopenharmony_ci		dev_printk(level, sdev->dev, "status code: %#x (%s)\n", error_code,
65662306a36Sopenharmony_ci			   error_text);
65762306a36Sopenharmony_ci	else
65862306a36Sopenharmony_ci		dev_printk(level, sdev->dev, "error code: %#x (%s)\n", error_code,
65962306a36Sopenharmony_ci			   error_text);
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic void hda_dsp_get_registers(struct snd_sof_dev *sdev,
66362306a36Sopenharmony_ci				  struct sof_ipc_dsp_oops_xtensa *xoops,
66462306a36Sopenharmony_ci				  struct sof_ipc_panic_info *panic_info,
66562306a36Sopenharmony_ci				  u32 *stack, size_t stack_words)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	u32 offset = sdev->dsp_oops_offset;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	/* first read registers */
67062306a36Sopenharmony_ci	sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops));
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	/* note: variable AR register array is not read */
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	/* then get panic info */
67562306a36Sopenharmony_ci	if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) {
67662306a36Sopenharmony_ci		dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n",
67762306a36Sopenharmony_ci			xoops->arch_hdr.totalsize);
67862306a36Sopenharmony_ci		return;
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_ci	offset += xoops->arch_hdr.totalsize;
68162306a36Sopenharmony_ci	sof_block_read(sdev, sdev->mmio_bar, offset,
68262306a36Sopenharmony_ci		       panic_info, sizeof(*panic_info));
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* then get the stack */
68562306a36Sopenharmony_ci	offset += sizeof(*panic_info);
68662306a36Sopenharmony_ci	sof_block_read(sdev, sdev->mmio_bar, offset, stack,
68762306a36Sopenharmony_ci		       stack_words * sizeof(u32));
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci/* dump the first 8 dwords representing the extended ROM status */
69162306a36Sopenharmony_cistatic void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, const char *level,
69262306a36Sopenharmony_ci					u32 flags)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip;
69562306a36Sopenharmony_ci	char msg[128];
69662306a36Sopenharmony_ci	int len = 0;
69762306a36Sopenharmony_ci	u32 value;
69862306a36Sopenharmony_ci	int i;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	chip = get_chip_info(sdev->pdata);
70162306a36Sopenharmony_ci	for (i = 0; i < HDA_EXT_ROM_STATUS_SIZE; i++) {
70262306a36Sopenharmony_ci		value = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->rom_status_reg + i * 0x4);
70362306a36Sopenharmony_ci		len += scnprintf(msg + len, sizeof(msg) - len, " 0x%x", value);
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	dev_printk(level, sdev->dev, "extended rom status: %s", msg);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_civoid hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
71362306a36Sopenharmony_ci	struct sof_ipc_dsp_oops_xtensa xoops;
71462306a36Sopenharmony_ci	struct sof_ipc_panic_info panic_info;
71562306a36Sopenharmony_ci	u32 stack[HDA_DSP_STACK_DUMP_SIZE];
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	/* print ROM/FW status */
71862306a36Sopenharmony_ci	hda_dsp_get_state(sdev, level);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	/* The firmware register dump only available with IPC3 */
72162306a36Sopenharmony_ci	if (flags & SOF_DBG_DUMP_REGS && sdev->pdata->ipc_type == SOF_IPC) {
72262306a36Sopenharmony_ci		u32 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_STATUS);
72362306a36Sopenharmony_ci		u32 panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_TRACEP);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci		hda_dsp_get_registers(sdev, &xoops, &panic_info, stack,
72662306a36Sopenharmony_ci				      HDA_DSP_STACK_DUMP_SIZE);
72762306a36Sopenharmony_ci		sof_print_oops_and_stack(sdev, level, status, panic, &xoops,
72862306a36Sopenharmony_ci					 &panic_info, stack, HDA_DSP_STACK_DUMP_SIZE);
72962306a36Sopenharmony_ci	} else {
73062306a36Sopenharmony_ci		hda_dsp_dump_ext_rom_status(sdev, level, flags);
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cistatic bool hda_check_ipc_irq(struct snd_sof_dev *sdev)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	chip = get_chip_info(sdev->pdata);
73962306a36Sopenharmony_ci	if (chip && chip->check_ipc_irq)
74062306a36Sopenharmony_ci		return chip->check_ipc_irq(sdev);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	return false;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_civoid hda_ipc_irq_dump(struct snd_sof_dev *sdev)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	u32 adspis;
74862306a36Sopenharmony_ci	u32 intsts;
74962306a36Sopenharmony_ci	u32 intctl;
75062306a36Sopenharmony_ci	u32 ppsts;
75162306a36Sopenharmony_ci	u8 rirbsts;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	/* read key IRQ stats and config registers */
75462306a36Sopenharmony_ci	adspis = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS);
75562306a36Sopenharmony_ci	intsts = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS);
75662306a36Sopenharmony_ci	intctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL);
75762306a36Sopenharmony_ci	ppsts = snd_sof_dsp_read(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPSTS);
75862306a36Sopenharmony_ci	rirbsts = snd_sof_dsp_read8(sdev, HDA_DSP_HDA_BAR, AZX_REG_RIRBSTS);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	dev_err(sdev->dev, "hda irq intsts 0x%8.8x intlctl 0x%8.8x rirb %2.2x\n",
76162306a36Sopenharmony_ci		intsts, intctl, rirbsts);
76262306a36Sopenharmony_ci	dev_err(sdev->dev, "dsp irq ppsts 0x%8.8x adspis 0x%8.8x\n", ppsts, adspis);
76362306a36Sopenharmony_ci}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_civoid hda_ipc_dump(struct snd_sof_dev *sdev)
76662306a36Sopenharmony_ci{
76762306a36Sopenharmony_ci	u32 hipcie;
76862306a36Sopenharmony_ci	u32 hipct;
76962306a36Sopenharmony_ci	u32 hipcctl;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	hda_ipc_irq_dump(sdev);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	/* read IPC status */
77462306a36Sopenharmony_ci	hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
77562306a36Sopenharmony_ci	hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
77662306a36Sopenharmony_ci	hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	/* dump the IPC regs */
77962306a36Sopenharmony_ci	/* TODO: parse the raw msg */
78062306a36Sopenharmony_ci	dev_err(sdev->dev, "host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n",
78162306a36Sopenharmony_ci		hipcie, hipct, hipcctl);
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_civoid hda_ipc4_dump(struct snd_sof_dev *sdev)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	u32 hipci, hipcie, hipct, hipcte, hipcctl;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	hda_ipc_irq_dump(sdev);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI);
79162306a36Sopenharmony_ci	hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
79262306a36Sopenharmony_ci	hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
79362306a36Sopenharmony_ci	hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCTE);
79462306a36Sopenharmony_ci	hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	/* dump the IPC regs */
79762306a36Sopenharmony_ci	/* TODO: parse the raw msg */
79862306a36Sopenharmony_ci	dev_err(sdev->dev, "Host IPC initiator: %#x|%#x, target: %#x|%#x, ctl: %#x\n",
79962306a36Sopenharmony_ci		hipci, hipcie, hipct, hipcte, hipcctl);
80062306a36Sopenharmony_ci}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_cibool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev)
80362306a36Sopenharmony_ci{
80462306a36Sopenharmony_ci	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
80562306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip = hda->desc;
80662306a36Sopenharmony_ci	u32 val;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, chip->ipc_req);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	return !!(val & chip->ipc_req_mask);
81162306a36Sopenharmony_ci}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_cistatic int hda_init(struct snd_sof_dev *sdev)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	struct hda_bus *hbus;
81662306a36Sopenharmony_ci	struct hdac_bus *bus;
81762306a36Sopenharmony_ci	struct pci_dev *pci = to_pci_dev(sdev->dev);
81862306a36Sopenharmony_ci	int ret;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	hbus = sof_to_hbus(sdev);
82162306a36Sopenharmony_ci	bus = sof_to_bus(sdev);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	/* HDA bus init */
82462306a36Sopenharmony_ci	sof_hda_bus_init(sdev, &pci->dev);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	if (sof_hda_position_quirk == SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS)
82762306a36Sopenharmony_ci		bus->use_posbuf = 0;
82862306a36Sopenharmony_ci	else
82962306a36Sopenharmony_ci		bus->use_posbuf = 1;
83062306a36Sopenharmony_ci	bus->bdl_pos_adj = 0;
83162306a36Sopenharmony_ci	bus->sync_write = 1;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	mutex_init(&hbus->prepare_mutex);
83462306a36Sopenharmony_ci	hbus->pci = pci;
83562306a36Sopenharmony_ci	hbus->mixer_assigned = -1;
83662306a36Sopenharmony_ci	hbus->modelname = hda_model;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	/* initialise hdac bus */
83962306a36Sopenharmony_ci	bus->addr = pci_resource_start(pci, 0);
84062306a36Sopenharmony_ci	bus->remap_addr = pci_ioremap_bar(pci, 0);
84162306a36Sopenharmony_ci	if (!bus->remap_addr) {
84262306a36Sopenharmony_ci		dev_err(bus->dev, "error: ioremap error\n");
84362306a36Sopenharmony_ci		return -ENXIO;
84462306a36Sopenharmony_ci	}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	/* HDA base */
84762306a36Sopenharmony_ci	sdev->bar[HDA_DSP_HDA_BAR] = bus->remap_addr;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	/* init i915 and HDMI codecs */
85062306a36Sopenharmony_ci	ret = hda_codec_i915_init(sdev);
85162306a36Sopenharmony_ci	if (ret < 0)
85262306a36Sopenharmony_ci		dev_warn(sdev->dev, "init of i915 and HDMI codec failed\n");
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	/* get controller capabilities */
85562306a36Sopenharmony_ci	ret = hda_dsp_ctrl_get_caps(sdev);
85662306a36Sopenharmony_ci	if (ret < 0)
85762306a36Sopenharmony_ci		dev_err(sdev->dev, "error: get caps error\n");
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	return ret;
86062306a36Sopenharmony_ci}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistatic int check_dmic_num(struct snd_sof_dev *sdev)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
86562306a36Sopenharmony_ci	struct nhlt_acpi_table *nhlt;
86662306a36Sopenharmony_ci	int dmic_num = 0;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	nhlt = hdev->nhlt;
86962306a36Sopenharmony_ci	if (nhlt)
87062306a36Sopenharmony_ci		dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	/* allow for module parameter override */
87362306a36Sopenharmony_ci	if (dmic_num_override != -1) {
87462306a36Sopenharmony_ci		dev_dbg(sdev->dev,
87562306a36Sopenharmony_ci			"overriding DMICs detected in NHLT tables %d by kernel param %d\n",
87662306a36Sopenharmony_ci			dmic_num, dmic_num_override);
87762306a36Sopenharmony_ci		dmic_num = dmic_num_override;
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	if (dmic_num < 0 || dmic_num > 4) {
88162306a36Sopenharmony_ci		dev_dbg(sdev->dev, "invalid dmic_number %d\n", dmic_num);
88262306a36Sopenharmony_ci		dmic_num = 0;
88362306a36Sopenharmony_ci	}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	return dmic_num;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_cistatic int check_nhlt_ssp_mask(struct snd_sof_dev *sdev)
88962306a36Sopenharmony_ci{
89062306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
89162306a36Sopenharmony_ci	struct nhlt_acpi_table *nhlt;
89262306a36Sopenharmony_ci	int ssp_mask = 0;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	nhlt = hdev->nhlt;
89562306a36Sopenharmony_ci	if (!nhlt)
89662306a36Sopenharmony_ci		return ssp_mask;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_SSP)) {
89962306a36Sopenharmony_ci		ssp_mask = intel_nhlt_ssp_endpoint_mask(nhlt, NHLT_DEVICE_I2S);
90062306a36Sopenharmony_ci		if (ssp_mask)
90162306a36Sopenharmony_ci			dev_info(sdev->dev, "NHLT_DEVICE_I2S detected, ssp_mask %#x\n", ssp_mask);
90262306a36Sopenharmony_ci	}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	return ssp_mask;
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic int check_nhlt_ssp_mclk_mask(struct snd_sof_dev *sdev, int ssp_num)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
91062306a36Sopenharmony_ci	struct nhlt_acpi_table *nhlt;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	nhlt = hdev->nhlt;
91362306a36Sopenharmony_ci	if (!nhlt)
91462306a36Sopenharmony_ci		return 0;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	return intel_nhlt_ssp_mclk_mask(nhlt, ssp_num);
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_cistatic const char *fixup_tplg_name(struct snd_sof_dev *sdev,
92262306a36Sopenharmony_ci				   const char *sof_tplg_filename,
92362306a36Sopenharmony_ci				   const char *idisp_str,
92462306a36Sopenharmony_ci				   const char *dmic_str)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	const char *tplg_filename = NULL;
92762306a36Sopenharmony_ci	char *filename, *tmp;
92862306a36Sopenharmony_ci	const char *split_ext;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	filename = kstrdup(sof_tplg_filename, GFP_KERNEL);
93162306a36Sopenharmony_ci	if (!filename)
93262306a36Sopenharmony_ci		return NULL;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	/* this assumes a .tplg extension */
93562306a36Sopenharmony_ci	tmp = filename;
93662306a36Sopenharmony_ci	split_ext = strsep(&tmp, ".");
93762306a36Sopenharmony_ci	if (split_ext)
93862306a36Sopenharmony_ci		tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
93962306a36Sopenharmony_ci					       "%s%s%s.tplg",
94062306a36Sopenharmony_ci					       split_ext, idisp_str, dmic_str);
94162306a36Sopenharmony_ci	kfree(filename);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	return tplg_filename;
94462306a36Sopenharmony_ci}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_cistatic int dmic_detect_topology_fixup(struct snd_sof_dev *sdev,
94762306a36Sopenharmony_ci				      const char **tplg_filename,
94862306a36Sopenharmony_ci				      const char *idisp_str,
94962306a36Sopenharmony_ci				      int *dmic_found,
95062306a36Sopenharmony_ci				      bool tplg_fixup)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	const char *dmic_str;
95362306a36Sopenharmony_ci	int dmic_num;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	/* first check for DMICs (using NHLT or module parameter) */
95662306a36Sopenharmony_ci	dmic_num = check_dmic_num(sdev);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	switch (dmic_num) {
95962306a36Sopenharmony_ci	case 1:
96062306a36Sopenharmony_ci		dmic_str = "-1ch";
96162306a36Sopenharmony_ci		break;
96262306a36Sopenharmony_ci	case 2:
96362306a36Sopenharmony_ci		dmic_str = "-2ch";
96462306a36Sopenharmony_ci		break;
96562306a36Sopenharmony_ci	case 3:
96662306a36Sopenharmony_ci		dmic_str = "-3ch";
96762306a36Sopenharmony_ci		break;
96862306a36Sopenharmony_ci	case 4:
96962306a36Sopenharmony_ci		dmic_str = "-4ch";
97062306a36Sopenharmony_ci		break;
97162306a36Sopenharmony_ci	default:
97262306a36Sopenharmony_ci		dmic_num = 0;
97362306a36Sopenharmony_ci		dmic_str = "";
97462306a36Sopenharmony_ci		break;
97562306a36Sopenharmony_ci	}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	if (tplg_fixup) {
97862306a36Sopenharmony_ci		const char *default_tplg_filename = *tplg_filename;
97962306a36Sopenharmony_ci		const char *fixed_tplg_filename;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci		fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
98262306a36Sopenharmony_ci						      idisp_str, dmic_str);
98362306a36Sopenharmony_ci		if (!fixed_tplg_filename)
98462306a36Sopenharmony_ci			return -ENOMEM;
98562306a36Sopenharmony_ci		*tplg_filename = fixed_tplg_filename;
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
98962306a36Sopenharmony_ci	*dmic_found = dmic_num;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	return 0;
99262306a36Sopenharmony_ci}
99362306a36Sopenharmony_ci#endif
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_cistatic int hda_init_caps(struct snd_sof_dev *sdev)
99662306a36Sopenharmony_ci{
99762306a36Sopenharmony_ci	u32 interface_mask = hda_get_interface_mask(sdev);
99862306a36Sopenharmony_ci	struct hdac_bus *bus = sof_to_bus(sdev);
99962306a36Sopenharmony_ci	struct snd_sof_pdata *pdata = sdev->pdata;
100062306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev = pdata->hw_pdata;
100162306a36Sopenharmony_ci	u32 link_mask;
100262306a36Sopenharmony_ci	int ret = 0;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	/* check if dsp is there */
100562306a36Sopenharmony_ci	if (bus->ppcap)
100662306a36Sopenharmony_ci		dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n");
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	/* Init HDA controller after i915 init */
100962306a36Sopenharmony_ci	ret = hda_dsp_ctrl_init_chip(sdev);
101062306a36Sopenharmony_ci	if (ret < 0) {
101162306a36Sopenharmony_ci		dev_err(bus->dev, "error: init chip failed with ret: %d\n",
101262306a36Sopenharmony_ci			ret);
101362306a36Sopenharmony_ci		return ret;
101462306a36Sopenharmony_ci	}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	hda_bus_ml_init(bus);
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	/* Skip SoundWire if it is not supported */
101962306a36Sopenharmony_ci	if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
102062306a36Sopenharmony_ci		goto skip_soundwire;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	/* scan SoundWire capabilities exposed by DSDT */
102362306a36Sopenharmony_ci	ret = hda_sdw_acpi_scan(sdev);
102462306a36Sopenharmony_ci	if (ret < 0) {
102562306a36Sopenharmony_ci		dev_dbg(sdev->dev, "skipping SoundWire, not detected with ACPI scan\n");
102662306a36Sopenharmony_ci		goto skip_soundwire;
102762306a36Sopenharmony_ci	}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	link_mask = hdev->info.link_mask;
103062306a36Sopenharmony_ci	if (!link_mask) {
103162306a36Sopenharmony_ci		dev_dbg(sdev->dev, "skipping SoundWire, no links enabled\n");
103262306a36Sopenharmony_ci		goto skip_soundwire;
103362306a36Sopenharmony_ci	}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	/*
103662306a36Sopenharmony_ci	 * probe/allocate SoundWire resources.
103762306a36Sopenharmony_ci	 * The hardware configuration takes place in hda_sdw_startup
103862306a36Sopenharmony_ci	 * after power rails are enabled.
103962306a36Sopenharmony_ci	 * It's entirely possible to have a mix of I2S/DMIC/SoundWire
104062306a36Sopenharmony_ci	 * devices, so we allocate the resources in all cases.
104162306a36Sopenharmony_ci	 */
104262306a36Sopenharmony_ci	ret = hda_sdw_probe(sdev);
104362306a36Sopenharmony_ci	if (ret < 0) {
104462306a36Sopenharmony_ci		dev_err(sdev->dev, "error: SoundWire probe error\n");
104562306a36Sopenharmony_ci		return ret;
104662306a36Sopenharmony_ci	}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ciskip_soundwire:
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	/* create codec instances */
105162306a36Sopenharmony_ci	hda_codec_probe_bus(sdev);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	if (!HDA_IDISP_CODEC(bus->codec_mask))
105462306a36Sopenharmony_ci		hda_codec_i915_display_power(sdev, false);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	hda_bus_ml_put_all(bus);
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	return 0;
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_cistatic irqreturn_t hda_dsp_interrupt_handler(int irq, void *context)
106262306a36Sopenharmony_ci{
106362306a36Sopenharmony_ci	struct snd_sof_dev *sdev = context;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	/*
106662306a36Sopenharmony_ci	 * Get global interrupt status. It includes all hardware interrupt
106762306a36Sopenharmony_ci	 * sources in the Intel HD Audio controller.
106862306a36Sopenharmony_ci	 */
106962306a36Sopenharmony_ci	if (snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS) &
107062306a36Sopenharmony_ci	    SOF_HDA_INTSTS_GIS) {
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci		/* disable GIE interrupt */
107362306a36Sopenharmony_ci		snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
107462306a36Sopenharmony_ci					SOF_HDA_INTCTL,
107562306a36Sopenharmony_ci					SOF_HDA_INT_GLOBAL_EN,
107662306a36Sopenharmony_ci					0);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci		return IRQ_WAKE_THREAD;
107962306a36Sopenharmony_ci	}
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	return IRQ_NONE;
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci	struct snd_sof_dev *sdev = context;
108762306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	/* deal with streams and controller first */
109062306a36Sopenharmony_ci	if (hda_dsp_check_stream_irq(sdev)) {
109162306a36Sopenharmony_ci		trace_sof_intel_hda_irq(sdev, "stream");
109262306a36Sopenharmony_ci		hda_dsp_stream_threaded_handler(irq, sdev);
109362306a36Sopenharmony_ci	}
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	if (hda_check_ipc_irq(sdev)) {
109662306a36Sopenharmony_ci		trace_sof_intel_hda_irq(sdev, "ipc");
109762306a36Sopenharmony_ci		sof_ops(sdev)->irq_thread(irq, sdev);
109862306a36Sopenharmony_ci	}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	if (hda_dsp_check_sdw_irq(sdev)) {
110162306a36Sopenharmony_ci		trace_sof_intel_hda_irq(sdev, "sdw");
110262306a36Sopenharmony_ci		hda_dsp_sdw_thread(irq, hdev->sdw);
110362306a36Sopenharmony_ci	}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	if (hda_sdw_check_wakeen_irq(sdev)) {
110662306a36Sopenharmony_ci		trace_sof_intel_hda_irq(sdev, "wakeen");
110762306a36Sopenharmony_ci		hda_sdw_process_wakeen(sdev);
110862306a36Sopenharmony_ci	}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	hda_codec_check_for_state_change(sdev);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	/* enable GIE interrupt */
111362306a36Sopenharmony_ci	snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
111462306a36Sopenharmony_ci				SOF_HDA_INTCTL,
111562306a36Sopenharmony_ci				SOF_HDA_INT_GLOBAL_EN,
111662306a36Sopenharmony_ci				SOF_HDA_INT_GLOBAL_EN);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	return IRQ_HANDLED;
111962306a36Sopenharmony_ci}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ciint hda_dsp_probe(struct snd_sof_dev *sdev)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	struct pci_dev *pci = to_pci_dev(sdev->dev);
112462306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev;
112562306a36Sopenharmony_ci	struct hdac_bus *bus;
112662306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip;
112762306a36Sopenharmony_ci	int ret = 0;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	if (!sdev->dspless_mode_selected) {
113062306a36Sopenharmony_ci		/*
113162306a36Sopenharmony_ci		 * detect DSP by checking class/subclass/prog-id information
113262306a36Sopenharmony_ci		 * class=04 subclass 03 prog-if 00: no DSP, legacy driver is required
113362306a36Sopenharmony_ci		 * class=04 subclass 01 prog-if 00: DSP is present
113462306a36Sopenharmony_ci		 *   (and may be required e.g. for DMIC or SSP support)
113562306a36Sopenharmony_ci		 * class=04 subclass 03 prog-if 80: either of DSP or legacy mode works
113662306a36Sopenharmony_ci		 */
113762306a36Sopenharmony_ci		if (pci->class == 0x040300) {
113862306a36Sopenharmony_ci			dev_err(sdev->dev, "the DSP is not enabled on this platform, aborting probe\n");
113962306a36Sopenharmony_ci			return -ENODEV;
114062306a36Sopenharmony_ci		} else if (pci->class != 0x040100 && pci->class != 0x040380) {
114162306a36Sopenharmony_ci			dev_err(sdev->dev, "unknown PCI class/subclass/prog-if 0x%06x found, aborting probe\n",
114262306a36Sopenharmony_ci				pci->class);
114362306a36Sopenharmony_ci			return -ENODEV;
114462306a36Sopenharmony_ci		}
114562306a36Sopenharmony_ci		dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n",
114662306a36Sopenharmony_ci			 pci->class);
114762306a36Sopenharmony_ci	}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	chip = get_chip_info(sdev->pdata);
115062306a36Sopenharmony_ci	if (!chip) {
115162306a36Sopenharmony_ci		dev_err(sdev->dev, "error: no such device supported, chip id:%x\n",
115262306a36Sopenharmony_ci			pci->device);
115362306a36Sopenharmony_ci		ret = -EIO;
115462306a36Sopenharmony_ci		goto err;
115562306a36Sopenharmony_ci	}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	sdev->num_cores = chip->cores_num;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL);
116062306a36Sopenharmony_ci	if (!hdev)
116162306a36Sopenharmony_ci		return -ENOMEM;
116262306a36Sopenharmony_ci	sdev->pdata->hw_pdata = hdev;
116362306a36Sopenharmony_ci	hdev->desc = chip;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	hdev->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec",
116662306a36Sopenharmony_ci						       PLATFORM_DEVID_NONE,
116762306a36Sopenharmony_ci						       NULL, 0);
116862306a36Sopenharmony_ci	if (IS_ERR(hdev->dmic_dev)) {
116962306a36Sopenharmony_ci		dev_err(sdev->dev, "error: failed to create DMIC device\n");
117062306a36Sopenharmony_ci		return PTR_ERR(hdev->dmic_dev);
117162306a36Sopenharmony_ci	}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	/*
117462306a36Sopenharmony_ci	 * use position update IPC if either it is forced
117562306a36Sopenharmony_ci	 * or we don't have other choice
117662306a36Sopenharmony_ci	 */
117762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION)
117862306a36Sopenharmony_ci	hdev->no_ipc_position = 0;
117962306a36Sopenharmony_ci#else
118062306a36Sopenharmony_ci	hdev->no_ipc_position = sof_ops(sdev)->pcm_pointer ? 1 : 0;
118162306a36Sopenharmony_ci#endif
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	if (sdev->dspless_mode_selected)
118462306a36Sopenharmony_ci		hdev->no_ipc_position = 1;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	/* set up HDA base */
118762306a36Sopenharmony_ci	bus = sof_to_bus(sdev);
118862306a36Sopenharmony_ci	ret = hda_init(sdev);
118962306a36Sopenharmony_ci	if (ret < 0)
119062306a36Sopenharmony_ci		goto hdac_bus_unmap;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	if (sdev->dspless_mode_selected)
119362306a36Sopenharmony_ci		goto skip_dsp_setup;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	/* DSP base */
119662306a36Sopenharmony_ci	sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR);
119762306a36Sopenharmony_ci	if (!sdev->bar[HDA_DSP_BAR]) {
119862306a36Sopenharmony_ci		dev_err(sdev->dev, "error: ioremap error\n");
119962306a36Sopenharmony_ci		ret = -ENXIO;
120062306a36Sopenharmony_ci		goto hdac_bus_unmap;
120162306a36Sopenharmony_ci	}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	sdev->mmio_bar = HDA_DSP_BAR;
120462306a36Sopenharmony_ci	sdev->mailbox_bar = HDA_DSP_BAR;
120562306a36Sopenharmony_ciskip_dsp_setup:
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	/* allow 64bit DMA address if supported by H/W */
120862306a36Sopenharmony_ci	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(64))) {
120962306a36Sopenharmony_ci		dev_dbg(sdev->dev, "DMA mask is 32 bit\n");
121062306a36Sopenharmony_ci		dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32));
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci	dma_set_max_seg_size(&pci->dev, UINT_MAX);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	/* init streams */
121562306a36Sopenharmony_ci	ret = hda_dsp_stream_init(sdev);
121662306a36Sopenharmony_ci	if (ret < 0) {
121762306a36Sopenharmony_ci		dev_err(sdev->dev, "error: failed to init streams\n");
121862306a36Sopenharmony_ci		/*
121962306a36Sopenharmony_ci		 * not all errors are due to memory issues, but trying
122062306a36Sopenharmony_ci		 * to free everything does not harm
122162306a36Sopenharmony_ci		 */
122262306a36Sopenharmony_ci		goto free_streams;
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	/*
122662306a36Sopenharmony_ci	 * register our IRQ
122762306a36Sopenharmony_ci	 * let's try to enable msi firstly
122862306a36Sopenharmony_ci	 * if it fails, use legacy interrupt mode
122962306a36Sopenharmony_ci	 * TODO: support msi multiple vectors
123062306a36Sopenharmony_ci	 */
123162306a36Sopenharmony_ci	if (hda_use_msi && pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI) > 0) {
123262306a36Sopenharmony_ci		dev_info(sdev->dev, "use msi interrupt mode\n");
123362306a36Sopenharmony_ci		sdev->ipc_irq = pci_irq_vector(pci, 0);
123462306a36Sopenharmony_ci		/* initialised to "false" by kzalloc() */
123562306a36Sopenharmony_ci		sdev->msi_enabled = true;
123662306a36Sopenharmony_ci	}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (!sdev->msi_enabled) {
123962306a36Sopenharmony_ci		dev_info(sdev->dev, "use legacy interrupt mode\n");
124062306a36Sopenharmony_ci		/*
124162306a36Sopenharmony_ci		 * in IO-APIC mode, hda->irq and ipc_irq are using the same
124262306a36Sopenharmony_ci		 * irq number of pci->irq
124362306a36Sopenharmony_ci		 */
124462306a36Sopenharmony_ci		sdev->ipc_irq = pci->irq;
124562306a36Sopenharmony_ci	}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq);
124862306a36Sopenharmony_ci	ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_interrupt_handler,
124962306a36Sopenharmony_ci				   hda_dsp_interrupt_thread,
125062306a36Sopenharmony_ci				   IRQF_SHARED, "AudioDSP", sdev);
125162306a36Sopenharmony_ci	if (ret < 0) {
125262306a36Sopenharmony_ci		dev_err(sdev->dev, "error: failed to register IPC IRQ %d\n",
125362306a36Sopenharmony_ci			sdev->ipc_irq);
125462306a36Sopenharmony_ci		goto free_irq_vector;
125562306a36Sopenharmony_ci	}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	pci_set_master(pci);
125862306a36Sopenharmony_ci	synchronize_irq(pci->irq);
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	/*
126162306a36Sopenharmony_ci	 * clear TCSEL to clear playback on some HD Audio
126262306a36Sopenharmony_ci	 * codecs. PCI TCSEL is defined in the Intel manuals.
126362306a36Sopenharmony_ci	 */
126462306a36Sopenharmony_ci	snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	/* init HDA capabilities */
126762306a36Sopenharmony_ci	ret = hda_init_caps(sdev);
126862306a36Sopenharmony_ci	if (ret < 0)
126962306a36Sopenharmony_ci		goto free_ipc_irq;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	if (!sdev->dspless_mode_selected) {
127262306a36Sopenharmony_ci		/* enable ppcap interrupt */
127362306a36Sopenharmony_ci		hda_dsp_ctrl_ppcap_enable(sdev, true);
127462306a36Sopenharmony_ci		hda_dsp_ctrl_ppcap_int_enable(sdev, true);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci		/* set default mailbox offset for FW ready message */
127762306a36Sopenharmony_ci		sdev->dsp_box.offset = HDA_DSP_MBOX_UPLINK_OFFSET;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci		INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work);
128062306a36Sopenharmony_ci	}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	init_waitqueue_head(&hdev->waitq);
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	hdev->nhlt = intel_nhlt_init(sdev->dev);
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	return 0;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_cifree_ipc_irq:
128962306a36Sopenharmony_ci	free_irq(sdev->ipc_irq, sdev);
129062306a36Sopenharmony_cifree_irq_vector:
129162306a36Sopenharmony_ci	if (sdev->msi_enabled)
129262306a36Sopenharmony_ci		pci_free_irq_vectors(pci);
129362306a36Sopenharmony_cifree_streams:
129462306a36Sopenharmony_ci	hda_dsp_stream_free(sdev);
129562306a36Sopenharmony_ci/* dsp_unmap: not currently used */
129662306a36Sopenharmony_ci	if (!sdev->dspless_mode_selected)
129762306a36Sopenharmony_ci		iounmap(sdev->bar[HDA_DSP_BAR]);
129862306a36Sopenharmony_cihdac_bus_unmap:
129962306a36Sopenharmony_ci	platform_device_unregister(hdev->dmic_dev);
130062306a36Sopenharmony_ci	iounmap(bus->remap_addr);
130162306a36Sopenharmony_ci	hda_codec_i915_exit(sdev);
130262306a36Sopenharmony_cierr:
130362306a36Sopenharmony_ci	return ret;
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ciint hda_dsp_remove(struct snd_sof_dev *sdev)
130762306a36Sopenharmony_ci{
130862306a36Sopenharmony_ci	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
130962306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip = hda->desc;
131062306a36Sopenharmony_ci	struct hdac_bus *bus = sof_to_bus(sdev);
131162306a36Sopenharmony_ci	struct pci_dev *pci = to_pci_dev(sdev->dev);
131262306a36Sopenharmony_ci	struct nhlt_acpi_table *nhlt = hda->nhlt;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	if (nhlt)
131562306a36Sopenharmony_ci		intel_nhlt_free(nhlt);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	if (!sdev->dspless_mode_selected)
131862306a36Sopenharmony_ci		/* cancel any attempt for DSP D0I3 */
131962306a36Sopenharmony_ci		cancel_delayed_work_sync(&hda->d0i3_work);
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	hda_codec_device_remove(sdev);
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	hda_sdw_exit(sdev);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(hda->dmic_dev))
132662306a36Sopenharmony_ci		platform_device_unregister(hda->dmic_dev);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	if (!sdev->dspless_mode_selected) {
132962306a36Sopenharmony_ci		/* disable DSP IRQ */
133062306a36Sopenharmony_ci		snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
133162306a36Sopenharmony_ci					SOF_HDA_PPCTL_PIE, 0);
133262306a36Sopenharmony_ci	}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	/* disable CIE and GIE interrupts */
133562306a36Sopenharmony_ci	snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
133662306a36Sopenharmony_ci				SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, 0);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	if (sdev->dspless_mode_selected)
133962306a36Sopenharmony_ci		goto skip_disable_dsp;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	/* no need to check for error as the DSP will be disabled anyway */
134262306a36Sopenharmony_ci	if (chip && chip->power_down_dsp)
134362306a36Sopenharmony_ci		chip->power_down_dsp(sdev);
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	/* disable DSP */
134662306a36Sopenharmony_ci	snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
134762306a36Sopenharmony_ci				SOF_HDA_PPCTL_GPROCEN, 0);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ciskip_disable_dsp:
135062306a36Sopenharmony_ci	free_irq(sdev->ipc_irq, sdev);
135162306a36Sopenharmony_ci	if (sdev->msi_enabled)
135262306a36Sopenharmony_ci		pci_free_irq_vectors(pci);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	hda_dsp_stream_free(sdev);
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	hda_bus_ml_free(sof_to_bus(sdev));
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	if (!sdev->dspless_mode_selected)
135962306a36Sopenharmony_ci		iounmap(sdev->bar[HDA_DSP_BAR]);
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	iounmap(bus->remap_addr);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	sof_hda_bus_exit(sdev);
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	hda_codec_i915_exit(sdev);
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	return 0;
136862306a36Sopenharmony_ci}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ciint hda_power_down_dsp(struct snd_sof_dev *sdev)
137162306a36Sopenharmony_ci{
137262306a36Sopenharmony_ci	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
137362306a36Sopenharmony_ci	const struct sof_intel_dsp_desc *chip = hda->desc;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	return hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
137662306a36Sopenharmony_ci}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
137962306a36Sopenharmony_cistatic void hda_generic_machine_select(struct snd_sof_dev *sdev,
138062306a36Sopenharmony_ci				       struct snd_soc_acpi_mach **mach)
138162306a36Sopenharmony_ci{
138262306a36Sopenharmony_ci	struct hdac_bus *bus = sof_to_bus(sdev);
138362306a36Sopenharmony_ci	struct snd_soc_acpi_mach_params *mach_params;
138462306a36Sopenharmony_ci	struct snd_soc_acpi_mach *hda_mach;
138562306a36Sopenharmony_ci	struct snd_sof_pdata *pdata = sdev->pdata;
138662306a36Sopenharmony_ci	const char *tplg_filename;
138762306a36Sopenharmony_ci	const char *idisp_str;
138862306a36Sopenharmony_ci	int dmic_num = 0;
138962306a36Sopenharmony_ci	int codec_num = 0;
139062306a36Sopenharmony_ci	int ret;
139162306a36Sopenharmony_ci	int i;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	/* codec detection */
139462306a36Sopenharmony_ci	if (!bus->codec_mask) {
139562306a36Sopenharmony_ci		dev_info(bus->dev, "no hda codecs found!\n");
139662306a36Sopenharmony_ci	} else {
139762306a36Sopenharmony_ci		dev_info(bus->dev, "hda codecs found, mask %lx\n",
139862306a36Sopenharmony_ci			 bus->codec_mask);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci		for (i = 0; i < HDA_MAX_CODECS; i++) {
140162306a36Sopenharmony_ci			if (bus->codec_mask & (1 << i))
140262306a36Sopenharmony_ci				codec_num++;
140362306a36Sopenharmony_ci		}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci		/*
140662306a36Sopenharmony_ci		 * If no machine driver is found, then:
140762306a36Sopenharmony_ci		 *
140862306a36Sopenharmony_ci		 * generic hda machine driver can handle:
140962306a36Sopenharmony_ci		 *  - one HDMI codec, and/or
141062306a36Sopenharmony_ci		 *  - one external HDAudio codec
141162306a36Sopenharmony_ci		 */
141262306a36Sopenharmony_ci		if (!*mach && codec_num <= 2) {
141362306a36Sopenharmony_ci			bool tplg_fixup;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci			hda_mach = snd_soc_acpi_intel_hda_machines;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci			dev_info(bus->dev, "using HDA machine driver %s now\n",
141862306a36Sopenharmony_ci				 hda_mach->drv_name);
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci			if (codec_num == 1 && HDA_IDISP_CODEC(bus->codec_mask))
142162306a36Sopenharmony_ci				idisp_str = "-idisp";
142262306a36Sopenharmony_ci			else
142362306a36Sopenharmony_ci				idisp_str = "";
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci			/* topology: use the info from hda_machines */
142662306a36Sopenharmony_ci			if (pdata->tplg_filename) {
142762306a36Sopenharmony_ci				tplg_fixup = false;
142862306a36Sopenharmony_ci				tplg_filename = pdata->tplg_filename;
142962306a36Sopenharmony_ci			} else {
143062306a36Sopenharmony_ci				tplg_fixup = true;
143162306a36Sopenharmony_ci				tplg_filename = hda_mach->sof_tplg_filename;
143262306a36Sopenharmony_ci			}
143362306a36Sopenharmony_ci			ret = dmic_detect_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num,
143462306a36Sopenharmony_ci							 tplg_fixup);
143562306a36Sopenharmony_ci			if (ret < 0)
143662306a36Sopenharmony_ci				return;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci			hda_mach->mach_params.dmic_num = dmic_num;
143962306a36Sopenharmony_ci			pdata->tplg_filename = tplg_filename;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci			if (codec_num == 2 ||
144262306a36Sopenharmony_ci			    (codec_num == 1 && !HDA_IDISP_CODEC(bus->codec_mask))) {
144362306a36Sopenharmony_ci				/*
144462306a36Sopenharmony_ci				 * Prevent SoundWire links from starting when an external
144562306a36Sopenharmony_ci				 * HDaudio codec is used
144662306a36Sopenharmony_ci				 */
144762306a36Sopenharmony_ci				hda_mach->mach_params.link_mask = 0;
144862306a36Sopenharmony_ci			} else {
144962306a36Sopenharmony_ci				/*
145062306a36Sopenharmony_ci				 * Allow SoundWire links to start when no external HDaudio codec
145162306a36Sopenharmony_ci				 * was detected. This will not create a SoundWire card but
145262306a36Sopenharmony_ci				 * will help detect if any SoundWire codec reports as ATTACHED.
145362306a36Sopenharmony_ci				 */
145462306a36Sopenharmony_ci				struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci				hda_mach->mach_params.link_mask = hdev->info.link_mask;
145762306a36Sopenharmony_ci			}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci			*mach = hda_mach;
146062306a36Sopenharmony_ci		}
146162306a36Sopenharmony_ci	}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	/* used by hda machine driver to create dai links */
146462306a36Sopenharmony_ci	if (*mach) {
146562306a36Sopenharmony_ci		mach_params = &(*mach)->mach_params;
146662306a36Sopenharmony_ci		mach_params->codec_mask = bus->codec_mask;
146762306a36Sopenharmony_ci		mach_params->common_hdmi_codec_drv = true;
146862306a36Sopenharmony_ci	}
146962306a36Sopenharmony_ci}
147062306a36Sopenharmony_ci#else
147162306a36Sopenharmony_cistatic void hda_generic_machine_select(struct snd_sof_dev *sdev,
147262306a36Sopenharmony_ci				       struct snd_soc_acpi_mach **mach)
147362306a36Sopenharmony_ci{
147462306a36Sopenharmony_ci}
147562306a36Sopenharmony_ci#endif
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_cistatic struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	struct snd_sof_pdata *pdata = sdev->pdata;
148262306a36Sopenharmony_ci	const struct snd_soc_acpi_link_adr *link;
148362306a36Sopenharmony_ci	struct snd_soc_acpi_mach *mach;
148462306a36Sopenharmony_ci	struct sof_intel_hda_dev *hdev;
148562306a36Sopenharmony_ci	u32 link_mask;
148662306a36Sopenharmony_ci	int i;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	hdev = pdata->hw_pdata;
148962306a36Sopenharmony_ci	link_mask = hdev->info.link_mask;
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	/*
149262306a36Sopenharmony_ci	 * Select SoundWire machine driver if needed using the
149362306a36Sopenharmony_ci	 * alternate tables. This case deals with SoundWire-only
149462306a36Sopenharmony_ci	 * machines, for mixed cases with I2C/I2S the detection relies
149562306a36Sopenharmony_ci	 * on the HID list.
149662306a36Sopenharmony_ci	 */
149762306a36Sopenharmony_ci	if (link_mask) {
149862306a36Sopenharmony_ci		for (mach = pdata->desc->alt_machines;
149962306a36Sopenharmony_ci		     mach && mach->link_mask; mach++) {
150062306a36Sopenharmony_ci			/*
150162306a36Sopenharmony_ci			 * On some platforms such as Up Extreme all links
150262306a36Sopenharmony_ci			 * are enabled but only one link can be used by
150362306a36Sopenharmony_ci			 * external codec. Instead of exact match of two masks,
150462306a36Sopenharmony_ci			 * first check whether link_mask of mach is subset of
150562306a36Sopenharmony_ci			 * link_mask supported by hw and then go on searching
150662306a36Sopenharmony_ci			 * link_adr
150762306a36Sopenharmony_ci			 */
150862306a36Sopenharmony_ci			if (~link_mask & mach->link_mask)
150962306a36Sopenharmony_ci				continue;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci			/* No need to match adr if there is no links defined */
151262306a36Sopenharmony_ci			if (!mach->links)
151362306a36Sopenharmony_ci				break;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci			link = mach->links;
151662306a36Sopenharmony_ci			for (i = 0; i < hdev->info.count && link->num_adr;
151762306a36Sopenharmony_ci			     i++, link++) {
151862306a36Sopenharmony_ci				/*
151962306a36Sopenharmony_ci				 * Try next machine if any expected Slaves
152062306a36Sopenharmony_ci				 * are not found on this link.
152162306a36Sopenharmony_ci				 */
152262306a36Sopenharmony_ci				if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link,
152362306a36Sopenharmony_ci									hdev->sdw->ids,
152462306a36Sopenharmony_ci									hdev->sdw->num_slaves))
152562306a36Sopenharmony_ci					break;
152662306a36Sopenharmony_ci			}
152762306a36Sopenharmony_ci			/* Found if all Slaves are checked */
152862306a36Sopenharmony_ci			if (i == hdev->info.count || !link->num_adr)
152962306a36Sopenharmony_ci				break;
153062306a36Sopenharmony_ci		}
153162306a36Sopenharmony_ci		if (mach && mach->link_mask) {
153262306a36Sopenharmony_ci			int dmic_num = 0;
153362306a36Sopenharmony_ci			bool tplg_fixup;
153462306a36Sopenharmony_ci			const char *tplg_filename;
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci			mach->mach_params.links = mach->links;
153762306a36Sopenharmony_ci			mach->mach_params.link_mask = mach->link_mask;
153862306a36Sopenharmony_ci			mach->mach_params.platform = dev_name(sdev->dev);
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci			if (pdata->tplg_filename) {
154162306a36Sopenharmony_ci				tplg_fixup = false;
154262306a36Sopenharmony_ci			} else {
154362306a36Sopenharmony_ci				tplg_fixup = true;
154462306a36Sopenharmony_ci				tplg_filename = mach->sof_tplg_filename;
154562306a36Sopenharmony_ci			}
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci			/*
154862306a36Sopenharmony_ci			 * DMICs use up to 4 pins and are typically pin-muxed with SoundWire
154962306a36Sopenharmony_ci			 * link 2 and 3, or link 1 and 2, thus we only try to enable dmics
155062306a36Sopenharmony_ci			 * if all conditions are true:
155162306a36Sopenharmony_ci			 * a) 2 or fewer links are used by SoundWire
155262306a36Sopenharmony_ci			 * b) the NHLT table reports the presence of microphones
155362306a36Sopenharmony_ci			 */
155462306a36Sopenharmony_ci			if (hweight_long(mach->link_mask) <= 2) {
155562306a36Sopenharmony_ci				int ret;
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci				ret = dmic_detect_topology_fixup(sdev, &tplg_filename, "",
155862306a36Sopenharmony_ci								 &dmic_num, tplg_fixup);
155962306a36Sopenharmony_ci				if (ret < 0)
156062306a36Sopenharmony_ci					return NULL;
156162306a36Sopenharmony_ci			}
156262306a36Sopenharmony_ci			if (tplg_fixup)
156362306a36Sopenharmony_ci				pdata->tplg_filename = tplg_filename;
156462306a36Sopenharmony_ci			mach->mach_params.dmic_num = dmic_num;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci			dev_dbg(sdev->dev,
156762306a36Sopenharmony_ci				"SoundWire machine driver %s topology %s\n",
156862306a36Sopenharmony_ci				mach->drv_name,
156962306a36Sopenharmony_ci				pdata->tplg_filename);
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci			return mach;
157262306a36Sopenharmony_ci		}
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci		dev_info(sdev->dev, "No SoundWire machine driver found\n");
157562306a36Sopenharmony_ci	}
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	return NULL;
157862306a36Sopenharmony_ci}
157962306a36Sopenharmony_ci#else
158062306a36Sopenharmony_cistatic struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev)
158162306a36Sopenharmony_ci{
158262306a36Sopenharmony_ci	return NULL;
158362306a36Sopenharmony_ci}
158462306a36Sopenharmony_ci#endif
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_civoid hda_set_mach_params(struct snd_soc_acpi_mach *mach,
158762306a36Sopenharmony_ci			 struct snd_sof_dev *sdev)
158862306a36Sopenharmony_ci{
158962306a36Sopenharmony_ci	struct snd_sof_pdata *pdata = sdev->pdata;
159062306a36Sopenharmony_ci	const struct sof_dev_desc *desc = pdata->desc;
159162306a36Sopenharmony_ci	struct snd_soc_acpi_mach_params *mach_params;
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	mach_params = &mach->mach_params;
159462306a36Sopenharmony_ci	mach_params->platform = dev_name(sdev->dev);
159562306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
159662306a36Sopenharmony_ci	    sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
159762306a36Sopenharmony_ci		mach_params->num_dai_drivers = SOF_SKL_NUM_DAIS_NOCODEC;
159862306a36Sopenharmony_ci	else
159962306a36Sopenharmony_ci		mach_params->num_dai_drivers = desc->ops->num_drv;
160062306a36Sopenharmony_ci	mach_params->dai_drivers = desc->ops->drv;
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_cistruct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	u32 interface_mask = hda_get_interface_mask(sdev);
160662306a36Sopenharmony_ci	struct snd_sof_pdata *sof_pdata = sdev->pdata;
160762306a36Sopenharmony_ci	const struct sof_dev_desc *desc = sof_pdata->desc;
160862306a36Sopenharmony_ci	struct snd_soc_acpi_mach *mach = NULL;
160962306a36Sopenharmony_ci	const char *tplg_filename;
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	/* Try I2S or DMIC if it is supported */
161262306a36Sopenharmony_ci	if (interface_mask & (BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC)))
161362306a36Sopenharmony_ci		mach = snd_soc_acpi_find_machine(desc->machines);
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	if (mach) {
161662306a36Sopenharmony_ci		bool add_extension = false;
161762306a36Sopenharmony_ci		bool tplg_fixup = false;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci		/*
162062306a36Sopenharmony_ci		 * If tplg file name is overridden, use it instead of
162162306a36Sopenharmony_ci		 * the one set in mach table
162262306a36Sopenharmony_ci		 */
162362306a36Sopenharmony_ci		if (!sof_pdata->tplg_filename) {
162462306a36Sopenharmony_ci			sof_pdata->tplg_filename = mach->sof_tplg_filename;
162562306a36Sopenharmony_ci			tplg_fixup = true;
162662306a36Sopenharmony_ci		}
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci		/* report to machine driver if any DMICs are found */
162962306a36Sopenharmony_ci		mach->mach_params.dmic_num = check_dmic_num(sdev);
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci		if (tplg_fixup &&
163262306a36Sopenharmony_ci		    mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER &&
163362306a36Sopenharmony_ci		    mach->mach_params.dmic_num) {
163462306a36Sopenharmony_ci			tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
163562306a36Sopenharmony_ci						       "%s%s%d%s",
163662306a36Sopenharmony_ci						       sof_pdata->tplg_filename,
163762306a36Sopenharmony_ci						       "-dmic",
163862306a36Sopenharmony_ci						       mach->mach_params.dmic_num,
163962306a36Sopenharmony_ci						       "ch");
164062306a36Sopenharmony_ci			if (!tplg_filename)
164162306a36Sopenharmony_ci				return NULL;
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci			sof_pdata->tplg_filename = tplg_filename;
164462306a36Sopenharmony_ci			add_extension = true;
164562306a36Sopenharmony_ci		}
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci		if (mach->link_mask) {
164862306a36Sopenharmony_ci			mach->mach_params.links = mach->links;
164962306a36Sopenharmony_ci			mach->mach_params.link_mask = mach->link_mask;
165062306a36Sopenharmony_ci		}
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci		/* report SSP link mask to machine driver */
165362306a36Sopenharmony_ci		mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev);
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci		if (tplg_fixup &&
165662306a36Sopenharmony_ci		    mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER &&
165762306a36Sopenharmony_ci		    mach->mach_params.i2s_link_mask) {
165862306a36Sopenharmony_ci			const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
165962306a36Sopenharmony_ci			int ssp_num;
166062306a36Sopenharmony_ci			int mclk_mask;
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci			if (hweight_long(mach->mach_params.i2s_link_mask) > 1 &&
166362306a36Sopenharmony_ci			    !(mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_MSB))
166462306a36Sopenharmony_ci				dev_warn(sdev->dev, "More than one SSP exposed by NHLT, choosing MSB\n");
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci			/* fls returns 1-based results, SSPs indices are 0-based */
166762306a36Sopenharmony_ci			ssp_num = fls(mach->mach_params.i2s_link_mask) - 1;
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci			if (ssp_num >= chip->ssp_count) {
167062306a36Sopenharmony_ci				dev_err(sdev->dev, "Invalid SSP %d, max on this platform is %d\n",
167162306a36Sopenharmony_ci					ssp_num, chip->ssp_count);
167262306a36Sopenharmony_ci				return NULL;
167362306a36Sopenharmony_ci			}
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci			tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
167662306a36Sopenharmony_ci						       "%s%s%d",
167762306a36Sopenharmony_ci						       sof_pdata->tplg_filename,
167862306a36Sopenharmony_ci						       "-ssp",
167962306a36Sopenharmony_ci						       ssp_num);
168062306a36Sopenharmony_ci			if (!tplg_filename)
168162306a36Sopenharmony_ci				return NULL;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci			sof_pdata->tplg_filename = tplg_filename;
168462306a36Sopenharmony_ci			add_extension = true;
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci			mclk_mask = check_nhlt_ssp_mclk_mask(sdev, ssp_num);
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci			if (mclk_mask < 0) {
168962306a36Sopenharmony_ci				dev_err(sdev->dev, "Invalid MCLK configuration\n");
169062306a36Sopenharmony_ci				return NULL;
169162306a36Sopenharmony_ci			}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci			dev_dbg(sdev->dev, "MCLK mask %#x found in NHLT\n", mclk_mask);
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci			if (mclk_mask) {
169662306a36Sopenharmony_ci				dev_info(sdev->dev, "Overriding topology with MCLK mask %#x from NHLT\n", mclk_mask);
169762306a36Sopenharmony_ci				sdev->mclk_id_override = true;
169862306a36Sopenharmony_ci				sdev->mclk_id_quirk = (mclk_mask & BIT(0)) ? 0 : 1;
169962306a36Sopenharmony_ci			}
170062306a36Sopenharmony_ci		}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci		if (tplg_fixup && add_extension) {
170362306a36Sopenharmony_ci			tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
170462306a36Sopenharmony_ci						       "%s%s",
170562306a36Sopenharmony_ci						       sof_pdata->tplg_filename,
170662306a36Sopenharmony_ci						       ".tplg");
170762306a36Sopenharmony_ci			if (!tplg_filename)
170862306a36Sopenharmony_ci				return NULL;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci			sof_pdata->tplg_filename = tplg_filename;
171162306a36Sopenharmony_ci		}
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci		/* check if mclk_id should be modified from topology defaults */
171462306a36Sopenharmony_ci		if (mclk_id_override >= 0) {
171562306a36Sopenharmony_ci			dev_info(sdev->dev, "Overriding topology with MCLK %d from kernel_parameter\n", mclk_id_override);
171662306a36Sopenharmony_ci			sdev->mclk_id_override = true;
171762306a36Sopenharmony_ci			sdev->mclk_id_quirk = mclk_id_override;
171862306a36Sopenharmony_ci		}
171962306a36Sopenharmony_ci	}
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	/* If I2S fails, try SoundWire if it is supported */
172262306a36Sopenharmony_ci	if (!mach && (interface_mask & BIT(SOF_DAI_INTEL_ALH)))
172362306a36Sopenharmony_ci		mach = hda_sdw_machine_select(sdev);
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	/*
172662306a36Sopenharmony_ci	 * Choose HDA generic machine driver if mach is NULL.
172762306a36Sopenharmony_ci	 * Otherwise, set certain mach params.
172862306a36Sopenharmony_ci	 */
172962306a36Sopenharmony_ci	hda_generic_machine_select(sdev, &mach);
173062306a36Sopenharmony_ci	if (!mach)
173162306a36Sopenharmony_ci		dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n");
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	return mach;
173462306a36Sopenharmony_ci}
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ciint hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
173762306a36Sopenharmony_ci{
173862306a36Sopenharmony_ci	int ret;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	ret = snd_intel_dsp_driver_probe(pci);
174162306a36Sopenharmony_ci	if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) {
174262306a36Sopenharmony_ci		dev_dbg(&pci->dev, "SOF PCI driver not selected, aborting probe\n");
174362306a36Sopenharmony_ci		return -ENODEV;
174462306a36Sopenharmony_ci	}
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	return sof_pci_probe(pci, pci_id);
174762306a36Sopenharmony_ci}
174862306a36Sopenharmony_ciEXPORT_SYMBOL_NS(hda_pci_intel_probe, SND_SOC_SOF_INTEL_HDA_COMMON);
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ciint hda_register_clients(struct snd_sof_dev *sdev)
175162306a36Sopenharmony_ci{
175262306a36Sopenharmony_ci	return hda_probes_register(sdev);
175362306a36Sopenharmony_ci}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_civoid hda_unregister_clients(struct snd_sof_dev *sdev)
175662306a36Sopenharmony_ci{
175762306a36Sopenharmony_ci	hda_probes_unregister(sdev);
175862306a36Sopenharmony_ci}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
176162306a36Sopenharmony_ciMODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
176262306a36Sopenharmony_ciMODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC);
176362306a36Sopenharmony_ciMODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
176462306a36Sopenharmony_ciMODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
176562306a36Sopenharmony_ciMODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);
176662306a36Sopenharmony_ciMODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT);
176762306a36Sopenharmony_ciMODULE_IMPORT_NS(SOUNDWIRE_INTEL);
176862306a36Sopenharmony_ciMODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK);
1769