aboutsummaryrefslogtreecommitdiffstats
path: root/sound/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/hda')
-rw-r--r--sound/hda/Kconfig1
-rw-r--r--sound/hda/Makefile8
-rw-r--r--sound/hda/ext/Makefile2
-rw-r--r--sound/hda/hdac_controller.c127
-rw-r--r--sound/hda/intel-dsp-config.c51
-rw-r--r--sound/hda/intel-sdw-acpi.c2
-rw-r--r--sound/hda/trace.h6
7 files changed, 169 insertions, 28 deletions
diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig
index 741179ccbd4e..e2ac247fc1d4 100644
--- a/sound/hda/Kconfig
+++ b/sound/hda/Kconfig
@@ -42,6 +42,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/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/intel-dsp-config.c b/sound/hda/intel-dsp-config.c
index 6a384b922e4f..537863447358 100644
--- a/sound/hda/intel-dsp-config.c
+++ b/sound/hda/intel-dsp-config.c
@@ -13,6 +13,8 @@
#include <sound/intel-nhlt.h>
#include <sound/soc-acpi.h>
+#include <acpi/nhlt.h>
+
static int dsp_driver;
module_param(dsp_driver, int, 0444);
@@ -557,9 +559,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 +595,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 +668,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 +678,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 +694,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 {
diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/intel-sdw-acpi.c
index 5f60658c6051..d7417a40392b 100644
--- a/sound/hda/intel-sdw-acpi.c
+++ b/sound/hda/intel-sdw-acpi.c
@@ -45,6 +45,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;
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;
),