Commit 442ece6b authored by Mark Brown's avatar Mark Brown

ASoC: SOF: Intel: add LunarLake support

Merge series from Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>:

This patchset first fixes a number of errors made in the hda-mlink
support, then adds Lunar Lake definitions. The main contribution is
the hda-dai changes where the HDaudio DMA is now used for SSP, DMIC
and SoundWire. In previous hardware the GPDMA (aka DesignWare) was
used and controlled by the audio firmware. The volume of code is
minimized with the abstraction added in previous kernel cycles.

Due to cross-dependencies between ASoC and SoundWire trees, the full
support for jack detection will be deferred to the next kernel
cycle. There's not much point to ask for a sync of the two trees to
support one patch for each tree - we are at -rc5 already.
parents 93fd2be6 02c7f872
This diff is collapsed.
......@@ -42,6 +42,7 @@ int hdac_bus_eml_power_down_unlocked(struct hdac_bus *bus, bool alt, int elid, i
int hdac_bus_eml_sdw_power_up_unlocked(struct hdac_bus *bus, int sublink);
int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink);
int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid);
int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num);
int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
......@@ -145,6 +146,9 @@ hdac_bus_eml_sdw_power_up_unlocked(struct hdac_bus *bus, int sublink) { return 0
static inline int
hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink) { return 0; }
static inline int
hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid) { return 0; }
static inline int
hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num) { return 0; }
......
......@@ -18,9 +18,6 @@
#include <sound/hda_verbs.h>
#include <sound/hda_regmap.h>
#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348)
/*
* Structures
*/
......
......@@ -11,6 +11,7 @@
#include <linux/io.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/iopoll.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/timecounter.h>
#include <sound/core.h>
......@@ -704,4 +705,29 @@ static inline unsigned int snd_array_index(struct snd_array *array, void *ptr)
for ((idx) = 0, (ptr) = (array)->list; (idx) < (array)->used; \
(ptr) = snd_array_elem(array, ++(idx)))
/*
* Device matching
*/
#define HDA_CONTROLLER_IS_HSW(pci) (pci_match_id((struct pci_device_id []){ \
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_HSW_0) }, \
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_HSW_2) }, \
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_HSW_3) }, \
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_BDW) }, \
{ } \
}, pci))
#define HDA_CONTROLLER_IS_APL(pci) (pci_match_id((struct pci_device_id []){ \
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_APL) }, \
{ } \
}, pci))
#define HDA_CONTROLLER_IN_GPU(pci) (pci_match_id((struct pci_device_id []){ \
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG1) }, \
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG2_0) }, \
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG2_1) }, \
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HDA_DG2_2) }, \
{ } \
}, pci) || HDA_CONTROLLER_IS_HSW(pci))
#endif /* __SOUND_HDAUDIO_H */
......@@ -11,11 +11,6 @@
#include <sound/hda_i915.h>
#include <sound/hda_register.h>
#define IS_HSW_CONTROLLER(pci) (((pci)->device == 0x0a0c) || \
((pci)->device == 0x0c0c) || \
((pci)->device == 0x0d0c) || \
((pci)->device == 0x160c))
/**
* snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW
* @bus: HDA core bus
......@@ -39,7 +34,7 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq)
return; /* only for i915 binding */
if (!IS_HSW_CONTROLLER(pci))
if (!HDA_CONTROLLER_IS_HSW(pci))
return; /* only HSW/BDW */
cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev);
......@@ -80,14 +75,20 @@ static bool connectivity_check(struct pci_dev *i915, struct pci_dev *hdac)
if (bus_a == bus_b)
return true;
/*
* on i915 discrete GPUs with embedded HDA audio, the two
* devices are connected via 2nd level PCI bridge
*/
bus_a = bus_a->parent;
bus_b = bus_b->parent;
/* connected via parent bus (may be NULL!) */
if (bus_a == bus_b)
return true;
if (!bus_a || !bus_b)
return false;
/*
* on i915 discrete GPUs with embedded HDA audio, the two
* devices are connected via 2nd level PCI bridge
*/
bus_a = bus_a->parent;
bus_b = bus_b->parent;
if (bus_a && bus_a == bus_b)
......
This diff is collapsed.
This diff is collapsed.
......@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/firmware.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/async.h>
......@@ -174,9 +175,9 @@ int sst_driver_ops(struct intel_sst_drv *sst)
{
switch (sst->dev_id) {
case SST_MRFLD_PCI_ID:
case SST_BYT_ACPI_ID:
case SST_CHV_ACPI_ID:
case PCI_DEVICE_ID_INTEL_SST_TNG:
case PCI_DEVICE_ID_INTEL_SST_BYT:
case PCI_DEVICE_ID_INTEL_SST_BSW:
sst->tstamp = SST_TIME_STAMP_MRFLD;
sst->ops = &mrfld_ops;
return 0;
......@@ -221,8 +222,13 @@ static void sst_init_locks(struct intel_sst_drv *ctx)
spin_lock_init(&ctx->block_lock);
}
/*
* Driver handles PCI IDs in ACPI - sst_acpi_probe() - and we are using only
* device ID part. If real ACPI ID appears, the kstrtouint() returns error, so
* we are fine with using unsigned short as dev_id type.
*/
int sst_alloc_drv_context(struct intel_sst_drv **ctx,
struct device *dev, unsigned int dev_id)
struct device *dev, unsigned short dev_id)
{
*ctx = devm_kzalloc(dev, sizeof(struct intel_sst_drv), GFP_KERNEL);
if (!(*ctx))
......
......@@ -20,9 +20,6 @@
/* driver names */
#define SST_DRV_NAME "intel_sst_driver"
#define SST_MRFLD_PCI_ID 0x119A
#define SST_BYT_ACPI_ID 0x80860F28
#define SST_CHV_ACPI_ID 0x808622A8
#define SST_SUSPEND_DELAY 2000
#define FW_CONTEXT_MEM (64*1024)
......@@ -358,7 +355,7 @@ struct sst_fw_save {
struct intel_sst_drv {
int sst_state;
int irq_num;
unsigned int dev_id;
unsigned short dev_id;
void __iomem *ddr;
void __iomem *shim;
void __iomem *mailbox;
......@@ -523,7 +520,7 @@ int sst_register(struct device *);
int sst_unregister(struct device *);
int sst_alloc_drv_context(struct intel_sst_drv **ctx,
struct device *dev, unsigned int dev_id);
struct device *dev, unsigned short dev_id);
int sst_context_init(struct intel_sst_drv *ctx);
void sst_context_cleanup(struct intel_sst_drv *ctx);
void sst_configure_runtime_pm(struct intel_sst_drv *ctx);
......
......@@ -32,7 +32,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx)
/* map registers */
/* DDR base */
if (ctx->dev_id == SST_MRFLD_PCI_ID) {
if (ctx->dev_id == PCI_DEVICE_ID_INTEL_SST_TNG) {
ctx->ddr_base = pci_resource_start(pci, 0);
/* check that the relocated IMR base matches with FW Binary */
ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base);
......@@ -173,7 +173,7 @@ static void intel_sst_remove(struct pci_dev *pci)
/* PCI Routines */
static const struct pci_device_id intel_sst_ids[] = {
{ PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
{ PCI_DEVICE_DATA(INTEL, SST_TNG, 0) },
{ 0, }
};
......
......@@ -279,14 +279,14 @@ struct avs_acpi_boards {
};
#define AVS_MACH_ENTRY(_id, _mach) \
{ .id = (_id), .machs = (_mach), }
{ .id = PCI_DEVICE_ID_INTEL_##_id, .machs = (_mach), }
/* supported I2S boards per platform */
static const struct avs_acpi_boards i2s_boards[] = {
AVS_MACH_ENTRY(0x9d70, avs_skl_i2s_machines), /* SKL */
AVS_MACH_ENTRY(0x9d71, avs_kbl_i2s_machines), /* KBL */
AVS_MACH_ENTRY(0x5a98, avs_apl_i2s_machines), /* APL */
AVS_MACH_ENTRY(0x3198, avs_gml_i2s_machines), /* GML */
AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines),
AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines),
AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines),
AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines),
{},
};
......
......@@ -745,14 +745,14 @@ static const struct avs_spec apl_desc = {
};
static const struct pci_device_id avs_ids[] = {
{ PCI_VDEVICE(INTEL, 0x9d70), (unsigned long)&skl_desc }, /* SKL */
{ PCI_VDEVICE(INTEL, 0xa170), (unsigned long)&skl_desc }, /* SKL-H */
{ PCI_VDEVICE(INTEL, 0x9d71), (unsigned long)&skl_desc }, /* KBL */
{ PCI_VDEVICE(INTEL, 0xa171), (unsigned long)&skl_desc }, /* KBL-H */
{ PCI_VDEVICE(INTEL, 0xa2f0), (unsigned long)&skl_desc }, /* KBL-S */
{ PCI_VDEVICE(INTEL, 0xa3f0), (unsigned long)&skl_desc }, /* CML-V */
{ PCI_VDEVICE(INTEL, 0x5a98), (unsigned long)&apl_desc }, /* APL */
{ PCI_VDEVICE(INTEL, 0x3198), (unsigned long)&apl_desc }, /* GML */
{ PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_SKL, &skl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &skl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_KBL, &skl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_KBL_H, &skl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_CML_S, &skl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_APL, &apl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_GML, &apl_desc) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, avs_ids);
......
......@@ -169,7 +169,7 @@ static struct skl_dsp_loader_ops bxt_get_loader_ops(void)
static const struct skl_dsp_ops dsp_ops[] = {
{
.id = 0x9d70,
.id = PCI_DEVICE_ID_INTEL_HDA_SKL_LP,
.num_cores = 2,
.loader_ops = skl_get_loader_ops,
.init = skl_sst_dsp_init,
......@@ -177,7 +177,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
.cleanup = skl_sst_dsp_cleanup
},
{
.id = 0x9d71,
.id = PCI_DEVICE_ID_INTEL_HDA_KBL_LP,
.num_cores = 2,
.loader_ops = skl_get_loader_ops,
.init = skl_sst_dsp_init,
......@@ -185,7 +185,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
.cleanup = skl_sst_dsp_cleanup
},
{
.id = 0x5a98,
.id = PCI_DEVICE_ID_INTEL_HDA_APL,
.num_cores = 2,
.loader_ops = bxt_get_loader_ops,
.init = bxt_sst_dsp_init,
......@@ -193,7 +193,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
.cleanup = bxt_sst_dsp_cleanup
},
{
.id = 0x3198,
.id = PCI_DEVICE_ID_INTEL_HDA_GML,
.num_cores = 2,
.loader_ops = bxt_get_loader_ops,
.init = bxt_sst_dsp_init,
......@@ -201,7 +201,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
.cleanup = bxt_sst_dsp_cleanup
},
{
.id = 0x9dc8,
.id = PCI_DEVICE_ID_INTEL_HDA_CNL_LP,
.num_cores = 4,
.loader_ops = bxt_get_loader_ops,
.init = cnl_sst_dsp_init,
......@@ -209,7 +209,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
.cleanup = cnl_sst_dsp_cleanup
},
{
.id = 0xa348,
.id = PCI_DEVICE_ID_INTEL_HDA_CNL_H,
.num_cores = 4,
.loader_ops = bxt_get_loader_ops,
.init = cnl_sst_dsp_init,
......@@ -217,7 +217,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
.cleanup = cnl_sst_dsp_cleanup
},
{
.id = 0x02c8,
.id = PCI_DEVICE_ID_INTEL_HDA_CML_LP,
.num_cores = 4,
.loader_ops = bxt_get_loader_ops,
.init = cnl_sst_dsp_init,
......@@ -225,7 +225,7 @@ static const struct skl_dsp_ops dsp_ops[] = {
.cleanup = cnl_sst_dsp_cleanup
},
{
.id = 0x06c8,
.id = PCI_DEVICE_ID_INTEL_HDA_CML_H,
.num_cores = 4,
.loader_ops = bxt_get_loader_ops,
.init = cnl_sst_dsp_init,
......
......@@ -13,6 +13,7 @@
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/delay.h>
#include <sound/hdaudio.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "skl.h"
......@@ -152,7 +153,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
* The recommended SDxFMT programming sequence for BXT
* platforms is to couple the stream before writing the format
*/
if (IS_BXT(skl->pci)) {
if (HDA_CONTROLLER_IS_APL(skl->pci)) {
snd_hdac_ext_stream_decouple(bus, stream, false);
err = snd_hdac_stream_setup(hdac_stream(stream));
snd_hdac_ext_stream_decouple(bus, stream, true);
......
......@@ -608,8 +608,8 @@ struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id)
static void init_skl_xtal_rate(int pci_id)
{
switch (pci_id) {
case 0x9d70:
case 0x9d71:
case PCI_DEVICE_ID_INTEL_HDA_SKL_LP:
case PCI_DEVICE_ID_INTEL_HDA_KBL_LP:
skl_clk_src[0].rate = 24000000;
return;
......@@ -1145,44 +1145,28 @@ static void skl_remove(struct pci_dev *pci)
/* PCI IDs */
static const struct pci_device_id skl_ids[] = {
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
/* Sunrise Point-LP */
{ PCI_DEVICE(0x8086, 0x9d70),
.driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines},
{ PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &snd_soc_acpi_intel_skl_machines) },
#endif
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
/* BXT-P */
{ PCI_DEVICE(0x8086, 0x5a98),
.driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines},
{ PCI_DEVICE_DATA(INTEL, HDA_APL, &snd_soc_acpi_intel_bxt_machines) },
#endif
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
/* KBL */
{ PCI_DEVICE(0x8086, 0x9D71),
.driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines},
{ PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &snd_soc_acpi_intel_kbl_machines) },
#endif
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK)
/* GLK */
{ PCI_DEVICE(0x8086, 0x3198),
.driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines},
{ PCI_DEVICE_DATA(INTEL, HDA_GML, &snd_soc_acpi_intel_glk_machines) },
#endif
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL)
/* CNL */
{ PCI_DEVICE(0x8086, 0x9dc8),
.driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
{ PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &snd_soc_acpi_intel_cnl_machines) },
#endif
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL)
/* CFL */
{ PCI_DEVICE(0x8086, 0xa348),
.driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
{ PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &snd_soc_acpi_intel_cnl_machines) },
#endif
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP)
/* CML-LP */
{ PCI_DEVICE(0x8086, 0x02c8),
.driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
{ PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &snd_soc_acpi_intel_cnl_machines) },
#endif
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H)
/* CML-H */
{ PCI_DEVICE(0x8086, 0x06c8),
.driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
{ PCI_DEVICE_DATA(INTEL, HDA_CML_H, &snd_soc_acpi_intel_cnl_machines) },
#endif
{ 0, }
};
......
......@@ -262,6 +262,22 @@ config SND_SOC_SOF_METEORLAKE
Say Y if you have such a device.
If unsure select "N".
config SND_SOC_SOF_INTEL_LNL
tristate
select SND_SOC_SOF_HDA_COMMON
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
select SND_SOC_SOF_INTEL_IPC4
config SND_SOC_SOF_LUNARLAKE
tristate "SOF support for Lunarlake"
default SND_SOC_SOF_PCI
select SND_SOC_SOF_INTEL_LNL
help
This adds support for Sound Open Firmware for Intel(R) platforms
using the Lunarlake processors.
Say Y if you have such a device.
If unsure select "N".
config SND_SOC_SOF_HDA_COMMON
tristate
select SND_SOC_SOF_INTEL_COMMON
......
......@@ -7,7 +7,7 @@ snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \
hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \
hda-dai.o hda-dai-ops.o hda-bus.o \
skl.o hda-loader-skl.o \
apl.o cnl.o tgl.o icl.o mtl.o hda-common-ops.o
apl.o cnl.o tgl.o icl.o mtl.o lnl.o hda-common-ops.o
snd-sof-intel-hda-mlink-objs := hda-mlink.o
......@@ -31,6 +31,7 @@ snd-sof-pci-intel-cnl-objs := pci-cnl.o
snd-sof-pci-intel-icl-objs := pci-icl.o
snd-sof-pci-intel-tgl-objs := pci-tgl.o
snd-sof-pci-intel-mtl-objs := pci-mtl.o
snd-sof-pci-intel-lnl-objs := pci-lnl.o
obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_SKL) += snd-sof-pci-intel-skl.o
......@@ -39,3 +40,4 @@ obj-$(CONFIG_SND_SOC_SOF_INTEL_CNL) += snd-sof-pci-intel-cnl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_MTL) += snd-sof-pci-intel-mtl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_LNL) += snd-sof-pci-intel-lnl.o
......@@ -466,6 +466,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
.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_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
......@@ -501,6 +502,7 @@ const struct sof_intel_dsp_desc jsl_chip_info = {
.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_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
......
......@@ -7,6 +7,7 @@
#include <sound/pcm_params.h>
#include <sound/hdaudio_ext.h>
#include <sound/hda-mlink.h>
#include <sound/sof/ipc4/header.h>
#include <uapi/sound/sof/header.h>
#include "../ipc4-priv.h"
......@@ -144,9 +145,17 @@ static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev,
struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *dai;
struct hdac_ext_stream *hext_stream;
hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
/* only allocate a stream_tag for the first DAI in the dailink */
dai = asoc_rtd_to_cpu(rtd, 0);
if (dai == cpu_dai)
hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
else
hext_stream = snd_soc_dai_get_dma_data(dai, substream);
if (!hext_stream)
return NULL;
......@@ -159,9 +168,14 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai
struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *dai;
/* only release a stream_tag for the first DAI in the dailink */
dai = asoc_rtd_to_cpu(rtd, 0);
if (dai == cpu_dai)
snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
}
static void hda_setup_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,
......@@ -219,6 +233,77 @@ static struct hdac_ext_link *hda_get_hlink(struct snd_sof_dev *sdev,
return snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
}
static unsigned int generic_calc_stream_format(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
unsigned int format_val;
format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params),
params_format(params),
params_physical_width(params),
0);
dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
params_rate(params), params_channels(params), params_format(params));
return format_val;
}
static unsigned int dmic_calc_stream_format(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
unsigned int format_val;
snd_pcm_format_t format;
unsigned int channels;
unsigned int width;
channels = params_channels(params);
format = params_format(params);
width = params_physical_width(params);
if (format == SNDRV_PCM_FORMAT_S16_LE) {
format = SNDRV_PCM_FORMAT_S32_LE;
channels /= 2;
width = 32;
}
format_val = snd_hdac_calc_stream_format(params_rate(params), channels,
format,
width,
0);
dev_dbg(sdev->dev, "format_val=%#x, rate=%d, ch=%d, format=%d\n", format_val,
params_rate(params), channels, format);
return format_val;
}
static struct hdac_ext_link *ssp_get_hlink(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
{
struct hdac_bus *bus = sof_to_bus(sdev);
return hdac_bus_eml_ssp_get_hlink(bus);
}
static struct hdac_ext_link *dmic_get_hlink(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
{
struct hdac_bus *bus = sof_to_bus(sdev);
return hdac_bus_eml_dmic_get_hlink(bus);
}
static struct hdac_ext_link *sdw_get_hlink(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
{
struct hdac_bus *bus = sof_to_bus(sdev);
return hdac_bus_eml_sdw_get_hlink(bus);
}
static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream, int cmd)
{
......@@ -234,6 +319,9 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
if (pipe_widget->instance_id < 0)
return 0;
mutex_lock(&ipc4_data->pipeline_state_mutex);
switch (cmd) {
......@@ -297,6 +385,9 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
if (pipe_widget->instance_id < 0)
return 0;
mutex_lock(&ipc4_data->pipeline_state_mutex);
switch (cmd) {
......@@ -343,6 +434,28 @@ static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c
return ret;
}
static struct hdac_ext_stream *sdw_hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev,
struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream)
{
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
struct snd_sof_widget *swidget = w->dobj.private;
struct snd_sof_dai *dai = swidget->private;
struct sof_ipc4_copier *ipc4_copier = dai->private;
struct sof_ipc4_alh_configuration_blob *blob;
blob = (struct sof_ipc4_alh_configuration_blob *)ipc4_copier->copier_config;
/*
* Starting with ACE_2_0, re-setting the device_count is mandatory to avoid using
* the multi-gateway firmware configuration. The DMA hardware can take care of
* multiple links without needing any firmware assistance
*/
blob->alh_cfg.device_count = 1;
return hda_ipc4_get_hext_stream(sdev, cpu_dai, substream);
}
static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
.get_hext_stream = hda_ipc4_get_hext_stream,
.assign_hext_stream = hda_assign_hext_stream,
......@@ -357,6 +470,45 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
.get_hlink = hda_get_hlink,
};
static const struct hda_dai_widget_dma_ops ssp_ipc4_dma_ops = {
.get_hext_stream = hda_ipc4_get_hext_stream,
.assign_hext_stream = hda_assign_hext_stream,
.release_hext_stream = hda_release_hext_stream,
.setup_hext_stream = hda_setup_hext_stream,
.reset_hext_stream = hda_reset_hext_stream,
.pre_trigger = hda_ipc4_pre_trigger,
.trigger = hda_trigger,
.post_trigger = hda_ipc4_post_trigger,
.calc_stream_format = generic_calc_stream_format,
.get_hlink = ssp_get_hlink,
};
static const struct hda_dai_widget_dma_ops dmic_ipc4_dma_ops = {
.get_hext_stream = hda_ipc4_get_hext_stream,
.assign_hext_stream = hda_assign_hext_stream,
.release_hext_stream = hda_release_hext_stream,
.setup_hext_stream = hda_setup_hext_stream,
.reset_hext_stream = hda_reset_hext_stream,
.pre_trigger = hda_ipc4_pre_trigger,
.trigger = hda_trigger,
.post_trigger = hda_ipc4_post_trigger,
.calc_stream_format = dmic_calc_stream_format,
.get_hlink = dmic_get_hlink,
};
static const struct hda_dai_widget_dma_ops sdw_ipc4_dma_ops = {
.get_hext_stream = sdw_hda_ipc4_get_hext_stream,
.assign_hext_stream = hda_assign_hext_stream,
.release_hext_stream = hda_release_hext_stream,
.setup_hext_stream = hda_setup_hext_stream,
.reset_hext_stream = hda_reset_hext_stream,
.pre_trigger = hda_ipc4_pre_trigger,
.trigger = hda_trigger,
.post_trigger = hda_ipc4_post_trigger,
.calc_stream_format = generic_calc_stream_format,
.get_hlink = sdw_get_hlink,
};
static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
.get_hext_stream = hda_get_hext_stream,
.assign_hext_stream = hda_assign_hext_stream,
......@@ -459,8 +611,13 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
case SOF_INTEL_IPC4:
{
struct sof_ipc4_copier *ipc4_copier = sdai->private;
const struct sof_intel_dsp_desc *chip;
if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) {
chip = get_chip_info(sdev->pdata);
switch (ipc4_copier->dai_type) {
case SOF_DAI_INTEL_HDA:
{
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
......@@ -469,6 +626,22 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
return &hda_ipc4_dma_ops;
}
case SOF_DAI_INTEL_SSP:
if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
return NULL;
return &ssp_ipc4_dma_ops;
case SOF_DAI_INTEL_DMIC:
if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
return NULL;
return &dmic_ipc4_dma_ops;
case SOF_DAI_INTEL_ALH:
if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
return NULL;
return &sdw_ipc4_dma_ops;
default:
break;
}
break;
}
default:
......
......@@ -10,6 +10,8 @@
#include <sound/pcm_params.h>
#include <sound/hdaudio_ext.h>
#include <sound/hda-mlink.h>
#include <sound/hda_register.h>
#include <sound/intel-nhlt.h>
#include <sound/sof/ipc4/header.h>
#include <uapi/sound/sof/header.h>
......@@ -330,6 +332,175 @@ static const struct snd_soc_dai_ops hda_dai_ops = {
#endif
static struct sof_ipc4_copier *widget_to_copier(struct snd_soc_dapm_widget *w)
{
struct snd_sof_widget *swidget = w->dobj.private;
struct snd_sof_dai *sdai = swidget->private;
struct sof_ipc4_copier *ipc4_copier = (struct sof_ipc4_copier *)sdai->private;
return ipc4_copier;
}
static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
struct sof_ipc4_dma_config_tlv *dma_config_tlv;
const struct hda_dai_widget_dma_ops *ops;
struct sof_ipc4_dma_config *dma_config;
struct sof_ipc4_copier *ipc4_copier;
struct hdac_ext_stream *hext_stream;
struct hdac_stream *hstream;
struct snd_sof_dev *sdev;
int stream_id;
int ret;
ops = hda_dai_get_ops(substream, cpu_dai);
if (!ops) {
dev_err(cpu_dai->dev, "DAI widget ops not set\n");
return -EINVAL;
}
/* use HDaudio stream handling */
ret = hda_dai_hw_params(substream, params, cpu_dai);
if (ret < 0) {
dev_err(cpu_dai->dev, "%s: hda_dai_hw_params failed: %d\n", __func__, ret);
return ret;
}
/* get stream_id */
sdev = widget_to_sdev(w);
hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
if (!hext_stream) {
dev_err(cpu_dai->dev, "%s: no hext_stream found\n", __func__);
return -ENODEV;
}
hstream = &hext_stream->hstream;
stream_id = hstream->stream_tag;
if (!stream_id) {
dev_err(cpu_dai->dev, "%s: no stream_id allocated\n", __func__);
return -ENODEV;
}
/* configure TLV */
ipc4_copier = widget_to_copier(w);
dma_config_tlv = &ipc4_copier->dma_config_tlv;
dma_config_tlv->type = SOF_IPC4_GTW_DMA_CONFIG_ID;
/* dma_config_priv_size is zero */
dma_config_tlv->length = sizeof(dma_config_tlv->dma_config);
dma_config = &dma_config_tlv->dma_config;
dma_config->dma_method = SOF_IPC4_DMA_METHOD_HDA;
dma_config->pre_allocated_by_host = 1;
dma_config->dma_channel_id = stream_id - 1;
dma_config->stream_id = stream_id;
dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */
dma_config->dma_priv_config_size = 0;
return 0;
}
static int non_hda_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
int stream = substream->stream;
return non_hda_dai_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai);
}
static const struct snd_soc_dai_ops ssp_dai_ops = {
.hw_params = non_hda_dai_hw_params,
.hw_free = hda_dai_hw_free,
.trigger = hda_dai_trigger,
.prepare = non_hda_dai_prepare,
};
static const struct snd_soc_dai_ops dmic_dai_ops = {
.hw_params = non_hda_dai_hw_params,
.hw_free = hda_dai_hw_free,
.trigger = hda_dai_trigger,
.prepare = non_hda_dai_prepare,
};
int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai,
int link_id)
{
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
const struct hda_dai_widget_dma_ops *ops;
struct hdac_ext_stream *hext_stream;
struct snd_sof_dev *sdev;
int ret;
ret = non_hda_dai_hw_params(substream, params, cpu_dai);
if (ret < 0) {
dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_params failed %d\n", __func__, ret);
return ret;
}
ops = hda_dai_get_ops(substream, cpu_dai);
sdev = widget_to_sdev(w);
hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
if (!hext_stream)
return -ENODEV;
/* in the case of SoundWire we need to program the PCMSyCM registers */
ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
GENMASK(params_channels(params) - 1, 0),
hdac_stream(hext_stream)->stream_tag,
substream->stream);
if (ret < 0) {
dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
__func__, ret);
return ret;
}
return 0;
}
int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai,
int link_id)
{
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
struct snd_sof_dev *sdev;
int ret;
ret = hda_dai_hw_free(substream, cpu_dai);
if (ret < 0) {
dev_err(cpu_dai->dev, "%s: non_hda_dai_hw_free failed %d\n", __func__, ret);
return ret;
}
sdev = widget_to_sdev(w);
/* in the case of SoundWire we need to reset the PCMSyCM registers */
ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
0, 0, substream->stream);
if (ret < 0) {
dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
__func__, ret);
return ret;
}
return 0;
}
int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *cpu_dai)
{
return hda_dai_trigger(substream, cmd, cpu_dai);
}
static int hda_dai_suspend(struct hdac_bus *bus)
{
struct snd_soc_pcm_runtime *rtd;
......@@ -384,7 +555,42 @@ static int hda_dai_suspend(struct hdac_bus *bus)
return 0;
}
#endif
static void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
{
const struct sof_intel_dsp_desc *chip;
int i;
chip = get_chip_info(sdev->pdata);
if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
for (i = 0; i < ops->num_drv; i++) {
if (strstr(ops->drv[i].name, "SSP"))
ops->drv[i].ops = &ssp_dai_ops;
}
}
}
static void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
{
const struct sof_intel_dsp_desc *chip;
int i;
chip = get_chip_info(sdev->pdata);
if (chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
for (i = 0; i < ops->num_drv; i++) {
if (strstr(ops->drv[i].name, "DMIC"))
ops->drv[i].ops = &dmic_dai_ops;
}
}
}
#else
static inline void ssp_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
static inline void dmic_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) {}
#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */
void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
{
......@@ -399,6 +605,9 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
#endif
}
ssp_set_dai_drv_ops(sdev, ops);
dmic_set_dai_drv_ops(sdev, ops);
if (sdev->pdata->ipc_type == SOF_INTEL_IPC4 && !hda_use_tplg_nhlt) {
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
......
......@@ -331,14 +331,19 @@ static bool hdaml_link_check_cmdsync(u32 __iomem *lsync, u32 cmdsync_mask)
return !!(val & cmdsync_mask);
}
static void hdaml_link_set_lsdiid(u32 __iomem *lsdiid, int dev_num)
static u16 hdaml_link_get_lsdiid(u16 __iomem *lsdiid)
{
u32 val;
return readw(lsdiid);
}
static void hdaml_link_set_lsdiid(u16 __iomem *lsdiid, int dev_num)
{
u16 val;
val = readl(lsdiid);
val = readw(lsdiid);
val |= BIT(dev_num);
writel(val, lsdiid);
writew(val, lsdiid);
}
static void hdaml_shim_map_stream_ch(u16 __iomem *pcmsycm, int lchan, int hchan,
......@@ -752,6 +757,22 @@ int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink)
}
EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_down_unlocked, SND_SOC_SOF_HDA_MLINK);
int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid)
{
struct hdac_ext2_link *h2link;
struct hdac_ext_link *hlink;
h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
if (!h2link)
return -ENODEV;
hlink = &h2link->hext_link;
*lsdiid = hdaml_link_get_lsdiid(hlink->ml_addr + AZX_REG_ML_LSDIID_OFFSET(sublink));
return 0;
} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_lsdiid_unlocked, SND_SOC_SOF_HDA_MLINK);
int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num)
{
struct hdac_ext2_link *h2link;
......@@ -781,6 +802,8 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
{
struct hdac_ext2_link *h2link;
u16 __iomem *pcmsycm;
int hchan;
int lchan;
u16 val;
h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
......@@ -791,17 +814,25 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
h2link->instance_offset * sublink +
AZX_REG_SDW_SHIM_PCMSyCM(y);
if (channel_mask) {
hchan = __fls(channel_mask);
lchan = __ffs(channel_mask);
} else {
hchan = 0;
lchan = 0;
}
mutex_lock(&h2link->eml_lock);
hdaml_shim_map_stream_ch(pcmsycm, 0, hweight32(channel_mask),
hdaml_shim_map_stream_ch(pcmsycm, lchan, hchan,
stream_id, dir);
mutex_unlock(&h2link->eml_lock);
val = readw(pcmsycm);
dev_dbg(bus->dev, "channel_mask %#x stream_id %d dir %d pcmscm %#x\n",
channel_mask, stream_id, dir, val);
dev_dbg(bus->dev, "sublink %d channel_mask %#x stream_id %d dir %d pcmscm %#x\n",
sublink, channel_mask, stream_id, dir, val);
return 0;
} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, SND_SOC_SOF_HDA_MLINK);
......
......@@ -71,6 +71,11 @@ static u32 hda_get_interface_mask(struct snd_sof_dev *sdev)
BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
interface_mask[1] = BIT(SOF_DAI_INTEL_HDA);
break;
case SOF_INTEL_ACE_2_0:
interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
interface_mask[1] = interface_mask[0]; /* all interfaces accessible without DSP */
break;
default:
break;
}
......@@ -107,6 +112,34 @@ struct sdw_intel_ops sdw_callback = {
.params_stream = sdw_params_stream,
};
static int sdw_ace2x_params_stream(struct device *dev,
struct sdw_intel_stream_params_data *params_data)
{
return sdw_hda_dai_hw_params(params_data->substream,
params_data->hw_params,
params_data->dai,
params_data->link_id);
}
static int sdw_ace2x_free_stream(struct device *dev,
struct sdw_intel_stream_free_data *free_data)
{
return sdw_hda_dai_hw_free(free_data->substream,
free_data->dai,
free_data->link_id);
}
static int sdw_ace2x_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
{
return sdw_hda_dai_trigger(substream, cmd, dai);
}
static struct sdw_intel_ops sdw_ace2x_callback = {
.params_stream = sdw_ace2x_params_stream,
.free_stream = sdw_ace2x_free_stream,
.trigger = sdw_ace2x_trigger,
};
void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
{
struct sof_intel_hda_dev *hdev;
......@@ -174,6 +207,7 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev)
res.shim_base = hdev->desc->sdw_shim_base;
res.alh_base = hdev->desc->sdw_alh_base;
res.ext = false;
res.ops = &sdw_callback;
} else {
/*
* retrieve eml_lock needed to protect shared registers
......@@ -191,11 +225,13 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev)
*/
res.hw_ops = &sdw_intel_lnl_hw_ops;
res.ext = true;
res.ops = &sdw_ace2x_callback;
}
res.irq = sdev->ipc_irq;
res.handle = hdev->info.handle;
res.parent = sdev->dev;
res.ops = &sdw_callback;
res.dev = sdev->dev;
res.clock_stop_quirks = sdw_clock_stop_quirks;
res.hbus = sof_to_bus(sdev);
......@@ -363,14 +399,10 @@ static irqreturn_t hda_dsp_sdw_thread(int irq, void *context)
return sdw_intel_thread(irq, context);
}
static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev)
{
u32 interface_mask = hda_get_interface_mask(sdev);
struct sof_intel_hda_dev *hdev;
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
return false;
hdev = sdev->pdata->hw_pdata;
if (hdev->sdw &&
snd_sof_dsp_read(sdev, HDA_DSP_BAR,
......@@ -380,6 +412,20 @@ static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
return false;
}
static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
{
u32 interface_mask = hda_get_interface_mask(sdev);
const struct sof_intel_dsp_desc *chip;
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
return false;
if (chip && chip->check_sdw_wakeen_irq)
return chip->check_sdw_wakeen_irq(sdev);
return false;
}
void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
{
u32 interface_mask = hda_get_interface_mask(sdev);
......
......@@ -785,6 +785,7 @@ int hda_sdw_check_lcount_ext(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);
bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev);
void hda_sdw_process_wakeen(struct snd_sof_dev *sdev);
bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev);
......@@ -813,6 +814,11 @@ static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
{
}
static inline bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev)
{
return false;
}
static inline void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
{
}
......@@ -824,6 +830,18 @@ static inline bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)
#endif
int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai,
int link_id);
int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai,
int link_id);
int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *cpu_dai);
/* common dai driver */
extern struct snd_soc_dai_driver skl_dai[];
int hda_dsp_dais_suspend(struct snd_sof_dev *sdev);
......@@ -845,6 +863,8 @@ extern struct snd_sof_dsp_ops sof_icl_ops;
int sof_icl_ops_init(struct snd_sof_dev *sdev);
extern struct snd_sof_dsp_ops sof_mtl_ops;
int sof_mtl_ops_init(struct snd_sof_dev *sdev);
extern struct snd_sof_dsp_ops sof_lnl_ops;
int sof_lnl_ops_init(struct snd_sof_dev *sdev);
extern const struct sof_intel_dsp_desc skl_chip_info;
extern const struct sof_intel_dsp_desc apl_chip_info;
......@@ -856,6 +876,7 @@ extern const struct sof_intel_dsp_desc ehl_chip_info;
extern const struct sof_intel_dsp_desc jsl_chip_info;
extern const struct sof_intel_dsp_desc adls_chip_info;
extern const struct sof_intel_dsp_desc mtl_chip_info;
extern const struct sof_intel_dsp_desc lnl_chip_info;
/* Probes support */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
......
......@@ -188,6 +188,7 @@ const struct sof_intel_dsp_desc icl_chip_info = {
.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_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
......
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// Copyright(c) 2023 Intel Corporation. All rights reserved.
/*
* Hardware interface for audio DSP on LunarLake.
*/
#include <linux/firmware.h>
#include <sound/hda_register.h>
#include <sound/sof/ipc4/header.h>
#include <trace/events/sof_intel.h>
#include "../ipc4-priv.h"
#include "../ops.h"
#include "hda.h"
#include "hda-ipc.h"
#include "../sof-audio.h"
#include "mtl.h"
#include "hda.h"
#include <sound/hda-mlink.h>
/* LunarLake ops */
struct snd_sof_dsp_ops sof_lnl_ops;
EXPORT_SYMBOL_NS(sof_lnl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = {
{"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
{"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
{"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
};
/* this helps allows the DSP to setup DMIC/SSP */
static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus)
{
int ret;
ret = hdac_bus_eml_enable_offload(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_SSP, true);
if (ret < 0)
return ret;
ret = hdac_bus_eml_enable_offload(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_DMIC, true);
if (ret < 0)
return ret;
return 0;
}
static int lnl_hda_dsp_probe(struct snd_sof_dev *sdev)
{
int ret;
ret = hda_dsp_probe(sdev);
if (ret < 0)
return ret;
return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev));
}
static int lnl_hda_dsp_resume(struct snd_sof_dev *sdev)
{
int ret;
ret = hda_dsp_resume(sdev);
if (ret < 0)
return ret;
return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev));
}
static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev)
{
int ret;
ret = hda_dsp_runtime_resume(sdev);
if (ret < 0)
return ret;
return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev));
}
int sof_lnl_ops_init(struct snd_sof_dev *sdev)
{
struct sof_ipc4_fw_data *ipc4_data;
/* common defaults */
memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
/* probe */
sof_lnl_ops.probe = lnl_hda_dsp_probe;
/* shutdown */
sof_lnl_ops.shutdown = hda_dsp_shutdown;
/* doorbell */
sof_lnl_ops.irq_thread = mtl_ipc_irq_thread;
/* ipc */
sof_lnl_ops.send_msg = mtl_ipc_send_msg;
sof_lnl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset;
sof_lnl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset;
/* debug */
sof_lnl_ops.debug_map = lnl_dsp_debugfs;
sof_lnl_ops.debug_map_count = ARRAY_SIZE(lnl_dsp_debugfs);
sof_lnl_ops.dbg_dump = mtl_dsp_dump;
sof_lnl_ops.ipc_dump = mtl_ipc_dump;
/* pre/post fw run */
sof_lnl_ops.pre_fw_run = mtl_dsp_pre_fw_run;
sof_lnl_ops.post_fw_run = mtl_dsp_post_fw_run;
/* parse platform specific extended manifest */
sof_lnl_ops.parse_platform_ext_manifest = NULL;
/* dsp core get/put */
/* TODO: add core_get and core_put */
/* PM */
sof_lnl_ops.resume = lnl_hda_dsp_resume;
sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume;
sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position;
sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
ipc4_data = sdev->private;
ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
/* External library loading support */
ipc4_data->load_library = hda_dsp_ipc4_load_library;
/* set DAI ops */
hda_set_dai_drv_ops(sdev, &sof_lnl_ops);
sof_lnl_ops.set_power_state = hda_dsp_set_power_state_ipc4;
return 0;
};
EXPORT_SYMBOL_NS(sof_lnl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
/* Check if an SDW IRQ occurred */
static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
return hdac_bus_eml_check_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
}
static void lnl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
{
struct hdac_bus *bus = sof_to_bus(sdev);
hdac_bus_eml_enable_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW, enable);
}
static int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
{
lnl_enable_sdw_irq(sdev, false);
mtl_disable_ipc_interrupts(sdev);
return mtl_enable_interrupts(sdev, false);
}
const struct sof_intel_dsp_desc lnl_chip_info = {
.cores_num = 5,
.init_core_mask = BIT(0),
.host_managed_cores_mask = BIT(0),
.ipc_req = MTL_DSP_REG_HFIPCXIDR,
.ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,
.ipc_ack = MTL_DSP_REG_HFIPCXIDA,
.ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
.ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
.rom_status_reg = MTL_DSP_ROM_STS,
.rom_init_timeout = 300,
.ssp_count = MTL_SSP_COUNT,
.d0i3_offset = MTL_HDA_VS_D0I3C,
.read_sdw_lcount = hda_sdw_check_lcount_ext,
.enable_sdw_irq = lnl_enable_sdw_irq,
.check_sdw_irq = lnl_dsp_check_sdw_irq,
.check_ipc_irq = mtl_dsp_check_ipc_irq,
.cl_init = mtl_dsp_cl_init,
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = lnl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_2_0,
};
EXPORT_SYMBOL_NS(lnl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
......@@ -91,7 +91,7 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
return false;
}
static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;
......@@ -230,7 +230,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
}
/* pre fw run operations */
static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
u32 dsphfpwrsts;
......@@ -279,7 +279,7 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
return ret;
}
static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
{
int ret;
......@@ -301,7 +301,7 @@ static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
return 0;
}
static void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
{
char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
u32 romdbgsts;
......@@ -495,7 +495,7 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
return ret;
}
static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
......@@ -578,17 +578,17 @@ static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
static int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
{
return MTL_DSP_MBOX_UPLINK_OFFSET;
}
static int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
{
return MTL_SRAM_WINDOW_OFFSET(id);
}
static void mtl_ipc_dump(struct snd_sof_dev *sdev)
void mtl_ipc_dump(struct snd_sof_dev *sdev)
{
u32 hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl;
......@@ -612,9 +612,9 @@ static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
return mtl_enable_interrupts(sdev, false);
}
static u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
struct snd_soc_component *component,
struct snd_pcm_substream *substream)
u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct hdac_stream *hstream = substream->runtime->private_data;
u32 llp_l, llp_u;
......@@ -735,6 +735,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = {
.read_sdw_lcount = hda_sdw_check_lcount_common,
.enable_sdw_irq = mtl_enable_sdw_irq,
.check_sdw_irq = mtl_dsp_check_sdw_irq,
.check_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = mtl_dsp_check_ipc_irq,
.cl_init = mtl_dsp_cl_init,
.power_down_dsp = mtl_power_down_dsp,
......
......@@ -82,10 +82,28 @@
#define MTL_DSP_REG_HfIMRIS1 0x162088
#define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0)
bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev);
void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev);
bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable);
int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev);
int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev);
void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
int mtl_power_down_dsp(struct snd_sof_dev *sdev);
int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
irqreturn_t mtl_ipc_irq_thread(int irq, void *context);
int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev);
int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id);
void mtl_ipc_dump(struct snd_sof_dev *sdev);
u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
struct snd_soc_component *component,
struct snd_pcm_substream *substream);
......@@ -85,12 +85,8 @@ static const struct sof_dev_desc glk_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
{ PCI_DEVICE(0x8086, 0x5a98), /* BXT-P (ApolloLake) */
.driver_data = (unsigned long)&bxt_desc},
{ PCI_DEVICE(0x8086, 0x1a98),/* BXT-T */
.driver_data = (unsigned long)&bxt_desc},
{ PCI_DEVICE(0x8086, 0x3198), /* GeminiLake */
.driver_data = (unsigned long)&glk_desc},
{ PCI_DEVICE_DATA(INTEL, HDA_APL, &bxt_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_GML, &glk_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
......
......@@ -120,16 +120,11 @@ static const struct sof_dev_desc cml_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
{ PCI_DEVICE(0x8086, 0x9dc8), /* CNL-LP */
.driver_data = (unsigned long)&cnl_desc},
{ PCI_DEVICE(0x8086, 0xa348), /* CNL-H */
.driver_data = (unsigned long)&cfl_desc},
{ PCI_DEVICE(0x8086, 0x02c8), /* CML-LP */
.driver_data = (unsigned long)&cml_desc},
{ PCI_DEVICE(0x8086, 0x06c8), /* CML-H */
.driver_data = (unsigned long)&cml_desc},
{ PCI_DEVICE(0x8086, 0xa3f0), /* CML-S */
.driver_data = (unsigned long)&cml_desc},
{ PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &cnl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &cfl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &cml_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_CML_H, &cml_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_CML_S, &cml_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
......
......@@ -86,14 +86,10 @@ static const struct sof_dev_desc jsl_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
{ PCI_DEVICE(0x8086, 0x34C8), /* ICL-LP */
.driver_data = (unsigned long)&icl_desc},
{ PCI_DEVICE(0x8086, 0x3dc8), /* ICL-H */
.driver_data = (unsigned long)&icl_desc},
{ PCI_DEVICE(0x8086, 0x38c8), /* ICL-N */
.driver_data = (unsigned long)&jsl_desc},
{ PCI_DEVICE(0x8086, 0x4dc8), /* JSL-N */
.driver_data = (unsigned long)&jsl_desc},
{ PCI_DEVICE_DATA(INTEL, HDA_ICL_LP, &icl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_ICL_H, &icl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_ICL_N, &jsl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_JSL_N, &jsl_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
......
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2023 Intel Corporation. All rights reserved.
//
// Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
//
#include <linux/module.h>
#include <linux/pci.h>
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
#include <sound/sof.h>
#include "../ops.h"
#include "../sof-pci-dev.h"
/* platform specific devices */
#include "hda.h"
#include "mtl.h"
static const struct sof_dev_desc lnl_desc = {
.use_acpi_target_states = true,
.machines = snd_soc_acpi_intel_lnl_machines,
.alt_machines = snd_soc_acpi_intel_lnl_sdw_machines,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = -1,
.resindex_imr_base = -1,
.irqindex_host_ipc = -1,
.chip_info = &lnl_chip_info,
.ipc_supported_mask = BIT(SOF_INTEL_IPC4),
.ipc_default = SOF_INTEL_IPC4,
.dspless_mode_supported = true,
.default_fw_path = {
[SOF_INTEL_IPC4] = "intel/sof-ipc4/lnl",
},
.default_tplg_path = {
[SOF_INTEL_IPC4] = "intel/sof-ace-tplg",
},
.default_fw_filename = {
[SOF_INTEL_IPC4] = "sof-lnl.ri",
},
.nocodec_tplg_filename = "sof-lnl-nocodec.tplg",
.ops = &sof_lnl_ops,
.ops_init = sof_lnl_ops_init,
};
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
{ PCI_DEVICE_DATA(INTEL, HDA_LNL_P, &lnl_desc) }, /* LNL-P */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
/* pci_driver definition */
static struct pci_driver snd_sof_pci_intel_lnl_driver = {
.name = "sof-audio-pci-intel-lnl",
.id_table = sof_pci_ids,
.probe = hda_pci_intel_probe,
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
.pm = &sof_pci_pm,
},
};
module_pci_driver(snd_sof_pci_intel_lnl_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
......@@ -52,8 +52,7 @@ static const struct sof_dev_desc mtl_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
{ PCI_DEVICE(0x8086, 0x7E28), /* MTL */
.driver_data = (unsigned long)&mtl_desc},
{ PCI_DEVICE_DATA(INTEL, HDA_MTL, &mtl_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
......
......@@ -69,10 +69,8 @@ static struct sof_dev_desc kbl_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
/* Sunrise Point-LP */
{ PCI_DEVICE(0x8086, 0x9d70), .driver_data = (unsigned long)&skl_desc},
/* KBL */
{ PCI_DEVICE(0x8086, 0x9d71), .driver_data = (unsigned long)&kbl_desc},
{ PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &kbl_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
......
......@@ -284,36 +284,21 @@ static const struct sof_dev_desc rpl_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
{ PCI_DEVICE(0x8086, 0xa0c8), /* TGL-LP */
.driver_data = (unsigned long)&tgl_desc},
{ PCI_DEVICE(0x8086, 0x43c8), /* TGL-H */
.driver_data = (unsigned long)&tglh_desc},
{ PCI_DEVICE(0x8086, 0x4b55), /* EHL */
.driver_data = (unsigned long)&ehl_desc},
{ PCI_DEVICE(0x8086, 0x4b58), /* EHL */
.driver_data = (unsigned long)&ehl_desc},
{ PCI_DEVICE(0x8086, 0x7ad0), /* ADL-S */
.driver_data = (unsigned long)&adls_desc},
{ PCI_DEVICE(0x8086, 0x7a50), /* RPL-S */
.driver_data = (unsigned long)&rpls_desc},
{ PCI_DEVICE(0x8086, 0x51c8), /* ADL-P */
.driver_data = (unsigned long)&adl_desc},
{ PCI_DEVICE(0x8086, 0x51c9), /* ADL-PS */
.driver_data = (unsigned long)&adl_desc},
{ PCI_DEVICE(0x8086, 0x51ca), /* RPL-P */
.driver_data = (unsigned long)&rpl_desc},
{ PCI_DEVICE(0x8086, 0x51cb), /* RPL-P */
.driver_data = (unsigned long)&rpl_desc},
{ PCI_DEVICE(0x8086, 0x51cc), /* ADL-M */
.driver_data = (unsigned long)&adl_desc},
{ PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */
.driver_data = (unsigned long)&adl_desc},
{ PCI_DEVICE(0x8086, 0x51ce), /* RPL-M */
.driver_data = (unsigned long)&rpl_desc},
{ PCI_DEVICE(0x8086, 0x51cf), /* RPL-PX */
.driver_data = (unsigned long)&rpl_desc},
{ PCI_DEVICE(0x8086, 0x54c8), /* ADL-N */
.driver_data = (unsigned long)&adl_n_desc},
{ PCI_DEVICE_DATA(INTEL, HDA_TGL_LP, &tgl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_TGL_H, &tglh_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_EHL_0, &ehl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_EHL_3, &ehl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_ADL_S, &adls_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_RPL_S, &rpls_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_ADL_P, &adl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_ADL_PS, &adl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_RPL_P_0, &rpl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, &rpl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_ADL_M, &adl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, &adl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_RPL_M, &rpl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, &rpl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_ADL_N, &adl_n_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
......
......@@ -225,8 +225,7 @@ static const struct sof_dev_desc tng_desc = {
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
{ PCI_DEVICE(0x8086, 0x119a),
.driver_data = (unsigned long)&tng_desc},
{ PCI_DEVICE_DATA(INTEL, SST_TNG, &tng_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
......
......@@ -189,6 +189,7 @@ struct sof_intel_dsp_desc {
int (*read_sdw_lcount)(struct snd_sof_dev *sdev);
void (*enable_sdw_irq)(struct snd_sof_dev *sdev, bool enable);
bool (*check_sdw_irq)(struct snd_sof_dev *sdev);
bool (*check_sdw_wakeen_irq)(struct snd_sof_dev *sdev);
bool (*check_ipc_irq)(struct snd_sof_dev *sdev);
int (*power_down_dsp)(struct snd_sof_dev *sdev);
int (*disable_interrupts)(struct snd_sof_dev *sdev);
......
......@@ -147,6 +147,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = {
.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_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
......@@ -175,6 +176,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
.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_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
......@@ -203,6 +205,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = {
.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_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
......@@ -231,6 +234,7 @@ const struct sof_intel_dsp_desc adls_chip_info = {
.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_sdw_wakeen_irq = hda_sdw_check_wakeen_irq_common,
.check_ipc_irq = hda_dsp_check_ipc_irq,
.cl_init = cl_dsp_init,
.power_down_dsp = hda_power_down_dsp,
......
......@@ -23,7 +23,8 @@ static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state
/* trigger a single pipeline */
if (trigger_list->count == 1)
return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_ids[0], state);
return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_instance_ids[0],
state);
primary = state;
primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
......@@ -42,15 +43,15 @@ static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state
return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, ipc_size);
}
int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state)
{
struct sof_ipc4_msg msg = {{ 0 }};
u32 primary;
dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state);
dev_dbg(sdev->dev, "ipc4 set pipeline instance %d state %d", instance_id, state);
primary = state;
primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id);
primary |= SOF_IPC4_GLB_PIPE_STATE_ID(instance_id);
primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
......@@ -79,19 +80,19 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state,
* for the first time
*/
if (spipe->started_count == spipe->paused_count)
trigger_list->pipeline_ids[trigger_list->count++] =
trigger_list->pipeline_instance_ids[trigger_list->count++] =
pipe_widget->instance_id;
break;
case SOF_IPC4_PIPE_RESET:
/* RESET if the pipeline is neither running nor paused */
if (!spipe->started_count && !spipe->paused_count)
trigger_list->pipeline_ids[trigger_list->count++] =
trigger_list->pipeline_instance_ids[trigger_list->count++] =
pipe_widget->instance_id;
break;
case SOF_IPC4_PIPE_PAUSED:
/* Pause the pipeline only when its started_count is 1 more than paused_count */
if (spipe->paused_count == (spipe->started_count - 1))
trigger_list->pipeline_ids[trigger_list->count++] =
trigger_list->pipeline_instance_ids[trigger_list->count++] =
pipe_widget->instance_id;
break;
default:
......@@ -113,7 +114,7 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
/* set state for pipeline if it was just triggered */
for (i = 0; i < trigger_list->count; i++) {
if (trigger_list->pipeline_ids[i] == pipe_widget->instance_id) {
if (trigger_list->pipeline_instance_ids[i] == pipe_widget->instance_id) {
pipeline->state = state;
break;
}
......@@ -314,8 +315,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
return sof_ipc4_chain_dma_trigger(sdev, pipeline_list, state, cmd);
/* allocate memory for the pipeline data */
trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count),
GFP_KERNEL);
trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids,
pipeline_list->count), GFP_KERNEL);
if (!trigger_list)
return -ENOMEM;
......
......@@ -1746,6 +1746,12 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
/* update pipeline memory usage */
sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
/*
* Restore gateway config length now that IPC payload is prepared. This avoids
* counting the DMA CONFIG TLV multiple times
*/
copier_data->gtw_cfg.config_length = gtw_cfg_config_length / 4;
return 0;
}
......@@ -2319,6 +2325,7 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
pipeline->mem_usage = 0;
pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
ida_free(&pipeline_ida, swidget->instance_id);
swidget->instance_id = -EINVAL;
} else {
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
......
......@@ -144,11 +144,11 @@ struct sof_ipc4_pipeline {
/**
* struct sof_ipc4_multi_pipeline_data - multi pipeline trigger IPC data
* @count: Number of pipelines to be triggered
* @pipeline_ids: Flexible array of IDs of the pipelines to be triggered
* @pipeline_instance_ids: Flexible array of IDs of the pipelines to be triggered
*/
struct ipc4_pipeline_set_state_data {
u32 count;
DECLARE_FLEX_ARRAY(u32, pipeline_ids);
DECLARE_FLEX_ARRAY(u32, pipeline_instance_ids);
} __packed;
/**
......
......@@ -2158,6 +2158,8 @@ static int sof_complete(struct snd_soc_component *scomp)
struct snd_sof_widget *pipe_widget = spipe->pipe_widget;
struct snd_sof_widget *swidget;
pipe_widget->instance_id = -EINVAL;
/* Update the scheduler widget's IPC structure */
if (widget_ops && widget_ops[pipe_widget->id].ipc_setup) {
ret = widget_ops[pipe_widget->id].ipc_setup(pipe_widget);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment