diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index f1baaa88e766df..f3e33a619508d0 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -361,6 +361,7 @@ void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex); int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec); void snd_hdac_bus_remove_device(struct hdac_bus *bus, struct hdac_device *codec); +void snd_hdac_bus_process_unsol_events(struct work_struct *work); static inline void snd_hdac_codec_link_up(struct hdac_device *codec) { diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index 1bd27576db98d5..a835558ddbc9b5 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -146,7 +146,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple); */ void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *stream) { - snd_hdac_updatel(stream->pplc_addr, AZX_REG_PPLCCTL, 0, AZX_PPLCCTL_RUN); + snd_hdac_updatel(stream->pplc_addr, AZX_REG_PPLCCTL, + AZX_PPLCCTL_RUN, AZX_PPLCCTL_RUN); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_stream_start); @@ -171,7 +172,8 @@ void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *stream) snd_hdac_ext_link_stream_clear(stream); - snd_hdac_updatel(stream->pplc_addr, AZX_REG_PPLCCTL, 0, AZX_PPLCCTL_STRST); + snd_hdac_updatel(stream->pplc_addr, AZX_REG_PPLCCTL, + AZX_PPLCCTL_STRST, AZX_PPLCCTL_STRST); udelay(3); timeout = 50; do { @@ -242,7 +244,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_link_set_stream_id); void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link, int stream) { - snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, 0, (1 << stream)); + snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, (1 << stream), 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_clear_stream_id); @@ -415,7 +417,6 @@ void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus, bool enable, int index) { u32 mask = 0; - u32 register_mask = 0; if (!bus->spbcap) { dev_err(bus->dev, "Address of SPB capability is NULL\n"); @@ -424,12 +425,8 @@ void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus, mask |= (1 << index); - register_mask = readl(bus->spbcap + AZX_REG_SPB_SPBFCCTL); - - mask |= register_mask; - if (enable) - snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, 0, mask); + snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, mask); else snd_hdac_updatel(bus->spbcap, AZX_REG_SPB_SPBFCCTL, mask, 0); } @@ -503,7 +500,6 @@ void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus, bool enable, int index) { u32 mask = 0; - u32 register_mask = 0; if (!bus->drsmcap) { dev_err(bus->dev, "Address of DRSM capability is NULL\n"); @@ -512,12 +508,8 @@ void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus, mask |= (1 << index); - register_mask = readl(bus->drsmcap + AZX_REG_SPB_SPBFCCTL); - - mask |= register_mask; - if (enable) - snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, 0, mask); + snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, mask); else snd_hdac_updatel(bus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); } diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index 714a51721a313c..012305177f6822 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -9,8 +9,6 @@ #include #include "trace.h" -static void process_unsol_events(struct work_struct *work); - static const struct hdac_bus_ops default_ops = { .command = snd_hdac_bus_send_cmd, .get_response = snd_hdac_bus_get_response, @@ -37,7 +35,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, bus->io_ops = io_ops; INIT_LIST_HEAD(&bus->stream_list); INIT_LIST_HEAD(&bus->codec_list); - INIT_WORK(&bus->unsol_work, process_unsol_events); + INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); spin_lock_init(&bus->reg_lock); mutex_init(&bus->cmd_mutex); bus->irq = -1; @@ -148,7 +146,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_bus_queue_event); /* * process queued unsolicited events */ -static void process_unsol_events(struct work_struct *work) +void snd_hdac_bus_process_unsol_events(struct work_struct *work) { struct hdac_bus *bus = container_of(work, struct hdac_bus, unsol_work); struct hdac_device *codec; @@ -171,6 +169,7 @@ static void process_unsol_events(struct work_struct *work) drv->unsol_event(codec, res); } } +EXPORT_SYMBOL_GPL(snd_hdac_bus_process_unsol_events); /** * snd_hdac_bus_add_device - Add a codec to bus diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 070a8d3799a8d7..437ecdde749fa8 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -289,7 +289,7 @@ static int sof_probe(struct platform_device *pdev) } /* load the firmware */ - ret = snd_sof_load_firmware(sdev, plat_data->fw, true); + ret = snd_sof_load_firmware(sdev, true); if (ret < 0) { dev_err(sdev->dev, "error: failed to load DSP firmware %d\n", ret); diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 85750054a5c90c..d777ddd80d893e 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -101,4 +101,16 @@ config SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_PCI select SND_SOC_ACPI_INTEL_MATCH +config SND_SOC_SOF_HDA + tristate "SOF support for HDA Links(HDA/HDMI)" + depends on SND_SOC_SOF_HDA_COMMON + select SND_HDA_EXT_CORE + select SND_SOC_HDAC_HDA + select SND_SOC_HDAC_HDMI + help + This adds support for HDA links(HDA/HDMI) with Sound Open Firmware + for Intel(R) platforms. + Say Y if you want to enble HDA links with SOF. + If unsure select "N". + endif ## SND_SOC_SOF_INTEL diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index 7b5784d88fd154..accb3d4d209d21 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -6,10 +6,14 @@ snd-sof-intel-byt-objs := byt.o snd-sof-intel-hsw-objs := hsw.o snd-sof-intel-bdw-objs := bdw.o 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-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ + hda-dai.o hda-bus.o \ skl.o apl.o cnl.o +snd-sof-intel-hda-objs := hda-codec.o + obj-$(CONFIG_SND_SOC_SOF_BAYTRAIL) += snd-sof-intel-byt.o obj-$(CONFIG_SND_SOC_SOF_HASWELL) += snd-sof-intel-hsw.o obj-$(CONFIG_SND_SOC_SOF_BROADWELL) += snd-sof-intel-bdw.o obj-$(CONFIG_SND_SOC_SOF_HDA_COMMON) += snd-sof-intel-hda-common.o +obj-$(CONFIG_SND_SOC_SOF_HDA) += snd-sof-intel-hda.o diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c new file mode 100644 index 00000000000000..0942ffb9110fa4 --- /dev/null +++ b/sound/soc/sof/intel/hda-bus.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: (GPL-2.0 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) 2018 Intel Corporation. All rights reserved. + * + * Authors: Jeeja KP + * Keyon Jie + */ + +#include + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + +static const struct hdac_bus_ops bus_ops = { + .command = snd_hdac_bus_send_cmd, + .get_response = snd_hdac_bus_get_response, +}; + +#endif + +static void sof_hda_writel(u32 value, u32 __iomem *addr) +{ + writel(value, addr); +} + +static u32 sof_hda_readl(u32 __iomem *addr) +{ + return readl(addr); +} + +static void sof_hda_writew(u16 value, u16 __iomem *addr) +{ + writew(value, addr); +} + +static u16 sof_hda_readw(u16 __iomem *addr) +{ + return readw(addr); +} + +static void sof_hda_writeb(u8 value, u8 __iomem *addr) +{ + writeb(value, addr); +} + +static u8 sof_hda_readb(u8 __iomem *addr) +{ + return readb(addr); +} + +static int sof_hda_dma_alloc_pages(struct hdac_bus *bus, int type, + size_t size, struct snd_dma_buffer *buf) +{ + return snd_dma_alloc_pages(type, bus->dev, size, buf); +} + +static void sof_hda_dma_free_pages(struct hdac_bus *bus, + struct snd_dma_buffer *buf) +{ + snd_dma_free_pages(buf); +} + +static const struct hdac_io_ops io_ops = { + .reg_writel = sof_hda_writel, + .reg_readl = sof_hda_readl, + .reg_writew = sof_hda_writew, + .reg_readw = sof_hda_readw, + .reg_writeb = sof_hda_writeb, + .reg_readb = sof_hda_readb, + .dma_alloc_pages = sof_hda_dma_alloc_pages, + .dma_free_pages = sof_hda_dma_free_pages, +}; + +/* + * This can be used for both with/without hda link support. + * Returns 0 if successful, or a negative error code. + */ +int sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, + const struct hdac_ext_bus_ops *ext_ops) +{ + static int idx; + + memset(bus, 0, sizeof(*bus)); + bus->dev = dev; + + bus->io_ops = &io_ops; + INIT_LIST_HEAD(&bus->stream_list); + INIT_LIST_HEAD(&bus->codec_list); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + bus->ops = &bus_ops; + INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); +#endif + spin_lock_init(&bus->reg_lock); + mutex_init(&bus->cmd_mutex); + bus->irq = -1; + + bus->ext_ops = ext_ops; + INIT_LIST_HEAD(&bus->hlink_list); + bus->idx = idx++; + + mutex_init(&bus->lock); + bus->cmd_dma_state = true; + + return 0; +} diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c new file mode 100644 index 00000000000000..6971e0e2d3adc7 --- /dev/null +++ b/sound/soc/sof/intel/hda-codec.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: (GPL-2.0 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) 2018 Intel Corporation. All rights reserved. +// +// Authors: Jeeja KP +// Rakesh Ughreja +// Keyon Jie +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../codecs/hdac_hda.h" + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +#define IDISP_VID_INTEL 0x80860000 + +/* load the legacy HDA codec driver */ +#ifdef MODULE +static void hda_codec_load_module(struct hda_codec *codec) +{ + char alias[MODULE_NAME_LEN]; + const char *module = alias; + + snd_hdac_codec_modalias(&codec->core, alias, sizeof(alias)); + dev_dbg(&codec->core.dev, "loading codec module: %s\n", module); + request_module(module); +} +#else +static void hda_codec_load_module(struct hda_codec *codec) {} +#endif + +/* probe individual codec */ +static int hda_codec_probe(struct snd_sof_dev *sdev, int address) +{ + struct hda_bus *hbus = sof_to_hbus(sdev); + struct hdac_device *hdev; + struct hdac_hda_priv *hda_priv; + u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) | + (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; + u32 resp = -1; + int ret; + + mutex_lock(&hbus->core.cmd_mutex); + snd_hdac_bus_send_cmd(&hbus->core, hda_cmd); + snd_hdac_bus_get_response(&hbus->core, address, &resp); + mutex_unlock(&hbus->core.cmd_mutex); + if (resp == -1) + return -EIO; + dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n", + address, resp); + + hda_priv = devm_kzalloc(&hbus->pci->dev, sizeof(*hda_priv), + GFP_KERNEL); + if (!hda_priv) + return -ENOMEM; + + hda_priv->codec.bus = hbus; + hdev = &hda_priv->codec.core; + + ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev); + if (ret < 0) + return ret; + + /* use legacy bus only for HDA codecs, idisp uses ext bus */ + if ((resp & 0xFFFF0000) != IDISP_VID_INTEL) { + hdev->type = HDA_DEV_LEGACY; + hda_codec_load_module(&hda_priv->codec); + } + + return 0; +} + +/* Codec initialization */ +int hda_codec_probe_bus(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int i, ret = 0; + + /* probe codecs in avail slots */ + for (i = 0; i < HDA_MAX_CODECS; i++) { + + if (!(bus->codec_mask & (1 << i))) + continue; + + ret = hda_codec_probe(sdev, i); + if (ret < 0) { + dev_err(bus->dev, "codec #%d probe error, ret: %d\n", + i, ret); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL(hda_codec_probe_bus); + +int hda_codec_i915_init(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int ret; + + /* i915 exposes a HDA codec for HDMI audio */ + ret = snd_hdac_i915_init(bus); + if (ret < 0) + return ret; + + ret = snd_hdac_display_power(bus, true); + if (ret < 0) + dev_err(bus->dev, "i915 HDAC power on failed %d\n", ret); + + return ret; +} +EXPORT_SYMBOL(hda_codec_i915_init); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 825deb59527dfa..867bc3c4c7d3e9 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -86,8 +86,9 @@ int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev) int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev) { + struct hdac_bus *bus = sof_to_bus(sdev); u32 cap, offset, feature; - int ret = -ENODEV, count = 0; + int count = 0; offset = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_LLCH); @@ -103,21 +104,30 @@ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev) case SOF_HDA_PP_CAP_ID: dev_dbg(sdev->dev, "found DSP capability at 0x%x\n", offset); - sdev->bar[HDA_DSP_PP_BAR] = sdev->bar[HDA_DSP_HDA_BAR] + - offset; - ret = 0; + bus->ppcap = bus->remap_addr + offset; + sdev->bar[HDA_DSP_PP_BAR] = bus->ppcap; break; case SOF_HDA_SPIB_CAP_ID: dev_dbg(sdev->dev, "found SPIB capability at 0x%x\n", offset); - sdev->bar[HDA_DSP_SPIB_BAR] = - sdev->bar[HDA_DSP_HDA_BAR] + offset; + bus->spbcap = bus->remap_addr + offset; + sdev->bar[HDA_DSP_SPIB_BAR] = bus->spbcap; break; case SOF_HDA_DRSM_CAP_ID: dev_dbg(sdev->dev, "found DRSM capability at 0x%x\n", offset); - sdev->bar[HDA_DSP_DRSM_BAR] = - sdev->bar[HDA_DSP_HDA_BAR] + offset; + bus->drsmcap = bus->remap_addr + offset; + sdev->bar[HDA_DSP_DRSM_BAR] = bus->drsmcap; + break; + case SOF_HDA_GTS_CAP_ID: + dev_dbg(sdev->dev, "found GTS capability at 0x%x\n", + offset); + bus->gtscap = bus->remap_addr + offset; + break; + case SOF_HDA_ML_CAP_ID: + dev_dbg(sdev->dev, "found ML capability at 0x%x\n", + offset); + bus->mlcap = bus->remap_addr + offset; break; default: dev_vdbg(sdev->dev, "found capability %d at 0x%x\n", @@ -128,6 +138,32 @@ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev) offset = cap & SOF_HDA_CAP_NEXT_MASK; } while (count++ <= SOF_HDA_MAX_CAPS && offset); + return 0; +} + +void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable) +{ + u32 val = enable ? PCI_CGCTL_MISCBDCGE_MASK : 0; + + snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_MISCBDCGE_MASK, val); +} + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +/* + * While performing reset, controller may not come back properly and causing + * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset + * (init chip) and then again set CGCTL.MISCBDCGE to 1 + */ +int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int ret; + + hda_dsp_ctrl_misc_clock_gating(sdev, false); + ret = snd_hdac_bus_init_chip(bus, full_reset); + hda_dsp_ctrl_misc_clock_gating(sdev, true); + return ret; } +#endif diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 5dc24b9067d278..72df362b86360b 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -38,7 +38,8 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, unsigned int size, struct snd_dma_buffer *dmab, int direction) { - struct sof_intel_hda_stream *stream = NULL; + struct hdac_ext_stream *stream = NULL; + struct hdac_stream *hstream; struct pci_dev *pci = sdev->pci; int ret; @@ -53,6 +54,7 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, dev_err(sdev->dev, "error: no stream available\n"); return -ENODEV; } + hstream = &stream->hstream; /* allocate DMA buffer */ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); @@ -61,8 +63,8 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, goto error; } - stream->config = format; - stream->bufsize = size; + hstream->format_val = format; + hstream->bufsize = size; ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL); if (ret < 0) { @@ -72,10 +74,10 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_ENABLE, size); - return stream->tag; + return hstream->stream_tag; error: - hda_dsp_stream_put_pstream(sdev, stream->tag); + hda_dsp_stream_put_pstream(sdev, hstream->stream_tag); snd_dma_free_pages(dmab); return ret; } @@ -188,8 +190,11 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, } static int cl_trigger(struct snd_sof_dev *sdev, - struct sof_intel_hda_stream *stream, int cmd) + struct hdac_ext_stream *stream, int cmd) { + struct hdac_stream *hstream = &stream->hstream; + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + /* code loader is special case that reuses stream ops */ switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -197,16 +202,17 @@ static int cl_trigger(struct snd_sof_dev *sdev, HDA_DSP_CL_TRIGGER_TIMEOUT); snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, - 1 << stream->index, 1 << stream->index); + 1 << hstream->index, + 1 << hstream->index); snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset, + sd_offset, SOF_HDA_SD_CTL_DMA_START | SOF_HDA_CL_DMA_SD_INT_MASK, SOF_HDA_SD_CTL_DMA_START | SOF_HDA_CL_DMA_SD_INT_MASK); - stream->running = true; + hstream->running = true; return 0; default: return hda_dsp_stream_trigger(sdev, stream, cmd); @@ -214,45 +220,50 @@ static int cl_trigger(struct snd_sof_dev *sdev, } static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, - struct sof_intel_hda_stream *stream) + struct hdac_ext_stream *stream) { + struct hdac_stream *hstream = &stream->hstream; + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); int ret; ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); /* TODO: spin lock ?*/ - stream->open = 0; - stream->running = 0; - stream->substream = NULL; + hstream->opened = 0; + hstream->running = 0; + hstream->substream = NULL; /* reset BDL address */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, 0); + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, 0); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0); + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0); - snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, stream->sd_offset, 0); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0); snd_dma_free_pages(dmab); dmab->area = NULL; - stream->bufsize = 0; - stream->config = 0; + hstream->bufsize = 0; + hstream->format_val = 0; return ret; } static int cl_copy_fw(struct snd_sof_dev *sdev, int tag) { - struct sof_intel_hda_stream *stream = NULL; - struct sof_intel_hda_dev *hdev = sdev->hda; - int ret, status, i; + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_stream *stream = NULL; + struct hdac_stream *s; + int ret, status; /* get stream with tag */ - for (i = 0; i < hdev->num_playback; i++) { - if (hdev->pstream[i].tag == tag) { - stream = &hdev->pstream[i]; + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == SNDRV_PCM_STREAM_PLAYBACK + && s->stream_tag == tag) { + stream = stream_to_hdac_ext_stream(s); break; } } + if (!stream) { dev_err(sdev->dev, "error: could not get stream with stream tag%d\n", @@ -287,28 +298,15 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, int tag) return status; } -int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, const struct firmware *fw, - bool first_boot) +int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot) { struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); - int ret; /* set code loading condition to true */ sdev->code_loading = 1; - ret = request_firmware(&plat_data->fw, - plat_data->machine->sof_fw_filename, sdev->dev); - - if (ret < 0) { - dev_err(sdev->dev, "error: request firmware failed err: %d\n", - ret); - return -EINVAL; - } - - if (!plat_data->fw) - return -EINVAL; - - return ret; + return request_firmware(&plat_data->fw, + plat_data->machine->sof_fw_filename, sdev->dev); } int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index fb256a12a8fd5e..45338f78df9d9e 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -98,7 +98,8 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct sof_intel_hda_stream *stream = substream->runtime->private_data; + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); struct snd_dma_buffer *dmab; int ret; u32 size, rate, bits; @@ -107,12 +108,12 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, rate = get_mult_div(sdev, params_rate(params)); bits = get_bits(sdev, params_width(params)); - stream->substream = substream; + hstream->substream = substream; dmab = substream->runtime->dma_buffer_p; - stream->config = rate | bits | (params_channels(params) - 1); - stream->bufsize = size; + hstream->format_val = rate | bits | (params_channels(params) - 1); + hstream->bufsize = size; ret = hda_dsp_stream_hw_params(sdev, stream, dmab, params); if (ret < 0) { @@ -123,13 +124,14 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, /* disable SPIB, to enable buffer wrap for stream */ hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); - return stream->tag; + return hstream->stream_tag; } int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, int cmd) { - struct sof_intel_hda_stream *stream = substream->runtime->private_data; + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); return hda_dsp_stream_trigger(sdev, stream, cmd); } @@ -137,7 +139,7 @@ int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, int hda_dsp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { - struct sof_intel_hda_stream *stream; + struct hdac_ext_stream *stream; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) stream = hda_dsp_stream_get_pstream(sdev); @@ -150,20 +152,20 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev, } /* binding pcm substream to hda stream */ - substream->runtime->private_data = stream; + substream->runtime->private_data = &stream->hstream; return 0; } int hda_dsp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { - struct sof_intel_hda_stream *stream = substream->runtime->private_data; + struct hdac_stream *hstream = substream->runtime->private_data; int ret; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ret = hda_dsp_stream_put_pstream(sdev, stream->tag); + ret = hda_dsp_stream_put_pstream(sdev, hstream->stream_tag); else - ret = hda_dsp_stream_put_cstream(sdev, stream->tag); + ret = hda_dsp_stream_put_cstream(sdev, hstream->stream_tag); if (ret) { dev_dbg(sdev->dev, "stream %s not opened!\n", substream->name); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 620a023c17384a..60e3844f72457b 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,7 @@ */ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, - struct sof_intel_hda_stream *stream, + struct hdac_stream *stream, struct sof_intel_dsp_bdl *bdl, int size, struct snd_pcm_hw_params *params) { @@ -92,9 +93,10 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, } int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, - struct sof_intel_hda_stream *stream, + struct hdac_ext_stream *stream, int enable, u32 size) { + struct hdac_stream *hstream = &stream->hstream; u32 mask = 0; if (!sdev->bar[HDA_DSP_SPIB_BAR]) { @@ -102,12 +104,12 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, return -EINVAL; } - mask |= (1 << stream->index); + mask |= (1 << hstream->index); /* enable/disable SPIB for the stream */ snd_sof_dsp_update_bits(sdev, HDA_DSP_SPIB_BAR, SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, mask, - enable << stream->index); + enable << hstream->index); /* set the SPIB value */ hda_dsp_write(sdev, stream->spib_addr, size); @@ -115,19 +117,47 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, return 0; } + +/* get next unused stream */ +struct hdac_ext_stream * +hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_stream *stream = NULL; + struct hdac_stream *s; + + /* get an unused playback stream */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == direction && !s->opened) { + s->opened = true; + stream = stream_to_hdac_ext_stream(s); + break; + } + } + + /* stream found ? */ + if (!stream) + dev_err(sdev->dev, "error: no free %s streams\n", + direction == SNDRV_PCM_STREAM_PLAYBACK ? + "playback" : "capture"); + + return stream; +} + /* get next unused playback stream */ -struct sof_intel_hda_stream * +struct hdac_ext_stream * hda_dsp_stream_get_pstream(struct snd_sof_dev *sdev) { - struct sof_intel_hda_dev *hdev = sdev->hda; - struct sof_intel_hda_stream *stream = NULL; - int i; + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_stream *stream = NULL; + struct hdac_stream *s; /* get an unused playback stream */ - for (i = 0; i < hdev->num_playback; i++) { - if (!hdev->pstream[i].open) { - hdev->pstream[i].open = true; - stream = &hdev->pstream[i]; + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == SNDRV_PCM_STREAM_PLAYBACK + && !s->opened) { + s->opened = true; + stream = stream_to_hdac_ext_stream(s); break; } } @@ -140,18 +170,19 @@ hda_dsp_stream_get_pstream(struct snd_sof_dev *sdev) } /* get next unused capture stream */ -struct sof_intel_hda_stream * +struct hdac_ext_stream * hda_dsp_stream_get_cstream(struct snd_sof_dev *sdev) { - struct sof_intel_hda_dev *hdev = sdev->hda; - struct sof_intel_hda_stream *stream = NULL; - int i; + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_stream *stream = NULL; + struct hdac_stream *s; /* get an unused capture stream */ - for (i = 0; i < hdev->num_capture; i++) { - if (!hdev->cstream[i].open) { - hdev->cstream[i].open = true; - stream = &hdev->cstream[i]; + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == SNDRV_PCM_STREAM_CAPTURE + && !s->opened) { + s->opened = true; + stream = stream_to_hdac_ext_stream(s); break; } } @@ -163,17 +194,36 @@ hda_dsp_stream_get_cstream(struct snd_sof_dev *sdev) return stream; } +/* free a stream */ +int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int tag) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *s; + + /* find used stream */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == direction + && s->opened && s->stream_tag == tag) { + s->opened = false; + return 0; + } + } + + dev_dbg(sdev->dev, "tag %d not opened!\n", tag); + return -ENODEV; +} + /* free playback stream */ int hda_dsp_stream_put_pstream(struct snd_sof_dev *sdev, int tag) { - struct sof_intel_hda_dev *hdev = sdev->hda; - int i; + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *s; /* find used playback stream */ - for (i = 0; i < hdev->num_playback; i++) { - if (hdev->pstream[i].open && - hdev->pstream[i].tag == tag) { - hdev->pstream[i].open = false; + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == SNDRV_PCM_STREAM_PLAYBACK + && s->opened && s->stream_tag == tag) { + s->opened = false; return 0; } } @@ -185,14 +235,14 @@ int hda_dsp_stream_put_pstream(struct snd_sof_dev *sdev, int tag) /* free capture stream */ int hda_dsp_stream_put_cstream(struct snd_sof_dev *sdev, int tag) { - struct sof_intel_hda_dev *hdev = sdev->hda; - int i; + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *s; /* find used capture stream */ - for (i = 0; i < hdev->num_capture; i++) { - if (hdev->cstream[i].open && - hdev->cstream[i].tag == tag) { - hdev->cstream[i].open = false; + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == SNDRV_PCM_STREAM_CAPTURE + && s->opened && s->stream_tag == tag) { + s->opened = false; return 0; } } @@ -202,41 +252,44 @@ int hda_dsp_stream_put_cstream(struct snd_sof_dev *sdev, int tag) } int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, - struct sof_intel_hda_stream *stream, int cmd) + struct hdac_ext_stream *stream, int cmd) { + struct hdac_stream *hstream = &stream->hstream; + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + /* cmd must be for audio stream */ switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_START: snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, - 1 << stream->index, - 1 << stream->index); + 1 << hstream->index, + 1 << hstream->index); snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset, + sd_offset, SOF_HDA_SD_CTL_DMA_START | SOF_HDA_CL_DMA_SD_INT_MASK, SOF_HDA_SD_CTL_DMA_START | SOF_HDA_CL_DMA_SD_INT_MASK); - stream->running = true; + hstream->running = true; break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_STOP: snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset, + sd_offset, SOF_HDA_SD_CTL_DMA_START | SOF_HDA_CL_DMA_SD_INT_MASK, 0x0); - snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, stream->sd_offset + + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK); - stream->running = false; + hstream->running = false; snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, - 1 << stream->index, 0x0); + 1 << hstream->index, 0x0); break; default: dev_err(sdev->dev, "error: unknown command: %d\n", cmd); @@ -251,12 +304,14 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, * and normal stream. */ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, - struct sof_intel_hda_stream *stream, + struct hdac_ext_stream *stream, struct snd_dma_buffer *dmab, struct snd_pcm_hw_params *params) { - struct sof_intel_hda_dev *hdev = sdev->hda; + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *hstream = &stream->hstream; struct sof_intel_dsp_bdl *bdl; + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); int ret, timeout = HDA_DSP_STREAM_RESET_TIMEOUT; u32 val, mask; @@ -266,31 +321,35 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, } /* decouple host and link DMA */ - mask = 0x1 << stream->index; + mask = 0x1 << hstream->index; snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, +#ifndef CONFIG_SND_SOC_SOF_FORCE_LEGACY_HDA mask, mask); - +#else + /* temporary using coupled mode */ + mask, 0); +#endif if (!dmab) { dev_err(sdev->dev, "error: no dma buffer allocated!\n"); return -ENODEV; } /* clear stream status */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, stream->sd_offset, + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_HDA_CL_DMA_SD_INT_MASK | SOF_HDA_SD_CTL_DMA_START, 0); snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK, SOF_HDA_CL_DMA_SD_INT_MASK); /* stream reset */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, stream->sd_offset, 0x1, + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 0x1, 0x1); udelay(3); do { val = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset); + sd_offset); if (val & 0x1) break; } while (--timeout); @@ -300,14 +359,14 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, } timeout = HDA_DSP_STREAM_RESET_TIMEOUT; - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, stream->sd_offset, 0x1, + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 0x1, 0x0); /* wait for hardware to report that stream is out of reset */ udelay(3); do { val = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset); + sd_offset); if ((val & 0x1) == 0) break; } while (--timeout); @@ -316,31 +375,31 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, return -ETIMEDOUT; } - if (stream->posbuf) - *stream->posbuf = 0; + if (hstream->posbuf) + *hstream->posbuf = 0; /* reset BDL address */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, 0x0); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0x0); /* clear stream status */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, stream->sd_offset, + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_HDA_CL_DMA_SD_INT_MASK | SOF_HDA_SD_CTL_DMA_START, 0); snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK, SOF_HDA_CL_DMA_SD_INT_MASK); - stream->frags = 0; + hstream->frags = 0; - bdl = (struct sof_intel_dsp_bdl *)stream->bdl.area; - ret = hda_dsp_stream_setup_bdl(sdev, dmab, stream, bdl, - stream->bufsize, params); + bdl = (struct sof_intel_dsp_bdl *)hstream->bdl.area; + ret = hda_dsp_stream_setup_bdl(sdev, dmab, hstream, bdl, + hstream->bufsize, params); if (ret < 0) { dev_err(sdev->dev, "error: set up of BDL failed\n"); return ret; @@ -348,57 +407,57 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, /* set up stream descriptor for DMA */ /* program stream tag */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, stream->sd_offset, + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_HDA_CL_SD_CTL_STREAM_TAG_MASK, - stream->tag << + hstream->stream_tag << SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT); /* program cyclic buffer length */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, - stream->bufsize); + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, + hstream->bufsize); /* program stream format */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + + sd_offset + SOF_HDA_ADSP_REG_CL_SD_FORMAT, - 0xffff, stream->config); + 0xffff, hstream->format_val); /* program last valid index */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, - 0xffff, (stream->frags - 1)); + sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, + 0xffff, (hstream->frags - 1)); /* program BDL address */ snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, - (u32)stream->bdl.addr); + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + (u32)hstream->bdl.addr); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, - upper_32_bits(stream->bdl.addr)); + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + upper_32_bits(hstream->bdl.addr)); /* enable position buffer */ if (!(snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE) & SOF_HDA_ADSP_DPLBASE_ENABLE)) snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE, - (u32)hdev->posbuffer.addr | + (u32)bus->posbuf.addr | SOF_HDA_ADSP_DPLBASE_ENABLE); /* set interrupt enable bits */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, stream->sd_offset, + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_HDA_CL_DMA_SD_INT_MASK, SOF_HDA_CL_DMA_SD_INT_MASK); /* read FIFO size */ - if (stream->direction == SNDRV_PCM_STREAM_PLAYBACK) { - stream->fifo_size = + if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) { + hstream->fifo_size = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + + sd_offset + SOF_HDA_ADSP_REG_CL_SD_FIFOSIZE); - stream->fifo_size &= 0xffff; - stream->fifo_size += 1; + hstream->fifo_size &= 0xffff; + hstream->fifo_size += 1; } else { - stream->fifo_size = 0; + hstream->fifo_size = 0; } return ret; @@ -406,77 +465,61 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) { - struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + struct hdac_bus *bus = (struct hdac_bus *)context; u32 status; - if (!pm_runtime_active(sdev->dev)) + if (!pm_runtime_active(bus->dev)) return IRQ_NONE; - status = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS); + spin_lock(&bus->reg_lock); - if (status == 0 || status == 0xffffffff) + status = snd_hdac_chip_readl(bus, INTSTS); + if (status == 0 || status == 0xffffffff) { + spin_unlock(&bus->reg_lock); return IRQ_NONE; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* clear rirb int */ + status = snd_hdac_chip_readb(bus, RIRBSTS); + if (status & RIRB_INT_MASK) { + if (status & RIRB_INT_RESPONSE) + snd_hdac_bus_update_rirb(bus); + snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); + } +#endif + + spin_unlock(&bus->reg_lock); - return status ? IRQ_WAKE_THREAD : IRQ_HANDLED; + return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED; } irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) { - struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; - struct sof_intel_hda_dev *hdev = sdev->hda; - u32 status = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS); + struct hdac_bus *bus = (struct hdac_bus *)context; + struct hdac_stream *s; + u32 status = snd_hdac_chip_readl(bus, INTSTS); u32 sd_status; - int i; - - /* check playback streams */ - for (i = 0; i < hdev->num_playback; i++) { - /* is IRQ for this stream ? */ - if (status & (1 << hdev->pstream[i].index)) { - sd_status = - snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, - hdev->pstream[i].sd_offset + - SOF_HDA_ADSP_REG_CL_SD_STS) & - 0xff; - - dev_dbg(sdev->dev, "pstream %d status 0x%x\n", - i, sd_status); - - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - hdev->pstream[i].sd_offset + - SOF_HDA_ADSP_REG_CL_SD_STS, - SOF_HDA_CL_DMA_SD_INT_MASK, - SOF_HDA_CL_DMA_SD_INT_MASK); - - if (!hdev->pstream[i].substream || - !hdev->pstream[i].running || - (sd_status & SOF_HDA_CL_DMA_SD_INT_MASK) == 0) - continue; - } - } - /* check capture streams */ - for (i = 0; i < hdev->num_capture; i++) { - /* is IRQ for this stream ? */ - if (status & (1 << hdev->cstream[i].index)) { - sd_status = - snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, - hdev->cstream[i].sd_offset + - SOF_HDA_ADSP_REG_CL_SD_STS) & - 0xff; - - dev_dbg(sdev->dev, "cstream %d status 0x%x\n", - i, sd_status); - - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - hdev->cstream[i].sd_offset + - SOF_HDA_ADSP_REG_CL_SD_STS, - SOF_HDA_CL_DMA_SD_INT_MASK, - SOF_HDA_CL_DMA_SD_INT_MASK); - - if (!hdev->cstream[i].substream || - !hdev->cstream[i].running || - (sd_status & SOF_HDA_CL_DMA_SD_INT_MASK) == 0) + /* check streams */ + list_for_each_entry(s, &bus->stream_list, list) { + if (status & (1 << s->index) + && s->opened) { + sd_status = snd_hdac_stream_readb(s, SD_STS); + + dev_dbg(bus->dev, "stream %d status 0x%x\n", + s->index, sd_status); + + snd_hdac_stream_writeb(s, SD_STS, SD_INT_MASK); + + if (!s->substream || + !s->running || + (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0) continue; +#ifdef USE_POS_BUF + snd_pcm_period_elapsed(s->substream); +#endif + } } @@ -485,9 +528,11 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) int hda_dsp_stream_init(struct snd_sof_dev *sdev) { - struct sof_intel_hda_dev *hdev = sdev->hda; - struct sof_intel_hda_stream *stream; + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_stream *stream; + struct hdac_stream *hstream; struct pci_dev *pci = sdev->pci; + int sd_offset; int i, num_playback, num_capture, num_total, ret; u32 gcap; @@ -499,9 +544,6 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) num_playback = (gcap >> 12) & 0x0f; num_total = num_playback + num_capture; - hdev->num_capture = num_capture; - hdev->num_playback = num_playback; - dev_dbg(sdev->dev, "detected %d playback and %d capture streams\n", num_playback, num_capture); @@ -518,16 +560,29 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) } /* mem alloc for the position buffer */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, 8, - &hdev->posbuffer); + /* TODO: check position buffer update */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, + SOF_HDA_DPIB_ENTRY_SIZE * num_total, + &bus->posbuf); if (ret < 0) { dev_err(sdev->dev, "error: posbuffer dma alloc failed\n"); return -ENOMEM; } + /* mem alloc for the CORB/RIRB ringbuffers */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, + PAGE_SIZE, &bus->rb); + if (ret < 0) { + dev_err(sdev->dev, "error: RB alloc failed\n"); + return -ENOMEM; + } + /* create capture streams */ for (i = 0; i < num_capture; i++) { - stream = &hdev->cstream[i]; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i; @@ -547,35 +602,45 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) SOF_HDA_SPIB_MAXFIFO; } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_DRSM) + /* FIXME: Remove? HDAC doesn't use DRSM so has no drsm_addr */ /* do we support DRSM */ if (sdev->bar[HDA_DSP_DRSM_BAR]) stream->drsm_addr = sdev->bar[HDA_DSP_DRSM_BAR] + SOF_HDA_DRSM_BASE + SOF_HDA_DRSM_INTERVAL * i; - - stream->sd_offset = 0x20 * i + SOF_HDA_ADSP_LOADER_BASE; - stream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + - stream->sd_offset; - - stream->tag = i + 1; - stream->open = false; - stream->running = false; - stream->direction = SNDRV_PCM_STREAM_CAPTURE; - stream->index = i; +#endif + + hstream = &stream->hstream; + hstream->bus = bus; + hstream->sd_int_sta_mask = 1 << i; + hstream->index = i; + sd_offset = SOF_STREAM_SD_OFFSET(hstream); + hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; + hstream->stream_tag = i + 1; + hstream->opened = false; + hstream->running = false; + hstream->direction = SNDRV_PCM_STREAM_CAPTURE; /* memory alloc for stream BDL */ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, - HDA_DSP_BDL_SIZE, &stream->bdl); + HDA_DSP_BDL_SIZE, &hstream->bdl); if (ret < 0) { dev_err(sdev->dev, "error: stream bdl dma alloc failed\n"); + kfree(stream); return -ENOMEM; } - stream->posbuf = (__le32 *)(hdev->posbuffer.area + - (stream->index) * 8); + hstream->posbuf = (__le32 *)(bus->posbuf.area + + (hstream->index) * 8); + + list_add_tail(&hstream->list, &bus->stream_list); } /* create playback streams */ for (i = num_capture; i < num_total; i++) { - stream = &hdev->pstream[i - num_capture]; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; /* we always have DSP support */ stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + @@ -596,30 +661,38 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) SOF_HDA_SPIB_MAXFIFO; } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_DRSM) + /* FIXME: Remove? HDAC doesn't use DRSM so has no drsm_addr */ /* do we support DRSM */ if (sdev->bar[HDA_DSP_DRSM_BAR]) stream->drsm_addr = sdev->bar[HDA_DSP_DRSM_BAR] + SOF_HDA_DRSM_BASE + SOF_HDA_DRSM_INTERVAL * i; - - stream->sd_offset = 0x20 * i + SOF_HDA_ADSP_LOADER_BASE; - stream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + - stream->sd_offset; - stream->tag = i - num_capture + 1; - stream->open = false; - stream->running = false; - stream->direction = SNDRV_PCM_STREAM_PLAYBACK; - stream->index = i; +#endif + + hstream = &stream->hstream; + hstream->bus = bus; + hstream->sd_int_sta_mask = 1 << i; + hstream->index = i; + sd_offset = SOF_STREAM_SD_OFFSET(hstream); + hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; + hstream->stream_tag = i - num_capture + 1; + hstream->opened = false; + hstream->running = false; + hstream->direction = SNDRV_PCM_STREAM_PLAYBACK; /* mem alloc for stream BDL */ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, - HDA_DSP_BDL_SIZE, &stream->bdl); + HDA_DSP_BDL_SIZE, &hstream->bdl); if (ret < 0) { dev_err(sdev->dev, "error: stream bdl dma alloc failed\n"); + kfree(stream); return -ENOMEM; } - stream->posbuf = (__le32 *)(hdev->posbuffer.area + - (stream->index) * 8); + hstream->posbuf = (__le32 *)(bus->posbuf.area + + (hstream->index) * 8); + + list_add_tail(&hstream->list, &bus->stream_list); } return 0; @@ -627,30 +700,23 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) void hda_dsp_stream_free(struct snd_sof_dev *sdev) { - struct sof_intel_hda_dev *hdev = sdev->hda; - struct sof_intel_hda_stream *stream; - int i; + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *s, *_s; + struct hdac_ext_stream *stream; /* free position buffer */ - if (hdev->posbuffer.area) - snd_dma_free_pages(&hdev->posbuffer); - - /* free capture streams */ - for (i = 0; i < hdev->num_capture; i++) { - stream = &hdev->cstream[i]; - - /* free bdl buffer */ - if (stream->bdl.area) - snd_dma_free_pages(&stream->bdl); - } + if (bus->posbuf.area) + snd_dma_free_pages(&bus->posbuf); - /* free playback streams */ - for (i = 0; i < hdev->num_playback; i++) { - stream = &hdev->pstream[i]; + list_for_each_entry_safe(s, _s, &bus->stream_list, list) { + /* TODO: decouple */ /* free bdl buffer */ - if (stream->bdl.area) - snd_dma_free_pages(&stream->bdl); + if (s->bdl.area) + snd_dma_free_pages(&s->bdl); + list_del(&s->list); + stream = stream_to_hdac_ext_stream(s); + kfree(stream); } } diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c index 273ac6d1a78ec3..a1c9f1b45dca14 100644 --- a/sound/soc/sof/intel/hda-trace.c +++ b/sound/soc/sof/intel/hda-trace.c @@ -36,11 +36,12 @@ static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev) { - struct sof_intel_hda_stream *stream = sdev->hda->dtrace_stream; + struct hdac_ext_stream *stream = sdev->hda->dtrace_stream; + struct hdac_stream *hstream = &stream->hstream; struct snd_dma_buffer *dmab = &sdev->dmatb; int ret; - stream->bufsize = sdev->dmatb.bytes; + hstream->bufsize = sdev->dmatb.bytes; ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL); if (ret < 0) @@ -59,7 +60,7 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *tag) return -ENODEV; } - *tag = sdev->hda->dtrace_stream->tag; + *tag = sdev->hda->dtrace_stream->hstream.stream_tag; /* * initialize capture stream, set BDL address and return corresponding @@ -70,10 +71,13 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *tag) int hda_dsp_trace_release(struct snd_sof_dev *sdev) { + struct hdac_stream *hstream; + if (sdev->hda->dtrace_stream) { - sdev->hda->dtrace_stream->open = false; + hstream = &sdev->hda->dtrace_stream->hstream; + hstream->opened = false; hda_dsp_stream_put_cstream(sdev, - sdev->hda->dtrace_stream->tag); + hstream->stream_tag); sdev->hda->dtrace_stream = NULL; return 0; } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index f9f1720c4c3150..21803e11228c9c 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -29,10 +29,18 @@ #include #include #include +#include +#include #include "../sof-priv.h" #include "../ops.h" #include "hda.h" +#include "../../codecs/hdac_hda.h" + +/* platform specific devices */ +#include "shim.h" + + /* * Register IO @@ -321,6 +329,133 @@ static const struct sof_intel_dsp_desc *get_chip_info(int pci_id) return NULL; } +static int hda_init(struct snd_sof_dev *sdev) +{ + struct hda_bus *hbus; + struct hdac_bus *bus; + struct hdac_ext_bus_ops *ext_ops = NULL; + struct pci_dev *pci = sdev->pci; + int ret; + + hbus = sof_to_hbus(sdev); + bus = sof_to_bus(sdev); + + /* HDA bus init */ +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDA) + ext_ops = snd_soc_hdac_hda_get_ops(); +#endif + sof_hda_bus_init(bus, &pci->dev, ext_ops); + bus->use_posbuf = 1; + bus->bdl_pos_adj = 0; + + mutex_init(&hbus->prepare_mutex); + hbus->pci = pci; + hbus->mixer_assigned = -1; + hbus->modelname = "sofbus"; + + /* initialise hdac bus */ + bus->addr = pci_resource_start(pci, 0); + bus->remap_addr = pci_ioremap_bar(pci, 0); + if (bus->remap_addr == NULL) { + dev_err(bus->dev, "ioremap error\n"); + return -ENXIO; + } + + /* HDA base */ + sdev->bar[HDA_DSP_HDA_BAR] = bus->remap_addr; + + /* get controller capabilities */ + ret = hda_dsp_ctrl_get_caps(sdev); + if (ret < 0) + dev_err(&pci->dev, "error: get caps error\n"); + + return ret; +} + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + +static int hda_init_caps(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct pci_dev *pci = sdev->pci; + struct hdac_ext_link *hlink = NULL; + int ret = 0; + + // FIXME: we do this a lot ! + hda_dsp_ctrl_init_chip(sdev, true); + + device_disable_async_suspend(bus->dev); + + /* check if dsp is there */ + if (bus->ppcap) + dev_dbg(&pci->dev, "PP capbility, will probe DSP later.\n"); + + if (bus->mlcap) + snd_hdac_ext_bus_get_ml_capabilities(bus); + + snd_hdac_bus_stop_chip(bus); + + /* probe i915 and HDA codecs */ + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { + ret = hda_codec_i915_init(sdev); + if (ret < 0) + return ret; + } + + // FIXME: we do this a lot ! + ret = hda_dsp_ctrl_init_chip(sdev, true); + if (ret < 0) { + dev_err(bus->dev, "Init chip failed with ret: %d\n", ret); + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, false); + return ret; + } + + /* codec detection */ + if (!bus->codec_mask) + dev_info(bus->dev, "no hda codecs found!\n"); + + /* create codec instances */ + hda_codec_probe_bus(sdev); + + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { + ret = snd_hdac_display_power(bus, false); + if (ret < 0) { + dev_err(bus->dev, "Cannot turn off display power on i915\n"); + return ret; + } + } + + /* + * we are done probing so decrement link counts + */ + list_for_each_entry(hlink, &bus->hlink_list, list) + snd_hdac_ext_bus_link_put(bus, hlink); + + return 0; +} + +#else + +static int hda_init_caps(struct snd_sof_dev *sdev) +{ + /* + * set CGCTL.MISCBDCGE to 0 during reset and set back to 1 + * when reset finished. + * TODO: maybe no need for init_caps? + */ + hda_dsp_ctrl_misc_clock_gating(sdev, 0); + + /* clear WAKESTS */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK, + SOF_HDA_WAKESTS_INT_MASK); + + return 0; +} + +#endif + /* * We don't need to do a full HDA codec probe as external HDA codec mode is * considered legacy and will not be supported under SOF. HDMI/DP HDA will @@ -330,10 +465,10 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = sdev->pci; struct sof_intel_hda_dev *hdev; - struct sof_intel_hda_stream *stream; + struct hdac_bus *bus; + struct hdac_stream *stream; const struct sof_intel_dsp_desc *chip; - int i; - int ret = 0; + int sd_offset, ret = 0; /* set DSP arch ops */ sdev->arch_ops = &sof_xtensa_arch_ops; @@ -352,33 +487,21 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) sdev->hda = hdev; hdev->desc = chip; - /* HDA base */ - sdev->bar[HDA_DSP_HDA_BAR] = pci_ioremap_bar(pci, HDA_DSP_HDA_BAR); - if (!sdev->bar[HDA_DSP_HDA_BAR]) { - dev_err(&pci->dev, "error: ioremap error\n"); - /* - * FIXME: why do we return directly, - * should we have a goto err here? - * or should all these gotos be replaced - * by a return? - */ - return -ENXIO; - } + /* set up HDA base */ + ret = hda_init(sdev); + if (ret < 0) + return ret; /* DSP base */ sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR); if (!sdev->bar[HDA_DSP_BAR]) { dev_err(&pci->dev, "error: ioremap error\n"); - ret = -ENXIO; - goto err; + return -ENXIO; } sdev->mmio_bar = HDA_DSP_BAR; sdev->mailbox_bar = HDA_DSP_BAR; - pci_set_master(pci); - synchronize_irq(pci->irq); - /* allow 64bit DMA address if supported by H/W */ if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(64))) { dev_dbg(&pci->dev, "DMA mask is 64 bit\n"); @@ -389,13 +512,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)); } - /* get controller capabilities */ - ret = hda_dsp_ctrl_get_caps(sdev); - if (ret < 0) { - dev_err(&pci->dev, "error: failed to find DSP capability\n"); - goto err; - } - /* init streams */ ret = hda_dsp_stream_init(sdev); if (ret < 0) { @@ -404,72 +520,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) * not all errors are due to memory issues, but trying * to free everything does not harm */ - goto stream_err; - } - - /* - * clear bits 0-2 of PCI register TCSEL (at offset 0x44) - * TCSEL == Traffic Class Select Register, which sets PCI express QOS - * Ensuring these bits are 0 clears playback static on some HD Audio - * codecs. PCI register TCSEL is defined in the Intel manuals. - */ - snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); - - /* - * while performing reset, controller may not come back properly causing - * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do - * reset (init chip) and then again set CGCTL.MISCBDCGE to 1 - */ - snd_sof_pci_update_bits(sdev, PCI_CGCTL, - PCI_CGCTL_MISCBDCGE_MASK, 0); - - /* clear WAKESTS */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, - SOF_HDA_WAKESTS_INT_MASK, - SOF_HDA_WAKESTS_INT_MASK); - - /* reset HDA controller */ - ret = hda_dsp_ctrl_link_reset(sdev); - if (ret < 0) { - dev_err(&pci->dev, "error: failed to reset HDA controller\n"); - goto stream_err; - } - - /* clear stream status */ - for (i = 0 ; i < hdev->num_capture ; i++) { - stream = &hdev->cstream[i]; - if (stream) - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + - SOF_HDA_ADSP_REG_CL_SD_STS, - SOF_HDA_CL_DMA_SD_INT_MASK, - SOF_HDA_CL_DMA_SD_INT_MASK); - } - - for (i = 0 ; i < hdev->num_playback ; i++) { - stream = &hdev->pstream[i]; - if (stream) - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - stream->sd_offset + - SOF_HDA_ADSP_REG_CL_SD_STS, - SOF_HDA_CL_DMA_SD_INT_MASK, - SOF_HDA_CL_DMA_SD_INT_MASK); + goto err; } - /* clear WAKESTS */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, - SOF_HDA_WAKESTS_INT_MASK, - SOF_HDA_WAKESTS_INT_MASK); - - /* clear interrupt status register */ - snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); - - /* enable CIE and GIE interrupts */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); - /* * register our IRQ * let's try to enable msi firstly @@ -477,7 +530,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) * TODO: support interrupt mode selection with kernel parameter * support msi multiple vectors */ - ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI); +// ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI); + /* todo: MSI mode doesn't work for HDMI yet, debug it later */ + ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_LEGACY); if (ret < 0) { dev_info(sdev->dev, "use legacy interrupt mode\n"); sdev->hda->irq = pci->irq; @@ -489,14 +544,15 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) sdev->ipc_irq = sdev->hda->irq; } + bus = sof_to_bus(sdev); dev_dbg(sdev->dev, "using HDA IRQ %d\n", sdev->hda->irq); ret = request_threaded_irq(sdev->hda->irq, hda_dsp_stream_interrupt, hda_dsp_stream_threaded_handler, - IRQF_SHARED, "AudioHDA", sdev); + IRQF_SHARED, "AudioHDA", bus); if (ret < 0) { dev_err(sdev->dev, "error: failed to register HDA IRQ %d\n", sdev->hda->irq); - goto stream_err; + goto free_streams; } dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq); @@ -506,13 +562,57 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: failed to register IPC IRQ %d\n", sdev->ipc_irq); - goto irq_err; + goto free_hda_irq; + } + + pci_set_master(pci); + synchronize_irq(pci->irq); + + /* + * clear TCSEL to clear playback on some HD Audio + * codecs. PCI TCSEL is defined in the Intel manuals. + */ + snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); + + + /* init HDA capabilities */ + ret = hda_init_caps(sdev); + if (ret < 0) + goto free_ipc_irq; + + /* reset HDA controller */ + ret = hda_dsp_ctrl_link_reset(sdev); + if (ret < 0) { + dev_err(&pci->dev, "error: failed to reset HDA controller\n"); + goto free_ipc_irq; + } + + /* clear stream status */ + list_for_each_entry(stream, &bus->stream_list, list) { + sd_offset = SOF_STREAM_SD_OFFSET(stream); + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_CL_DMA_SD_INT_MASK); } + /* clear WAKESTS */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK, + SOF_HDA_WAKESTS_INT_MASK); + + /* clear interrupt status register */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); + + /* enable CIE and GIE interrupts */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); + /* re-enable CGCTL.MISCBDCGE after reset */ - snd_sof_pci_update_bits(sdev, PCI_CGCTL, - PCI_CGCTL_MISCBDCGE_MASK, - PCI_CGCTL_MISCBDCGE_MASK); + hda_dsp_ctrl_misc_clock_gating(sdev, true); device_disable_async_suspend(&pci->dev); @@ -532,10 +632,12 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) return 0; -irq_err: - free_irq(sdev->hda->irq, sdev); -stream_err: +free_ipc_irq: + free_irq(sdev->ipc_irq, sdev); +free_hda_irq: + free_irq(sdev->hda->irq, bus); pci_free_irq_vectors(pci); +free_streams: hda_dsp_stream_free(sdev); err: /* disable DSP */ @@ -546,6 +648,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) int hda_dsp_remove(struct snd_sof_dev *sdev) { + struct hdac_bus *bus = sof_to_bus(sdev); struct pci_dev *pci = sdev->pci; const struct sof_intel_dsp_desc *chip = sdev->hda->desc; @@ -566,7 +669,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) SOF_HDA_PPCTL_GPROCEN, 0); free_irq(sdev->ipc_irq, sdev); - free_irq(sdev->pci->irq, sdev); + free_irq(sdev->pci->irq, bus); pci_free_irq_vectors(pci); hda_dsp_stream_free(sdev); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 2f3bc45efb10d0..e8919b635a9c14 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -11,6 +11,8 @@ #ifndef __SOF_INTEL_HDA_H #define __SOF_INTEL_HDA_H +#include + /* PCI registers */ #define PCI_TCSEL 0x44 #define PCI_CGCTL 0x48 @@ -28,6 +30,7 @@ #define SOF_HDA_INTSTS 0x24 #define SOF_HDA_WAKESTS 0x0E #define SOF_HDA_WAKESTS_INT_MASK ((1 << 8) - 1) +#define SOF_HDA_RIRBSTS 0x5d /* SOF_HDA_GCTL register bist */ #define SOF_HDA_GCTL_RESET BIT(0) @@ -42,12 +45,18 @@ #define SOF_HDA_CAP_ID_MASK (0xFFF << SOF_HDA_CAP_ID_OFF) #define SOF_HDA_CAP_NEXT_MASK 0xFFFF +#define SOF_HDA_GTS_CAP_ID 0x1 +#define SOF_HDA_ML_CAP_ID 0x2 + #define SOF_HDA_PP_CAP_ID 0x3 #define SOF_HDA_REG_PP_PPCH 0x10 #define SOF_HDA_REG_PP_PPCTL 0x04 #define SOF_HDA_PPCTL_PIE BIT(31) #define SOF_HDA_PPCTL_GPROCEN BIT(30) +/* DPIB entry size: 8 Bytes = 2 DWords */ +#define SOF_HDA_DPIB_ENTRY_SIZE 0x8 + #define SOF_HDA_SPIB_CAP_ID 0x4 #define SOF_HDA_DRSM_CAP_ID 0x5 @@ -99,6 +108,7 @@ #define SOF_HDA_ADSP_REG_CL_SD_FIFOL 0x14 #define SOF_HDA_ADSP_REG_CL_SD_BDLPL 0x18 #define SOF_HDA_ADSP_REG_CL_SD_BDLPU 0x1C +#define SOF_HDA_ADSP_SD_ENTRY_SIZE 0x20 /* CL: Software Position Based FIFO Capability Registers */ #define SOF_DSP_REG_CL_SPBFIFO \ @@ -328,40 +338,6 @@ struct sof_intel_dsp_desc { struct snd_sof_dsp_ops *ops; }; -/* per stream data for HDA DSP Frontend */ -struct sof_intel_hda_stream { - - /* addresses for stream HDA functions */ - void __iomem *pphc_addr; - void __iomem *pplc_addr; - void __iomem *spib_addr; - void __iomem *fifo_addr; - void __iomem *drsm_addr; - - /* runtime state */ - u32 dpib; - u32 lpib; - int tag; - int direction; - bool open; - bool running; - u32 index; - - /* buffer & descriptors */ - struct snd_dma_buffer bdl; - void __iomem *sd_addr; /* stream descriptor pointer */ - int sd_offset; /* Stream descriptor offset */ - unsigned int bufsize; /* size of the play buffer in bytes */ - unsigned int fifo_size; /* FIFO size */ - - __le32 *posbuf; /* position buffer pointer */ - unsigned int frags; /* number for period in the play buffer */ - unsigned int config; /* format config value */ - - /* PCM */ - struct snd_pcm_substream *substream; -}; - #define SOF_HDA_PLAYBACK_STREAMS 16 #define SOF_HDA_CAPTURE_STREAMS 16 #define SOF_HDA_PLAYBACK 0 @@ -370,24 +346,21 @@ struct sof_intel_hda_stream { /* represents DSP HDA controller frontend - i.e. host facing control */ struct sof_intel_hda_dev { + struct hda_bus hbus; + /* hw config */ const struct sof_intel_dsp_desc *desc; - /* streams */ - struct sof_intel_hda_stream pstream[SOF_HDA_PLAYBACK_STREAMS]; - struct sof_intel_hda_stream cstream[SOF_HDA_CAPTURE_STREAMS]; - int num_capture; - int num_playback; - - /* position buffers */ - struct snd_dma_buffer posbuffer; - /*trace */ - struct sof_intel_hda_stream *dtrace_stream; + struct hdac_ext_stream *dtrace_stream; int irq; }; +#define SOF_STREAM_SD_OFFSET(s) \ + (SOF_HDA_ADSP_SD_ENTRY_SIZE * ((s)->index) \ + + SOF_HDA_ADSP_LOADER_BASE) + /* * DSP Core services. */ @@ -445,26 +418,30 @@ int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, int hda_dsp_stream_init(struct snd_sof_dev *sdev); void hda_dsp_stream_free(struct snd_sof_dev *sdev); int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, - struct sof_intel_hda_stream *stream, + struct hdac_ext_stream *stream, struct snd_dma_buffer *dmab, struct snd_pcm_hw_params *params); int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, - struct sof_intel_hda_stream *stream, int cmd); + struct hdac_ext_stream *stream, int cmd); irqreturn_t hda_dsp_stream_interrupt(int irq, void *context); irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context); int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, - struct sof_intel_hda_stream *stream, + struct hdac_stream *stream, struct sof_intel_dsp_bdl *bdl, int size, struct snd_pcm_hw_params *params); -struct sof_intel_hda_stream * + +struct hdac_ext_stream * + hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction); +struct hdac_ext_stream * hda_dsp_stream_get_cstream(struct snd_sof_dev *sdev); -struct sof_intel_hda_stream * +struct hdac_ext_stream * hda_dsp_stream_get_pstream(struct snd_sof_dev *sdev); +int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag); int hda_dsp_stream_put_pstream(struct snd_sof_dev *sdev, int stream_tag); int hda_dsp_stream_put_cstream(struct snd_sof_dev *sdev, int stream_tag); int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, - struct sof_intel_hda_stream *stream, + struct hdac_ext_stream *stream, int enable, u32 size); /* @@ -483,8 +460,7 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); /* * DSP Code loader. */ -int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, const struct firmware *fw, - bool first_boot); +int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot); int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev); /* @@ -492,6 +468,22 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev); */ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev); int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev); +void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable); +int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset); + +/* + * HDA bus operations. + */ +int sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, + const struct hdac_ext_bus_ops *ext_ops); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +/* + * HDA Codec operations. + */ +int hda_codec_probe_bus(struct snd_sof_dev *sdev); +int hda_codec_i915_init(struct snd_sof_dev *sdev); +#endif /* * Trace Control. diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 03bbdc342b8ee4..d5839c0f3356ce 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "sof-priv.h" #include "ops.h" @@ -208,42 +209,60 @@ static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) } int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev, - const struct firmware *fw, bool first_boot) + bool first_boot) { + struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); int ret; + /* set code loading condition to true */ + sdev->code_loading = 1; + + ret = request_firmware(&plat_data->fw, + plat_data->machine->sof_fw_filename, sdev->dev); + + if (ret < 0) { + dev_err(sdev->dev, "error: request firmware failed err: %d\n", + ret); + return ret; + } + /* make sure the FW header and file is valid */ - ret = check_header(sdev, fw); + ret = check_header(sdev, plat_data->fw); if (ret < 0) { dev_err(sdev->dev, "error: invalid FW header\n"); - return ret; + goto error; } /* prepare the DSP for FW loading */ ret = snd_sof_dsp_reset(sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to reset DSP\n"); - return ret; + goto error; } /* parse and load firmware modules to DSP */ - ret = load_modules(sdev, fw); + ret = load_modules(sdev, plat_data->fw); if (ret < 0) { dev_err(sdev->dev, "error: invalid FW modules\n"); - return ret; + goto error; } + return 0; + +error: + release_firmware(plat_data->fw); return ret; + } EXPORT_SYMBOL(snd_sof_load_firmware_memcpy); int snd_sof_load_firmware(struct snd_sof_dev *sdev, - const struct firmware *fw, bool first_boot) + bool first_boot) { dev_dbg(sdev->dev, "loading firmware\n"); if (sdev->ops->load_firmware) - return sdev->ops->load_firmware(sdev, fw, first_boot); + return sdev->ops->load_firmware(sdev, first_boot); return 0; } EXPORT_SYMBOL(snd_sof_load_firmware); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index c34e4af1abaaa9..d746cdf4d14eaa 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -665,7 +665,8 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, /* TODO: add any other DMIC specific fixups */ break; case SOF_DAI_INTEL_HDA: - /* fallthrough */ + /* do nothing for HDA dai_link */ + break; default: dev_err(sdev->dev, "error: invalid DAI type %d\n", dai->dai_config.type); diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index bdbd7084e8895a..0ebc3fc8cd9d6a 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -224,7 +224,7 @@ static int sof_resume(struct device *dev) } /* load the firmware */ - ret = snd_sof_load_firmware(sdev, sdev->pdata->fw, false); + ret = snd_sof_load_firmware(sdev, false); if (ret < 0) { dev_err(sdev->dev, "error: failed to load DSP firmware after resume %d\n", diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index b1bf0ee9c9b427..3d6750526860bf 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -134,30 +134,6 @@ static struct platform_device * return pdev; } -static void sof_acpi_fw_cb(const struct firmware *fw, void *context) -{ - struct sof_platform_priv *priv = context; - struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - const struct snd_soc_acpi_mach *mach = sof_pdata->machine; - struct device *dev = sof_pdata->dev; - - sof_pdata->fw = fw; - if (!fw) { - dev_err(dev, "Cannot load firmware %s\n", - mach->sof_fw_filename); - return; - } - - /* register PCM and DAI driver */ - priv->pdev_pcm = - platform_device_register_data(dev, "sof-audio", -1, - sof_pdata, sizeof(*sof_pdata)); - if (IS_ERR(priv->pdev_pcm)) { - dev_err(dev, "Cannot register device sof-audio. Error %d\n", - (int)PTR_ERR(priv->pdev_pcm)); - } -} - static const struct dev_pm_ops sof_acpi_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -291,14 +267,12 @@ static int sof_acpi_probe(struct platform_device *pdev) dev_dbg(dev, "created machine %s\n", dev_name(&sof_pdata->pdev_mach->dev)); - /* continue SST probing after firmware is loaded */ - dev_info(dev, "info: loading firmware %s\n", mach->sof_fw_filename); - ret = request_firmware_nowait(THIS_MODULE, true, mach->sof_fw_filename, - dev, GFP_KERNEL, priv, sof_acpi_fw_cb); + /* register sof-audio platform driver */ + ret = sof_create_platform_device(priv); if (ret) { platform_device_unregister(sof_pdata->pdev_mach); - dev_err(dev, "error: failed to load firmware %s\n", - mach->sof_fw_filename); + dev_err(dev, "error: failed to create platform device!\n"); + return ret; } /* allow runtime_pm */ diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index c5371faa08e641..d2ec640306f305 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -127,30 +127,6 @@ static const struct sof_dev_desc icl_desc = { }; #endif -static void sof_pci_fw_cb(const struct firmware *fw, void *context) -{ - struct sof_platform_priv *priv = context; - struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - const struct snd_soc_acpi_mach *mach = sof_pdata->machine; - struct device *dev = sof_pdata->dev; - - sof_pdata->fw = fw; - if (!fw) { - dev_err(dev, "Cannot load firmware %s\n", - mach->sof_fw_filename); - return; - } - - /* register PCM and DAI driver */ - priv->pdev_pcm = - platform_device_register_data(dev, "sof-audio", -1, - sof_pdata, sizeof(*sof_pdata)); - if (IS_ERR(priv->pdev_pcm)) { - dev_err(dev, "Cannot register device sof-audio. Error %d\n", - (int)PTR_ERR(priv->pdev_pcm)); - } -} - static const struct dev_pm_ops sof_pci_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -282,14 +258,11 @@ static int sof_pci_probe(struct pci_dev *pci, dev_dbg(dev, "created machine %s\n", dev_name(&sof_pdata->pdev_mach->dev)); - /* continue probing after firmware is loaded */ - dev_info(dev, "info: loading firmware %s\n", mach->sof_fw_filename); - ret = request_firmware_nowait(THIS_MODULE, true, mach->sof_fw_filename, - dev, GFP_KERNEL, priv, sof_pci_fw_cb); + /* register sof-audio platform driver */ + ret = sof_create_platform_device(priv); if (ret) { platform_device_unregister(sof_pdata->pdev_mach); - dev_err(dev, "error: failed to load firmware %s\n", - mach->sof_fw_filename); + dev_err(dev, "error: failed to create platform device!\n"); goto release_regions; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index bd33e9437d0222..e8b0c65b1b4a3e 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -140,7 +140,7 @@ struct snd_sof_dsp_ops { /* FW loading */ int (*load_firmware)(struct snd_sof_dev *sof_dev, - const struct firmware *fw, bool first_boot); + bool first_boot); int (*load_module)(struct snd_sof_dev *sof_dev, struct snd_sof_mod_hdr *hdr); int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); @@ -362,6 +362,9 @@ struct snd_sof_dev { void *private; /* core does not touch this */ }; +#define sof_to_bus(s) (&(s)->hda->hbus.core) +#define sof_to_hbus(s) (&(s)->hda->hbus) + /* * SOF platform private struct used as drvdata of * platform dev (e.g. pci/acpi/spi...) drvdata. @@ -391,9 +394,9 @@ int snd_sof_create_page_table(struct snd_sof_dev *sdev, * Firmware loading. */ int snd_sof_load_firmware(struct snd_sof_dev *sdev, - const struct firmware *fw, bool first_boot); + bool first_boot); int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev, - const struct firmware *fw, bool first_boot); + bool first_boot); int snd_sof_run_firmware(struct snd_sof_dev *sdev); int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_mod_hdr *module); @@ -516,4 +519,9 @@ static inline void sof_oops(struct snd_sof_dev *sdev, void *oops) } extern const struct sof_arch_ops sof_xtensa_arch_ops; + +/* + * Utilities + */ +int sof_create_platform_device(struct sof_platform_priv *priv); #endif diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index c0e651ce48376c..c55be66267f6a4 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -19,30 +19,6 @@ #include #include "sof-priv.h" -static void sof_spi_fw_cb(const struct firmware *fw, void *context) -{ - struct sof_platform_priv *priv = context; - struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - const struct snd_sof_machine *mach = sof_pdata->machine; - struct device *dev = sof_pdata->dev; - - sof_pdata->fw = fw; - if (!fw) { - dev_err(dev, "Cannot load firmware %s\n", - mach->sof_fw_filename); - return; - } - - /* register PCM and DAI driver */ - priv->pdev_pcm = - platform_device_register_data(dev, "sof-audio", -1, - sof_pdata, sizeof(*sof_pdata)); - if (IS_ERR(priv->pdev_pcm)) { - dev_err(dev, "Cannot register device sof-audio. Error %d\n", - (int)PTR_ERR(priv->pdev_pcm)); - } -} - static const struct dev_pm_ops sof_spi_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -101,11 +77,13 @@ static int sof_spi_probe(struct spi_device *spi) dev_dbg(dev, "created machine %s\n", dev_name(&sof_pdata->pdev_mach->dev)); - /* continue probing after firmware is loaded */ - ret = request_firmware_nowait(THIS_MODULE, true, mach->sof_fw_filename, - dev, GFP_KERNEL, priv, sof_spi_fw_cb); - if (ret) + /* register sof-audio platform driver */ + ret = sof_create_platform_device(priv); + if (ret) { platform_device_unregister(sof_pdata->pdev_mach); + dev_err(dev, "error: failed to create platform device!\n"); + return ret; + } /* allow runtime_pm */ pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 32bef181dde9f7..e4b7cc0a96f937 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1786,12 +1786,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, if (!link->no_pcm) return 0; - /* only support 1 config atm */ - if (le32_to_cpu(cfg->num_hw_configs) != 1) { - dev_err(sdev->dev, "error: unexpected DAI config count %d\n", + /* usually we use 1 config, but for HDA it may be 0 ATM */ + if (le32_to_cpu(cfg->num_hw_configs) != 1) + dev_warn(sdev->dev, "warn: unexpected DAI config count %d!\n", le32_to_cpu(cfg->num_hw_configs)); - return -EINVAL; - } /* check we have some tokens - we need at least DAI type */ if (le32_to_cpu(private->size) == 0) { diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index a38cd0c01f80e8..23597064b8e33b 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -9,6 +9,7 @@ // #include +#include #include #include #include "sof-priv.h" @@ -47,3 +48,21 @@ int sof_bes_setup(struct device *dev, struct snd_sof_dsp_ops *ops, } EXPORT_SYMBOL(sof_bes_setup); +/* register sof platform device */ +int sof_create_platform_device(struct sof_platform_priv *priv) +{ + struct snd_sof_pdata *sof_pdata = priv->sof_pdata; + struct device *dev = sof_pdata->dev; + + priv->pdev_pcm = + platform_device_register_data(dev, "sof-audio", -1, + sof_pdata, sizeof(*sof_pdata)); + if (IS_ERR(priv->pdev_pcm)) { + dev_err(dev, "Cannot register device sof-audio. Error %d\n", + (int)PTR_ERR(priv->pdev_pcm)); + return PTR_ERR(priv->pdev_pcm); + } + + return 0; +} +EXPORT_SYMBOL(sof_create_platform_device);