diff options
Diffstat (limited to 'sound/hda')
-rw-r--r-- | sound/hda/Kconfig | 6 | ||||
-rw-r--r-- | sound/hda/Makefile | 8 | ||||
-rw-r--r-- | sound/hda/ext/Makefile | 2 | ||||
-rw-r--r-- | sound/hda/ext/hdac_ext_controller.c | 19 | ||||
-rw-r--r-- | sound/hda/hda_bus_type.c | 8 | ||||
-rw-r--r-- | sound/hda/hdac_component.c | 7 | ||||
-rw-r--r-- | sound/hda/hdac_controller.c | 127 | ||||
-rw-r--r-- | sound/hda/hdac_device.c | 3 | ||||
-rw-r--r-- | sound/hda/hdac_stream.c | 89 | ||||
-rw-r--r-- | sound/hda/hdmi_chmap.c | 18 | ||||
-rw-r--r-- | sound/hda/intel-dsp-config.c | 138 | ||||
-rw-r--r-- | sound/hda/intel-nhlt.c | 43 | ||||
-rw-r--r-- | sound/hda/intel-sdw-acpi.c | 52 | ||||
-rw-r--r-- | sound/hda/trace.h | 6 |
14 files changed, 387 insertions, 139 deletions
diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index 741179ccbd4e..eb488a522572 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -21,7 +21,7 @@ config SND_HDA_EXT_CORE select SND_HDA_CORE config SND_HDA_PREALLOC_SIZE - int "Pre-allocated buffer size for HD-audio driver" if !SND_DMA_SGBUF + int "Pre-allocated buffer size for HD-audio driver" range 0 32768 default 0 if SND_DMA_SGBUF default 64 if !SND_DMA_SGBUF @@ -30,7 +30,8 @@ config SND_HDA_PREALLOC_SIZE HD-audio driver. A larger buffer (e.g. 2048) is preferred for systems using PulseAudio. The default 64 is chosen just for compatibility reasons. - On x86 systems, the default is zero as we need no preallocation. + On x86 systems, the default is zero as S/G allocation works + and no preallocation is needed in most cases. Note that the pre-allocation size can be changed dynamically via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. @@ -42,6 +43,7 @@ config SND_INTEL_NHLT config SND_INTEL_DSP_CONFIG tristate + select ACPI_NHLT if ACPI select SND_INTEL_NHLT if ACPI select SND_INTEL_SOUNDWIRE_ACPI if ACPI # this config should be selected only for Intel DSP platforms. diff --git a/sound/hda/Makefile b/sound/hda/Makefile index 78f487a635f8..83cceafe0d4c 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 -snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o \ +snd-hda-core-y := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o \ hdac_regmap.o hdac_controller.o hdac_stream.o array.o hdmi_chmap.o -snd-hda-core-objs += trace.o +snd-hda-core-y += trace.o CFLAGS_trace.o := -I$(src) # for sync with i915 gfx driver @@ -14,9 +14,9 @@ obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o #extended hda obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/ -snd-intel-dspcfg-objs := intel-dsp-config.o +snd-intel-dspcfg-y := intel-dsp-config.o snd-intel-dspcfg-$(CONFIG_SND_INTEL_NHLT) += intel-nhlt.o obj-$(CONFIG_SND_INTEL_DSP_CONFIG) += snd-intel-dspcfg.o -snd-intel-sdw-acpi-objs := intel-sdw-acpi.o +snd-intel-sdw-acpi-y := intel-sdw-acpi.o obj-$(CONFIG_SND_INTEL_SOUNDWIRE_ACPI) += snd-intel-sdw-acpi.o diff --git a/sound/hda/ext/Makefile b/sound/hda/ext/Makefile index 154779bdc0ba..05883fb28d28 100644 --- a/sound/hda/ext/Makefile +++ b/sound/hda/ext/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-hda-ext-core-objs := hdac_ext_bus.o hdac_ext_controller.o hdac_ext_stream.o +snd-hda-ext-core-y := hdac_ext_bus.o hdac_ext_controller.o hdac_ext_stream.o obj-$(CONFIG_SND_HDA_EXT_CORE) += snd-hda-ext-core.o diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 6199bb60ccf0..c84754434d16 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -9,6 +9,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include <linux/bitfield.h> #include <linux/delay.h> #include <linux/slab.h> #include <sound/hda_register.h> @@ -81,6 +82,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus) int idx; u32 link_count; struct hdac_ext_link *hlink; + u32 leptr; link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1; @@ -96,6 +98,12 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus) (AZX_ML_INTERVAL * idx); hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP); hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); + hlink->slcount = FIELD_GET(AZX_ML_HDA_LCAP_SLCOUNT, hlink->lcaps) + 1; + + if (hdac_ext_link_alt(hlink)) { + leptr = readl(hlink->ml_addr + AZX_REG_ML_LEPTR); + hlink->id = FIELD_GET(AZX_REG_ML_LEPTR_ID, leptr); + } /* since link in On, update the ref */ hlink->ref_count = 1; @@ -125,6 +133,17 @@ void snd_hdac_ext_link_free_all(struct hdac_bus *bus) } EXPORT_SYMBOL_GPL(snd_hdac_ext_link_free_all); +struct hdac_ext_link *snd_hdac_ext_bus_get_hlink_by_id(struct hdac_bus *bus, u32 id) +{ + struct hdac_ext_link *hlink; + + list_for_each_entry(hlink, &bus->hlink_list, list) + if (hdac_ext_link_alt(hlink) && hlink->id == id) + return hlink; + return NULL; +} +EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_hlink_by_id); + /** * snd_hdac_ext_bus_get_hlink_by_addr - get hlink at specified address * @bus: hlink's parent bus device diff --git a/sound/hda/hda_bus_type.c b/sound/hda/hda_bus_type.c index cce2c30511a2..eb72a7af2e56 100644 --- a/sound/hda/hda_bus_type.c +++ b/sound/hda/hda_bus_type.c @@ -21,7 +21,7 @@ MODULE_LICENSE("GPL"); * driver id_table and returns the matching device id entry. */ const struct hda_device_id * -hdac_get_device_id(struct hdac_device *hdev, struct hdac_driver *drv) +hdac_get_device_id(struct hdac_device *hdev, const struct hdac_driver *drv) { if (drv->id_table) { const struct hda_device_id *id = drv->id_table; @@ -38,7 +38,7 @@ hdac_get_device_id(struct hdac_device *hdev, struct hdac_driver *drv) } EXPORT_SYMBOL_GPL(hdac_get_device_id); -static int hdac_codec_match(struct hdac_device *dev, struct hdac_driver *drv) +static int hdac_codec_match(struct hdac_device *dev, const struct hdac_driver *drv) { if (hdac_get_device_id(dev, drv)) return 1; @@ -46,10 +46,10 @@ static int hdac_codec_match(struct hdac_device *dev, struct hdac_driver *drv) return 0; } -static int hda_bus_match(struct device *dev, struct device_driver *drv) +static int hda_bus_match(struct device *dev, const struct device_driver *drv) { struct hdac_device *hdev = dev_to_hdac_dev(dev); - struct hdac_driver *hdrv = drv_to_hdac_driver(drv); + const struct hdac_driver *hdrv = drv_to_hdac_driver(drv); if (hdev->type != hdrv->type) return 0; diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c index bb37e7e0bd79..9c82a2864a2f 100644 --- a/sound/hda/hdac_component.c +++ b/sound/hda/hdac_component.c @@ -5,6 +5,7 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/component.h> +#include <linux/string_choices.h> #include <sound/core.h> #include <sound/hdaudio.h> #include <sound/hda_component.h> @@ -42,8 +43,7 @@ int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) if (!acomp->ops->codec_wake_override) return 0; - dev_dbg(bus->dev, "%s codec wakeup\n", - enable ? "enable" : "disable"); + dev_dbg(bus->dev, "%s codec wakeup\n", str_enable_disable(enable)); acomp->ops->codec_wake_override(acomp->dev, enable); @@ -67,8 +67,7 @@ void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) { struct drm_audio_component *acomp = bus->audio_component; - dev_dbg(bus->dev, "display power %s\n", - enable ? "enable" : "disable"); + dev_dbg(bus->dev, "display power %s\n", str_enable_disable(enable)); mutex_lock(&bus->lock); if (enable) diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index 7f3a000fab0c..b5c833b9f8b9 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -62,7 +62,8 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus) azx_clear_corbrp(bus); /* enable corb dma */ - snd_hdac_chip_writeb(bus, CORBCTL, AZX_CORBCTL_RUN); + if (!bus->use_pio_for_commands) + snd_hdac_chip_writeb(bus, CORBCTL, AZX_CORBCTL_RUN); /* RIRB set up */ bus->rirb.addr = bus->rb.addr + 2048; @@ -135,14 +136,94 @@ static unsigned int azx_command_addr(u32 cmd) return addr; } +/* receive an Immediate Response with PIO */ +static int snd_hdac_bus_wait_for_pio_response(struct hdac_bus *bus, + unsigned int addr) +{ + int timeout = 50; + + while (timeout--) { + /* check IRV bit */ + if (snd_hdac_chip_readw(bus, IRS) & AZX_IRS_VALID) { + /* reuse rirb.res as the response return value */ + bus->rirb.res[addr] = snd_hdac_chip_readl(bus, IR); + return 0; + } + udelay(1); + } + + dev_dbg_ratelimited(bus->dev, "get_response_pio timeout: IRS=%#x\n", + snd_hdac_chip_readw(bus, IRS)); + + bus->rirb.res[addr] = -1; + + return -EIO; +} + /** - * snd_hdac_bus_send_cmd - send a command verb via CORB + * snd_hdac_bus_send_cmd_pio - send a command verb via Immediate Command * @bus: HD-audio core bus * @val: encoded verb value to send * * Returns zero for success or a negative error code. */ -int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val) +static int snd_hdac_bus_send_cmd_pio(struct hdac_bus *bus, unsigned int val) +{ + unsigned int addr = azx_command_addr(val); + int timeout = 50; + int ret = -EIO; + + spin_lock_irq(&bus->reg_lock); + + while (timeout--) { + /* check ICB bit */ + if (!((snd_hdac_chip_readw(bus, IRS) & AZX_IRS_BUSY))) { + /* Clear IRV bit */ + snd_hdac_chip_updatew(bus, IRS, AZX_IRS_VALID, AZX_IRS_VALID); + snd_hdac_chip_writel(bus, IC, val); + /* Set ICB bit */ + snd_hdac_chip_updatew(bus, IRS, AZX_IRS_BUSY, AZX_IRS_BUSY); + + ret = snd_hdac_bus_wait_for_pio_response(bus, addr); + goto out; + } + udelay(1); + } + + dev_dbg_ratelimited(bus->dev, "send_cmd_pio timeout: IRS=%#x, val=%#x\n", + snd_hdac_chip_readw(bus, IRS), val); + +out: + spin_unlock_irq(&bus->reg_lock); + + return ret; +} + +/** + * snd_hdac_bus_get_response_pio - receive a response via Immediate Response + * @bus: HD-audio core bus + * @addr: codec address + * @res: pointer to store the value, NULL when not needed + * + * Returns zero if a value is read, or a negative error code. + */ +static int snd_hdac_bus_get_response_pio(struct hdac_bus *bus, + unsigned int addr, unsigned int *res) +{ + if (res) + *res = bus->rirb.res[addr]; + + return 0; +} + +/** + * snd_hdac_bus_send_cmd_corb - send a command verb via CORB + * @bus: HD-audio core bus + * @val: encoded verb value to send + * + * Returns zero for success or a negative error code. + */ +static int snd_hdac_bus_send_cmd_corb(struct hdac_bus *bus, unsigned int val) { unsigned int addr = azx_command_addr(val); unsigned int wp, rp; @@ -176,7 +257,6 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val) return 0; } -EXPORT_SYMBOL_GPL(snd_hdac_bus_send_cmd); #define AZX_RIRB_EX_UNSOL_EV (1<<4) @@ -234,15 +314,15 @@ void snd_hdac_bus_update_rirb(struct hdac_bus *bus) EXPORT_SYMBOL_GPL(snd_hdac_bus_update_rirb); /** - * snd_hdac_bus_get_response - receive a response via RIRB + * snd_hdac_bus_get_response_rirb - receive a response via RIRB * @bus: HD-audio core bus * @addr: codec address * @res: pointer to store the value, NULL when not needed * * Returns zero if a value is read, or a negative error code. */ -int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, - unsigned int *res) +static int snd_hdac_bus_get_response_rirb(struct hdac_bus *bus, + unsigned int addr, unsigned int *res) { unsigned long timeout; unsigned long loopcounter; @@ -293,6 +373,39 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, return -EIO; } + +/** + * snd_hdac_bus_send_cmd - send a command verb via CORB or PIO + * @bus: HD-audio core bus + * @val: encoded verb value to send + * + * Returns zero for success or a negative error code. + */ +int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val) +{ + if (bus->use_pio_for_commands) + return snd_hdac_bus_send_cmd_pio(bus, val); + + return snd_hdac_bus_send_cmd_corb(bus, val); +} +EXPORT_SYMBOL_GPL(snd_hdac_bus_send_cmd); + +/** + * snd_hdac_bus_get_response - receive a response via RIRB or PIO + * @bus: HD-audio core bus + * @addr: codec address + * @res: pointer to store the value, NULL when not needed + * + * Returns zero if a value is read, or a negative error code. + */ +int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, + unsigned int *res) +{ + if (bus->use_pio_for_commands) + return snd_hdac_bus_get_response_pio(bus, addr, res); + + return snd_hdac_bus_get_response_rirb(bus, addr, res); +} EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response); #define HDAC_MAX_CAPS 10 diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index 068c16e52dff..0053831eed2d 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -665,6 +665,7 @@ static const struct hda_vendor_id hda_vendor_ids[] = { { 0x19e5, "Huawei" }, { 0x1aec, "Wolfson Microelectronics" }, { 0x1af4, "QEMU" }, + { 0x1fa8, "Senarytech" }, { 0x434d, "C-Media" }, { 0x8086, "Intel" }, { 0x8384, "SigmaTel" }, @@ -800,7 +801,7 @@ unsigned int snd_hdac_stream_format(unsigned int channels, unsigned int bits, un if (!rate_bits[i].hz) return 0; - if (channels == 0 || channels > 8) + if (channels == 0 || channels > 16) return 0; val |= channels - 1; diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index b53de020309f..e7f6208af5b0 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -492,32 +492,21 @@ static int setup_bdle(struct hdac_bus *bus, } /** - * snd_hdac_stream_setup_periods - set up BDL entries + * snd_hdac_stream_setup_bdle - set up BDL entries * @azx_dev: HD-audio core stream to set up + * @dmab: allocated DMA buffer + * @runtime: substream runtime, optional * * Set up the buffer descriptor table of the given stream based on the * period and buffer sizes of the assigned PCM substream. */ -int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev) +static int snd_hdac_stream_setup_bdle(struct hdac_stream *azx_dev, struct snd_dma_buffer *dmab, + struct snd_pcm_runtime *runtime) { struct hdac_bus *bus = azx_dev->bus; - struct snd_pcm_substream *substream = azx_dev->substream; - struct snd_compr_stream *cstream = azx_dev->cstream; - struct snd_pcm_runtime *runtime = NULL; - struct snd_dma_buffer *dmab; - __le32 *bdl; int i, ofs, periods, period_bytes; int pos_adj, pos_align; - - if (substream) { - runtime = substream->runtime; - dmab = snd_pcm_get_dma_buf(substream); - } else if (cstream) { - dmab = snd_pcm_get_dma_buf(cstream); - } else { - WARN(1, "No substream or cstream assigned\n"); - return -EINVAL; - } + __le32 *bdl; /* reset BDL address */ snd_hdac_stream_writel(azx_dev, SD_BDLPL, 0); @@ -571,6 +560,33 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev) azx_dev->bufsize, period_bytes); return -EINVAL; } + +/** + * snd_hdac_stream_setup_periods - set up BDL entries + * @azx_dev: HD-audio core stream to set up + * + * Set up the buffer descriptor table of the given stream based on the + * period and buffer sizes of the assigned PCM substream. + */ +int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev) +{ + struct snd_pcm_substream *substream = azx_dev->substream; + struct snd_compr_stream *cstream = azx_dev->cstream; + struct snd_pcm_runtime *runtime = NULL; + struct snd_dma_buffer *dmab; + + if (substream) { + runtime = substream->runtime; + dmab = snd_pcm_get_dma_buf(substream); + } else if (cstream) { + dmab = snd_pcm_get_dma_buf(cstream); + } else { + WARN(1, "No substream or cstream assigned\n"); + return -EINVAL; + } + + return snd_hdac_stream_setup_bdle(azx_dev, dmab, runtime); +} EXPORT_SYMBOL_GPL(snd_hdac_stream_setup_periods); /** @@ -657,6 +673,7 @@ static void azx_timecounter_init(struct hdac_stream *azx_dev, * snd_hdac_stream_timecounter_init - initialize time counter * @azx_dev: HD-audio core stream (master stream) * @streams: bit flags of streams to set up + * @start: true for PCM trigger start, false for other cases * * Initializes the time counter of streams marked by the bit flags (each * bit corresponds to the stream index). @@ -664,7 +681,7 @@ static void azx_timecounter_init(struct hdac_stream *azx_dev, * updated accordingly, too. */ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev, - unsigned int streams) + unsigned int streams, bool start) { struct hdac_bus *bus = azx_dev->bus; struct snd_pcm_runtime *runtime = azx_dev->substream->runtime; @@ -672,6 +689,9 @@ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev, bool inited = false; u64 cycle_last = 0; + if (!start) + goto skip; + list_for_each_entry(s, &bus->stream_list, list) { if ((streams & (1 << s->index))) { azx_timecounter_init(s, inited, cycle_last); @@ -682,6 +702,7 @@ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev, } } +skip: snd_pcm_gettime(runtime, &runtime->trigger_tstamp); runtime->trigger_tstamp_latched = true; } @@ -805,25 +826,6 @@ int snd_hdac_stream_set_spib(struct hdac_bus *bus, EXPORT_SYMBOL_GPL(snd_hdac_stream_set_spib); /** - * snd_hdac_stream_get_spbmaxfifo - gets the spib value of a stream - * @bus: HD-audio core bus - * @azx_dev: hdac_stream - * - * Return maxfifo for the stream - */ -int snd_hdac_stream_get_spbmaxfifo(struct hdac_bus *bus, - struct hdac_stream *azx_dev) -{ - if (!bus->spbcap) { - dev_err(bus->dev, "Address of SPB capability is NULL\n"); - return -EINVAL; - } - - return readl(azx_dev->fifo_addr); -} -EXPORT_SYMBOL_GPL(snd_hdac_stream_get_spbmaxfifo); - -/** * snd_hdac_stream_drsm_enable - enable DMA resume for a stream * @bus: HD-audio core bus * @enable: flag to enable/disable DRSM @@ -918,7 +920,6 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format, unsigned int byte_size, struct snd_dma_buffer *bufp) { struct hdac_bus *bus = azx_dev->bus; - __le32 *bdl; int err; snd_hdac_dsp_lock(azx_dev); @@ -938,18 +939,14 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format, azx_dev->substream = NULL; azx_dev->bufsize = byte_size; - azx_dev->period_bytes = byte_size; + /* It is recommended to transfer the firmware in two or more chunks. */ + azx_dev->period_bytes = byte_size / 2; azx_dev->format_val = format; + azx_dev->no_period_wakeup = 1; snd_hdac_stream_reset(azx_dev); - /* reset BDL address */ - snd_hdac_stream_writel(azx_dev, SD_BDLPL, 0); - snd_hdac_stream_writel(azx_dev, SD_BDLPU, 0); - - azx_dev->frags = 0; - bdl = (__le32 *)azx_dev->bdl.area; - err = setup_bdle(bus, bufp, azx_dev, &bdl, 0, byte_size, 0); + err = snd_hdac_stream_setup_bdle(azx_dev, bufp, NULL); if (err < 0) goto error; diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c index 5d8e1d944b0a..7b276047f85a 100644 --- a/sound/hda/hdmi_chmap.c +++ b/sound/hda/hdmi_chmap.c @@ -753,6 +753,20 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol, return 0; } +/* a simple sanity check for input values to chmap kcontrol */ +static int chmap_value_check(struct hdac_chmap *hchmap, + const struct snd_ctl_elem_value *ucontrol) +{ + int i; + + for (i = 0; i < hchmap->channels_max; i++) { + if (ucontrol->value.integer.value[i] < 0 || + ucontrol->value.integer.value[i] > SNDRV_CHMAP_LAST) + return -EINVAL; + } + return 0; +} + static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -764,6 +778,10 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, unsigned char chmap[8], per_pin_chmap[8]; int i, err, ca, prepared = 0; + err = chmap_value_check(hchmap, ucontrol); + if (err < 0) + return err; + /* No monitor is connected in dyn_pcm_assign. * It's invalid to setup the chmap */ diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 6a384b922e4f..3cb1e7fc3b3b 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -13,10 +13,12 @@ #include <sound/intel-nhlt.h> #include <sound/soc-acpi.h> +#include <acpi/nhlt.h> + static int dsp_driver; module_param(dsp_driver, int, 0444); -MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF)"); +MODULE_PARM_DESC(dsp_driver, "Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF, 4=AVS)"); #define FLAG_SST BIT(0) #define FLAG_SOF BIT(1) @@ -54,35 +56,31 @@ static const struct config_entry config_table[] = { }, #endif /* - * Apollolake (Broxton-P) + * Skylake, Kabylake, Apollolake * the legacy HDAudio driver is used except on Up Squared (SOF) and * Chromebooks (SST), as well as devices based on the ES8336 codec */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_AVS) { - .flags = FLAG_SOF, - .device = PCI_DEVICE_ID_INTEL_HDA_APL, + .flags = FLAG_SST, + .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, .dmi_table = (const struct dmi_system_id []) { { - .ident = "Up Squared", + .ident = "Google Chromebooks", .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), - DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"), + DMI_MATCH(DMI_SYS_VENDOR, "Google"), } }, {} } }, { - .flags = FLAG_SOF, - .device = PCI_DEVICE_ID_INTEL_HDA_APL, - .codec_hid = &essx_83x6, + .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, + .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) { .flags = FLAG_SST, - .device = PCI_DEVICE_ID_INTEL_HDA_APL, + .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -93,17 +91,13 @@ static const struct config_entry config_table[] = { {} } }, -#endif -/* - * Skylake and Kabylake use legacy HDAudio driver except for Google - * Chromebooks (SST) - */ - -/* Sunrise Point-LP */ -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) + { + .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, + .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, + }, { .flags = FLAG_SST, - .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, + .device = PCI_DEVICE_ID_INTEL_HDA_APL, .dmi_table = (const struct dmi_system_id []) { { .ident = "Google Chromebooks", @@ -115,28 +109,33 @@ static const struct config_entry config_table[] = { } }, { - .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, - .device = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, + .flags = FLAG_SST, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M, }, -#endif -/* Kabylake-LP */ -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) { .flags = FLAG_SST, - .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, + .device = PCI_DEVICE_ID_INTEL_HDA_FCL, + }, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) + { + .flags = FLAG_SOF, + .device = PCI_DEVICE_ID_INTEL_HDA_APL, .dmi_table = (const struct dmi_system_id []) { { - .ident = "Google Chromebooks", + .ident = "Up Squared", .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), + DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"), } }, {} } }, { - .flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC, - .device = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, + .flags = FLAG_SOF, + .device = PCI_DEVICE_ID_INTEL_HDA_APL, + .codec_hid = &essx_83x6, }, #endif @@ -541,6 +540,24 @@ static const struct config_entry config_table[] = { .device = PCI_DEVICE_ID_INTEL_HDA_LNL_P, }, #endif + + /* Panther Lake, Wildcat Lake */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_PANTHERLAKE) + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, + .device = PCI_DEVICE_ID_INTEL_HDA_PTL, + }, + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, + .device = PCI_DEVICE_ID_INTEL_HDA_PTL_H, + }, + { + .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE, + .device = PCI_DEVICE_ID_INTEL_HDA_WCL, + }, + +#endif + }; static const struct config_entry *snd_intel_dsp_find_config @@ -557,9 +574,32 @@ static const struct config_entry *snd_intel_dsp_find_config if (table->codec_hid) { int i; - for (i = 0; i < table->codec_hid->num_codecs; i++) - if (acpi_dev_present(table->codec_hid->codecs[i], NULL, -1)) + for (i = 0; i < table->codec_hid->num_codecs; i++) { + struct nhlt_acpi_table *nhlt; + bool ssp_found = false; + + if (!acpi_dev_present(table->codec_hid->codecs[i], NULL, -1)) + continue; + + nhlt = intel_nhlt_init(&pci->dev); + if (!nhlt) { + dev_warn(&pci->dev, "%s: NHLT table not found, skipped HID %s\n", + __func__, table->codec_hid->codecs[i]); + continue; + } + + if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_SSP) && + intel_nhlt_ssp_endpoint_mask(nhlt, NHLT_DEVICE_I2S)) + ssp_found = true; + + intel_nhlt_free(nhlt); + + if (ssp_found) break; + + dev_warn(&pci->dev, "%s: no valid SSP found for HID %s, skipped\n", + __func__, table->codec_hid->codecs[i]); + } if (i == table->codec_hid->num_codecs) continue; } @@ -570,15 +610,15 @@ static const struct config_entry *snd_intel_dsp_find_config static int snd_intel_dsp_check_dmic(struct pci_dev *pci) { - struct nhlt_acpi_table *nhlt; int ret = 0; - nhlt = intel_nhlt_init(&pci->dev); - if (nhlt) { - if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_DMIC)) - ret = 1; - intel_nhlt_free(nhlt); - } + acpi_nhlt_get_gbl_table(); + + if (acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) + ret = 1; + + acpi_nhlt_put_gbl_table(); + return ret; } @@ -643,7 +683,7 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci) return SND_INTEL_DSP_DRIVER_LEGACY; } - dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); + dev_dbg(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); /* find the configuration for the specific device */ cfg = snd_intel_dsp_find_config(pci, config_table, ARRAY_SIZE(config_table)); @@ -653,12 +693,12 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci) if (cfg->flags & FLAG_SOF) { if (cfg->flags & FLAG_SOF_ONLY_IF_SOUNDWIRE && snd_intel_dsp_check_soundwire(pci) > 0) { - dev_info(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n"); + dev_info_once(&pci->dev, "SoundWire enabled on CannonLake+ platform, using SOF driver\n"); return SND_INTEL_DSP_DRIVER_SOF; } if (cfg->flags & FLAG_SOF_ONLY_IF_DMIC && snd_intel_dsp_check_dmic(pci)) { - dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n"); + dev_info_once(&pci->dev, "Digital mics found on Skylake+ platform, using SOF driver\n"); return SND_INTEL_DSP_DRIVER_SOF; } if (!(cfg->flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE)) @@ -669,7 +709,7 @@ int snd_intel_dsp_driver_probe(struct pci_dev *pci) if (cfg->flags & FLAG_SST) { if (cfg->flags & FLAG_SST_ONLY_IF_DMIC) { if (snd_intel_dsp_check_dmic(pci)) { - dev_info(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n"); + dev_info_once(&pci->dev, "Digital mics found on Skylake+ platform, using SST driver\n"); return SND_INTEL_DSP_DRIVER_SST; } } else { @@ -700,6 +740,10 @@ static const struct config_entry acpi_config_table[] = { /* BayTrail */ { .flags = FLAG_SST_OR_SOF_BYT, + .acpi_hid = "LPE0F28", + }, + { + .flags = FLAG_SST_OR_SOF_BYT, .acpi_hid = "80860F28", }, /* CherryTrail */ @@ -774,4 +818,4 @@ EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel DSP config driver"); -MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI); +MODULE_IMPORT_NS("SND_INTEL_SOUNDWIRE_ACPI"); diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index 696a958d93e9..6d72a871bda0 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -343,3 +343,46 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt, return NULL; } EXPORT_SYMBOL(intel_nhlt_get_endpoint_blob); + +int intel_nhlt_ssp_device_type(struct device *dev, struct nhlt_acpi_table *nhlt, + u8 virtual_bus_id) +{ + struct nhlt_endpoint *epnt; + int i; + + if (!nhlt) { + dev_err(dev, "%s: NHLT table is missing (query for SSP%d)\n", + __func__, virtual_bus_id); + return -EINVAL; + } + + epnt = (struct nhlt_endpoint *)nhlt->desc; + for (i = 0; i < nhlt->endpoint_count; i++) { + /* for SSP link the virtual bus id is the SSP port number */ + if (epnt->linktype == NHLT_LINK_SSP && + epnt->virtual_bus_id == virtual_bus_id) { + dev_dbg(dev, "SSP%d: dev_type=%d\n", virtual_bus_id, + epnt->device_type); + return epnt->device_type; + } + + epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); + } + + dev_err(dev, "%s: No match for SSP%d in NHLT table\n", __func__, + virtual_bus_id); + + dev_dbg(dev, "Available endpoints:\n"); + epnt = (struct nhlt_endpoint *)nhlt->desc; + for (i = 0; i < nhlt->endpoint_count; i++) { + dev_dbg(dev, + "%d: link_type: %d, vbus_id: %d, dir: %d, dev_type: %d\n", + i, epnt->linktype, epnt->virtual_bus_id, + epnt->direction, epnt->device_type); + + epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); + } + + return -EINVAL; +} +EXPORT_SYMBOL(intel_nhlt_ssp_device_type); diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/intel-sdw-acpi.c index 5f60658c6051..d3511135f7d3 100644 --- a/sound/hda/intel-sdw-acpi.c +++ b/sound/hda/intel-sdw-acpi.c @@ -11,13 +11,12 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/export.h> -#include <linux/fwnode.h> #include <linux/module.h> +#include <linux/property.h> #include <linux/soundwire/sdw_intel.h> #include <linux/string.h> #define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */ -#define SDW_MAX_LINKS 4 static int ctrl_link_mask; module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444); @@ -45,6 +44,8 @@ static bool is_link_enabled(struct fwnode_handle *fw_node, u8 idx) "intel-quirk-mask", &quirk_mask); + fwnode_handle_put(link); + if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE) return false; @@ -55,18 +56,21 @@ static int sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) { struct acpi_device *adev = acpi_fetch_acpi_dev(info->handle); - u8 count, i; + struct fwnode_handle *fwnode; + unsigned long list; + unsigned int i; + u32 count; + u32 tmp; int ret; if (!adev) return -EINVAL; - /* Found controller, find links supported */ - count = 0; - ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev), - "mipi-sdw-master-count", &count, 1); + fwnode = acpi_fwnode_handle(adev); /* + * Found controller, find links supported + * * In theory we could check the number of links supported in * hardware, but in that step we cannot assume SoundWire IP is * powered. @@ -77,17 +81,25 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) * * We will check the hardware capabilities in the startup() step */ - + ret = fwnode_property_read_u32(fwnode, "mipi-sdw-manager-list", &tmp); if (ret) { - dev_err(&adev->dev, - "Failed to read mipi-sdw-master-count: %d\n", ret); - return -EINVAL; + ret = fwnode_property_read_u32(fwnode, "mipi-sdw-master-count", &count); + if (ret) { + dev_err(&adev->dev, + "Failed to read mipi-sdw-master-count: %d\n", + ret); + return ret; + } + list = GENMASK(count - 1, 0); + } else { + list = tmp; + count = hweight32(list); } /* Check count is within bounds */ - if (count > SDW_MAX_LINKS) { + if (count > SDW_INTEL_MAX_LINKS) { dev_err(&adev->dev, "Link count %d exceeds max %d\n", - count, SDW_MAX_LINKS); + count, SDW_INTEL_MAX_LINKS); return -EINVAL; } @@ -100,14 +112,14 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) info->count = count; info->link_mask = 0; - for (i = 0; i < count; i++) { + for_each_set_bit(i, &list, SDW_INTEL_MAX_LINKS) { if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) { dev_dbg(&adev->dev, "Link %d masked, will not be enabled\n", i); continue; } - if (!is_link_enabled(acpi_fwnode_handle(adev), i)) { + if (!is_link_enabled(fwnode, i)) { dev_dbg(&adev->dev, "Link %d not selected in firmware\n", i); continue; @@ -123,11 +135,11 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, void *cdata, void **return_value) { struct sdw_intel_acpi_info *info = cdata; - acpi_status status; u64 adr; + int ret; - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); - if (ACPI_FAILURE(status)) + ret = acpi_get_local_u64_address(handle, &adr); + if (ret < 0) return AE_OK; /* keep going */ if (!acpi_fetch_acpi_dev(handle)) { @@ -165,7 +177,7 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, * sdw_intel_startup() is required for creation of devices and bus * startup */ -int sdw_intel_acpi_scan(acpi_handle *parent_handle, +int sdw_intel_acpi_scan(acpi_handle parent_handle, struct sdw_intel_acpi_info *info) { acpi_status status; @@ -186,7 +198,7 @@ int sdw_intel_acpi_scan(acpi_handle *parent_handle, return sdw_intel_scan_controller(info); } -EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SND_INTEL_SOUNDWIRE_ACPI); +EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, "SND_INTEL_SOUNDWIRE_ACPI"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("Intel Soundwire ACPI helpers"); diff --git a/sound/hda/trace.h b/sound/hda/trace.h index 2cc493434a8f..280c42f3eb75 100644 --- a/sound/hda/trace.h +++ b/sound/hda/trace.h @@ -24,7 +24,7 @@ TRACE_EVENT(hda_send_cmd, __field(u32, cmd) ), TP_fast_assign( - __assign_str(name, dev_name((bus)->dev)); + __assign_str(name); __entry->cmd = cmd; ), TP_printk("[%s:%d] val=0x%08x", __get_str(name), __entry->cmd >> 28, __entry->cmd) @@ -39,7 +39,7 @@ TRACE_EVENT(hda_get_response, __field(u32, res) ), TP_fast_assign( - __assign_str(name, dev_name((bus)->dev)); + __assign_str(name); __entry->addr = addr; __entry->res = res; ), @@ -55,7 +55,7 @@ TRACE_EVENT(hda_unsol_event, __field(u32, res_ex) ), TP_fast_assign( - __assign_str(name, dev_name((bus)->dev)); + __assign_str(name); __entry->res = res; __entry->res_ex = res_ex; ), |