Unverified Commit eb73f6d6 authored by Mark Brown's avatar Mark Brown
Browse files

ASoC/soundwire: revisit interrupt and lcount handling

Merge series from Bard Liao <yung-chuan.liao@linux.intel.com>:

The code in drivers/soundwire/intel_init.c is hardware-dependent and the
code does not apply to new generations starting with MeteorLake. Refactor
and clean-up the code to make this intel_init.c hardware-agnostic and
move all hardware-dependencies in the SOF driver using chip descriptors.
parents 57405d8b 5e2cbc4a
Loading
Loading
Loading
Loading
+0 −37
Original line number Diff line number Diff line
@@ -125,30 +125,6 @@ static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx)
	return 0;
}

#define HDA_DSP_REG_ADSPIC2             (0x10)
#define HDA_DSP_REG_ADSPIS2             (0x14)
#define HDA_DSP_REG_ADSPIC2_SNDW        BIT(5)

/**
 * sdw_intel_enable_irq() - enable/disable Intel SoundWire IRQ
 * @mmio_base: The mmio base of the control register
 * @enable: true if enable
 */
void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable)
{
	u32 val;

	val = readl(mmio_base + HDA_DSP_REG_ADSPIC2);

	if (enable)
		val |= HDA_DSP_REG_ADSPIC2_SNDW;
	else
		val &= ~HDA_DSP_REG_ADSPIC2_SNDW;

	writel(val, mmio_base + HDA_DSP_REG_ADSPIC2);
}
EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT);

irqreturn_t sdw_intel_thread(int irq, void *dev_id)
{
	struct sdw_intel_ctx *ctx = dev_id;
@@ -157,7 +133,6 @@ irqreturn_t sdw_intel_thread(int irq, void *dev_id)
	list_for_each_entry(link, &ctx->link_list, list)
		sdw_cdns_irq(irq, link->cdns);

	sdw_intel_enable_irq(ctx->mmio_base, true);
	return IRQ_HANDLED;
}
EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT);
@@ -297,24 +272,12 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
{
	struct acpi_device *adev = acpi_fetch_acpi_dev(ctx->handle);
	struct sdw_intel_link_dev *ldev;
	u32 caps;
	u32 link_mask;
	int i;

	if (!adev)
		return -EINVAL;

	/* Check SNDWLCAP.LCOUNT */
	caps = ioread32(ctx->mmio_base + ctx->shim_base + SDW_SHIM_LCAP);
	caps &= SDW_SHIM_LCAP_LCOUNT_MASK;

	/* Check HW supported vs property value */
	if (caps < ctx->count) {
		dev_err(&adev->dev,
			"BIOS master count is larger than hardware capabilities\n");
		return -EINVAL;
	}

	if (!ctx->ldev)
		return -EINVAL;

+0 −2
Original line number Diff line number Diff line
@@ -286,8 +286,6 @@ int sdw_intel_startup(struct sdw_intel_ctx *ctx);

void sdw_intel_exit(struct sdw_intel_ctx *ctx);

void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable);

irqreturn_t sdw_intel_thread(int irq, void *dev_id);

#define SDW_INTEL_QUIRK_MASK_BUS_DISABLE      BIT(1)
+4 −0
Original line number Diff line number Diff line
@@ -457,6 +457,8 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
	.sdw_shim_base = SDW_SHIM_BASE,
	.sdw_alh_base = SDW_ALH_BASE,
	.d0i3_offset = SOF_HDA_VS_D0I3C,
	.read_sdw_lcount =  hda_sdw_check_lcount_common,
	.enable_sdw_irq	= hda_common_enable_sdw_irq,
	.check_sdw_irq	= hda_common_check_sdw_irq,
	.check_ipc_irq	= hda_dsp_check_ipc_irq,
	.cl_init = cl_dsp_init,
@@ -490,6 +492,8 @@ const struct sof_intel_dsp_desc jsl_chip_info = {
	.sdw_shim_base = SDW_SHIM_BASE,
	.sdw_alh_base = SDW_ALH_BASE,
	.d0i3_offset = SOF_HDA_VS_D0I3C,
	.read_sdw_lcount =  hda_sdw_check_lcount_common,
	.enable_sdw_irq	= hda_common_enable_sdw_irq,
	.check_sdw_irq	= hda_common_check_sdw_irq,
	.check_ipc_irq	= hda_dsp_check_ipc_irq,
	.cl_init = cl_dsp_init,
+60 −3
Original line number Diff line number Diff line
@@ -155,9 +155,27 @@ struct sdw_intel_ops sdw_callback = {
	.free_stream = sdw_free_stream,
};

void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
{
	struct sof_intel_hda_dev *hdev;

	hdev = sdev->pdata->hw_pdata;

	if (!hdev->sdw)
		return;

	snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC2,
				HDA_DSP_REG_ADSPIC2_SNDW,
				enable ? HDA_DSP_REG_ADSPIC2_SNDW : 0);
}

void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
{
	sdw_intel_enable_irq(sdev->bar[HDA_DSP_BAR], enable);
	const struct sof_intel_dsp_desc *chip;

	chip = get_chip_info(sdev->pdata);
	if (chip && chip->enable_sdw_irq)
		chip->enable_sdw_irq(sdev, enable);
}

static int hda_sdw_acpi_scan(struct snd_sof_dev *sdev)
@@ -220,10 +238,45 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev)
	return 0;
}

int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
{
	struct sof_intel_hda_dev *hdev;
	struct sdw_intel_ctx *ctx;
	u32 caps;

	hdev = sdev->pdata->hw_pdata;
	ctx = hdev->sdw;

	caps = snd_sof_dsp_read(sdev, HDA_DSP_BAR, ctx->shim_base + SDW_SHIM_LCAP);
	caps &= SDW_SHIM_LCAP_LCOUNT_MASK;

	/* Check HW supported vs property value */
	if (caps < ctx->count) {
		dev_err(sdev->dev,
			"BIOS master count %d is larger than hardware capabilities %d\n",
			ctx->count, caps);
		return -EINVAL;
	}

	return 0;
}

static int hda_sdw_check_lcount(struct snd_sof_dev *sdev)
{
	const struct sof_intel_dsp_desc *chip;

	chip = get_chip_info(sdev->pdata);
	if (chip && chip->read_sdw_lcount)
		return chip->read_sdw_lcount(sdev);

	return 0;
}

int hda_sdw_startup(struct snd_sof_dev *sdev)
{
	struct sof_intel_hda_dev *hdev;
	struct snd_sof_pdata *pdata = sdev->pdata;
	int ret;

	hdev = sdev->pdata->hw_pdata;

@@ -233,6 +286,10 @@ int hda_sdw_startup(struct snd_sof_dev *sdev)
	if (pdata->machine && !pdata->machine->mach_params.link_mask)
		return 0;

	ret = hda_sdw_check_lcount(sdev);
	if (ret < 0)
		return ret;

	return sdw_intel_startup(hdev->sdw);
}

@@ -887,6 +944,8 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
		return ret;
	}

	hda_bus_ml_get_capabilities(bus);

	/* scan SoundWire capabilities exposed by DSDT */
	ret = hda_sdw_acpi_scan(sdev);
	if (ret < 0) {
@@ -915,8 +974,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev)

skip_soundwire:

	hda_bus_ml_get_capabilities(bus);

	/* create codec instances */
	hda_codec_probe_bus(sdev);

+12 −0
Original line number Diff line number Diff line
@@ -294,6 +294,7 @@
#define HDA_DSP_REG_ADSPIC2		(HDA_DSP_GEN_BASE + 0x10)
#define HDA_DSP_REG_ADSPIS2		(HDA_DSP_GEN_BASE + 0x14)

#define HDA_DSP_REG_ADSPIC2_SNDW	BIT(5)
#define HDA_DSP_REG_ADSPIS2_SNDW	BIT(5)

/* Intel HD Audio Inter-Processor Communication Registers */
@@ -794,18 +795,29 @@ int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd);
 */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)

int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev);
int hda_sdw_startup(struct snd_sof_dev *sdev);
void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable);
void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable);
void hda_sdw_process_wakeen(struct snd_sof_dev *sdev);
bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev);

#else

static inline int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
{
	return 0;
}

static inline int hda_sdw_startup(struct snd_sof_dev *sdev)
{
	return 0;
}

static inline void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
{
}

static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
{
}
Loading