162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  hda_intel.c - Implementation of primary alsa driver code base
562306a36Sopenharmony_ci *                for Intel HD Audio.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  Copyright(c) 2004 Intel Corporation. All rights reserved.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *  Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
1062306a36Sopenharmony_ci *                     PeiSen Hou <pshou@realtek.com.tw>
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *  CONTACTS:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *  Matt Jared		matt.jared@intel.com
1562306a36Sopenharmony_ci *  Andy Kopp		andy.kopp@intel.com
1662306a36Sopenharmony_ci *  Dan Kogan		dan.d.kogan@intel.com
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *  CHANGES:
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci *  2004.12.01	Major rewrite by tiwai, merged the work of pshou
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/delay.h>
2462306a36Sopenharmony_ci#include <linux/interrupt.h>
2562306a36Sopenharmony_ci#include <linux/kernel.h>
2662306a36Sopenharmony_ci#include <linux/module.h>
2762306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2862306a36Sopenharmony_ci#include <linux/moduleparam.h>
2962306a36Sopenharmony_ci#include <linux/init.h>
3062306a36Sopenharmony_ci#include <linux/slab.h>
3162306a36Sopenharmony_ci#include <linux/pci.h>
3262306a36Sopenharmony_ci#include <linux/mutex.h>
3362306a36Sopenharmony_ci#include <linux/io.h>
3462306a36Sopenharmony_ci#include <linux/pm_runtime.h>
3562306a36Sopenharmony_ci#include <linux/clocksource.h>
3662306a36Sopenharmony_ci#include <linux/time.h>
3762306a36Sopenharmony_ci#include <linux/completion.h>
3862306a36Sopenharmony_ci#include <linux/acpi.h>
3962306a36Sopenharmony_ci#include <linux/pgtable.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#ifdef CONFIG_X86
4262306a36Sopenharmony_ci/* for snoop control */
4362306a36Sopenharmony_ci#include <asm/set_memory.h>
4462306a36Sopenharmony_ci#include <asm/cpufeature.h>
4562306a36Sopenharmony_ci#endif
4662306a36Sopenharmony_ci#include <sound/core.h>
4762306a36Sopenharmony_ci#include <sound/initval.h>
4862306a36Sopenharmony_ci#include <sound/hdaudio.h>
4962306a36Sopenharmony_ci#include <sound/hda_i915.h>
5062306a36Sopenharmony_ci#include <sound/intel-dsp-config.h>
5162306a36Sopenharmony_ci#include <linux/vgaarb.h>
5262306a36Sopenharmony_ci#include <linux/vga_switcheroo.h>
5362306a36Sopenharmony_ci#include <linux/apple-gmux.h>
5462306a36Sopenharmony_ci#include <linux/firmware.h>
5562306a36Sopenharmony_ci#include <sound/hda_codec.h>
5662306a36Sopenharmony_ci#include "hda_controller.h"
5762306a36Sopenharmony_ci#include "hda_intel.h"
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
6062306a36Sopenharmony_ci#include "hda_intel_trace.h"
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* position fix mode */
6362306a36Sopenharmony_cienum {
6462306a36Sopenharmony_ci	POS_FIX_AUTO,
6562306a36Sopenharmony_ci	POS_FIX_LPIB,
6662306a36Sopenharmony_ci	POS_FIX_POSBUF,
6762306a36Sopenharmony_ci	POS_FIX_VIACOMBO,
6862306a36Sopenharmony_ci	POS_FIX_COMBO,
6962306a36Sopenharmony_ci	POS_FIX_SKL,
7062306a36Sopenharmony_ci	POS_FIX_FIFO,
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* Defines for ATI HD Audio support in SB450 south bridge */
7462306a36Sopenharmony_ci#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR   0x42
7562306a36Sopenharmony_ci#define ATI_SB450_HDAUDIO_ENABLE_SNOOP      0x02
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* Defines for Nvidia HDA support */
7862306a36Sopenharmony_ci#define NVIDIA_HDA_TRANSREG_ADDR      0x4e
7962306a36Sopenharmony_ci#define NVIDIA_HDA_ENABLE_COHBITS     0x0f
8062306a36Sopenharmony_ci#define NVIDIA_HDA_ISTRM_COH          0x4d
8162306a36Sopenharmony_ci#define NVIDIA_HDA_OSTRM_COH          0x4c
8262306a36Sopenharmony_ci#define NVIDIA_HDA_ENABLE_COHBIT      0x01
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/* Defines for Intel SCH HDA snoop control */
8562306a36Sopenharmony_ci#define INTEL_HDA_CGCTL	 0x48
8662306a36Sopenharmony_ci#define INTEL_HDA_CGCTL_MISCBDCGE        (0x1 << 6)
8762306a36Sopenharmony_ci#define INTEL_SCH_HDA_DEVC      0x78
8862306a36Sopenharmony_ci#define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/* max number of SDs */
9162306a36Sopenharmony_ci/* ICH, ATI and VIA have 4 playback and 4 capture */
9262306a36Sopenharmony_ci#define ICH6_NUM_CAPTURE	4
9362306a36Sopenharmony_ci#define ICH6_NUM_PLAYBACK	4
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* ULI has 6 playback and 5 capture */
9662306a36Sopenharmony_ci#define ULI_NUM_CAPTURE		5
9762306a36Sopenharmony_ci#define ULI_NUM_PLAYBACK	6
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/* ATI HDMI may have up to 8 playbacks and 0 capture */
10062306a36Sopenharmony_ci#define ATIHDMI_NUM_CAPTURE	0
10162306a36Sopenharmony_ci#define ATIHDMI_NUM_PLAYBACK	8
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
10562306a36Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
10662306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
10762306a36Sopenharmony_cistatic char *model[SNDRV_CARDS];
10862306a36Sopenharmony_cistatic int position_fix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
10962306a36Sopenharmony_cistatic int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
11062306a36Sopenharmony_cistatic int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
11162306a36Sopenharmony_cistatic int probe_only[SNDRV_CARDS];
11262306a36Sopenharmony_cistatic int jackpoll_ms[SNDRV_CARDS];
11362306a36Sopenharmony_cistatic int single_cmd = -1;
11462306a36Sopenharmony_cistatic int enable_msi = -1;
11562306a36Sopenharmony_ci#ifdef CONFIG_SND_HDA_PATCH_LOADER
11662306a36Sopenharmony_cistatic char *patch[SNDRV_CARDS];
11762306a36Sopenharmony_ci#endif
11862306a36Sopenharmony_ci#ifdef CONFIG_SND_HDA_INPUT_BEEP
11962306a36Sopenharmony_cistatic bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] =
12062306a36Sopenharmony_ci					CONFIG_SND_HDA_INPUT_BEEP_MODE};
12162306a36Sopenharmony_ci#endif
12262306a36Sopenharmony_cistatic bool dmic_detect = 1;
12362306a36Sopenharmony_cistatic bool ctl_dev_id = IS_ENABLED(CONFIG_SND_HDA_CTL_DEV_ID) ? 1 : 0;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444);
12662306a36Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
12762306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444);
12862306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for Intel HD audio interface.");
12962306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444);
13062306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
13162306a36Sopenharmony_cimodule_param_array(model, charp, NULL, 0444);
13262306a36Sopenharmony_ciMODULE_PARM_DESC(model, "Use the given board model.");
13362306a36Sopenharmony_cimodule_param_array(position_fix, int, NULL, 0444);
13462306a36Sopenharmony_ciMODULE_PARM_DESC(position_fix, "DMA pointer read method."
13562306a36Sopenharmony_ci		 "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO, 5 = SKL+, 6 = FIFO).");
13662306a36Sopenharmony_cimodule_param_array(bdl_pos_adj, int, NULL, 0644);
13762306a36Sopenharmony_ciMODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
13862306a36Sopenharmony_cimodule_param_array(probe_mask, int, NULL, 0444);
13962306a36Sopenharmony_ciMODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
14062306a36Sopenharmony_cimodule_param_array(probe_only, int, NULL, 0444);
14162306a36Sopenharmony_ciMODULE_PARM_DESC(probe_only, "Only probing and no codec initialization.");
14262306a36Sopenharmony_cimodule_param_array(jackpoll_ms, int, NULL, 0444);
14362306a36Sopenharmony_ciMODULE_PARM_DESC(jackpoll_ms, "Ms between polling for jack events (default = 0, using unsol events only)");
14462306a36Sopenharmony_cimodule_param(single_cmd, bint, 0444);
14562306a36Sopenharmony_ciMODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
14662306a36Sopenharmony_ci		 "(for debugging only).");
14762306a36Sopenharmony_cimodule_param(enable_msi, bint, 0444);
14862306a36Sopenharmony_ciMODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
14962306a36Sopenharmony_ci#ifdef CONFIG_SND_HDA_PATCH_LOADER
15062306a36Sopenharmony_cimodule_param_array(patch, charp, NULL, 0444);
15162306a36Sopenharmony_ciMODULE_PARM_DESC(patch, "Patch file for Intel HD audio interface.");
15262306a36Sopenharmony_ci#endif
15362306a36Sopenharmony_ci#ifdef CONFIG_SND_HDA_INPUT_BEEP
15462306a36Sopenharmony_cimodule_param_array(beep_mode, bool, NULL, 0444);
15562306a36Sopenharmony_ciMODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
15662306a36Sopenharmony_ci			    "(0=off, 1=on) (default=1).");
15762306a36Sopenharmony_ci#endif
15862306a36Sopenharmony_cimodule_param(dmic_detect, bool, 0444);
15962306a36Sopenharmony_ciMODULE_PARM_DESC(dmic_detect, "Allow DSP driver selection (bypass this driver) "
16062306a36Sopenharmony_ci			     "(0=off, 1=on) (default=1); "
16162306a36Sopenharmony_ci		 "deprecated, use snd-intel-dspcfg.dsp_driver option instead");
16262306a36Sopenharmony_cimodule_param(ctl_dev_id, bool, 0444);
16362306a36Sopenharmony_ciMODULE_PARM_DESC(ctl_dev_id, "Use control device identifier (based on codec address).");
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci#ifdef CONFIG_PM
16662306a36Sopenharmony_cistatic int param_set_xint(const char *val, const struct kernel_param *kp);
16762306a36Sopenharmony_cistatic const struct kernel_param_ops param_ops_xint = {
16862306a36Sopenharmony_ci	.set = param_set_xint,
16962306a36Sopenharmony_ci	.get = param_get_int,
17062306a36Sopenharmony_ci};
17162306a36Sopenharmony_ci#define param_check_xint param_check_int
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
17462306a36Sopenharmony_cimodule_param(power_save, xint, 0644);
17562306a36Sopenharmony_ciMODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
17662306a36Sopenharmony_ci		 "(in second, 0 = disable).");
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic bool pm_blacklist = true;
17962306a36Sopenharmony_cimodule_param(pm_blacklist, bool, 0644);
18062306a36Sopenharmony_ciMODULE_PARM_DESC(pm_blacklist, "Enable power-management denylist");
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci/* reset the HD-audio controller in power save mode.
18362306a36Sopenharmony_ci * this may give more power-saving, but will take longer time to
18462306a36Sopenharmony_ci * wake up.
18562306a36Sopenharmony_ci */
18662306a36Sopenharmony_cistatic bool power_save_controller = 1;
18762306a36Sopenharmony_cimodule_param(power_save_controller, bool, 0644);
18862306a36Sopenharmony_ciMODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
18962306a36Sopenharmony_ci#else
19062306a36Sopenharmony_ci#define power_save	0
19162306a36Sopenharmony_ci#endif /* CONFIG_PM */
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic int align_buffer_size = -1;
19462306a36Sopenharmony_cimodule_param(align_buffer_size, bint, 0644);
19562306a36Sopenharmony_ciMODULE_PARM_DESC(align_buffer_size,
19662306a36Sopenharmony_ci		"Force buffer and period sizes to be multiple of 128 bytes.");
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci#ifdef CONFIG_X86
19962306a36Sopenharmony_cistatic int hda_snoop = -1;
20062306a36Sopenharmony_cimodule_param_named(snoop, hda_snoop, bint, 0444);
20162306a36Sopenharmony_ciMODULE_PARM_DESC(snoop, "Enable/disable snooping");
20262306a36Sopenharmony_ci#else
20362306a36Sopenharmony_ci#define hda_snoop		true
20462306a36Sopenharmony_ci#endif
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
20862306a36Sopenharmony_ciMODULE_DESCRIPTION("Intel HDA driver");
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci#if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO)
21162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
21262306a36Sopenharmony_ci#define SUPPORT_VGA_SWITCHEROO
21362306a36Sopenharmony_ci#endif
21462306a36Sopenharmony_ci#endif
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/*
21862306a36Sopenharmony_ci */
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci/* driver types */
22162306a36Sopenharmony_cienum {
22262306a36Sopenharmony_ci	AZX_DRIVER_ICH,
22362306a36Sopenharmony_ci	AZX_DRIVER_PCH,
22462306a36Sopenharmony_ci	AZX_DRIVER_SCH,
22562306a36Sopenharmony_ci	AZX_DRIVER_SKL,
22662306a36Sopenharmony_ci	AZX_DRIVER_HDMI,
22762306a36Sopenharmony_ci	AZX_DRIVER_ATI,
22862306a36Sopenharmony_ci	AZX_DRIVER_ATIHDMI,
22962306a36Sopenharmony_ci	AZX_DRIVER_ATIHDMI_NS,
23062306a36Sopenharmony_ci	AZX_DRIVER_GFHDMI,
23162306a36Sopenharmony_ci	AZX_DRIVER_VIA,
23262306a36Sopenharmony_ci	AZX_DRIVER_SIS,
23362306a36Sopenharmony_ci	AZX_DRIVER_ULI,
23462306a36Sopenharmony_ci	AZX_DRIVER_NVIDIA,
23562306a36Sopenharmony_ci	AZX_DRIVER_TERA,
23662306a36Sopenharmony_ci	AZX_DRIVER_CTX,
23762306a36Sopenharmony_ci	AZX_DRIVER_CTHDA,
23862306a36Sopenharmony_ci	AZX_DRIVER_CMEDIA,
23962306a36Sopenharmony_ci	AZX_DRIVER_ZHAOXIN,
24062306a36Sopenharmony_ci	AZX_DRIVER_LOONGSON,
24162306a36Sopenharmony_ci	AZX_DRIVER_GENERIC,
24262306a36Sopenharmony_ci	AZX_NUM_DRIVERS, /* keep this as last entry */
24362306a36Sopenharmony_ci};
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci#define azx_get_snoop_type(chip) \
24662306a36Sopenharmony_ci	(((chip)->driver_caps & AZX_DCAPS_SNOOP_MASK) >> 10)
24762306a36Sopenharmony_ci#define AZX_DCAPS_SNOOP_TYPE(type) ((AZX_SNOOP_TYPE_ ## type) << 10)
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci/* quirks for old Intel chipsets */
25062306a36Sopenharmony_ci#define AZX_DCAPS_INTEL_ICH \
25162306a36Sopenharmony_ci	(AZX_DCAPS_OLD_SSYNC | AZX_DCAPS_NO_ALIGN_BUFSIZE)
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci/* quirks for Intel PCH */
25462306a36Sopenharmony_ci#define AZX_DCAPS_INTEL_PCH_BASE \
25562306a36Sopenharmony_ci	(AZX_DCAPS_NO_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\
25662306a36Sopenharmony_ci	 AZX_DCAPS_SNOOP_TYPE(SCH))
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci/* PCH up to IVB; no runtime PM; bind with i915 gfx */
25962306a36Sopenharmony_ci#define AZX_DCAPS_INTEL_PCH_NOPM \
26062306a36Sopenharmony_ci	(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT)
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/* PCH for HSW/BDW; with runtime PM */
26362306a36Sopenharmony_ci/* no i915 binding for this as HSW/BDW has another controller for HDMI */
26462306a36Sopenharmony_ci#define AZX_DCAPS_INTEL_PCH \
26562306a36Sopenharmony_ci	(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME)
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/* HSW HDMI */
26862306a36Sopenharmony_ci#define AZX_DCAPS_INTEL_HASWELL \
26962306a36Sopenharmony_ci	(/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\
27062306a36Sopenharmony_ci	 AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\
27162306a36Sopenharmony_ci	 AZX_DCAPS_SNOOP_TYPE(SCH))
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci/* Broadwell HDMI can't use position buffer reliably, force to use LPIB */
27462306a36Sopenharmony_ci#define AZX_DCAPS_INTEL_BROADWELL \
27562306a36Sopenharmony_ci	(/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\
27662306a36Sopenharmony_ci	 AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\
27762306a36Sopenharmony_ci	 AZX_DCAPS_SNOOP_TYPE(SCH))
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci#define AZX_DCAPS_INTEL_BAYTRAIL \
28062306a36Sopenharmony_ci	(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT)
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci#define AZX_DCAPS_INTEL_BRASWELL \
28362306a36Sopenharmony_ci	(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
28462306a36Sopenharmony_ci	 AZX_DCAPS_I915_COMPONENT)
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci#define AZX_DCAPS_INTEL_SKYLAKE \
28762306a36Sopenharmony_ci	(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
28862306a36Sopenharmony_ci	 AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci#define AZX_DCAPS_INTEL_BROXTON		AZX_DCAPS_INTEL_SKYLAKE
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci/* quirks for ATI SB / AMD Hudson */
29362306a36Sopenharmony_ci#define AZX_DCAPS_PRESET_ATI_SB \
29462306a36Sopenharmony_ci	(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_POSFIX_LPIB |\
29562306a36Sopenharmony_ci	 AZX_DCAPS_SNOOP_TYPE(ATI))
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci/* quirks for ATI/AMD HDMI */
29862306a36Sopenharmony_ci#define AZX_DCAPS_PRESET_ATI_HDMI \
29962306a36Sopenharmony_ci	(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_POSFIX_LPIB|\
30062306a36Sopenharmony_ci	 AZX_DCAPS_NO_MSI64)
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci/* quirks for ATI HDMI with snoop off */
30362306a36Sopenharmony_ci#define AZX_DCAPS_PRESET_ATI_HDMI_NS \
30462306a36Sopenharmony_ci	(AZX_DCAPS_PRESET_ATI_HDMI | AZX_DCAPS_SNOOP_OFF)
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci/* quirks for AMD SB */
30762306a36Sopenharmony_ci#define AZX_DCAPS_PRESET_AMD_SB \
30862306a36Sopenharmony_ci	(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_AMD_WORKAROUND |\
30962306a36Sopenharmony_ci	 AZX_DCAPS_SNOOP_TYPE(ATI) | AZX_DCAPS_PM_RUNTIME |\
31062306a36Sopenharmony_ci	 AZX_DCAPS_RETRY_PROBE)
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci/* quirks for Nvidia */
31362306a36Sopenharmony_ci#define AZX_DCAPS_PRESET_NVIDIA \
31462306a36Sopenharmony_ci	(AZX_DCAPS_NO_MSI | AZX_DCAPS_CORBRP_SELF_CLEAR |\
31562306a36Sopenharmony_ci	 AZX_DCAPS_SNOOP_TYPE(NVIDIA))
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci#define AZX_DCAPS_PRESET_CTHDA \
31862306a36Sopenharmony_ci	(AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB |\
31962306a36Sopenharmony_ci	 AZX_DCAPS_NO_64BIT |\
32062306a36Sopenharmony_ci	 AZX_DCAPS_4K_BDLE_BOUNDARY | AZX_DCAPS_SNOOP_OFF)
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci/*
32362306a36Sopenharmony_ci * vga_switcheroo support
32462306a36Sopenharmony_ci */
32562306a36Sopenharmony_ci#ifdef SUPPORT_VGA_SWITCHEROO
32662306a36Sopenharmony_ci#define use_vga_switcheroo(chip)	((chip)->use_vga_switcheroo)
32762306a36Sopenharmony_ci#define needs_eld_notify_link(chip)	((chip)->bus.keep_power)
32862306a36Sopenharmony_ci#else
32962306a36Sopenharmony_ci#define use_vga_switcheroo(chip)	0
33062306a36Sopenharmony_ci#define needs_eld_notify_link(chip)	false
33162306a36Sopenharmony_ci#endif
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic const char * const driver_short_names[] = {
33462306a36Sopenharmony_ci	[AZX_DRIVER_ICH] = "HDA Intel",
33562306a36Sopenharmony_ci	[AZX_DRIVER_PCH] = "HDA Intel PCH",
33662306a36Sopenharmony_ci	[AZX_DRIVER_SCH] = "HDA Intel MID",
33762306a36Sopenharmony_ci	[AZX_DRIVER_SKL] = "HDA Intel PCH", /* kept old name for compatibility */
33862306a36Sopenharmony_ci	[AZX_DRIVER_HDMI] = "HDA Intel HDMI",
33962306a36Sopenharmony_ci	[AZX_DRIVER_ATI] = "HDA ATI SB",
34062306a36Sopenharmony_ci	[AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
34162306a36Sopenharmony_ci	[AZX_DRIVER_ATIHDMI_NS] = "HDA ATI HDMI",
34262306a36Sopenharmony_ci	[AZX_DRIVER_GFHDMI] = "HDA GF HDMI",
34362306a36Sopenharmony_ci	[AZX_DRIVER_VIA] = "HDA VIA VT82xx",
34462306a36Sopenharmony_ci	[AZX_DRIVER_SIS] = "HDA SIS966",
34562306a36Sopenharmony_ci	[AZX_DRIVER_ULI] = "HDA ULI M5461",
34662306a36Sopenharmony_ci	[AZX_DRIVER_NVIDIA] = "HDA NVidia",
34762306a36Sopenharmony_ci	[AZX_DRIVER_TERA] = "HDA Teradici",
34862306a36Sopenharmony_ci	[AZX_DRIVER_CTX] = "HDA Creative",
34962306a36Sopenharmony_ci	[AZX_DRIVER_CTHDA] = "HDA Creative",
35062306a36Sopenharmony_ci	[AZX_DRIVER_CMEDIA] = "HDA C-Media",
35162306a36Sopenharmony_ci	[AZX_DRIVER_ZHAOXIN] = "HDA Zhaoxin",
35262306a36Sopenharmony_ci	[AZX_DRIVER_LOONGSON] = "HDA Loongson",
35362306a36Sopenharmony_ci	[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
35462306a36Sopenharmony_ci};
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic int azx_acquire_irq(struct azx *chip, int do_disconnect);
35762306a36Sopenharmony_cistatic void set_default_power_save(struct azx *chip);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci/*
36062306a36Sopenharmony_ci * initialize the PCI registers
36162306a36Sopenharmony_ci */
36262306a36Sopenharmony_ci/* update bits in a PCI register byte */
36362306a36Sopenharmony_cistatic void update_pci_byte(struct pci_dev *pci, unsigned int reg,
36462306a36Sopenharmony_ci			    unsigned char mask, unsigned char val)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	unsigned char data;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	pci_read_config_byte(pci, reg, &data);
36962306a36Sopenharmony_ci	data &= ~mask;
37062306a36Sopenharmony_ci	data |= (val & mask);
37162306a36Sopenharmony_ci	pci_write_config_byte(pci, reg, data);
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_cistatic void azx_init_pci(struct azx *chip)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	int snoop_type = azx_get_snoop_type(chip);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
37962306a36Sopenharmony_ci	 * TCSEL == Traffic Class Select Register, which sets PCI express QOS
38062306a36Sopenharmony_ci	 * Ensuring these bits are 0 clears playback static on some HD Audio
38162306a36Sopenharmony_ci	 * codecs.
38262306a36Sopenharmony_ci	 * The PCI register TCSEL is defined in the Intel manuals.
38362306a36Sopenharmony_ci	 */
38462306a36Sopenharmony_ci	if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) {
38562306a36Sopenharmony_ci		dev_dbg(chip->card->dev, "Clearing TCSEL\n");
38662306a36Sopenharmony_ci		update_pci_byte(chip->pci, AZX_PCIREG_TCSEL, 0x07, 0);
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	/* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio,
39062306a36Sopenharmony_ci	 * we need to enable snoop.
39162306a36Sopenharmony_ci	 */
39262306a36Sopenharmony_ci	if (snoop_type == AZX_SNOOP_TYPE_ATI) {
39362306a36Sopenharmony_ci		dev_dbg(chip->card->dev, "Setting ATI snoop: %d\n",
39462306a36Sopenharmony_ci			azx_snoop(chip));
39562306a36Sopenharmony_ci		update_pci_byte(chip->pci,
39662306a36Sopenharmony_ci				ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07,
39762306a36Sopenharmony_ci				azx_snoop(chip) ? ATI_SB450_HDAUDIO_ENABLE_SNOOP : 0);
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* For NVIDIA HDA, enable snoop */
40162306a36Sopenharmony_ci	if (snoop_type == AZX_SNOOP_TYPE_NVIDIA) {
40262306a36Sopenharmony_ci		dev_dbg(chip->card->dev, "Setting Nvidia snoop: %d\n",
40362306a36Sopenharmony_ci			azx_snoop(chip));
40462306a36Sopenharmony_ci		update_pci_byte(chip->pci,
40562306a36Sopenharmony_ci				NVIDIA_HDA_TRANSREG_ADDR,
40662306a36Sopenharmony_ci				0x0f, NVIDIA_HDA_ENABLE_COHBITS);
40762306a36Sopenharmony_ci		update_pci_byte(chip->pci,
40862306a36Sopenharmony_ci				NVIDIA_HDA_ISTRM_COH,
40962306a36Sopenharmony_ci				0x01, NVIDIA_HDA_ENABLE_COHBIT);
41062306a36Sopenharmony_ci		update_pci_byte(chip->pci,
41162306a36Sopenharmony_ci				NVIDIA_HDA_OSTRM_COH,
41262306a36Sopenharmony_ci				0x01, NVIDIA_HDA_ENABLE_COHBIT);
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* Enable SCH/PCH snoop if needed */
41662306a36Sopenharmony_ci	if (snoop_type == AZX_SNOOP_TYPE_SCH) {
41762306a36Sopenharmony_ci		unsigned short snoop;
41862306a36Sopenharmony_ci		pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
41962306a36Sopenharmony_ci		if ((!azx_snoop(chip) && !(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)) ||
42062306a36Sopenharmony_ci		    (azx_snoop(chip) && (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP))) {
42162306a36Sopenharmony_ci			snoop &= ~INTEL_SCH_HDA_DEVC_NOSNOOP;
42262306a36Sopenharmony_ci			if (!azx_snoop(chip))
42362306a36Sopenharmony_ci				snoop |= INTEL_SCH_HDA_DEVC_NOSNOOP;
42462306a36Sopenharmony_ci			pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, snoop);
42562306a36Sopenharmony_ci			pci_read_config_word(chip->pci,
42662306a36Sopenharmony_ci				INTEL_SCH_HDA_DEVC, &snoop);
42762306a36Sopenharmony_ci		}
42862306a36Sopenharmony_ci		dev_dbg(chip->card->dev, "SCH snoop: %s\n",
42962306a36Sopenharmony_ci			(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) ?
43062306a36Sopenharmony_ci			"Disabled" : "Enabled");
43162306a36Sopenharmony_ci        }
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci/*
43562306a36Sopenharmony_ci * In BXT-P A0, HD-Audio DMA requests is later than expected,
43662306a36Sopenharmony_ci * and makes an audio stream sensitive to system latencies when
43762306a36Sopenharmony_ci * 24/32 bits are playing.
43862306a36Sopenharmony_ci * Adjusting threshold of DMA fifo to force the DMA request
43962306a36Sopenharmony_ci * sooner to improve latency tolerance at the expense of power.
44062306a36Sopenharmony_ci */
44162306a36Sopenharmony_cistatic void bxt_reduce_dma_latency(struct azx *chip)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	u32 val;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	val = azx_readl(chip, VS_EM4L);
44662306a36Sopenharmony_ci	val &= (0x3 << 20);
44762306a36Sopenharmony_ci	azx_writel(chip, VS_EM4L, val);
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci/*
45162306a36Sopenharmony_ci * ML_LCAP bits:
45262306a36Sopenharmony_ci *  bit 0: 6 MHz Supported
45362306a36Sopenharmony_ci *  bit 1: 12 MHz Supported
45462306a36Sopenharmony_ci *  bit 2: 24 MHz Supported
45562306a36Sopenharmony_ci *  bit 3: 48 MHz Supported
45662306a36Sopenharmony_ci *  bit 4: 96 MHz Supported
45762306a36Sopenharmony_ci *  bit 5: 192 MHz Supported
45862306a36Sopenharmony_ci */
45962306a36Sopenharmony_cistatic int intel_get_lctl_scf(struct azx *chip)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
46262306a36Sopenharmony_ci	static const int preferred_bits[] = { 2, 3, 1, 4, 5 };
46362306a36Sopenharmony_ci	u32 val, t;
46462306a36Sopenharmony_ci	int i;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCAP);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(preferred_bits); i++) {
46962306a36Sopenharmony_ci		t = preferred_bits[i];
47062306a36Sopenharmony_ci		if (val & (1 << t))
47162306a36Sopenharmony_ci			return t;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	dev_warn(chip->card->dev, "set audio clock frequency to 6MHz");
47562306a36Sopenharmony_ci	return 0;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic int intel_ml_lctl_set_power(struct azx *chip, int state)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
48162306a36Sopenharmony_ci	u32 val;
48262306a36Sopenharmony_ci	int timeout;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	/*
48562306a36Sopenharmony_ci	 * Changes to LCTL.SCF are only needed for the first multi-link dealing
48662306a36Sopenharmony_ci	 * with external codecs
48762306a36Sopenharmony_ci	 */
48862306a36Sopenharmony_ci	val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
48962306a36Sopenharmony_ci	val &= ~AZX_ML_LCTL_SPA;
49062306a36Sopenharmony_ci	val |= state << AZX_ML_LCTL_SPA_SHIFT;
49162306a36Sopenharmony_ci	writel(val, bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
49262306a36Sopenharmony_ci	/* wait for CPA */
49362306a36Sopenharmony_ci	timeout = 50;
49462306a36Sopenharmony_ci	while (timeout) {
49562306a36Sopenharmony_ci		if (((readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL)) &
49662306a36Sopenharmony_ci		    AZX_ML_LCTL_CPA) == (state << AZX_ML_LCTL_CPA_SHIFT))
49762306a36Sopenharmony_ci			return 0;
49862306a36Sopenharmony_ci		timeout--;
49962306a36Sopenharmony_ci		udelay(10);
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	return -1;
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic void intel_init_lctl(struct azx *chip)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
50862306a36Sopenharmony_ci	u32 val;
50962306a36Sopenharmony_ci	int ret;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/* 0. check lctl register value is correct or not */
51262306a36Sopenharmony_ci	val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
51362306a36Sopenharmony_ci	/* only perform additional configurations if the SCF is initially based on 6MHz */
51462306a36Sopenharmony_ci	if ((val & AZX_ML_LCTL_SCF) != 0)
51562306a36Sopenharmony_ci		return;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	/*
51862306a36Sopenharmony_ci	 * Before operating on SPA, CPA must match SPA.
51962306a36Sopenharmony_ci	 * Any deviation may result in undefined behavior.
52062306a36Sopenharmony_ci	 */
52162306a36Sopenharmony_ci	if (((val & AZX_ML_LCTL_SPA) >> AZX_ML_LCTL_SPA_SHIFT) !=
52262306a36Sopenharmony_ci		((val & AZX_ML_LCTL_CPA) >> AZX_ML_LCTL_CPA_SHIFT))
52362306a36Sopenharmony_ci		return;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	/* 1. turn link down: set SPA to 0 and wait CPA to 0 */
52662306a36Sopenharmony_ci	ret = intel_ml_lctl_set_power(chip, 0);
52762306a36Sopenharmony_ci	udelay(100);
52862306a36Sopenharmony_ci	if (ret)
52962306a36Sopenharmony_ci		goto set_spa;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* 2. update SCF to select an audio clock different from 6MHz */
53262306a36Sopenharmony_ci	val &= ~AZX_ML_LCTL_SCF;
53362306a36Sopenharmony_ci	val |= intel_get_lctl_scf(chip);
53462306a36Sopenharmony_ci	writel(val, bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ciset_spa:
53762306a36Sopenharmony_ci	/* 4. turn link up: set SPA to 1 and wait CPA to 1 */
53862306a36Sopenharmony_ci	intel_ml_lctl_set_power(chip, 1);
53962306a36Sopenharmony_ci	udelay(100);
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic void hda_intel_init_chip(struct azx *chip, bool full_reset)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
54562306a36Sopenharmony_ci	struct pci_dev *pci = chip->pci;
54662306a36Sopenharmony_ci	u32 val;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	snd_hdac_set_codec_wakeup(bus, true);
54962306a36Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_SKL) {
55062306a36Sopenharmony_ci		pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val);
55162306a36Sopenharmony_ci		val = val & ~INTEL_HDA_CGCTL_MISCBDCGE;
55262306a36Sopenharmony_ci		pci_write_config_dword(pci, INTEL_HDA_CGCTL, val);
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci	azx_init_chip(chip, full_reset);
55562306a36Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_SKL) {
55662306a36Sopenharmony_ci		pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val);
55762306a36Sopenharmony_ci		val = val | INTEL_HDA_CGCTL_MISCBDCGE;
55862306a36Sopenharmony_ci		pci_write_config_dword(pci, INTEL_HDA_CGCTL, val);
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	snd_hdac_set_codec_wakeup(bus, false);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	/* reduce dma latency to avoid noise */
56462306a36Sopenharmony_ci	if (HDA_CONTROLLER_IS_APL(pci))
56562306a36Sopenharmony_ci		bxt_reduce_dma_latency(chip);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (bus->mlcap != NULL)
56862306a36Sopenharmony_ci		intel_init_lctl(chip);
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci/* calculate runtime delay from LPIB */
57262306a36Sopenharmony_cistatic int azx_get_delay_from_lpib(struct azx *chip, struct azx_dev *azx_dev,
57362306a36Sopenharmony_ci				   unsigned int pos)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	struct snd_pcm_substream *substream = azx_dev->core.substream;
57662306a36Sopenharmony_ci	int stream = substream->stream;
57762306a36Sopenharmony_ci	unsigned int lpib_pos = azx_get_pos_lpib(chip, azx_dev);
57862306a36Sopenharmony_ci	int delay;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
58162306a36Sopenharmony_ci		delay = pos - lpib_pos;
58262306a36Sopenharmony_ci	else
58362306a36Sopenharmony_ci		delay = lpib_pos - pos;
58462306a36Sopenharmony_ci	if (delay < 0) {
58562306a36Sopenharmony_ci		if (delay >= azx_dev->core.delay_negative_threshold)
58662306a36Sopenharmony_ci			delay = 0;
58762306a36Sopenharmony_ci		else
58862306a36Sopenharmony_ci			delay += azx_dev->core.bufsize;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (delay >= azx_dev->core.period_bytes) {
59262306a36Sopenharmony_ci		dev_info(chip->card->dev,
59362306a36Sopenharmony_ci			 "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n",
59462306a36Sopenharmony_ci			 delay, azx_dev->core.period_bytes);
59562306a36Sopenharmony_ci		delay = 0;
59662306a36Sopenharmony_ci		chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY;
59762306a36Sopenharmony_ci		chip->get_delay[stream] = NULL;
59862306a36Sopenharmony_ci	}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	return bytes_to_frames(substream->runtime, delay);
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci/* called from IRQ */
60662306a36Sopenharmony_cistatic int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
60962306a36Sopenharmony_ci	int ok;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	ok = azx_position_ok(chip, azx_dev);
61262306a36Sopenharmony_ci	if (ok == 1) {
61362306a36Sopenharmony_ci		azx_dev->irq_pending = 0;
61462306a36Sopenharmony_ci		return ok;
61562306a36Sopenharmony_ci	} else if (ok == 0) {
61662306a36Sopenharmony_ci		/* bogus IRQ, process it later */
61762306a36Sopenharmony_ci		azx_dev->irq_pending = 1;
61862306a36Sopenharmony_ci		schedule_work(&hda->irq_pending_work);
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci	return 0;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci#define display_power(chip, enable) \
62462306a36Sopenharmony_ci	snd_hdac_display_power(azx_bus(chip), HDA_CODEC_IDX_CONTROLLER, enable)
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci/*
62762306a36Sopenharmony_ci * Check whether the current DMA position is acceptable for updating
62862306a36Sopenharmony_ci * periods.  Returns non-zero if it's OK.
62962306a36Sopenharmony_ci *
63062306a36Sopenharmony_ci * Many HD-audio controllers appear pretty inaccurate about
63162306a36Sopenharmony_ci * the update-IRQ timing.  The IRQ is issued before actually the
63262306a36Sopenharmony_ci * data is processed.  So, we need to process it afterwords in a
63362306a36Sopenharmony_ci * workqueue.
63462306a36Sopenharmony_ci *
63562306a36Sopenharmony_ci * Returns 1 if OK to proceed, 0 for delay handling, -1 for skipping update
63662306a36Sopenharmony_ci */
63762306a36Sopenharmony_cistatic int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	struct snd_pcm_substream *substream = azx_dev->core.substream;
64062306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
64162306a36Sopenharmony_ci	int stream = substream->stream;
64262306a36Sopenharmony_ci	u32 wallclk;
64362306a36Sopenharmony_ci	unsigned int pos;
64462306a36Sopenharmony_ci	snd_pcm_uframes_t hwptr, target;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/*
64762306a36Sopenharmony_ci	 * The value of the WALLCLK register is always 0
64862306a36Sopenharmony_ci	 * on the Loongson controller, so we return directly.
64962306a36Sopenharmony_ci	 */
65062306a36Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_LOONGSON)
65162306a36Sopenharmony_ci		return 1;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	wallclk = azx_readl(chip, WALLCLK) - azx_dev->core.start_wallclk;
65462306a36Sopenharmony_ci	if (wallclk < (azx_dev->core.period_wallclk * 2) / 3)
65562306a36Sopenharmony_ci		return -1;	/* bogus (too early) interrupt */
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (chip->get_position[stream])
65862306a36Sopenharmony_ci		pos = chip->get_position[stream](chip, azx_dev);
65962306a36Sopenharmony_ci	else { /* use the position buffer as default */
66062306a36Sopenharmony_ci		pos = azx_get_pos_posbuf(chip, azx_dev);
66162306a36Sopenharmony_ci		if (!pos || pos == (u32)-1) {
66262306a36Sopenharmony_ci			dev_info(chip->card->dev,
66362306a36Sopenharmony_ci				 "Invalid position buffer, using LPIB read method instead.\n");
66462306a36Sopenharmony_ci			chip->get_position[stream] = azx_get_pos_lpib;
66562306a36Sopenharmony_ci			if (chip->get_position[0] == azx_get_pos_lpib &&
66662306a36Sopenharmony_ci			    chip->get_position[1] == azx_get_pos_lpib)
66762306a36Sopenharmony_ci				azx_bus(chip)->use_posbuf = false;
66862306a36Sopenharmony_ci			pos = azx_get_pos_lpib(chip, azx_dev);
66962306a36Sopenharmony_ci			chip->get_delay[stream] = NULL;
67062306a36Sopenharmony_ci		} else {
67162306a36Sopenharmony_ci			chip->get_position[stream] = azx_get_pos_posbuf;
67262306a36Sopenharmony_ci			if (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)
67362306a36Sopenharmony_ci				chip->get_delay[stream] = azx_get_delay_from_lpib;
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if (pos >= azx_dev->core.bufsize)
67862306a36Sopenharmony_ci		pos = 0;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (WARN_ONCE(!azx_dev->core.period_bytes,
68162306a36Sopenharmony_ci		      "hda-intel: zero azx_dev->period_bytes"))
68262306a36Sopenharmony_ci		return -1; /* this shouldn't happen! */
68362306a36Sopenharmony_ci	if (wallclk < (azx_dev->core.period_wallclk * 5) / 4 &&
68462306a36Sopenharmony_ci	    pos % azx_dev->core.period_bytes > azx_dev->core.period_bytes / 2)
68562306a36Sopenharmony_ci		/* NG - it's below the first next period boundary */
68662306a36Sopenharmony_ci		return chip->bdl_pos_adj ? 0 : -1;
68762306a36Sopenharmony_ci	azx_dev->core.start_wallclk += wallclk;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	if (azx_dev->core.no_period_wakeup)
69062306a36Sopenharmony_ci		return 1; /* OK, no need to check period boundary */
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	if (runtime->hw_ptr_base != runtime->hw_ptr_interrupt)
69362306a36Sopenharmony_ci		return 1; /* OK, already in hwptr updating process */
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	/* check whether the period gets really elapsed */
69662306a36Sopenharmony_ci	pos = bytes_to_frames(runtime, pos);
69762306a36Sopenharmony_ci	hwptr = runtime->hw_ptr_base + pos;
69862306a36Sopenharmony_ci	if (hwptr < runtime->status->hw_ptr)
69962306a36Sopenharmony_ci		hwptr += runtime->buffer_size;
70062306a36Sopenharmony_ci	target = runtime->hw_ptr_interrupt + runtime->period_size;
70162306a36Sopenharmony_ci	if (hwptr < target) {
70262306a36Sopenharmony_ci		/* too early wakeup, process it later */
70362306a36Sopenharmony_ci		return chip->bdl_pos_adj ? 0 : -1;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	return 1; /* OK, it's fine */
70762306a36Sopenharmony_ci}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci/*
71062306a36Sopenharmony_ci * The work for pending PCM period updates.
71162306a36Sopenharmony_ci */
71262306a36Sopenharmony_cistatic void azx_irq_pending_work(struct work_struct *work)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	struct hda_intel *hda = container_of(work, struct hda_intel, irq_pending_work);
71562306a36Sopenharmony_ci	struct azx *chip = &hda->chip;
71662306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
71762306a36Sopenharmony_ci	struct hdac_stream *s;
71862306a36Sopenharmony_ci	int pending, ok;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (!hda->irq_pending_warned) {
72162306a36Sopenharmony_ci		dev_info(chip->card->dev,
72262306a36Sopenharmony_ci			 "IRQ timing workaround is activated for card #%d. Suggest a bigger bdl_pos_adj.\n",
72362306a36Sopenharmony_ci			 chip->card->number);
72462306a36Sopenharmony_ci		hda->irq_pending_warned = 1;
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	for (;;) {
72862306a36Sopenharmony_ci		pending = 0;
72962306a36Sopenharmony_ci		spin_lock_irq(&bus->reg_lock);
73062306a36Sopenharmony_ci		list_for_each_entry(s, &bus->stream_list, list) {
73162306a36Sopenharmony_ci			struct azx_dev *azx_dev = stream_to_azx_dev(s);
73262306a36Sopenharmony_ci			if (!azx_dev->irq_pending ||
73362306a36Sopenharmony_ci			    !s->substream ||
73462306a36Sopenharmony_ci			    !s->running)
73562306a36Sopenharmony_ci				continue;
73662306a36Sopenharmony_ci			ok = azx_position_ok(chip, azx_dev);
73762306a36Sopenharmony_ci			if (ok > 0) {
73862306a36Sopenharmony_ci				azx_dev->irq_pending = 0;
73962306a36Sopenharmony_ci				spin_unlock(&bus->reg_lock);
74062306a36Sopenharmony_ci				snd_pcm_period_elapsed(s->substream);
74162306a36Sopenharmony_ci				spin_lock(&bus->reg_lock);
74262306a36Sopenharmony_ci			} else if (ok < 0) {
74362306a36Sopenharmony_ci				pending = 0;	/* too early */
74462306a36Sopenharmony_ci			} else
74562306a36Sopenharmony_ci				pending++;
74662306a36Sopenharmony_ci		}
74762306a36Sopenharmony_ci		spin_unlock_irq(&bus->reg_lock);
74862306a36Sopenharmony_ci		if (!pending)
74962306a36Sopenharmony_ci			return;
75062306a36Sopenharmony_ci		msleep(1);
75162306a36Sopenharmony_ci	}
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci/* clear irq_pending flags and assure no on-going workq */
75562306a36Sopenharmony_cistatic void azx_clear_irq_pending(struct azx *chip)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
75862306a36Sopenharmony_ci	struct hdac_stream *s;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	spin_lock_irq(&bus->reg_lock);
76162306a36Sopenharmony_ci	list_for_each_entry(s, &bus->stream_list, list) {
76262306a36Sopenharmony_ci		struct azx_dev *azx_dev = stream_to_azx_dev(s);
76362306a36Sopenharmony_ci		azx_dev->irq_pending = 0;
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci	spin_unlock_irq(&bus->reg_lock);
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic int azx_acquire_irq(struct azx *chip, int do_disconnect)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	if (request_irq(chip->pci->irq, azx_interrupt,
77362306a36Sopenharmony_ci			chip->msi ? 0 : IRQF_SHARED,
77462306a36Sopenharmony_ci			chip->card->irq_descr, chip)) {
77562306a36Sopenharmony_ci		dev_err(chip->card->dev,
77662306a36Sopenharmony_ci			"unable to grab IRQ %d, disabling device\n",
77762306a36Sopenharmony_ci			chip->pci->irq);
77862306a36Sopenharmony_ci		if (do_disconnect)
77962306a36Sopenharmony_ci			snd_card_disconnect(chip->card);
78062306a36Sopenharmony_ci		return -1;
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci	bus->irq = chip->pci->irq;
78362306a36Sopenharmony_ci	chip->card->sync_irq = bus->irq;
78462306a36Sopenharmony_ci	pci_intx(chip->pci, !chip->msi);
78562306a36Sopenharmony_ci	return 0;
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci/* get the current DMA position with correction on VIA chips */
78962306a36Sopenharmony_cistatic unsigned int azx_via_get_position(struct azx *chip,
79062306a36Sopenharmony_ci					 struct azx_dev *azx_dev)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	unsigned int link_pos, mini_pos, bound_pos;
79362306a36Sopenharmony_ci	unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos;
79462306a36Sopenharmony_ci	unsigned int fifo_size;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	link_pos = snd_hdac_stream_get_pos_lpib(azx_stream(azx_dev));
79762306a36Sopenharmony_ci	if (azx_dev->core.substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
79862306a36Sopenharmony_ci		/* Playback, no problem using link position */
79962306a36Sopenharmony_ci		return link_pos;
80062306a36Sopenharmony_ci	}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	/* Capture */
80362306a36Sopenharmony_ci	/* For new chipset,
80462306a36Sopenharmony_ci	 * use mod to get the DMA position just like old chipset
80562306a36Sopenharmony_ci	 */
80662306a36Sopenharmony_ci	mod_dma_pos = le32_to_cpu(*azx_dev->core.posbuf);
80762306a36Sopenharmony_ci	mod_dma_pos %= azx_dev->core.period_bytes;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	fifo_size = azx_stream(azx_dev)->fifo_size - 1;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	if (azx_dev->insufficient) {
81262306a36Sopenharmony_ci		/* Link position never gather than FIFO size */
81362306a36Sopenharmony_ci		if (link_pos <= fifo_size)
81462306a36Sopenharmony_ci			return 0;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci		azx_dev->insufficient = 0;
81762306a36Sopenharmony_ci	}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	if (link_pos <= fifo_size)
82062306a36Sopenharmony_ci		mini_pos = azx_dev->core.bufsize + link_pos - fifo_size;
82162306a36Sopenharmony_ci	else
82262306a36Sopenharmony_ci		mini_pos = link_pos - fifo_size;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	/* Find nearest previous boudary */
82562306a36Sopenharmony_ci	mod_mini_pos = mini_pos % azx_dev->core.period_bytes;
82662306a36Sopenharmony_ci	mod_link_pos = link_pos % azx_dev->core.period_bytes;
82762306a36Sopenharmony_ci	if (mod_link_pos >= fifo_size)
82862306a36Sopenharmony_ci		bound_pos = link_pos - mod_link_pos;
82962306a36Sopenharmony_ci	else if (mod_dma_pos >= mod_mini_pos)
83062306a36Sopenharmony_ci		bound_pos = mini_pos - mod_mini_pos;
83162306a36Sopenharmony_ci	else {
83262306a36Sopenharmony_ci		bound_pos = mini_pos - mod_mini_pos + azx_dev->core.period_bytes;
83362306a36Sopenharmony_ci		if (bound_pos >= azx_dev->core.bufsize)
83462306a36Sopenharmony_ci			bound_pos = 0;
83562306a36Sopenharmony_ci	}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	/* Calculate real DMA position we want */
83862306a36Sopenharmony_ci	return bound_pos + mod_dma_pos;
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci#define AMD_FIFO_SIZE	32
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci/* get the current DMA position with FIFO size correction */
84462306a36Sopenharmony_cistatic unsigned int azx_get_pos_fifo(struct azx *chip, struct azx_dev *azx_dev)
84562306a36Sopenharmony_ci{
84662306a36Sopenharmony_ci	struct snd_pcm_substream *substream = azx_dev->core.substream;
84762306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
84862306a36Sopenharmony_ci	unsigned int pos, delay;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	pos = snd_hdac_stream_get_pos_lpib(azx_stream(azx_dev));
85162306a36Sopenharmony_ci	if (!runtime)
85262306a36Sopenharmony_ci		return pos;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	runtime->delay = AMD_FIFO_SIZE;
85562306a36Sopenharmony_ci	delay = frames_to_bytes(runtime, AMD_FIFO_SIZE);
85662306a36Sopenharmony_ci	if (azx_dev->insufficient) {
85762306a36Sopenharmony_ci		if (pos < delay) {
85862306a36Sopenharmony_ci			delay = pos;
85962306a36Sopenharmony_ci			runtime->delay = bytes_to_frames(runtime, pos);
86062306a36Sopenharmony_ci		} else {
86162306a36Sopenharmony_ci			azx_dev->insufficient = 0;
86262306a36Sopenharmony_ci		}
86362306a36Sopenharmony_ci	}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/* correct the DMA position for capture stream */
86662306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
86762306a36Sopenharmony_ci		if (pos < delay)
86862306a36Sopenharmony_ci			pos += azx_dev->core.bufsize;
86962306a36Sopenharmony_ci		pos -= delay;
87062306a36Sopenharmony_ci	}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	return pos;
87362306a36Sopenharmony_ci}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_cistatic int azx_get_delay_from_fifo(struct azx *chip, struct azx_dev *azx_dev,
87662306a36Sopenharmony_ci				   unsigned int pos)
87762306a36Sopenharmony_ci{
87862306a36Sopenharmony_ci	struct snd_pcm_substream *substream = azx_dev->core.substream;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	/* just read back the calculated value in the above */
88162306a36Sopenharmony_ci	return substream->runtime->delay;
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_cistatic void __azx_shutdown_chip(struct azx *chip, bool skip_link_reset)
88562306a36Sopenharmony_ci{
88662306a36Sopenharmony_ci	azx_stop_chip(chip);
88762306a36Sopenharmony_ci	if (!skip_link_reset)
88862306a36Sopenharmony_ci		azx_enter_link_reset(chip);
88962306a36Sopenharmony_ci	azx_clear_irq_pending(chip);
89062306a36Sopenharmony_ci	display_power(chip, false);
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci#ifdef CONFIG_PM
89462306a36Sopenharmony_cistatic DEFINE_MUTEX(card_list_lock);
89562306a36Sopenharmony_cistatic LIST_HEAD(card_list);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_cistatic void azx_shutdown_chip(struct azx *chip)
89862306a36Sopenharmony_ci{
89962306a36Sopenharmony_ci	__azx_shutdown_chip(chip, false);
90062306a36Sopenharmony_ci}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_cistatic void azx_add_card_list(struct azx *chip)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
90562306a36Sopenharmony_ci	mutex_lock(&card_list_lock);
90662306a36Sopenharmony_ci	list_add(&hda->list, &card_list);
90762306a36Sopenharmony_ci	mutex_unlock(&card_list_lock);
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_cistatic void azx_del_card_list(struct azx *chip)
91162306a36Sopenharmony_ci{
91262306a36Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
91362306a36Sopenharmony_ci	mutex_lock(&card_list_lock);
91462306a36Sopenharmony_ci	list_del_init(&hda->list);
91562306a36Sopenharmony_ci	mutex_unlock(&card_list_lock);
91662306a36Sopenharmony_ci}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci/* trigger power-save check at writing parameter */
91962306a36Sopenharmony_cistatic int param_set_xint(const char *val, const struct kernel_param *kp)
92062306a36Sopenharmony_ci{
92162306a36Sopenharmony_ci	struct hda_intel *hda;
92262306a36Sopenharmony_ci	struct azx *chip;
92362306a36Sopenharmony_ci	int prev = power_save;
92462306a36Sopenharmony_ci	int ret = param_set_int(val, kp);
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	if (ret || prev == power_save)
92762306a36Sopenharmony_ci		return ret;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	mutex_lock(&card_list_lock);
93062306a36Sopenharmony_ci	list_for_each_entry(hda, &card_list, list) {
93162306a36Sopenharmony_ci		chip = &hda->chip;
93262306a36Sopenharmony_ci		if (!hda->probe_continued || chip->disabled)
93362306a36Sopenharmony_ci			continue;
93462306a36Sopenharmony_ci		snd_hda_set_power_save(&chip->bus, power_save * 1000);
93562306a36Sopenharmony_ci	}
93662306a36Sopenharmony_ci	mutex_unlock(&card_list_lock);
93762306a36Sopenharmony_ci	return 0;
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci/*
94162306a36Sopenharmony_ci * power management
94262306a36Sopenharmony_ci */
94362306a36Sopenharmony_cistatic bool azx_is_pm_ready(struct snd_card *card)
94462306a36Sopenharmony_ci{
94562306a36Sopenharmony_ci	struct azx *chip;
94662306a36Sopenharmony_ci	struct hda_intel *hda;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	if (!card)
94962306a36Sopenharmony_ci		return false;
95062306a36Sopenharmony_ci	chip = card->private_data;
95162306a36Sopenharmony_ci	hda = container_of(chip, struct hda_intel, chip);
95262306a36Sopenharmony_ci	if (chip->disabled || hda->init_failed || !chip->running)
95362306a36Sopenharmony_ci		return false;
95462306a36Sopenharmony_ci	return true;
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic void __azx_runtime_resume(struct azx *chip)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
96062306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
96162306a36Sopenharmony_ci	struct hda_codec *codec;
96262306a36Sopenharmony_ci	int status;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	display_power(chip, true);
96562306a36Sopenharmony_ci	if (hda->need_i915_power)
96662306a36Sopenharmony_ci		snd_hdac_i915_set_bclk(bus);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	/* Read STATESTS before controller reset */
96962306a36Sopenharmony_ci	status = azx_readw(chip, STATESTS);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	azx_init_pci(chip);
97262306a36Sopenharmony_ci	hda_intel_init_chip(chip, true);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	/* Avoid codec resume if runtime resume is for system suspend */
97562306a36Sopenharmony_ci	if (!chip->pm_prepared) {
97662306a36Sopenharmony_ci		list_for_each_codec(codec, &chip->bus) {
97762306a36Sopenharmony_ci			if (codec->relaxed_resume)
97862306a36Sopenharmony_ci				continue;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci			if (codec->forced_resume || (status & (1 << codec->addr)))
98162306a36Sopenharmony_ci				pm_request_resume(hda_codec_dev(codec));
98262306a36Sopenharmony_ci		}
98362306a36Sopenharmony_ci	}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	/* power down again for link-controlled chips */
98662306a36Sopenharmony_ci	if (!hda->need_i915_power)
98762306a36Sopenharmony_ci		display_power(chip, false);
98862306a36Sopenharmony_ci}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
99162306a36Sopenharmony_cistatic int azx_prepare(struct device *dev)
99262306a36Sopenharmony_ci{
99362306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
99462306a36Sopenharmony_ci	struct azx *chip;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	if (!azx_is_pm_ready(card))
99762306a36Sopenharmony_ci		return 0;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	chip = card->private_data;
100062306a36Sopenharmony_ci	chip->pm_prepared = 1;
100162306a36Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	flush_work(&azx_bus(chip)->unsol_work);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	/* HDA controller always requires different WAKEEN for runtime suspend
100662306a36Sopenharmony_ci	 * and system suspend, so don't use direct-complete here.
100762306a36Sopenharmony_ci	 */
100862306a36Sopenharmony_ci	return 0;
100962306a36Sopenharmony_ci}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_cistatic void azx_complete(struct device *dev)
101262306a36Sopenharmony_ci{
101362306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
101462306a36Sopenharmony_ci	struct azx *chip;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	if (!azx_is_pm_ready(card))
101762306a36Sopenharmony_ci		return;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	chip = card->private_data;
102062306a36Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
102162306a36Sopenharmony_ci	chip->pm_prepared = 0;
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic int azx_suspend(struct device *dev)
102562306a36Sopenharmony_ci{
102662306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
102762306a36Sopenharmony_ci	struct azx *chip;
102862306a36Sopenharmony_ci	struct hdac_bus *bus;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	if (!azx_is_pm_ready(card))
103162306a36Sopenharmony_ci		return 0;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	chip = card->private_data;
103462306a36Sopenharmony_ci	bus = azx_bus(chip);
103562306a36Sopenharmony_ci	azx_shutdown_chip(chip);
103662306a36Sopenharmony_ci	if (bus->irq >= 0) {
103762306a36Sopenharmony_ci		free_irq(bus->irq, chip);
103862306a36Sopenharmony_ci		bus->irq = -1;
103962306a36Sopenharmony_ci		chip->card->sync_irq = -1;
104062306a36Sopenharmony_ci	}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	if (chip->msi)
104362306a36Sopenharmony_ci		pci_disable_msi(chip->pci);
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	trace_azx_suspend(chip);
104662306a36Sopenharmony_ci	return 0;
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_cistatic int azx_resume(struct device *dev)
105062306a36Sopenharmony_ci{
105162306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
105262306a36Sopenharmony_ci	struct azx *chip;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	if (!azx_is_pm_ready(card))
105562306a36Sopenharmony_ci		return 0;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	chip = card->private_data;
105862306a36Sopenharmony_ci	if (chip->msi)
105962306a36Sopenharmony_ci		if (pci_enable_msi(chip->pci) < 0)
106062306a36Sopenharmony_ci			chip->msi = 0;
106162306a36Sopenharmony_ci	if (azx_acquire_irq(chip, 1) < 0)
106262306a36Sopenharmony_ci		return -EIO;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	__azx_runtime_resume(chip);
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	trace_azx_resume(chip);
106762306a36Sopenharmony_ci	return 0;
106862306a36Sopenharmony_ci}
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci/* put codec down to D3 at hibernation for Intel SKL+;
107162306a36Sopenharmony_ci * otherwise BIOS may still access the codec and screw up the driver
107262306a36Sopenharmony_ci */
107362306a36Sopenharmony_cistatic int azx_freeze_noirq(struct device *dev)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
107662306a36Sopenharmony_ci	struct azx *chip = card->private_data;
107762306a36Sopenharmony_ci	struct pci_dev *pci = to_pci_dev(dev);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	if (!azx_is_pm_ready(card))
108062306a36Sopenharmony_ci		return 0;
108162306a36Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_SKL)
108262306a36Sopenharmony_ci		pci_set_power_state(pci, PCI_D3hot);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	return 0;
108562306a36Sopenharmony_ci}
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_cistatic int azx_thaw_noirq(struct device *dev)
108862306a36Sopenharmony_ci{
108962306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
109062306a36Sopenharmony_ci	struct azx *chip = card->private_data;
109162306a36Sopenharmony_ci	struct pci_dev *pci = to_pci_dev(dev);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	if (!azx_is_pm_ready(card))
109462306a36Sopenharmony_ci		return 0;
109562306a36Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_SKL)
109662306a36Sopenharmony_ci		pci_set_power_state(pci, PCI_D0);
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	return 0;
109962306a36Sopenharmony_ci}
110062306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_cistatic int azx_runtime_suspend(struct device *dev)
110362306a36Sopenharmony_ci{
110462306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
110562306a36Sopenharmony_ci	struct azx *chip;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	if (!azx_is_pm_ready(card))
110862306a36Sopenharmony_ci		return 0;
110962306a36Sopenharmony_ci	chip = card->private_data;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	/* enable controller wake up event */
111262306a36Sopenharmony_ci	azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | STATESTS_INT_MASK);
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	azx_shutdown_chip(chip);
111562306a36Sopenharmony_ci	trace_azx_runtime_suspend(chip);
111662306a36Sopenharmony_ci	return 0;
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_cistatic int azx_runtime_resume(struct device *dev)
112062306a36Sopenharmony_ci{
112162306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
112262306a36Sopenharmony_ci	struct azx *chip;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	if (!azx_is_pm_ready(card))
112562306a36Sopenharmony_ci		return 0;
112662306a36Sopenharmony_ci	chip = card->private_data;
112762306a36Sopenharmony_ci	__azx_runtime_resume(chip);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	/* disable controller Wake Up event*/
113062306a36Sopenharmony_ci	azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & ~STATESTS_INT_MASK);
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	trace_azx_runtime_resume(chip);
113362306a36Sopenharmony_ci	return 0;
113462306a36Sopenharmony_ci}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_cistatic int azx_runtime_idle(struct device *dev)
113762306a36Sopenharmony_ci{
113862306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
113962306a36Sopenharmony_ci	struct azx *chip;
114062306a36Sopenharmony_ci	struct hda_intel *hda;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	if (!card)
114362306a36Sopenharmony_ci		return 0;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	chip = card->private_data;
114662306a36Sopenharmony_ci	hda = container_of(chip, struct hda_intel, chip);
114762306a36Sopenharmony_ci	if (chip->disabled || hda->init_failed)
114862306a36Sopenharmony_ci		return 0;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	if (!power_save_controller || !azx_has_pm_runtime(chip) ||
115162306a36Sopenharmony_ci	    azx_bus(chip)->codec_powered || !chip->running)
115262306a36Sopenharmony_ci		return -EBUSY;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	/* ELD notification gets broken when HD-audio bus is off */
115562306a36Sopenharmony_ci	if (needs_eld_notify_link(chip))
115662306a36Sopenharmony_ci		return -EBUSY;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	return 0;
115962306a36Sopenharmony_ci}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_cistatic const struct dev_pm_ops azx_pm = {
116262306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume)
116362306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
116462306a36Sopenharmony_ci	.prepare = azx_prepare,
116562306a36Sopenharmony_ci	.complete = azx_complete,
116662306a36Sopenharmony_ci	.freeze_noirq = azx_freeze_noirq,
116762306a36Sopenharmony_ci	.thaw_noirq = azx_thaw_noirq,
116862306a36Sopenharmony_ci#endif
116962306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle)
117062306a36Sopenharmony_ci};
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci#define AZX_PM_OPS	&azx_pm
117362306a36Sopenharmony_ci#else
117462306a36Sopenharmony_ci#define azx_add_card_list(chip) /* NOP */
117562306a36Sopenharmony_ci#define azx_del_card_list(chip) /* NOP */
117662306a36Sopenharmony_ci#define AZX_PM_OPS	NULL
117762306a36Sopenharmony_ci#endif /* CONFIG_PM */
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic int azx_probe_continue(struct azx *chip);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci#ifdef SUPPORT_VGA_SWITCHEROO
118362306a36Sopenharmony_cistatic struct pci_dev *get_bound_vga(struct pci_dev *pci);
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_cistatic void azx_vs_set_state(struct pci_dev *pci,
118662306a36Sopenharmony_ci			     enum vga_switcheroo_state state)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	struct snd_card *card = pci_get_drvdata(pci);
118962306a36Sopenharmony_ci	struct azx *chip = card->private_data;
119062306a36Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
119162306a36Sopenharmony_ci	struct hda_codec *codec;
119262306a36Sopenharmony_ci	bool disabled;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	wait_for_completion(&hda->probe_wait);
119562306a36Sopenharmony_ci	if (hda->init_failed)
119662306a36Sopenharmony_ci		return;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	disabled = (state == VGA_SWITCHEROO_OFF);
119962306a36Sopenharmony_ci	if (chip->disabled == disabled)
120062306a36Sopenharmony_ci		return;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	if (!hda->probe_continued) {
120362306a36Sopenharmony_ci		chip->disabled = disabled;
120462306a36Sopenharmony_ci		if (!disabled) {
120562306a36Sopenharmony_ci			dev_info(chip->card->dev,
120662306a36Sopenharmony_ci				 "Start delayed initialization\n");
120762306a36Sopenharmony_ci			if (azx_probe_continue(chip) < 0)
120862306a36Sopenharmony_ci				dev_err(chip->card->dev, "initialization error\n");
120962306a36Sopenharmony_ci		}
121062306a36Sopenharmony_ci	} else {
121162306a36Sopenharmony_ci		dev_info(chip->card->dev, "%s via vga_switcheroo\n",
121262306a36Sopenharmony_ci			 disabled ? "Disabling" : "Enabling");
121362306a36Sopenharmony_ci		if (disabled) {
121462306a36Sopenharmony_ci			list_for_each_codec(codec, &chip->bus) {
121562306a36Sopenharmony_ci				pm_runtime_suspend(hda_codec_dev(codec));
121662306a36Sopenharmony_ci				pm_runtime_disable(hda_codec_dev(codec));
121762306a36Sopenharmony_ci			}
121862306a36Sopenharmony_ci			pm_runtime_suspend(card->dev);
121962306a36Sopenharmony_ci			pm_runtime_disable(card->dev);
122062306a36Sopenharmony_ci			/* when we get suspended by vga_switcheroo we end up in D3cold,
122162306a36Sopenharmony_ci			 * however we have no ACPI handle, so pci/acpi can't put us there,
122262306a36Sopenharmony_ci			 * put ourselves there */
122362306a36Sopenharmony_ci			pci->current_state = PCI_D3cold;
122462306a36Sopenharmony_ci			chip->disabled = true;
122562306a36Sopenharmony_ci			if (snd_hda_lock_devices(&chip->bus))
122662306a36Sopenharmony_ci				dev_warn(chip->card->dev,
122762306a36Sopenharmony_ci					 "Cannot lock devices!\n");
122862306a36Sopenharmony_ci		} else {
122962306a36Sopenharmony_ci			snd_hda_unlock_devices(&chip->bus);
123062306a36Sopenharmony_ci			chip->disabled = false;
123162306a36Sopenharmony_ci			pm_runtime_enable(card->dev);
123262306a36Sopenharmony_ci			list_for_each_codec(codec, &chip->bus) {
123362306a36Sopenharmony_ci				pm_runtime_enable(hda_codec_dev(codec));
123462306a36Sopenharmony_ci				pm_runtime_resume(hda_codec_dev(codec));
123562306a36Sopenharmony_ci			}
123662306a36Sopenharmony_ci		}
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_cistatic bool azx_vs_can_switch(struct pci_dev *pci)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	struct snd_card *card = pci_get_drvdata(pci);
124362306a36Sopenharmony_ci	struct azx *chip = card->private_data;
124462306a36Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	wait_for_completion(&hda->probe_wait);
124762306a36Sopenharmony_ci	if (hda->init_failed)
124862306a36Sopenharmony_ci		return false;
124962306a36Sopenharmony_ci	if (chip->disabled || !hda->probe_continued)
125062306a36Sopenharmony_ci		return true;
125162306a36Sopenharmony_ci	if (snd_hda_lock_devices(&chip->bus))
125262306a36Sopenharmony_ci		return false;
125362306a36Sopenharmony_ci	snd_hda_unlock_devices(&chip->bus);
125462306a36Sopenharmony_ci	return true;
125562306a36Sopenharmony_ci}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci/*
125862306a36Sopenharmony_ci * The discrete GPU cannot power down unless the HDA controller runtime
125962306a36Sopenharmony_ci * suspends, so activate runtime PM on codecs even if power_save == 0.
126062306a36Sopenharmony_ci */
126162306a36Sopenharmony_cistatic void setup_vga_switcheroo_runtime_pm(struct azx *chip)
126262306a36Sopenharmony_ci{
126362306a36Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
126462306a36Sopenharmony_ci	struct hda_codec *codec;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	if (hda->use_vga_switcheroo && !needs_eld_notify_link(chip)) {
126762306a36Sopenharmony_ci		list_for_each_codec(codec, &chip->bus)
126862306a36Sopenharmony_ci			codec->auto_runtime_pm = 1;
126962306a36Sopenharmony_ci		/* reset the power save setup */
127062306a36Sopenharmony_ci		if (chip->running)
127162306a36Sopenharmony_ci			set_default_power_save(chip);
127262306a36Sopenharmony_ci	}
127362306a36Sopenharmony_ci}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_cistatic void azx_vs_gpu_bound(struct pci_dev *pci,
127662306a36Sopenharmony_ci			     enum vga_switcheroo_client_id client_id)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	struct snd_card *card = pci_get_drvdata(pci);
127962306a36Sopenharmony_ci	struct azx *chip = card->private_data;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	if (client_id == VGA_SWITCHEROO_DIS)
128262306a36Sopenharmony_ci		chip->bus.keep_power = 0;
128362306a36Sopenharmony_ci	setup_vga_switcheroo_runtime_pm(chip);
128462306a36Sopenharmony_ci}
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_cistatic void init_vga_switcheroo(struct azx *chip)
128762306a36Sopenharmony_ci{
128862306a36Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
128962306a36Sopenharmony_ci	struct pci_dev *p = get_bound_vga(chip->pci);
129062306a36Sopenharmony_ci	struct pci_dev *parent;
129162306a36Sopenharmony_ci	if (p) {
129262306a36Sopenharmony_ci		dev_info(chip->card->dev,
129362306a36Sopenharmony_ci			 "Handle vga_switcheroo audio client\n");
129462306a36Sopenharmony_ci		hda->use_vga_switcheroo = 1;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci		/* cleared in either gpu_bound op or codec probe, or when its
129762306a36Sopenharmony_ci		 * upstream port has _PR3 (i.e. dGPU).
129862306a36Sopenharmony_ci		 */
129962306a36Sopenharmony_ci		parent = pci_upstream_bridge(p);
130062306a36Sopenharmony_ci		chip->bus.keep_power = parent ? !pci_pr3_present(parent) : 1;
130162306a36Sopenharmony_ci		chip->driver_caps |= AZX_DCAPS_PM_RUNTIME;
130262306a36Sopenharmony_ci		pci_dev_put(p);
130362306a36Sopenharmony_ci	}
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_cistatic const struct vga_switcheroo_client_ops azx_vs_ops = {
130762306a36Sopenharmony_ci	.set_gpu_state = azx_vs_set_state,
130862306a36Sopenharmony_ci	.can_switch = azx_vs_can_switch,
130962306a36Sopenharmony_ci	.gpu_bound = azx_vs_gpu_bound,
131062306a36Sopenharmony_ci};
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_cistatic int register_vga_switcheroo(struct azx *chip)
131362306a36Sopenharmony_ci{
131462306a36Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
131562306a36Sopenharmony_ci	struct pci_dev *p;
131662306a36Sopenharmony_ci	int err;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	if (!hda->use_vga_switcheroo)
131962306a36Sopenharmony_ci		return 0;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	p = get_bound_vga(chip->pci);
132262306a36Sopenharmony_ci	err = vga_switcheroo_register_audio_client(chip->pci, &azx_vs_ops, p);
132362306a36Sopenharmony_ci	pci_dev_put(p);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	if (err < 0)
132662306a36Sopenharmony_ci		return err;
132762306a36Sopenharmony_ci	hda->vga_switcheroo_registered = 1;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	return 0;
133062306a36Sopenharmony_ci}
133162306a36Sopenharmony_ci#else
133262306a36Sopenharmony_ci#define init_vga_switcheroo(chip)		/* NOP */
133362306a36Sopenharmony_ci#define register_vga_switcheroo(chip)		0
133462306a36Sopenharmony_ci#define check_hdmi_disabled(pci)	false
133562306a36Sopenharmony_ci#define setup_vga_switcheroo_runtime_pm(chip)	/* NOP */
133662306a36Sopenharmony_ci#endif /* SUPPORT_VGA_SWITCHER */
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci/*
133962306a36Sopenharmony_ci * destructor
134062306a36Sopenharmony_ci */
134162306a36Sopenharmony_cistatic void azx_free(struct azx *chip)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	struct pci_dev *pci = chip->pci;
134462306a36Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
134562306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	if (hda->freed)
134862306a36Sopenharmony_ci		return;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	if (azx_has_pm_runtime(chip) && chip->running) {
135162306a36Sopenharmony_ci		pm_runtime_get_noresume(&pci->dev);
135262306a36Sopenharmony_ci		pm_runtime_forbid(&pci->dev);
135362306a36Sopenharmony_ci		pm_runtime_dont_use_autosuspend(&pci->dev);
135462306a36Sopenharmony_ci	}
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	chip->running = 0;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	azx_del_card_list(chip);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	hda->init_failed = 1; /* to be sure */
136162306a36Sopenharmony_ci	complete_all(&hda->probe_wait);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	if (use_vga_switcheroo(hda)) {
136462306a36Sopenharmony_ci		if (chip->disabled && hda->probe_continued)
136562306a36Sopenharmony_ci			snd_hda_unlock_devices(&chip->bus);
136662306a36Sopenharmony_ci		if (hda->vga_switcheroo_registered)
136762306a36Sopenharmony_ci			vga_switcheroo_unregister_client(chip->pci);
136862306a36Sopenharmony_ci	}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	if (bus->chip_init) {
137162306a36Sopenharmony_ci		azx_clear_irq_pending(chip);
137262306a36Sopenharmony_ci		azx_stop_all_streams(chip);
137362306a36Sopenharmony_ci		azx_stop_chip(chip);
137462306a36Sopenharmony_ci	}
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	if (bus->irq >= 0)
137762306a36Sopenharmony_ci		free_irq(bus->irq, (void*)chip);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	azx_free_stream_pages(chip);
138062306a36Sopenharmony_ci	azx_free_streams(chip);
138162306a36Sopenharmony_ci	snd_hdac_bus_exit(bus);
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci#ifdef CONFIG_SND_HDA_PATCH_LOADER
138462306a36Sopenharmony_ci	release_firmware(chip->fw);
138562306a36Sopenharmony_ci#endif
138662306a36Sopenharmony_ci	display_power(chip, false);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT)
138962306a36Sopenharmony_ci		snd_hdac_i915_exit(bus);
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	hda->freed = 1;
139262306a36Sopenharmony_ci}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_cistatic int azx_dev_disconnect(struct snd_device *device)
139562306a36Sopenharmony_ci{
139662306a36Sopenharmony_ci	struct azx *chip = device->device_data;
139762306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	chip->bus.shutdown = 1;
140062306a36Sopenharmony_ci	cancel_work_sync(&bus->unsol_work);
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	return 0;
140362306a36Sopenharmony_ci}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_cistatic int azx_dev_free(struct snd_device *device)
140662306a36Sopenharmony_ci{
140762306a36Sopenharmony_ci	azx_free(device->device_data);
140862306a36Sopenharmony_ci	return 0;
140962306a36Sopenharmony_ci}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci#ifdef SUPPORT_VGA_SWITCHEROO
141262306a36Sopenharmony_ci#ifdef CONFIG_ACPI
141362306a36Sopenharmony_ci/* ATPX is in the integrated GPU's namespace */
141462306a36Sopenharmony_cistatic bool atpx_present(void)
141562306a36Sopenharmony_ci{
141662306a36Sopenharmony_ci	struct pci_dev *pdev = NULL;
141762306a36Sopenharmony_ci	acpi_handle dhandle, atpx_handle;
141862306a36Sopenharmony_ci	acpi_status status;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
142162306a36Sopenharmony_ci		dhandle = ACPI_HANDLE(&pdev->dev);
142262306a36Sopenharmony_ci		if (dhandle) {
142362306a36Sopenharmony_ci			status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
142462306a36Sopenharmony_ci			if (ACPI_SUCCESS(status)) {
142562306a36Sopenharmony_ci				pci_dev_put(pdev);
142662306a36Sopenharmony_ci				return true;
142762306a36Sopenharmony_ci			}
142862306a36Sopenharmony_ci		}
142962306a36Sopenharmony_ci	}
143062306a36Sopenharmony_ci	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
143162306a36Sopenharmony_ci		dhandle = ACPI_HANDLE(&pdev->dev);
143262306a36Sopenharmony_ci		if (dhandle) {
143362306a36Sopenharmony_ci			status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
143462306a36Sopenharmony_ci			if (ACPI_SUCCESS(status)) {
143562306a36Sopenharmony_ci				pci_dev_put(pdev);
143662306a36Sopenharmony_ci				return true;
143762306a36Sopenharmony_ci			}
143862306a36Sopenharmony_ci		}
143962306a36Sopenharmony_ci	}
144062306a36Sopenharmony_ci	return false;
144162306a36Sopenharmony_ci}
144262306a36Sopenharmony_ci#else
144362306a36Sopenharmony_cistatic bool atpx_present(void)
144462306a36Sopenharmony_ci{
144562306a36Sopenharmony_ci	return false;
144662306a36Sopenharmony_ci}
144762306a36Sopenharmony_ci#endif
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci/*
145062306a36Sopenharmony_ci * Check of disabled HDMI controller by vga_switcheroo
145162306a36Sopenharmony_ci */
145262306a36Sopenharmony_cistatic struct pci_dev *get_bound_vga(struct pci_dev *pci)
145362306a36Sopenharmony_ci{
145462306a36Sopenharmony_ci	struct pci_dev *p;
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	/* check only discrete GPU */
145762306a36Sopenharmony_ci	switch (pci->vendor) {
145862306a36Sopenharmony_ci	case PCI_VENDOR_ID_ATI:
145962306a36Sopenharmony_ci	case PCI_VENDOR_ID_AMD:
146062306a36Sopenharmony_ci		if (pci->devfn == 1) {
146162306a36Sopenharmony_ci			p = pci_get_domain_bus_and_slot(pci_domain_nr(pci->bus),
146262306a36Sopenharmony_ci							pci->bus->number, 0);
146362306a36Sopenharmony_ci			if (p) {
146462306a36Sopenharmony_ci				/* ATPX is in the integrated GPU's ACPI namespace
146562306a36Sopenharmony_ci				 * rather than the dGPU's namespace. However,
146662306a36Sopenharmony_ci				 * the dGPU is the one who is involved in
146762306a36Sopenharmony_ci				 * vgaswitcheroo.
146862306a36Sopenharmony_ci				 */
146962306a36Sopenharmony_ci				if (((p->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
147062306a36Sopenharmony_ci				    (atpx_present() || apple_gmux_detect(NULL, NULL)))
147162306a36Sopenharmony_ci					return p;
147262306a36Sopenharmony_ci				pci_dev_put(p);
147362306a36Sopenharmony_ci			}
147462306a36Sopenharmony_ci		}
147562306a36Sopenharmony_ci		break;
147662306a36Sopenharmony_ci	case PCI_VENDOR_ID_NVIDIA:
147762306a36Sopenharmony_ci		if (pci->devfn == 1) {
147862306a36Sopenharmony_ci			p = pci_get_domain_bus_and_slot(pci_domain_nr(pci->bus),
147962306a36Sopenharmony_ci							pci->bus->number, 0);
148062306a36Sopenharmony_ci			if (p) {
148162306a36Sopenharmony_ci				if ((p->class >> 16) == PCI_BASE_CLASS_DISPLAY)
148262306a36Sopenharmony_ci					return p;
148362306a36Sopenharmony_ci				pci_dev_put(p);
148462306a36Sopenharmony_ci			}
148562306a36Sopenharmony_ci		}
148662306a36Sopenharmony_ci		break;
148762306a36Sopenharmony_ci	}
148862306a36Sopenharmony_ci	return NULL;
148962306a36Sopenharmony_ci}
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_cistatic bool check_hdmi_disabled(struct pci_dev *pci)
149262306a36Sopenharmony_ci{
149362306a36Sopenharmony_ci	bool vga_inactive = false;
149462306a36Sopenharmony_ci	struct pci_dev *p = get_bound_vga(pci);
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	if (p) {
149762306a36Sopenharmony_ci		if (vga_switcheroo_get_client_state(p) == VGA_SWITCHEROO_OFF)
149862306a36Sopenharmony_ci			vga_inactive = true;
149962306a36Sopenharmony_ci		pci_dev_put(p);
150062306a36Sopenharmony_ci	}
150162306a36Sopenharmony_ci	return vga_inactive;
150262306a36Sopenharmony_ci}
150362306a36Sopenharmony_ci#endif /* SUPPORT_VGA_SWITCHEROO */
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci/*
150662306a36Sopenharmony_ci * allow/deny-listing for position_fix
150762306a36Sopenharmony_ci */
150862306a36Sopenharmony_cistatic const struct snd_pci_quirk position_fix_list[] = {
150962306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
151062306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
151162306a36Sopenharmony_ci	SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
151262306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
151362306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
151462306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
151562306a36Sopenharmony_ci	SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
151662306a36Sopenharmony_ci	SND_PCI_QUIRK(0x10de, 0xcb89, "Macbook Pro 7,1", POS_FIX_LPIB),
151762306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB),
151862306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB),
151962306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
152062306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB),
152162306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB),
152262306a36Sopenharmony_ci	SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB),
152362306a36Sopenharmony_ci	{}
152462306a36Sopenharmony_ci};
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_cistatic int check_position_fix(struct azx *chip, int fix)
152762306a36Sopenharmony_ci{
152862306a36Sopenharmony_ci	const struct snd_pci_quirk *q;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	switch (fix) {
153162306a36Sopenharmony_ci	case POS_FIX_AUTO:
153262306a36Sopenharmony_ci	case POS_FIX_LPIB:
153362306a36Sopenharmony_ci	case POS_FIX_POSBUF:
153462306a36Sopenharmony_ci	case POS_FIX_VIACOMBO:
153562306a36Sopenharmony_ci	case POS_FIX_COMBO:
153662306a36Sopenharmony_ci	case POS_FIX_SKL:
153762306a36Sopenharmony_ci	case POS_FIX_FIFO:
153862306a36Sopenharmony_ci		return fix;
153962306a36Sopenharmony_ci	}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
154262306a36Sopenharmony_ci	if (q) {
154362306a36Sopenharmony_ci		dev_info(chip->card->dev,
154462306a36Sopenharmony_ci			 "position_fix set to %d for device %04x:%04x\n",
154562306a36Sopenharmony_ci			 q->value, q->subvendor, q->subdevice);
154662306a36Sopenharmony_ci		return q->value;
154762306a36Sopenharmony_ci	}
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	/* Check VIA/ATI HD Audio Controller exist */
155062306a36Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_VIA) {
155162306a36Sopenharmony_ci		dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n");
155262306a36Sopenharmony_ci		return POS_FIX_VIACOMBO;
155362306a36Sopenharmony_ci	}
155462306a36Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_AMD_WORKAROUND) {
155562306a36Sopenharmony_ci		dev_dbg(chip->card->dev, "Using FIFO position fix\n");
155662306a36Sopenharmony_ci		return POS_FIX_FIFO;
155762306a36Sopenharmony_ci	}
155862306a36Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) {
155962306a36Sopenharmony_ci		dev_dbg(chip->card->dev, "Using LPIB position fix\n");
156062306a36Sopenharmony_ci		return POS_FIX_LPIB;
156162306a36Sopenharmony_ci	}
156262306a36Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_SKL) {
156362306a36Sopenharmony_ci		dev_dbg(chip->card->dev, "Using SKL position fix\n");
156462306a36Sopenharmony_ci		return POS_FIX_SKL;
156562306a36Sopenharmony_ci	}
156662306a36Sopenharmony_ci	return POS_FIX_AUTO;
156762306a36Sopenharmony_ci}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_cistatic void assign_position_fix(struct azx *chip, int fix)
157062306a36Sopenharmony_ci{
157162306a36Sopenharmony_ci	static const azx_get_pos_callback_t callbacks[] = {
157262306a36Sopenharmony_ci		[POS_FIX_AUTO] = NULL,
157362306a36Sopenharmony_ci		[POS_FIX_LPIB] = azx_get_pos_lpib,
157462306a36Sopenharmony_ci		[POS_FIX_POSBUF] = azx_get_pos_posbuf,
157562306a36Sopenharmony_ci		[POS_FIX_VIACOMBO] = azx_via_get_position,
157662306a36Sopenharmony_ci		[POS_FIX_COMBO] = azx_get_pos_lpib,
157762306a36Sopenharmony_ci		[POS_FIX_SKL] = azx_get_pos_posbuf,
157862306a36Sopenharmony_ci		[POS_FIX_FIFO] = azx_get_pos_fifo,
157962306a36Sopenharmony_ci	};
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	chip->get_position[0] = chip->get_position[1] = callbacks[fix];
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	/* combo mode uses LPIB only for playback */
158462306a36Sopenharmony_ci	if (fix == POS_FIX_COMBO)
158562306a36Sopenharmony_ci		chip->get_position[1] = NULL;
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	if ((fix == POS_FIX_POSBUF || fix == POS_FIX_SKL) &&
158862306a36Sopenharmony_ci	    (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
158962306a36Sopenharmony_ci		chip->get_delay[0] = chip->get_delay[1] =
159062306a36Sopenharmony_ci			azx_get_delay_from_lpib;
159162306a36Sopenharmony_ci	}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	if (fix == POS_FIX_FIFO)
159462306a36Sopenharmony_ci		chip->get_delay[0] = chip->get_delay[1] =
159562306a36Sopenharmony_ci			azx_get_delay_from_fifo;
159662306a36Sopenharmony_ci}
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci/*
159962306a36Sopenharmony_ci * deny-lists for probe_mask
160062306a36Sopenharmony_ci */
160162306a36Sopenharmony_cistatic const struct snd_pci_quirk probe_mask_list[] = {
160262306a36Sopenharmony_ci	/* Thinkpad often breaks the controller communication when accessing
160362306a36Sopenharmony_ci	 * to the non-working (or non-existing) modem codec slot.
160462306a36Sopenharmony_ci	 */
160562306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01),
160662306a36Sopenharmony_ci	SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01),
160762306a36Sopenharmony_ci	SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01),
160862306a36Sopenharmony_ci	/* broken BIOS */
160962306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01),
161062306a36Sopenharmony_ci	/* including bogus ALC268 in slot#2 that conflicts with ALC888 */
161162306a36Sopenharmony_ci	SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01),
161262306a36Sopenharmony_ci	/* forced codec slots */
161362306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x1262, "ASUS W5Fm", 0x103),
161462306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103),
161562306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1558, 0x0351, "Schenker Dock 15", 0x105),
161662306a36Sopenharmony_ci	/* WinFast VP200 H (Teradici) user reported broken communication */
161762306a36Sopenharmony_ci	SND_PCI_QUIRK(0x3a21, 0x040d, "WinFast VP200 H", 0x101),
161862306a36Sopenharmony_ci	{}
161962306a36Sopenharmony_ci};
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci#define AZX_FORCE_CODEC_MASK	0x100
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_cistatic void check_probe_mask(struct azx *chip, int dev)
162462306a36Sopenharmony_ci{
162562306a36Sopenharmony_ci	const struct snd_pci_quirk *q;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	chip->codec_probe_mask = probe_mask[dev];
162862306a36Sopenharmony_ci	if (chip->codec_probe_mask == -1) {
162962306a36Sopenharmony_ci		q = snd_pci_quirk_lookup(chip->pci, probe_mask_list);
163062306a36Sopenharmony_ci		if (q) {
163162306a36Sopenharmony_ci			dev_info(chip->card->dev,
163262306a36Sopenharmony_ci				 "probe_mask set to 0x%x for device %04x:%04x\n",
163362306a36Sopenharmony_ci				 q->value, q->subvendor, q->subdevice);
163462306a36Sopenharmony_ci			chip->codec_probe_mask = q->value;
163562306a36Sopenharmony_ci		}
163662306a36Sopenharmony_ci	}
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	/* check forced option */
163962306a36Sopenharmony_ci	if (chip->codec_probe_mask != -1 &&
164062306a36Sopenharmony_ci	    (chip->codec_probe_mask & AZX_FORCE_CODEC_MASK)) {
164162306a36Sopenharmony_ci		azx_bus(chip)->codec_mask = chip->codec_probe_mask & 0xff;
164262306a36Sopenharmony_ci		dev_info(chip->card->dev, "codec_mask forced to 0x%x\n",
164362306a36Sopenharmony_ci			 (int)azx_bus(chip)->codec_mask);
164462306a36Sopenharmony_ci	}
164562306a36Sopenharmony_ci}
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci/*
164862306a36Sopenharmony_ci * allow/deny-list for enable_msi
164962306a36Sopenharmony_ci */
165062306a36Sopenharmony_cistatic const struct snd_pci_quirk msi_deny_list[] = {
165162306a36Sopenharmony_ci	SND_PCI_QUIRK(0x103c, 0x2191, "HP", 0), /* AMD Hudson */
165262306a36Sopenharmony_ci	SND_PCI_QUIRK(0x103c, 0x2192, "HP", 0), /* AMD Hudson */
165362306a36Sopenharmony_ci	SND_PCI_QUIRK(0x103c, 0x21f7, "HP", 0), /* AMD Hudson */
165462306a36Sopenharmony_ci	SND_PCI_QUIRK(0x103c, 0x21fa, "HP", 0), /* AMD Hudson */
165562306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */
165662306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x81f6, "ASUS", 0), /* nvidia */
165762306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x822d, "ASUS", 0), /* Athlon64 X2 + nvidia MCP55 */
165862306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1179, 0xfb44, "Toshiba Satellite C870", 0), /* AMD Hudson */
165962306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1849, 0x0888, "ASRock", 0), /* Athlon64 X2 + nvidia */
166062306a36Sopenharmony_ci	SND_PCI_QUIRK(0xa0a0, 0x0575, "Aopen MZ915-M", 0), /* ICH6 */
166162306a36Sopenharmony_ci	{}
166262306a36Sopenharmony_ci};
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_cistatic void check_msi(struct azx *chip)
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	const struct snd_pci_quirk *q;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	if (enable_msi >= 0) {
166962306a36Sopenharmony_ci		chip->msi = !!enable_msi;
167062306a36Sopenharmony_ci		return;
167162306a36Sopenharmony_ci	}
167262306a36Sopenharmony_ci	chip->msi = 1;	/* enable MSI as default */
167362306a36Sopenharmony_ci	q = snd_pci_quirk_lookup(chip->pci, msi_deny_list);
167462306a36Sopenharmony_ci	if (q) {
167562306a36Sopenharmony_ci		dev_info(chip->card->dev,
167662306a36Sopenharmony_ci			 "msi for device %04x:%04x set to %d\n",
167762306a36Sopenharmony_ci			 q->subvendor, q->subdevice, q->value);
167862306a36Sopenharmony_ci		chip->msi = q->value;
167962306a36Sopenharmony_ci		return;
168062306a36Sopenharmony_ci	}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	/* NVidia chipsets seem to cause troubles with MSI */
168362306a36Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_NO_MSI) {
168462306a36Sopenharmony_ci		dev_info(chip->card->dev, "Disabling MSI\n");
168562306a36Sopenharmony_ci		chip->msi = 0;
168662306a36Sopenharmony_ci	}
168762306a36Sopenharmony_ci}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci/* check the snoop mode availability */
169062306a36Sopenharmony_cistatic void azx_check_snoop_available(struct azx *chip)
169162306a36Sopenharmony_ci{
169262306a36Sopenharmony_ci	int snoop = hda_snoop;
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	if (snoop >= 0) {
169562306a36Sopenharmony_ci		dev_info(chip->card->dev, "Force to %s mode by module option\n",
169662306a36Sopenharmony_ci			 snoop ? "snoop" : "non-snoop");
169762306a36Sopenharmony_ci		chip->snoop = snoop;
169862306a36Sopenharmony_ci		chip->uc_buffer = !snoop;
169962306a36Sopenharmony_ci		return;
170062306a36Sopenharmony_ci	}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	snoop = true;
170362306a36Sopenharmony_ci	if (azx_get_snoop_type(chip) == AZX_SNOOP_TYPE_NONE &&
170462306a36Sopenharmony_ci	    chip->driver_type == AZX_DRIVER_VIA) {
170562306a36Sopenharmony_ci		/* force to non-snoop mode for a new VIA controller
170662306a36Sopenharmony_ci		 * when BIOS is set
170762306a36Sopenharmony_ci		 */
170862306a36Sopenharmony_ci		u8 val;
170962306a36Sopenharmony_ci		pci_read_config_byte(chip->pci, 0x42, &val);
171062306a36Sopenharmony_ci		if (!(val & 0x80) && (chip->pci->revision == 0x30 ||
171162306a36Sopenharmony_ci				      chip->pci->revision == 0x20))
171262306a36Sopenharmony_ci			snoop = false;
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_SNOOP_OFF)
171662306a36Sopenharmony_ci		snoop = false;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	chip->snoop = snoop;
171962306a36Sopenharmony_ci	if (!snoop) {
172062306a36Sopenharmony_ci		dev_info(chip->card->dev, "Force to non-snoop mode\n");
172162306a36Sopenharmony_ci		/* C-Media requires non-cached pages only for CORB/RIRB */
172262306a36Sopenharmony_ci		if (chip->driver_type != AZX_DRIVER_CMEDIA)
172362306a36Sopenharmony_ci			chip->uc_buffer = true;
172462306a36Sopenharmony_ci	}
172562306a36Sopenharmony_ci}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_cistatic void azx_probe_work(struct work_struct *work)
172862306a36Sopenharmony_ci{
172962306a36Sopenharmony_ci	struct hda_intel *hda = container_of(work, struct hda_intel, probe_work.work);
173062306a36Sopenharmony_ci	azx_probe_continue(&hda->chip);
173162306a36Sopenharmony_ci}
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_cistatic int default_bdl_pos_adj(struct azx *chip)
173462306a36Sopenharmony_ci{
173562306a36Sopenharmony_ci	/* some exceptions: Atoms seem problematic with value 1 */
173662306a36Sopenharmony_ci	if (chip->pci->vendor == PCI_VENDOR_ID_INTEL) {
173762306a36Sopenharmony_ci		switch (chip->pci->device) {
173862306a36Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HDA_BYT:
173962306a36Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HDA_BSW:
174062306a36Sopenharmony_ci			return 32;
174162306a36Sopenharmony_ci		case PCI_DEVICE_ID_INTEL_HDA_APL:
174262306a36Sopenharmony_ci			return 64;
174362306a36Sopenharmony_ci		}
174462306a36Sopenharmony_ci	}
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	switch (chip->driver_type) {
174762306a36Sopenharmony_ci	/*
174862306a36Sopenharmony_ci	 * increase the bdl size for Glenfly Gpus for hardware
174962306a36Sopenharmony_ci	 * limitation on hdac interrupt interval
175062306a36Sopenharmony_ci	 */
175162306a36Sopenharmony_ci	case AZX_DRIVER_GFHDMI:
175262306a36Sopenharmony_ci		return 128;
175362306a36Sopenharmony_ci	case AZX_DRIVER_ICH:
175462306a36Sopenharmony_ci	case AZX_DRIVER_PCH:
175562306a36Sopenharmony_ci		return 1;
175662306a36Sopenharmony_ci	default:
175762306a36Sopenharmony_ci		return 32;
175862306a36Sopenharmony_ci	}
175962306a36Sopenharmony_ci}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci/*
176262306a36Sopenharmony_ci * constructor
176362306a36Sopenharmony_ci */
176462306a36Sopenharmony_cistatic const struct hda_controller_ops pci_hda_ops;
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_cistatic int azx_create(struct snd_card *card, struct pci_dev *pci,
176762306a36Sopenharmony_ci		      int dev, unsigned int driver_caps,
176862306a36Sopenharmony_ci		      struct azx **rchip)
176962306a36Sopenharmony_ci{
177062306a36Sopenharmony_ci	static const struct snd_device_ops ops = {
177162306a36Sopenharmony_ci		.dev_disconnect = azx_dev_disconnect,
177262306a36Sopenharmony_ci		.dev_free = azx_dev_free,
177362306a36Sopenharmony_ci	};
177462306a36Sopenharmony_ci	struct hda_intel *hda;
177562306a36Sopenharmony_ci	struct azx *chip;
177662306a36Sopenharmony_ci	int err;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	*rchip = NULL;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	err = pcim_enable_device(pci);
178162306a36Sopenharmony_ci	if (err < 0)
178262306a36Sopenharmony_ci		return err;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	hda = devm_kzalloc(&pci->dev, sizeof(*hda), GFP_KERNEL);
178562306a36Sopenharmony_ci	if (!hda)
178662306a36Sopenharmony_ci		return -ENOMEM;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	chip = &hda->chip;
178962306a36Sopenharmony_ci	mutex_init(&chip->open_mutex);
179062306a36Sopenharmony_ci	chip->card = card;
179162306a36Sopenharmony_ci	chip->pci = pci;
179262306a36Sopenharmony_ci	chip->ops = &pci_hda_ops;
179362306a36Sopenharmony_ci	chip->driver_caps = driver_caps;
179462306a36Sopenharmony_ci	chip->driver_type = driver_caps & 0xff;
179562306a36Sopenharmony_ci	check_msi(chip);
179662306a36Sopenharmony_ci	chip->dev_index = dev;
179762306a36Sopenharmony_ci	if (jackpoll_ms[dev] >= 50 && jackpoll_ms[dev] <= 60000)
179862306a36Sopenharmony_ci		chip->jackpoll_interval = msecs_to_jiffies(jackpoll_ms[dev]);
179962306a36Sopenharmony_ci	INIT_LIST_HEAD(&chip->pcm_list);
180062306a36Sopenharmony_ci	INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work);
180162306a36Sopenharmony_ci	INIT_LIST_HEAD(&hda->list);
180262306a36Sopenharmony_ci	init_vga_switcheroo(chip);
180362306a36Sopenharmony_ci	init_completion(&hda->probe_wait);
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	assign_position_fix(chip, check_position_fix(chip, position_fix[dev]));
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	if (single_cmd < 0) /* allow fallback to single_cmd at errors */
180862306a36Sopenharmony_ci		chip->fallback_to_single_cmd = 1;
180962306a36Sopenharmony_ci	else /* explicitly set to single_cmd or not */
181062306a36Sopenharmony_ci		chip->single_cmd = single_cmd;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	azx_check_snoop_available(chip);
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	if (bdl_pos_adj[dev] < 0)
181562306a36Sopenharmony_ci		chip->bdl_pos_adj = default_bdl_pos_adj(chip);
181662306a36Sopenharmony_ci	else
181762306a36Sopenharmony_ci		chip->bdl_pos_adj = bdl_pos_adj[dev];
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	err = azx_bus_init(chip, model[dev]);
182062306a36Sopenharmony_ci	if (err < 0)
182162306a36Sopenharmony_ci		return err;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	/* use the non-cached pages in non-snoop mode */
182462306a36Sopenharmony_ci	if (!azx_snoop(chip))
182562306a36Sopenharmony_ci		azx_bus(chip)->dma_type = SNDRV_DMA_TYPE_DEV_WC_SG;
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_NVIDIA) {
182862306a36Sopenharmony_ci		dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
182962306a36Sopenharmony_ci		chip->bus.core.needs_damn_long_delay = 1;
183062306a36Sopenharmony_ci	}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	check_probe_mask(chip, dev);
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
183562306a36Sopenharmony_ci	if (err < 0) {
183662306a36Sopenharmony_ci		dev_err(card->dev, "Error creating device [card]!\n");
183762306a36Sopenharmony_ci		azx_free(chip);
183862306a36Sopenharmony_ci		return err;
183962306a36Sopenharmony_ci	}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	/* continue probing in work context as may trigger request module */
184262306a36Sopenharmony_ci	INIT_DELAYED_WORK(&hda->probe_work, azx_probe_work);
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	*rchip = chip;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	return 0;
184762306a36Sopenharmony_ci}
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_cistatic int azx_first_init(struct azx *chip)
185062306a36Sopenharmony_ci{
185162306a36Sopenharmony_ci	int dev = chip->dev_index;
185262306a36Sopenharmony_ci	struct pci_dev *pci = chip->pci;
185362306a36Sopenharmony_ci	struct snd_card *card = chip->card;
185462306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
185562306a36Sopenharmony_ci	int err;
185662306a36Sopenharmony_ci	unsigned short gcap;
185762306a36Sopenharmony_ci	unsigned int dma_bits = 64;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci#if BITS_PER_LONG != 64
186062306a36Sopenharmony_ci	/* Fix up base address on ULI M5461 */
186162306a36Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_ULI) {
186262306a36Sopenharmony_ci		u16 tmp3;
186362306a36Sopenharmony_ci		pci_read_config_word(pci, 0x40, &tmp3);
186462306a36Sopenharmony_ci		pci_write_config_word(pci, 0x40, tmp3 | 0x10);
186562306a36Sopenharmony_ci		pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, 0);
186662306a36Sopenharmony_ci	}
186762306a36Sopenharmony_ci#endif
186862306a36Sopenharmony_ci	/*
186962306a36Sopenharmony_ci	 * Fix response write request not synced to memory when handle
187062306a36Sopenharmony_ci	 * hdac interrupt on Glenfly Gpus
187162306a36Sopenharmony_ci	 */
187262306a36Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_GFHDMI)
187362306a36Sopenharmony_ci		bus->polling_mode = 1;
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_LOONGSON) {
187662306a36Sopenharmony_ci		bus->polling_mode = 1;
187762306a36Sopenharmony_ci		bus->not_use_interrupts = 1;
187862306a36Sopenharmony_ci		bus->access_sdnctl_in_dword = 1;
187962306a36Sopenharmony_ci	}
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	err = pcim_iomap_regions(pci, 1 << 0, "ICH HD audio");
188262306a36Sopenharmony_ci	if (err < 0)
188362306a36Sopenharmony_ci		return err;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	bus->addr = pci_resource_start(pci, 0);
188662306a36Sopenharmony_ci	bus->remap_addr = pcim_iomap_table(pci)[0];
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_SKL)
188962306a36Sopenharmony_ci		snd_hdac_bus_parse_capabilities(bus);
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	/*
189262306a36Sopenharmony_ci	 * Some Intel CPUs has always running timer (ART) feature and
189362306a36Sopenharmony_ci	 * controller may have Global time sync reporting capability, so
189462306a36Sopenharmony_ci	 * check both of these before declaring synchronized time reporting
189562306a36Sopenharmony_ci	 * capability SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME
189662306a36Sopenharmony_ci	 */
189762306a36Sopenharmony_ci	chip->gts_present = false;
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci#ifdef CONFIG_X86
190062306a36Sopenharmony_ci	if (bus->ppcap && boot_cpu_has(X86_FEATURE_ART))
190162306a36Sopenharmony_ci		chip->gts_present = true;
190262306a36Sopenharmony_ci#endif
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	if (chip->msi) {
190562306a36Sopenharmony_ci		if (chip->driver_caps & AZX_DCAPS_NO_MSI64) {
190662306a36Sopenharmony_ci			dev_dbg(card->dev, "Disabling 64bit MSI\n");
190762306a36Sopenharmony_ci			pci->no_64bit_msi = true;
190862306a36Sopenharmony_ci		}
190962306a36Sopenharmony_ci		if (pci_enable_msi(pci) < 0)
191062306a36Sopenharmony_ci			chip->msi = 0;
191162306a36Sopenharmony_ci	}
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	pci_set_master(pci);
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	gcap = azx_readw(chip, GCAP);
191662306a36Sopenharmony_ci	dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap);
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	/* AMD devices support 40 or 48bit DMA, take the safe one */
191962306a36Sopenharmony_ci	if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
192062306a36Sopenharmony_ci		dma_bits = 40;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	/* disable SB600 64bit support for safety */
192362306a36Sopenharmony_ci	if (chip->pci->vendor == PCI_VENDOR_ID_ATI) {
192462306a36Sopenharmony_ci		struct pci_dev *p_smbus;
192562306a36Sopenharmony_ci		dma_bits = 40;
192662306a36Sopenharmony_ci		p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
192762306a36Sopenharmony_ci					 PCI_DEVICE_ID_ATI_SBX00_SMBUS,
192862306a36Sopenharmony_ci					 NULL);
192962306a36Sopenharmony_ci		if (p_smbus) {
193062306a36Sopenharmony_ci			if (p_smbus->revision < 0x30)
193162306a36Sopenharmony_ci				gcap &= ~AZX_GCAP_64OK;
193262306a36Sopenharmony_ci			pci_dev_put(p_smbus);
193362306a36Sopenharmony_ci		}
193462306a36Sopenharmony_ci	}
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	/* NVidia hardware normally only supports up to 40 bits of DMA */
193762306a36Sopenharmony_ci	if (chip->pci->vendor == PCI_VENDOR_ID_NVIDIA)
193862306a36Sopenharmony_ci		dma_bits = 40;
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci	/* disable 64bit DMA address on some devices */
194162306a36Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_NO_64BIT) {
194262306a36Sopenharmony_ci		dev_dbg(card->dev, "Disabling 64bit DMA\n");
194362306a36Sopenharmony_ci		gcap &= ~AZX_GCAP_64OK;
194462306a36Sopenharmony_ci	}
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	/* disable buffer size rounding to 128-byte multiples if supported */
194762306a36Sopenharmony_ci	if (align_buffer_size >= 0)
194862306a36Sopenharmony_ci		chip->align_buffer_size = !!align_buffer_size;
194962306a36Sopenharmony_ci	else {
195062306a36Sopenharmony_ci		if (chip->driver_caps & AZX_DCAPS_NO_ALIGN_BUFSIZE)
195162306a36Sopenharmony_ci			chip->align_buffer_size = 0;
195262306a36Sopenharmony_ci		else
195362306a36Sopenharmony_ci			chip->align_buffer_size = 1;
195462306a36Sopenharmony_ci	}
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	/* allow 64bit DMA address if supported by H/W */
195762306a36Sopenharmony_ci	if (!(gcap & AZX_GCAP_64OK))
195862306a36Sopenharmony_ci		dma_bits = 32;
195962306a36Sopenharmony_ci	if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(dma_bits)))
196062306a36Sopenharmony_ci		dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32));
196162306a36Sopenharmony_ci	dma_set_max_seg_size(&pci->dev, UINT_MAX);
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	/* read number of streams from GCAP register instead of using
196462306a36Sopenharmony_ci	 * hardcoded value
196562306a36Sopenharmony_ci	 */
196662306a36Sopenharmony_ci	chip->capture_streams = (gcap >> 8) & 0x0f;
196762306a36Sopenharmony_ci	chip->playback_streams = (gcap >> 12) & 0x0f;
196862306a36Sopenharmony_ci	if (!chip->playback_streams && !chip->capture_streams) {
196962306a36Sopenharmony_ci		/* gcap didn't give any info, switching to old method */
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci		switch (chip->driver_type) {
197262306a36Sopenharmony_ci		case AZX_DRIVER_ULI:
197362306a36Sopenharmony_ci			chip->playback_streams = ULI_NUM_PLAYBACK;
197462306a36Sopenharmony_ci			chip->capture_streams = ULI_NUM_CAPTURE;
197562306a36Sopenharmony_ci			break;
197662306a36Sopenharmony_ci		case AZX_DRIVER_ATIHDMI:
197762306a36Sopenharmony_ci		case AZX_DRIVER_ATIHDMI_NS:
197862306a36Sopenharmony_ci			chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
197962306a36Sopenharmony_ci			chip->capture_streams = ATIHDMI_NUM_CAPTURE;
198062306a36Sopenharmony_ci			break;
198162306a36Sopenharmony_ci		case AZX_DRIVER_GFHDMI:
198262306a36Sopenharmony_ci		case AZX_DRIVER_GENERIC:
198362306a36Sopenharmony_ci		default:
198462306a36Sopenharmony_ci			chip->playback_streams = ICH6_NUM_PLAYBACK;
198562306a36Sopenharmony_ci			chip->capture_streams = ICH6_NUM_CAPTURE;
198662306a36Sopenharmony_ci			break;
198762306a36Sopenharmony_ci		}
198862306a36Sopenharmony_ci	}
198962306a36Sopenharmony_ci	chip->capture_index_offset = 0;
199062306a36Sopenharmony_ci	chip->playback_index_offset = chip->capture_streams;
199162306a36Sopenharmony_ci	chip->num_streams = chip->playback_streams + chip->capture_streams;
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	/* sanity check for the SDxCTL.STRM field overflow */
199462306a36Sopenharmony_ci	if (chip->num_streams > 15 &&
199562306a36Sopenharmony_ci	    (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG) == 0) {
199662306a36Sopenharmony_ci		dev_warn(chip->card->dev, "number of I/O streams is %d, "
199762306a36Sopenharmony_ci			 "forcing separate stream tags", chip->num_streams);
199862306a36Sopenharmony_ci		chip->driver_caps |= AZX_DCAPS_SEPARATE_STREAM_TAG;
199962306a36Sopenharmony_ci	}
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci	/* initialize streams */
200262306a36Sopenharmony_ci	err = azx_init_streams(chip);
200362306a36Sopenharmony_ci	if (err < 0)
200462306a36Sopenharmony_ci		return err;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	err = azx_alloc_stream_pages(chip);
200762306a36Sopenharmony_ci	if (err < 0)
200862306a36Sopenharmony_ci		return err;
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	/* initialize chip */
201162306a36Sopenharmony_ci	azx_init_pci(chip);
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	snd_hdac_i915_set_bclk(bus);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0);
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci	/* codec detection */
201862306a36Sopenharmony_ci	if (!azx_bus(chip)->codec_mask) {
201962306a36Sopenharmony_ci		dev_err(card->dev, "no codecs found!\n");
202062306a36Sopenharmony_ci		/* keep running the rest for the runtime PM */
202162306a36Sopenharmony_ci	}
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	if (azx_acquire_irq(chip, 0) < 0)
202462306a36Sopenharmony_ci		return -EBUSY;
202562306a36Sopenharmony_ci
202662306a36Sopenharmony_ci	strcpy(card->driver, "HDA-Intel");
202762306a36Sopenharmony_ci	strscpy(card->shortname, driver_short_names[chip->driver_type],
202862306a36Sopenharmony_ci		sizeof(card->shortname));
202962306a36Sopenharmony_ci	snprintf(card->longname, sizeof(card->longname),
203062306a36Sopenharmony_ci		 "%s at 0x%lx irq %i",
203162306a36Sopenharmony_ci		 card->shortname, bus->addr, bus->irq);
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	return 0;
203462306a36Sopenharmony_ci}
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci#ifdef CONFIG_SND_HDA_PATCH_LOADER
203762306a36Sopenharmony_ci/* callback from request_firmware_nowait() */
203862306a36Sopenharmony_cistatic void azx_firmware_cb(const struct firmware *fw, void *context)
203962306a36Sopenharmony_ci{
204062306a36Sopenharmony_ci	struct snd_card *card = context;
204162306a36Sopenharmony_ci	struct azx *chip = card->private_data;
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	if (fw)
204462306a36Sopenharmony_ci		chip->fw = fw;
204562306a36Sopenharmony_ci	else
204662306a36Sopenharmony_ci		dev_err(card->dev, "Cannot load firmware, continue without patching\n");
204762306a36Sopenharmony_ci	if (!chip->disabled) {
204862306a36Sopenharmony_ci		/* continue probing */
204962306a36Sopenharmony_ci		azx_probe_continue(chip);
205062306a36Sopenharmony_ci	}
205162306a36Sopenharmony_ci}
205262306a36Sopenharmony_ci#endif
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_cistatic int disable_msi_reset_irq(struct azx *chip)
205562306a36Sopenharmony_ci{
205662306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
205762306a36Sopenharmony_ci	int err;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	free_irq(bus->irq, chip);
206062306a36Sopenharmony_ci	bus->irq = -1;
206162306a36Sopenharmony_ci	chip->card->sync_irq = -1;
206262306a36Sopenharmony_ci	pci_disable_msi(chip->pci);
206362306a36Sopenharmony_ci	chip->msi = 0;
206462306a36Sopenharmony_ci	err = azx_acquire_irq(chip, 1);
206562306a36Sopenharmony_ci	if (err < 0)
206662306a36Sopenharmony_ci		return err;
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	return 0;
206962306a36Sopenharmony_ci}
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci/* Denylist for skipping the whole probe:
207262306a36Sopenharmony_ci * some HD-audio PCI entries are exposed without any codecs, and such devices
207362306a36Sopenharmony_ci * should be ignored from the beginning.
207462306a36Sopenharmony_ci */
207562306a36Sopenharmony_cistatic const struct pci_device_id driver_denylist[] = {
207662306a36Sopenharmony_ci	{ PCI_DEVICE_SUB(0x1022, 0x1487, 0x1043, 0x874f) }, /* ASUS ROG Zenith II / Strix */
207762306a36Sopenharmony_ci	{ PCI_DEVICE_SUB(0x1022, 0x1487, 0x1462, 0xcb59) }, /* MSI TRX40 Creator */
207862306a36Sopenharmony_ci	{ PCI_DEVICE_SUB(0x1022, 0x1487, 0x1462, 0xcb60) }, /* MSI TRX40 */
207962306a36Sopenharmony_ci	{}
208062306a36Sopenharmony_ci};
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_cistatic const struct hda_controller_ops pci_hda_ops = {
208362306a36Sopenharmony_ci	.disable_msi_reset_irq = disable_msi_reset_irq,
208462306a36Sopenharmony_ci	.position_check = azx_position_check,
208562306a36Sopenharmony_ci};
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_cistatic DECLARE_BITMAP(probed_devs, SNDRV_CARDS);
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_cistatic int azx_probe(struct pci_dev *pci,
209062306a36Sopenharmony_ci		     const struct pci_device_id *pci_id)
209162306a36Sopenharmony_ci{
209262306a36Sopenharmony_ci	struct snd_card *card;
209362306a36Sopenharmony_ci	struct hda_intel *hda;
209462306a36Sopenharmony_ci	struct azx *chip;
209562306a36Sopenharmony_ci	bool schedule_probe;
209662306a36Sopenharmony_ci	int dev;
209762306a36Sopenharmony_ci	int err;
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	if (pci_match_id(driver_denylist, pci)) {
210062306a36Sopenharmony_ci		dev_info(&pci->dev, "Skipping the device on the denylist\n");
210162306a36Sopenharmony_ci		return -ENODEV;
210262306a36Sopenharmony_ci	}
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	dev = find_first_zero_bit(probed_devs, SNDRV_CARDS);
210562306a36Sopenharmony_ci	if (dev >= SNDRV_CARDS)
210662306a36Sopenharmony_ci		return -ENODEV;
210762306a36Sopenharmony_ci	if (!enable[dev]) {
210862306a36Sopenharmony_ci		set_bit(dev, probed_devs);
210962306a36Sopenharmony_ci		return -ENOENT;
211062306a36Sopenharmony_ci	}
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	/*
211362306a36Sopenharmony_ci	 * stop probe if another Intel's DSP driver should be activated
211462306a36Sopenharmony_ci	 */
211562306a36Sopenharmony_ci	if (dmic_detect) {
211662306a36Sopenharmony_ci		err = snd_intel_dsp_driver_probe(pci);
211762306a36Sopenharmony_ci		if (err != SND_INTEL_DSP_DRIVER_ANY && err != SND_INTEL_DSP_DRIVER_LEGACY) {
211862306a36Sopenharmony_ci			dev_dbg(&pci->dev, "HDAudio driver not selected, aborting probe\n");
211962306a36Sopenharmony_ci			return -ENODEV;
212062306a36Sopenharmony_ci		}
212162306a36Sopenharmony_ci	} else {
212262306a36Sopenharmony_ci		dev_warn(&pci->dev, "dmic_detect option is deprecated, pass snd-intel-dspcfg.dsp_driver=1 option instead\n");
212362306a36Sopenharmony_ci	}
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
212662306a36Sopenharmony_ci			   0, &card);
212762306a36Sopenharmony_ci	if (err < 0) {
212862306a36Sopenharmony_ci		dev_err(&pci->dev, "Error creating card!\n");
212962306a36Sopenharmony_ci		return err;
213062306a36Sopenharmony_ci	}
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
213362306a36Sopenharmony_ci	if (err < 0)
213462306a36Sopenharmony_ci		goto out_free;
213562306a36Sopenharmony_ci	card->private_data = chip;
213662306a36Sopenharmony_ci	hda = container_of(chip, struct hda_intel, chip);
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	pci_set_drvdata(pci, card);
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	err = register_vga_switcheroo(chip);
214162306a36Sopenharmony_ci	if (err < 0) {
214262306a36Sopenharmony_ci		dev_err(card->dev, "Error registering vga_switcheroo client\n");
214362306a36Sopenharmony_ci		goto out_free;
214462306a36Sopenharmony_ci	}
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	if (check_hdmi_disabled(pci)) {
214762306a36Sopenharmony_ci		dev_info(card->dev, "VGA controller is disabled\n");
214862306a36Sopenharmony_ci		dev_info(card->dev, "Delaying initialization\n");
214962306a36Sopenharmony_ci		chip->disabled = true;
215062306a36Sopenharmony_ci	}
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	schedule_probe = !chip->disabled;
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci#ifdef CONFIG_SND_HDA_PATCH_LOADER
215562306a36Sopenharmony_ci	if (patch[dev] && *patch[dev]) {
215662306a36Sopenharmony_ci		dev_info(card->dev, "Applying patch firmware '%s'\n",
215762306a36Sopenharmony_ci			 patch[dev]);
215862306a36Sopenharmony_ci		err = request_firmware_nowait(THIS_MODULE, true, patch[dev],
215962306a36Sopenharmony_ci					      &pci->dev, GFP_KERNEL, card,
216062306a36Sopenharmony_ci					      azx_firmware_cb);
216162306a36Sopenharmony_ci		if (err < 0)
216262306a36Sopenharmony_ci			goto out_free;
216362306a36Sopenharmony_ci		schedule_probe = false; /* continued in azx_firmware_cb() */
216462306a36Sopenharmony_ci	}
216562306a36Sopenharmony_ci#endif /* CONFIG_SND_HDA_PATCH_LOADER */
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci#ifndef CONFIG_SND_HDA_I915
216862306a36Sopenharmony_ci	if (HDA_CONTROLLER_IN_GPU(pci))
216962306a36Sopenharmony_ci		dev_err(card->dev, "Haswell/Broadwell HDMI/DP must build in CONFIG_SND_HDA_I915\n");
217062306a36Sopenharmony_ci#endif
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	if (schedule_probe)
217362306a36Sopenharmony_ci		schedule_delayed_work(&hda->probe_work, 0);
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	set_bit(dev, probed_devs);
217662306a36Sopenharmony_ci	if (chip->disabled)
217762306a36Sopenharmony_ci		complete_all(&hda->probe_wait);
217862306a36Sopenharmony_ci	return 0;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ciout_free:
218162306a36Sopenharmony_ci	snd_card_free(card);
218262306a36Sopenharmony_ci	return err;
218362306a36Sopenharmony_ci}
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci#ifdef CONFIG_PM
218662306a36Sopenharmony_ci/* On some boards setting power_save to a non 0 value leads to clicking /
218762306a36Sopenharmony_ci * popping sounds when ever we enter/leave powersaving mode. Ideally we would
218862306a36Sopenharmony_ci * figure out how to avoid these sounds, but that is not always feasible.
218962306a36Sopenharmony_ci * So we keep a list of devices where we disable powersaving as its known
219062306a36Sopenharmony_ci * to causes problems on these devices.
219162306a36Sopenharmony_ci */
219262306a36Sopenharmony_cistatic const struct snd_pci_quirk power_save_denylist[] = {
219362306a36Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
219462306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1849, 0xc892, "Asrock B85M-ITX", 0),
219562306a36Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
219662306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1849, 0x0397, "Asrock N68C-S UCC", 0),
219762306a36Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
219862306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1849, 0x7662, "Asrock H81M-HDS", 0),
219962306a36Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
220062306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x8733, "Asus Prime X370-Pro", 0),
220162306a36Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
220262306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1028, 0x0497, "Dell Precision T3600", 0),
220362306a36Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
220462306a36Sopenharmony_ci	/* Note the P55A-UD3 and Z87-D3HP share the subsys id for the HDA dev */
220562306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P55A-UD3 / Z87-D3HP", 0),
220662306a36Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
220762306a36Sopenharmony_ci	SND_PCI_QUIRK(0x8086, 0x2040, "Intel DZ77BH-55K", 0),
220862306a36Sopenharmony_ci	/* https://bugzilla.kernel.org/show_bug.cgi?id=199607 */
220962306a36Sopenharmony_ci	SND_PCI_QUIRK(0x8086, 0x2057, "Intel NUC5i7RYB", 0),
221062306a36Sopenharmony_ci	/* https://bugs.launchpad.net/bugs/1821663 */
221162306a36Sopenharmony_ci	SND_PCI_QUIRK(0x8086, 0x2064, "Intel SDP 8086:2064", 0),
221262306a36Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1520902 */
221362306a36Sopenharmony_ci	SND_PCI_QUIRK(0x8086, 0x2068, "Intel NUC7i3BNB", 0),
221462306a36Sopenharmony_ci	/* https://bugzilla.kernel.org/show_bug.cgi?id=198611 */
221562306a36Sopenharmony_ci	SND_PCI_QUIRK(0x17aa, 0x2227, "Lenovo X1 Carbon 3rd Gen", 0),
221662306a36Sopenharmony_ci	SND_PCI_QUIRK(0x17aa, 0x316e, "Lenovo ThinkCentre M70q", 0),
221762306a36Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1689623 */
221862306a36Sopenharmony_ci	SND_PCI_QUIRK(0x17aa, 0x367b, "Lenovo IdeaCentre B550", 0),
221962306a36Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1572975 */
222062306a36Sopenharmony_ci	SND_PCI_QUIRK(0x17aa, 0x36a7, "Lenovo C50 All in one", 0),
222162306a36Sopenharmony_ci	/* https://bugs.launchpad.net/bugs/1821663 */
222262306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1631, 0xe017, "Packard Bell NEC IMEDIA 5204", 0),
222362306a36Sopenharmony_ci	/* KONTRON SinglePC may cause a stall at runtime resume */
222462306a36Sopenharmony_ci	SND_PCI_QUIRK(0x1734, 0x1232, "KONTRON SinglePC", 0),
222562306a36Sopenharmony_ci	{}
222662306a36Sopenharmony_ci};
222762306a36Sopenharmony_ci#endif /* CONFIG_PM */
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_cistatic void set_default_power_save(struct azx *chip)
223062306a36Sopenharmony_ci{
223162306a36Sopenharmony_ci	int val = power_save;
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci#ifdef CONFIG_PM
223462306a36Sopenharmony_ci	if (pm_blacklist) {
223562306a36Sopenharmony_ci		const struct snd_pci_quirk *q;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci		q = snd_pci_quirk_lookup(chip->pci, power_save_denylist);
223862306a36Sopenharmony_ci		if (q && val) {
223962306a36Sopenharmony_ci			dev_info(chip->card->dev, "device %04x:%04x is on the power_save denylist, forcing power_save to 0\n",
224062306a36Sopenharmony_ci				 q->subvendor, q->subdevice);
224162306a36Sopenharmony_ci			val = 0;
224262306a36Sopenharmony_ci		}
224362306a36Sopenharmony_ci	}
224462306a36Sopenharmony_ci#endif /* CONFIG_PM */
224562306a36Sopenharmony_ci	snd_hda_set_power_save(&chip->bus, val * 1000);
224662306a36Sopenharmony_ci}
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
224962306a36Sopenharmony_cistatic const unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = {
225062306a36Sopenharmony_ci	[AZX_DRIVER_NVIDIA] = 8,
225162306a36Sopenharmony_ci	[AZX_DRIVER_TERA] = 1,
225262306a36Sopenharmony_ci};
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_cistatic int azx_probe_continue(struct azx *chip)
225562306a36Sopenharmony_ci{
225662306a36Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
225762306a36Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
225862306a36Sopenharmony_ci	struct pci_dev *pci = chip->pci;
225962306a36Sopenharmony_ci	int dev = chip->dev_index;
226062306a36Sopenharmony_ci	int err;
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	if (chip->disabled || hda->init_failed)
226362306a36Sopenharmony_ci		return -EIO;
226462306a36Sopenharmony_ci	if (hda->probe_retry)
226562306a36Sopenharmony_ci		goto probe_retry;
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	to_hda_bus(bus)->bus_probing = 1;
226862306a36Sopenharmony_ci	hda->probe_continued = 1;
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	/* bind with i915 if needed */
227162306a36Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) {
227262306a36Sopenharmony_ci		err = snd_hdac_i915_init(bus);
227362306a36Sopenharmony_ci		if (err < 0) {
227462306a36Sopenharmony_ci			/* if the controller is bound only with HDMI/DP
227562306a36Sopenharmony_ci			 * (for HSW and BDW), we need to abort the probe;
227662306a36Sopenharmony_ci			 * for other chips, still continue probing as other
227762306a36Sopenharmony_ci			 * codecs can be on the same link.
227862306a36Sopenharmony_ci			 */
227962306a36Sopenharmony_ci			if (HDA_CONTROLLER_IN_GPU(pci)) {
228062306a36Sopenharmony_ci				dev_err(chip->card->dev,
228162306a36Sopenharmony_ci					"HSW/BDW HD-audio HDMI/DP requires binding with gfx driver\n");
228262306a36Sopenharmony_ci				goto out_free;
228362306a36Sopenharmony_ci			} else {
228462306a36Sopenharmony_ci				/* don't bother any longer */
228562306a36Sopenharmony_ci				chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT;
228662306a36Sopenharmony_ci			}
228762306a36Sopenharmony_ci		}
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci		/* HSW/BDW controllers need this power */
229062306a36Sopenharmony_ci		if (HDA_CONTROLLER_IN_GPU(pci))
229162306a36Sopenharmony_ci			hda->need_i915_power = true;
229262306a36Sopenharmony_ci	}
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	/* Request display power well for the HDA controller or codec. For
229562306a36Sopenharmony_ci	 * Haswell/Broadwell, both the display HDA controller and codec need
229662306a36Sopenharmony_ci	 * this power. For other platforms, like Baytrail/Braswell, only the
229762306a36Sopenharmony_ci	 * display codec needs the power and it can be released after probe.
229862306a36Sopenharmony_ci	 */
229962306a36Sopenharmony_ci	display_power(chip, true);
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	err = azx_first_init(chip);
230262306a36Sopenharmony_ci	if (err < 0)
230362306a36Sopenharmony_ci		goto out_free;
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci#ifdef CONFIG_SND_HDA_INPUT_BEEP
230662306a36Sopenharmony_ci	chip->beep_mode = beep_mode[dev];
230762306a36Sopenharmony_ci#endif
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	chip->ctl_dev_id = ctl_dev_id;
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	/* create codec instances */
231262306a36Sopenharmony_ci	if (bus->codec_mask) {
231362306a36Sopenharmony_ci		err = azx_probe_codecs(chip, azx_max_codecs[chip->driver_type]);
231462306a36Sopenharmony_ci		if (err < 0)
231562306a36Sopenharmony_ci			goto out_free;
231662306a36Sopenharmony_ci	}
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci#ifdef CONFIG_SND_HDA_PATCH_LOADER
231962306a36Sopenharmony_ci	if (chip->fw) {
232062306a36Sopenharmony_ci		err = snd_hda_load_patch(&chip->bus, chip->fw->size,
232162306a36Sopenharmony_ci					 chip->fw->data);
232262306a36Sopenharmony_ci		if (err < 0)
232362306a36Sopenharmony_ci			goto out_free;
232462306a36Sopenharmony_ci#ifndef CONFIG_PM
232562306a36Sopenharmony_ci		release_firmware(chip->fw); /* no longer needed */
232662306a36Sopenharmony_ci		chip->fw = NULL;
232762306a36Sopenharmony_ci#endif
232862306a36Sopenharmony_ci	}
232962306a36Sopenharmony_ci#endif
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_ci probe_retry:
233262306a36Sopenharmony_ci	if (bus->codec_mask && !(probe_only[dev] & 1)) {
233362306a36Sopenharmony_ci		err = azx_codec_configure(chip);
233462306a36Sopenharmony_ci		if (err) {
233562306a36Sopenharmony_ci			if ((chip->driver_caps & AZX_DCAPS_RETRY_PROBE) &&
233662306a36Sopenharmony_ci			    ++hda->probe_retry < 60) {
233762306a36Sopenharmony_ci				schedule_delayed_work(&hda->probe_work,
233862306a36Sopenharmony_ci						      msecs_to_jiffies(1000));
233962306a36Sopenharmony_ci				return 0; /* keep things up */
234062306a36Sopenharmony_ci			}
234162306a36Sopenharmony_ci			dev_err(chip->card->dev, "Cannot probe codecs, giving up\n");
234262306a36Sopenharmony_ci			goto out_free;
234362306a36Sopenharmony_ci		}
234462306a36Sopenharmony_ci	}
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	err = snd_card_register(chip->card);
234762306a36Sopenharmony_ci	if (err < 0)
234862306a36Sopenharmony_ci		goto out_free;
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	setup_vga_switcheroo_runtime_pm(chip);
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci	chip->running = 1;
235362306a36Sopenharmony_ci	azx_add_card_list(chip);
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	set_default_power_save(chip);
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci	if (azx_has_pm_runtime(chip)) {
235862306a36Sopenharmony_ci		pm_runtime_use_autosuspend(&pci->dev);
235962306a36Sopenharmony_ci		pm_runtime_allow(&pci->dev);
236062306a36Sopenharmony_ci		pm_runtime_put_autosuspend(&pci->dev);
236162306a36Sopenharmony_ci	}
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ciout_free:
236462306a36Sopenharmony_ci	if (err < 0) {
236562306a36Sopenharmony_ci		pci_set_drvdata(pci, NULL);
236662306a36Sopenharmony_ci		snd_card_free(chip->card);
236762306a36Sopenharmony_ci		return err;
236862306a36Sopenharmony_ci	}
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	if (!hda->need_i915_power)
237162306a36Sopenharmony_ci		display_power(chip, false);
237262306a36Sopenharmony_ci	complete_all(&hda->probe_wait);
237362306a36Sopenharmony_ci	to_hda_bus(bus)->bus_probing = 0;
237462306a36Sopenharmony_ci	hda->probe_retry = 0;
237562306a36Sopenharmony_ci	return 0;
237662306a36Sopenharmony_ci}
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_cistatic void azx_remove(struct pci_dev *pci)
237962306a36Sopenharmony_ci{
238062306a36Sopenharmony_ci	struct snd_card *card = pci_get_drvdata(pci);
238162306a36Sopenharmony_ci	struct azx *chip;
238262306a36Sopenharmony_ci	struct hda_intel *hda;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	if (card) {
238562306a36Sopenharmony_ci		/* cancel the pending probing work */
238662306a36Sopenharmony_ci		chip = card->private_data;
238762306a36Sopenharmony_ci		hda = container_of(chip, struct hda_intel, chip);
238862306a36Sopenharmony_ci		/* FIXME: below is an ugly workaround.
238962306a36Sopenharmony_ci		 * Both device_release_driver() and driver_probe_device()
239062306a36Sopenharmony_ci		 * take *both* the device's and its parent's lock before
239162306a36Sopenharmony_ci		 * calling the remove() and probe() callbacks.  The codec
239262306a36Sopenharmony_ci		 * probe takes the locks of both the codec itself and its
239362306a36Sopenharmony_ci		 * parent, i.e. the PCI controller dev.  Meanwhile, when
239462306a36Sopenharmony_ci		 * the PCI controller is unbound, it takes its lock, too
239562306a36Sopenharmony_ci		 * ==> ouch, a deadlock!
239662306a36Sopenharmony_ci		 * As a workaround, we unlock temporarily here the controller
239762306a36Sopenharmony_ci		 * device during cancel_work_sync() call.
239862306a36Sopenharmony_ci		 */
239962306a36Sopenharmony_ci		device_unlock(&pci->dev);
240062306a36Sopenharmony_ci		cancel_delayed_work_sync(&hda->probe_work);
240162306a36Sopenharmony_ci		device_lock(&pci->dev);
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_ci		clear_bit(chip->dev_index, probed_devs);
240462306a36Sopenharmony_ci		pci_set_drvdata(pci, NULL);
240562306a36Sopenharmony_ci		snd_card_free(card);
240662306a36Sopenharmony_ci	}
240762306a36Sopenharmony_ci}
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_cistatic void azx_shutdown(struct pci_dev *pci)
241062306a36Sopenharmony_ci{
241162306a36Sopenharmony_ci	struct snd_card *card = pci_get_drvdata(pci);
241262306a36Sopenharmony_ci	struct azx *chip;
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	if (!card)
241562306a36Sopenharmony_ci		return;
241662306a36Sopenharmony_ci	chip = card->private_data;
241762306a36Sopenharmony_ci	if (chip && chip->running)
241862306a36Sopenharmony_ci		__azx_shutdown_chip(chip, true);
241962306a36Sopenharmony_ci}
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci/* PCI IDs */
242262306a36Sopenharmony_cistatic const struct pci_device_id azx_ids[] = {
242362306a36Sopenharmony_ci	/* CPT */
242462306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_CPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) },
242562306a36Sopenharmony_ci	/* PBG */
242662306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_PBG, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) },
242762306a36Sopenharmony_ci	/* Panther Point */
242862306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_PPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM) },
242962306a36Sopenharmony_ci	/* Lynx Point */
243062306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_LPT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
243162306a36Sopenharmony_ci	/* 9 Series */
243262306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_9_SERIES, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
243362306a36Sopenharmony_ci	/* Wellsburg */
243462306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_WBG_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
243562306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_WBG_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
243662306a36Sopenharmony_ci	/* Lewisburg */
243762306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_LBG_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE) },
243862306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_LBG_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE) },
243962306a36Sopenharmony_ci	/* Lynx Point-LP */
244062306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_LPT_LP_0, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
244162306a36Sopenharmony_ci	/* Lynx Point-LP */
244262306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_LPT_LP_1, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
244362306a36Sopenharmony_ci	/* Wildcat Point-LP */
244462306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_WPT_LP, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH) },
244562306a36Sopenharmony_ci	/* Skylake (Sunrise Point) */
244662306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_SKL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
244762306a36Sopenharmony_ci	/* Skylake-LP (Sunrise Point-LP) */
244862306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
244962306a36Sopenharmony_ci	/* Kabylake */
245062306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_KBL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
245162306a36Sopenharmony_ci	/* Kabylake-LP */
245262306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
245362306a36Sopenharmony_ci	/* Kabylake-H */
245462306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_KBL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
245562306a36Sopenharmony_ci	/* Coffelake */
245662306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_CNL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
245762306a36Sopenharmony_ci	/* Cannonlake */
245862306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
245962306a36Sopenharmony_ci	/* CometLake-LP */
246062306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_CML_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
246162306a36Sopenharmony_ci	/* CometLake-H */
246262306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_CML_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
246362306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_RKL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
246462306a36Sopenharmony_ci	/* CometLake-S */
246562306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_CML_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
246662306a36Sopenharmony_ci	/* CometLake-R */
246762306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_CML_R, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
246862306a36Sopenharmony_ci	/* Icelake */
246962306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ICL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
247062306a36Sopenharmony_ci	/* Icelake-H */
247162306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ICL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
247262306a36Sopenharmony_ci	/* Jasperlake */
247362306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ICL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
247462306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_JSL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
247562306a36Sopenharmony_ci	/* Tigerlake */
247662306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_TGL_LP, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
247762306a36Sopenharmony_ci	/* Tigerlake-H */
247862306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_TGL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
247962306a36Sopenharmony_ci	/* DG1 */
248062306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_DG1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
248162306a36Sopenharmony_ci	/* DG2 */
248262306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_DG2_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
248362306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_DG2_1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
248462306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_DG2_2, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
248562306a36Sopenharmony_ci	/* Alderlake-S */
248662306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ADL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
248762306a36Sopenharmony_ci	/* Alderlake-P */
248862306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ADL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
248962306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ADL_PS, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
249062306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
249162306a36Sopenharmony_ci	/* Alderlake-M */
249262306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ADL_M, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
249362306a36Sopenharmony_ci	/* Alderlake-N */
249462306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ADL_N, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
249562306a36Sopenharmony_ci	/* Elkhart Lake */
249662306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_EHL_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
249762306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_EHL_3, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
249862306a36Sopenharmony_ci	/* Raptor Lake */
249962306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_RPL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
250062306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_RPL_P_0, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
250162306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
250262306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_RPL_M, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
250362306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
250462306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_MTL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
250562306a36Sopenharmony_ci	/* Lunarlake-P */
250662306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_LNL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
250762306a36Sopenharmony_ci	/* Arrow Lake-S */
250862306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ARL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
250962306a36Sopenharmony_ci	/* Arrow Lake */
251062306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ARL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
251162306a36Sopenharmony_ci	/* Apollolake (Broxton-P) */
251262306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_APL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) },
251362306a36Sopenharmony_ci	/* Gemini-Lake */
251462306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_GML, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) },
251562306a36Sopenharmony_ci	/* Haswell */
251662306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_HSW_0, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) },
251762306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_HSW_2, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) },
251862306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_HSW_3, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL) },
251962306a36Sopenharmony_ci	/* Broadwell */
252062306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_BDW, AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_BROADWELL) },
252162306a36Sopenharmony_ci	/* 5 Series/3400 */
252262306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_5_3400_SERIES_0, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM) },
252362306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_5_3400_SERIES_1, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM) },
252462306a36Sopenharmony_ci	/* Poulsbo */
252562306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_POULSBO, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE |
252662306a36Sopenharmony_ci	  AZX_DCAPS_POSFIX_LPIB) },
252762306a36Sopenharmony_ci	/* Oaktrail */
252862306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_OAKTRAIL, AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE) },
252962306a36Sopenharmony_ci	/* BayTrail */
253062306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_BYT, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL) },
253162306a36Sopenharmony_ci	/* Braswell */
253262306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_BSW, AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BRASWELL) },
253362306a36Sopenharmony_ci	/* ICH6 */
253462306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ICH6, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
253562306a36Sopenharmony_ci	/* ICH7 */
253662306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ICH7, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
253762306a36Sopenharmony_ci	/* ESB2 */
253862306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ESB2, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
253962306a36Sopenharmony_ci	/* ICH8 */
254062306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ICH8, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
254162306a36Sopenharmony_ci	/* ICH9 */
254262306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ICH9_0, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
254362306a36Sopenharmony_ci	/* ICH9 */
254462306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ICH9_1, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
254562306a36Sopenharmony_ci	/* ICH10 */
254662306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ICH10_0, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
254762306a36Sopenharmony_ci	/* ICH10 */
254862306a36Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ICH10_1, AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH) },
254962306a36Sopenharmony_ci	/* Generic Intel */
255062306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
255162306a36Sopenharmony_ci	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
255262306a36Sopenharmony_ci	  .class_mask = 0xffffff,
255362306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_NO_ALIGN_BUFSIZE },
255462306a36Sopenharmony_ci	/* ATI SB 450/600/700/800/900 */
255562306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x437b),
255662306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
255762306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x4383),
255862306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
255962306a36Sopenharmony_ci	/* AMD Hudson */
256062306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x780d),
256162306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
256262306a36Sopenharmony_ci	/* AMD, X370 & co */
256362306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x1457),
256462306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
256562306a36Sopenharmony_ci	/* AMD, X570 & co */
256662306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x1487),
256762306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
256862306a36Sopenharmony_ci	/* AMD Stoney */
256962306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x157a),
257062306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB |
257162306a36Sopenharmony_ci			 AZX_DCAPS_PM_RUNTIME },
257262306a36Sopenharmony_ci	/* AMD Raven */
257362306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x15e3),
257462306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
257562306a36Sopenharmony_ci	/* ATI HDMI */
257662306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x0002),
257762306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
257862306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
257962306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x1308),
258062306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
258162306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x157a),
258262306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
258362306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x15b3),
258462306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
258562306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x793b),
258662306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
258762306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x7919),
258862306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
258962306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x960f),
259062306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
259162306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x970f),
259262306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
259362306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x9840),
259462306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
259562306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa00),
259662306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
259762306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa08),
259862306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
259962306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa10),
260062306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
260162306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa18),
260262306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
260362306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa20),
260462306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
260562306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa28),
260662306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
260762306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa30),
260862306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
260962306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa38),
261062306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
261162306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa40),
261262306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
261362306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa48),
261462306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
261562306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa50),
261662306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
261762306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa58),
261862306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
261962306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa60),
262062306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
262162306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa68),
262262306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
262362306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa80),
262462306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
262562306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa88),
262662306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
262762306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa90),
262862306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
262962306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaa98),
263062306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
263162306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0x9902),
263262306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
263362306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaaa0),
263462306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
263562306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaaa8),
263662306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
263762306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaab0),
263862306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
263962306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaac0),
264062306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
264162306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
264262306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaac8),
264362306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
264462306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
264562306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaad8),
264662306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
264762306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
264862306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaae0),
264962306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
265062306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
265162306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaae8),
265262306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
265362306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
265462306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaaf0),
265562306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
265662306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
265762306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xaaf8),
265862306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
265962306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
266062306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xab00),
266162306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
266262306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
266362306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xab08),
266462306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
266562306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
266662306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xab10),
266762306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
266862306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
266962306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xab18),
267062306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
267162306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
267262306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xab20),
267362306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
267462306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
267562306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xab28),
267662306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
267762306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
267862306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xab30),
267962306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
268062306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
268162306a36Sopenharmony_ci	{ PCI_VDEVICE(ATI, 0xab38),
268262306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
268362306a36Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
268462306a36Sopenharmony_ci	/* GLENFLY */
268562306a36Sopenharmony_ci	{ PCI_DEVICE(0x6766, PCI_ANY_ID),
268662306a36Sopenharmony_ci	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
268762306a36Sopenharmony_ci	  .class_mask = 0xffffff,
268862306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_GFHDMI | AZX_DCAPS_POSFIX_LPIB |
268962306a36Sopenharmony_ci	  AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT },
269062306a36Sopenharmony_ci	/* VIA VT8251/VT8237A */
269162306a36Sopenharmony_ci	{ PCI_VDEVICE(VIA, 0x3288), .driver_data = AZX_DRIVER_VIA },
269262306a36Sopenharmony_ci	/* VIA GFX VT7122/VX900 */
269362306a36Sopenharmony_ci	{ PCI_VDEVICE(VIA, 0x9170), .driver_data = AZX_DRIVER_GENERIC },
269462306a36Sopenharmony_ci	/* VIA GFX VT6122/VX11 */
269562306a36Sopenharmony_ci	{ PCI_VDEVICE(VIA, 0x9140), .driver_data = AZX_DRIVER_GENERIC },
269662306a36Sopenharmony_ci	/* SIS966 */
269762306a36Sopenharmony_ci	{ PCI_VDEVICE(SI, 0x7502), .driver_data = AZX_DRIVER_SIS },
269862306a36Sopenharmony_ci	/* ULI M5461 */
269962306a36Sopenharmony_ci	{ PCI_VDEVICE(AL, 0x5461), .driver_data = AZX_DRIVER_ULI },
270062306a36Sopenharmony_ci	/* NVIDIA MCP */
270162306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
270262306a36Sopenharmony_ci	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
270362306a36Sopenharmony_ci	  .class_mask = 0xffffff,
270462306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_NVIDIA | AZX_DCAPS_PRESET_NVIDIA },
270562306a36Sopenharmony_ci	/* Teradici */
270662306a36Sopenharmony_ci	{ PCI_DEVICE(0x6549, 0x1200),
270762306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT },
270862306a36Sopenharmony_ci	{ PCI_DEVICE(0x6549, 0x2200),
270962306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT },
271062306a36Sopenharmony_ci	/* Creative X-Fi (CA0110-IBG) */
271162306a36Sopenharmony_ci	/* CTHDA chips */
271262306a36Sopenharmony_ci	{ PCI_VDEVICE(CREATIVE, 0x0010),
271362306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
271462306a36Sopenharmony_ci	{ PCI_VDEVICE(CREATIVE, 0x0012),
271562306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
271662306a36Sopenharmony_ci#if !IS_ENABLED(CONFIG_SND_CTXFI)
271762306a36Sopenharmony_ci	/* the following entry conflicts with snd-ctxfi driver,
271862306a36Sopenharmony_ci	 * as ctxfi driver mutates from HD-audio to native mode with
271962306a36Sopenharmony_ci	 * a special command sequence.
272062306a36Sopenharmony_ci	 */
272162306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
272262306a36Sopenharmony_ci	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
272362306a36Sopenharmony_ci	  .class_mask = 0xffffff,
272462306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
272562306a36Sopenharmony_ci	  AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB },
272662306a36Sopenharmony_ci#else
272762306a36Sopenharmony_ci	/* this entry seems still valid -- i.e. without emu20kx chip */
272862306a36Sopenharmony_ci	{ PCI_VDEVICE(CREATIVE, 0x0009),
272962306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
273062306a36Sopenharmony_ci	  AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB },
273162306a36Sopenharmony_ci#endif
273262306a36Sopenharmony_ci	/* CM8888 */
273362306a36Sopenharmony_ci	{ PCI_VDEVICE(CMEDIA, 0x5011),
273462306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_CMEDIA |
273562306a36Sopenharmony_ci	  AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_SNOOP_OFF },
273662306a36Sopenharmony_ci	/* Vortex86MX */
273762306a36Sopenharmony_ci	{ PCI_VDEVICE(RDC, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
273862306a36Sopenharmony_ci	/* VMware HDAudio */
273962306a36Sopenharmony_ci	{ PCI_VDEVICE(VMWARE, 0x1977), .driver_data = AZX_DRIVER_GENERIC },
274062306a36Sopenharmony_ci	/* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
274162306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
274262306a36Sopenharmony_ci	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
274362306a36Sopenharmony_ci	  .class_mask = 0xffffff,
274462306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
274562306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_ANY_ID),
274662306a36Sopenharmony_ci	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
274762306a36Sopenharmony_ci	  .class_mask = 0xffffff,
274862306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
274962306a36Sopenharmony_ci	/* Zhaoxin */
275062306a36Sopenharmony_ci	{ PCI_VDEVICE(ZHAOXIN, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN },
275162306a36Sopenharmony_ci	/* Loongson HDAudio*/
275262306a36Sopenharmony_ci	{ PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDA),
275362306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_LOONGSON },
275462306a36Sopenharmony_ci	{ PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI),
275562306a36Sopenharmony_ci	  .driver_data = AZX_DRIVER_LOONGSON },
275662306a36Sopenharmony_ci	{ 0, }
275762306a36Sopenharmony_ci};
275862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, azx_ids);
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci/* pci_driver definition */
276162306a36Sopenharmony_cistatic struct pci_driver azx_driver = {
276262306a36Sopenharmony_ci	.name = KBUILD_MODNAME,
276362306a36Sopenharmony_ci	.id_table = azx_ids,
276462306a36Sopenharmony_ci	.probe = azx_probe,
276562306a36Sopenharmony_ci	.remove = azx_remove,
276662306a36Sopenharmony_ci	.shutdown = azx_shutdown,
276762306a36Sopenharmony_ci	.driver = {
276862306a36Sopenharmony_ci		.pm = AZX_PM_OPS,
276962306a36Sopenharmony_ci	},
277062306a36Sopenharmony_ci};
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_cimodule_pci_driver(azx_driver);
2773