summaryrefslogtreecommitdiff
path: root/sound/pci/hda/hda_intel.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/hda_intel.c')
-rw-r--r--sound/pci/hda/hda_intel.c79
1 files changed, 67 insertions, 12 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c71dcacea807..e2f649fffd56 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -186,6 +186,10 @@ module_param(power_save, xint, 0644);
MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
"(in second, 0 = disable).");
+static bool pm_blacklist = true;
+module_param(pm_blacklist, bool, 0644);
+MODULE_PARM_DESC(pm_blacklist, "Enable power-management blacklist");
+
/* reset the HD-audio controller in power save mode.
* this may give more power-saving, but will take longer time to
* wake up.
@@ -371,6 +375,7 @@ enum {
((pci)->device == 0x160c))
#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
+#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348)
static char *driver_short_names[] = {
[AZX_DRIVER_ICH] = "HDA Intel",
@@ -1227,6 +1232,7 @@ static void azx_vs_set_state(struct pci_dev *pci,
struct snd_card *card = pci_get_drvdata(pci);
struct azx *chip = card->private_data;
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+ struct hda_codec *codec;
bool disabled;
wait_for_completion(&hda->probe_wait);
@@ -1251,8 +1257,12 @@ static void azx_vs_set_state(struct pci_dev *pci,
dev_info(chip->card->dev, "%s via vga_switcheroo\n",
disabled ? "Disabling" : "Enabling");
if (disabled) {
- pm_runtime_put_sync_suspend(card->dev);
- azx_suspend(card->dev);
+ list_for_each_codec(codec, &chip->bus) {
+ pm_runtime_suspend(hda_codec_dev(codec));
+ pm_runtime_disable(hda_codec_dev(codec));
+ }
+ pm_runtime_suspend(card->dev);
+ pm_runtime_disable(card->dev);
/* when we get suspended by vga_switcheroo we end up in D3cold,
* however we have no ACPI handle, so pci/acpi can't put us there,
* put ourselves there */
@@ -1263,9 +1273,12 @@ static void azx_vs_set_state(struct pci_dev *pci,
"Cannot lock devices!\n");
} else {
snd_hda_unlock_devices(&chip->bus);
- pm_runtime_get_noresume(card->dev);
chip->disabled = false;
- azx_resume(card->dev);
+ pm_runtime_enable(card->dev);
+ list_for_each_codec(codec, &chip->bus) {
+ pm_runtime_enable(hda_codec_dev(codec));
+ pm_runtime_resume(hda_codec_dev(codec));
+ }
}
}
}
@@ -1295,6 +1308,7 @@ static void init_vga_switcheroo(struct azx *chip)
dev_info(chip->card->dev,
"Handle vga_switcheroo audio client\n");
hda->use_vga_switcheroo = 1;
+ chip->driver_caps |= AZX_DCAPS_PM_RUNTIME;
pci_dev_put(p);
}
}
@@ -1320,9 +1334,6 @@ static int register_vga_switcheroo(struct azx *chip)
return err;
hda->vga_switcheroo_registered = 1;
- /* register as an optimus hdmi audio power domain */
- vga_switcheroo_init_domain_pm_optimus_hdmi_audio(chip->card->dev,
- &hda->hdmi_pm_domain);
return 0;
}
#else
@@ -1351,10 +1362,8 @@ static int azx_free(struct azx *chip)
if (use_vga_switcheroo(hda)) {
if (chip->disabled && hda->probe_continued)
snd_hda_unlock_devices(&chip->bus);
- if (hda->vga_switcheroo_registered) {
+ if (hda->vga_switcheroo_registered)
vga_switcheroo_unregister_client(chip->pci);
- vga_switcheroo_fini_domain_pm_ops(chip->card->dev);
- }
}
if (bus->chip_init) {
@@ -1740,6 +1749,10 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
else
chip->bdl_pos_adj = bdl_pos_adj[dev];
+ /* Workaround for a communication error on CFL (bko#199007) */
+ if (IS_CFL(pci))
+ chip->polling_mode = 1;
+
err = azx_bus_init(chip, model[dev], &pci_hda_io_ops);
if (err < 0) {
kfree(hda);
@@ -2186,6 +2199,24 @@ out_free:
return err;
}
+#ifdef CONFIG_PM
+/* On some boards setting power_save to a non 0 value leads to clicking /
+ * popping sounds when ever we enter/leave powersaving mode. Ideally we would
+ * figure out how to avoid these sounds, but that is not always feasible.
+ * So we keep a list of devices where we disable powersaving as its known
+ * to causes problems on these devices.
+ */
+static struct snd_pci_quirk power_save_blacklist[] = {
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
+ SND_PCI_QUIRK(0x1849, 0x0c0c, "Asrock B85M-ITX", 0),
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
+ SND_PCI_QUIRK(0x1043, 0x8733, "Asus Prime X370-Pro", 0),
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=198611 */
+ SND_PCI_QUIRK(0x17aa, 0x2227, "Lenovo X1 Carbon 3rd Gen", 0),
+ {}
+};
+#endif /* CONFIG_PM */
+
/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = {
[AZX_DRIVER_NVIDIA] = 8,
@@ -2197,7 +2228,9 @@ static int azx_probe_continue(struct azx *chip)
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
struct hdac_bus *bus = azx_bus(chip);
struct pci_dev *pci = chip->pci;
+ struct hda_codec *codec;
int dev = chip->dev_index;
+ int val;
int err;
hda->probe_continued = 1;
@@ -2278,8 +2311,30 @@ static int azx_probe_continue(struct azx *chip)
chip->running = 1;
azx_add_card_list(chip);
- snd_hda_set_power_save(&chip->bus, power_save * 1000);
- if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo)
+
+ val = power_save;
+#ifdef CONFIG_PM
+ if (pm_blacklist) {
+ const struct snd_pci_quirk *q;
+
+ q = snd_pci_quirk_lookup(chip->pci, power_save_blacklist);
+ if (q && val) {
+ dev_info(chip->card->dev, "device %04x:%04x is on the power_save blacklist, forcing power_save to 0\n",
+ q->subvendor, q->subdevice);
+ val = 0;
+ }
+ }
+#endif /* CONFIG_PM */
+ /*
+ * The discrete GPU cannot power down unless the HDA controller runtime
+ * suspends, so activate runtime PM on codecs even if power_save == 0.
+ */
+ if (use_vga_switcheroo(hda))
+ list_for_each_codec(codec, &chip->bus)
+ codec->auto_runtime_pm = 1;
+
+ snd_hda_set_power_save(&chip->bus, val * 1000);
+ if (azx_has_pm_runtime(chip))
pm_runtime_put_autosuspend(&pci->dev);
out_free: