18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *  hda_intel.c - Implementation of primary alsa driver code base
58c2ecf20Sopenharmony_ci *                for Intel HD Audio.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Copyright(c) 2004 Intel Corporation. All rights reserved.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *  Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
108c2ecf20Sopenharmony_ci *                     PeiSen Hou <pshou@realtek.com.tw>
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci *  CONTACTS:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *  Matt Jared		matt.jared@intel.com
158c2ecf20Sopenharmony_ci *  Andy Kopp		andy.kopp@intel.com
168c2ecf20Sopenharmony_ci *  Dan Kogan		dan.d.kogan@intel.com
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *  CHANGES:
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci *  2004.12.01	Major rewrite by tiwai, merged the work of pshou
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include <linux/delay.h>
248c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
258c2ecf20Sopenharmony_ci#include <linux/kernel.h>
268c2ecf20Sopenharmony_ci#include <linux/module.h>
278c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
288c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
298c2ecf20Sopenharmony_ci#include <linux/init.h>
308c2ecf20Sopenharmony_ci#include <linux/slab.h>
318c2ecf20Sopenharmony_ci#include <linux/pci.h>
328c2ecf20Sopenharmony_ci#include <linux/mutex.h>
338c2ecf20Sopenharmony_ci#include <linux/io.h>
348c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
358c2ecf20Sopenharmony_ci#include <linux/clocksource.h>
368c2ecf20Sopenharmony_ci#include <linux/time.h>
378c2ecf20Sopenharmony_ci#include <linux/completion.h>
388c2ecf20Sopenharmony_ci#include <linux/acpi.h>
398c2ecf20Sopenharmony_ci#include <linux/pgtable.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
428c2ecf20Sopenharmony_ci/* for snoop control */
438c2ecf20Sopenharmony_ci#include <asm/set_memory.h>
448c2ecf20Sopenharmony_ci#include <asm/cpufeature.h>
458c2ecf20Sopenharmony_ci#endif
468c2ecf20Sopenharmony_ci#include <sound/core.h>
478c2ecf20Sopenharmony_ci#include <sound/initval.h>
488c2ecf20Sopenharmony_ci#include <sound/hdaudio.h>
498c2ecf20Sopenharmony_ci#include <sound/hda_i915.h>
508c2ecf20Sopenharmony_ci#include <sound/intel-dsp-config.h>
518c2ecf20Sopenharmony_ci#include <linux/vgaarb.h>
528c2ecf20Sopenharmony_ci#include <linux/vga_switcheroo.h>
538c2ecf20Sopenharmony_ci#include <linux/firmware.h>
548c2ecf20Sopenharmony_ci#include <sound/hda_codec.h>
558c2ecf20Sopenharmony_ci#include "hda_controller.h"
568c2ecf20Sopenharmony_ci#include "hda_intel.h"
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS
598c2ecf20Sopenharmony_ci#include "hda_intel_trace.h"
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/* position fix mode */
628c2ecf20Sopenharmony_cienum {
638c2ecf20Sopenharmony_ci	POS_FIX_AUTO,
648c2ecf20Sopenharmony_ci	POS_FIX_LPIB,
658c2ecf20Sopenharmony_ci	POS_FIX_POSBUF,
668c2ecf20Sopenharmony_ci	POS_FIX_VIACOMBO,
678c2ecf20Sopenharmony_ci	POS_FIX_COMBO,
688c2ecf20Sopenharmony_ci	POS_FIX_SKL,
698c2ecf20Sopenharmony_ci	POS_FIX_FIFO,
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/* Defines for ATI HD Audio support in SB450 south bridge */
738c2ecf20Sopenharmony_ci#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR   0x42
748c2ecf20Sopenharmony_ci#define ATI_SB450_HDAUDIO_ENABLE_SNOOP      0x02
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/* Defines for Nvidia HDA support */
778c2ecf20Sopenharmony_ci#define NVIDIA_HDA_TRANSREG_ADDR      0x4e
788c2ecf20Sopenharmony_ci#define NVIDIA_HDA_ENABLE_COHBITS     0x0f
798c2ecf20Sopenharmony_ci#define NVIDIA_HDA_ISTRM_COH          0x4d
808c2ecf20Sopenharmony_ci#define NVIDIA_HDA_OSTRM_COH          0x4c
818c2ecf20Sopenharmony_ci#define NVIDIA_HDA_ENABLE_COHBIT      0x01
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/* Defines for Intel SCH HDA snoop control */
848c2ecf20Sopenharmony_ci#define INTEL_HDA_CGCTL	 0x48
858c2ecf20Sopenharmony_ci#define INTEL_HDA_CGCTL_MISCBDCGE        (0x1 << 6)
868c2ecf20Sopenharmony_ci#define INTEL_SCH_HDA_DEVC      0x78
878c2ecf20Sopenharmony_ci#define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci/* Define VIA HD Audio Device ID*/
908c2ecf20Sopenharmony_ci#define VIA_HDAC_DEVICE_ID		0x3288
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/* max number of SDs */
938c2ecf20Sopenharmony_ci/* ICH, ATI and VIA have 4 playback and 4 capture */
948c2ecf20Sopenharmony_ci#define ICH6_NUM_CAPTURE	4
958c2ecf20Sopenharmony_ci#define ICH6_NUM_PLAYBACK	4
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/* ULI has 6 playback and 5 capture */
988c2ecf20Sopenharmony_ci#define ULI_NUM_CAPTURE		5
998c2ecf20Sopenharmony_ci#define ULI_NUM_PLAYBACK	6
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/* ATI HDMI may have up to 8 playbacks and 0 capture */
1028c2ecf20Sopenharmony_ci#define ATIHDMI_NUM_CAPTURE	0
1038c2ecf20Sopenharmony_ci#define ATIHDMI_NUM_PLAYBACK	8
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/* TERA has 4 playback and 3 capture */
1068c2ecf20Sopenharmony_ci#define TERA_NUM_CAPTURE	3
1078c2ecf20Sopenharmony_ci#define TERA_NUM_PLAYBACK	4
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
1118c2ecf20Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
1128c2ecf20Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
1138c2ecf20Sopenharmony_cistatic char *model[SNDRV_CARDS];
1148c2ecf20Sopenharmony_cistatic int position_fix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
1158c2ecf20Sopenharmony_cistatic int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
1168c2ecf20Sopenharmony_cistatic int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
1178c2ecf20Sopenharmony_cistatic int probe_only[SNDRV_CARDS];
1188c2ecf20Sopenharmony_cistatic int jackpoll_ms[SNDRV_CARDS];
1198c2ecf20Sopenharmony_cistatic int single_cmd = -1;
1208c2ecf20Sopenharmony_cistatic int enable_msi = -1;
1218c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_HDA_PATCH_LOADER
1228c2ecf20Sopenharmony_cistatic char *patch[SNDRV_CARDS];
1238c2ecf20Sopenharmony_ci#endif
1248c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_HDA_INPUT_BEEP
1258c2ecf20Sopenharmony_cistatic bool beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] =
1268c2ecf20Sopenharmony_ci					CONFIG_SND_HDA_INPUT_BEEP_MODE};
1278c2ecf20Sopenharmony_ci#endif
1288c2ecf20Sopenharmony_cistatic bool dmic_detect = 1;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cimodule_param_array(index, int, NULL, 0444);
1318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
1328c2ecf20Sopenharmony_cimodule_param_array(id, charp, NULL, 0444);
1338c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for Intel HD audio interface.");
1348c2ecf20Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444);
1358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable Intel HD audio interface.");
1368c2ecf20Sopenharmony_cimodule_param_array(model, charp, NULL, 0444);
1378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(model, "Use the given board model.");
1388c2ecf20Sopenharmony_cimodule_param_array(position_fix, int, NULL, 0444);
1398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(position_fix, "DMA pointer read method."
1408c2ecf20Sopenharmony_ci		 "(-1 = system default, 0 = auto, 1 = LPIB, 2 = POSBUF, 3 = VIACOMBO, 4 = COMBO, 5 = SKL+, 6 = FIFO).");
1418c2ecf20Sopenharmony_cimodule_param_array(bdl_pos_adj, int, NULL, 0644);
1428c2ecf20Sopenharmony_ciMODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset.");
1438c2ecf20Sopenharmony_cimodule_param_array(probe_mask, int, NULL, 0444);
1448c2ecf20Sopenharmony_ciMODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
1458c2ecf20Sopenharmony_cimodule_param_array(probe_only, int, NULL, 0444);
1468c2ecf20Sopenharmony_ciMODULE_PARM_DESC(probe_only, "Only probing and no codec initialization.");
1478c2ecf20Sopenharmony_cimodule_param_array(jackpoll_ms, int, NULL, 0444);
1488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(jackpoll_ms, "Ms between polling for jack events (default = 0, using unsol events only)");
1498c2ecf20Sopenharmony_cimodule_param(single_cmd, bint, 0444);
1508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
1518c2ecf20Sopenharmony_ci		 "(for debugging only).");
1528c2ecf20Sopenharmony_cimodule_param(enable_msi, bint, 0444);
1538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
1548c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_HDA_PATCH_LOADER
1558c2ecf20Sopenharmony_cimodule_param_array(patch, charp, NULL, 0444);
1568c2ecf20Sopenharmony_ciMODULE_PARM_DESC(patch, "Patch file for Intel HD audio interface.");
1578c2ecf20Sopenharmony_ci#endif
1588c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_HDA_INPUT_BEEP
1598c2ecf20Sopenharmony_cimodule_param_array(beep_mode, bool, NULL, 0444);
1608c2ecf20Sopenharmony_ciMODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode "
1618c2ecf20Sopenharmony_ci			    "(0=off, 1=on) (default=1).");
1628c2ecf20Sopenharmony_ci#endif
1638c2ecf20Sopenharmony_cimodule_param(dmic_detect, bool, 0444);
1648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dmic_detect, "Allow DSP driver selection (bypass this driver) "
1658c2ecf20Sopenharmony_ci			     "(0=off, 1=on) (default=1); "
1668c2ecf20Sopenharmony_ci		 "deprecated, use snd-intel-dspcfg.dsp_driver option instead");
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
1698c2ecf20Sopenharmony_cistatic int param_set_xint(const char *val, const struct kernel_param *kp);
1708c2ecf20Sopenharmony_cistatic const struct kernel_param_ops param_ops_xint = {
1718c2ecf20Sopenharmony_ci	.set = param_set_xint,
1728c2ecf20Sopenharmony_ci	.get = param_get_int,
1738c2ecf20Sopenharmony_ci};
1748c2ecf20Sopenharmony_ci#define param_check_xint param_check_int
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
1778c2ecf20Sopenharmony_cimodule_param(power_save, xint, 0644);
1788c2ecf20Sopenharmony_ciMODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
1798c2ecf20Sopenharmony_ci		 "(in second, 0 = disable).");
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic bool pm_blacklist = true;
1828c2ecf20Sopenharmony_cimodule_param(pm_blacklist, bool, 0644);
1838c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pm_blacklist, "Enable power-management denylist");
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci/* reset the HD-audio controller in power save mode.
1868c2ecf20Sopenharmony_ci * this may give more power-saving, but will take longer time to
1878c2ecf20Sopenharmony_ci * wake up.
1888c2ecf20Sopenharmony_ci */
1898c2ecf20Sopenharmony_cistatic bool power_save_controller = 1;
1908c2ecf20Sopenharmony_cimodule_param(power_save_controller, bool, 0644);
1918c2ecf20Sopenharmony_ciMODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
1928c2ecf20Sopenharmony_ci#else
1938c2ecf20Sopenharmony_ci#define power_save	0
1948c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic int align_buffer_size = -1;
1978c2ecf20Sopenharmony_cimodule_param(align_buffer_size, bint, 0644);
1988c2ecf20Sopenharmony_ciMODULE_PARM_DESC(align_buffer_size,
1998c2ecf20Sopenharmony_ci		"Force buffer and period sizes to be multiple of 128 bytes.");
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
2028c2ecf20Sopenharmony_cistatic int hda_snoop = -1;
2038c2ecf20Sopenharmony_cimodule_param_named(snoop, hda_snoop, bint, 0444);
2048c2ecf20Sopenharmony_ciMODULE_PARM_DESC(snoop, "Enable/disable snooping");
2058c2ecf20Sopenharmony_ci#else
2068c2ecf20Sopenharmony_ci#define hda_snoop		true
2078c2ecf20Sopenharmony_ci#endif
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
2118c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
2128c2ecf20Sopenharmony_ci			 "{Intel, ICH6M},"
2138c2ecf20Sopenharmony_ci			 "{Intel, ICH7},"
2148c2ecf20Sopenharmony_ci			 "{Intel, ESB2},"
2158c2ecf20Sopenharmony_ci			 "{Intel, ICH8},"
2168c2ecf20Sopenharmony_ci			 "{Intel, ICH9},"
2178c2ecf20Sopenharmony_ci			 "{Intel, ICH10},"
2188c2ecf20Sopenharmony_ci			 "{Intel, PCH},"
2198c2ecf20Sopenharmony_ci			 "{Intel, CPT},"
2208c2ecf20Sopenharmony_ci			 "{Intel, PPT},"
2218c2ecf20Sopenharmony_ci			 "{Intel, LPT},"
2228c2ecf20Sopenharmony_ci			 "{Intel, LPT_LP},"
2238c2ecf20Sopenharmony_ci			 "{Intel, WPT_LP},"
2248c2ecf20Sopenharmony_ci			 "{Intel, SPT},"
2258c2ecf20Sopenharmony_ci			 "{Intel, SPT_LP},"
2268c2ecf20Sopenharmony_ci			 "{Intel, HPT},"
2278c2ecf20Sopenharmony_ci			 "{Intel, PBG},"
2288c2ecf20Sopenharmony_ci			 "{Intel, SCH},"
2298c2ecf20Sopenharmony_ci			 "{ATI, SB450},"
2308c2ecf20Sopenharmony_ci			 "{ATI, SB600},"
2318c2ecf20Sopenharmony_ci			 "{ATI, RS600},"
2328c2ecf20Sopenharmony_ci			 "{ATI, RS690},"
2338c2ecf20Sopenharmony_ci			 "{ATI, RS780},"
2348c2ecf20Sopenharmony_ci			 "{ATI, R600},"
2358c2ecf20Sopenharmony_ci			 "{ATI, RV630},"
2368c2ecf20Sopenharmony_ci			 "{ATI, RV610},"
2378c2ecf20Sopenharmony_ci			 "{ATI, RV670},"
2388c2ecf20Sopenharmony_ci			 "{ATI, RV635},"
2398c2ecf20Sopenharmony_ci			 "{ATI, RV620},"
2408c2ecf20Sopenharmony_ci			 "{ATI, RV770},"
2418c2ecf20Sopenharmony_ci			 "{VIA, VT8251},"
2428c2ecf20Sopenharmony_ci			 "{VIA, VT8237A},"
2438c2ecf20Sopenharmony_ci			 "{SiS, SIS966},"
2448c2ecf20Sopenharmony_ci			 "{ULI, M5461}}");
2458c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel HDA driver");
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci#if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO)
2488c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
2498c2ecf20Sopenharmony_ci#define SUPPORT_VGA_SWITCHEROO
2508c2ecf20Sopenharmony_ci#endif
2518c2ecf20Sopenharmony_ci#endif
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci/*
2558c2ecf20Sopenharmony_ci */
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci/* driver types */
2588c2ecf20Sopenharmony_cienum {
2598c2ecf20Sopenharmony_ci	AZX_DRIVER_ICH,
2608c2ecf20Sopenharmony_ci	AZX_DRIVER_PCH,
2618c2ecf20Sopenharmony_ci	AZX_DRIVER_SCH,
2628c2ecf20Sopenharmony_ci	AZX_DRIVER_SKL,
2638c2ecf20Sopenharmony_ci	AZX_DRIVER_HDMI,
2648c2ecf20Sopenharmony_ci	AZX_DRIVER_ATI,
2658c2ecf20Sopenharmony_ci	AZX_DRIVER_ATIHDMI,
2668c2ecf20Sopenharmony_ci	AZX_DRIVER_ATIHDMI_NS,
2678c2ecf20Sopenharmony_ci	AZX_DRIVER_GFHDMI,
2688c2ecf20Sopenharmony_ci	AZX_DRIVER_VIA,
2698c2ecf20Sopenharmony_ci	AZX_DRIVER_SIS,
2708c2ecf20Sopenharmony_ci	AZX_DRIVER_ULI,
2718c2ecf20Sopenharmony_ci	AZX_DRIVER_NVIDIA,
2728c2ecf20Sopenharmony_ci	AZX_DRIVER_TERA,
2738c2ecf20Sopenharmony_ci	AZX_DRIVER_CTX,
2748c2ecf20Sopenharmony_ci	AZX_DRIVER_CTHDA,
2758c2ecf20Sopenharmony_ci	AZX_DRIVER_CMEDIA,
2768c2ecf20Sopenharmony_ci	AZX_DRIVER_ZHAOXIN,
2778c2ecf20Sopenharmony_ci	AZX_DRIVER_GENERIC,
2788c2ecf20Sopenharmony_ci	AZX_NUM_DRIVERS, /* keep this as last entry */
2798c2ecf20Sopenharmony_ci};
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci#define azx_get_snoop_type(chip) \
2828c2ecf20Sopenharmony_ci	(((chip)->driver_caps & AZX_DCAPS_SNOOP_MASK) >> 10)
2838c2ecf20Sopenharmony_ci#define AZX_DCAPS_SNOOP_TYPE(type) ((AZX_SNOOP_TYPE_ ## type) << 10)
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci/* quirks for old Intel chipsets */
2868c2ecf20Sopenharmony_ci#define AZX_DCAPS_INTEL_ICH \
2878c2ecf20Sopenharmony_ci	(AZX_DCAPS_OLD_SSYNC | AZX_DCAPS_NO_ALIGN_BUFSIZE)
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci/* quirks for Intel PCH */
2908c2ecf20Sopenharmony_ci#define AZX_DCAPS_INTEL_PCH_BASE \
2918c2ecf20Sopenharmony_ci	(AZX_DCAPS_NO_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\
2928c2ecf20Sopenharmony_ci	 AZX_DCAPS_SNOOP_TYPE(SCH))
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci/* PCH up to IVB; no runtime PM; bind with i915 gfx */
2958c2ecf20Sopenharmony_ci#define AZX_DCAPS_INTEL_PCH_NOPM \
2968c2ecf20Sopenharmony_ci	(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT)
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci/* PCH for HSW/BDW; with runtime PM */
2998c2ecf20Sopenharmony_ci/* no i915 binding for this as HSW/BDW has another controller for HDMI */
3008c2ecf20Sopenharmony_ci#define AZX_DCAPS_INTEL_PCH \
3018c2ecf20Sopenharmony_ci	(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME)
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci/* HSW HDMI */
3048c2ecf20Sopenharmony_ci#define AZX_DCAPS_INTEL_HASWELL \
3058c2ecf20Sopenharmony_ci	(/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\
3068c2ecf20Sopenharmony_ci	 AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\
3078c2ecf20Sopenharmony_ci	 AZX_DCAPS_SNOOP_TYPE(SCH))
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci/* Broadwell HDMI can't use position buffer reliably, force to use LPIB */
3108c2ecf20Sopenharmony_ci#define AZX_DCAPS_INTEL_BROADWELL \
3118c2ecf20Sopenharmony_ci	(/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\
3128c2ecf20Sopenharmony_ci	 AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\
3138c2ecf20Sopenharmony_ci	 AZX_DCAPS_SNOOP_TYPE(SCH))
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci#define AZX_DCAPS_INTEL_BAYTRAIL \
3168c2ecf20Sopenharmony_ci	(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT)
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci#define AZX_DCAPS_INTEL_BRASWELL \
3198c2ecf20Sopenharmony_ci	(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
3208c2ecf20Sopenharmony_ci	 AZX_DCAPS_I915_COMPONENT)
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci#define AZX_DCAPS_INTEL_SKYLAKE \
3238c2ecf20Sopenharmony_ci	(AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\
3248c2ecf20Sopenharmony_ci	 AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT)
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci#define AZX_DCAPS_INTEL_BROXTON		AZX_DCAPS_INTEL_SKYLAKE
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci/* quirks for ATI SB / AMD Hudson */
3298c2ecf20Sopenharmony_ci#define AZX_DCAPS_PRESET_ATI_SB \
3308c2ecf20Sopenharmony_ci	(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_POSFIX_LPIB |\
3318c2ecf20Sopenharmony_ci	 AZX_DCAPS_SNOOP_TYPE(ATI))
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci/* quirks for ATI/AMD HDMI */
3348c2ecf20Sopenharmony_ci#define AZX_DCAPS_PRESET_ATI_HDMI \
3358c2ecf20Sopenharmony_ci	(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_POSFIX_LPIB|\
3368c2ecf20Sopenharmony_ci	 AZX_DCAPS_NO_MSI64)
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci/* quirks for ATI HDMI with snoop off */
3398c2ecf20Sopenharmony_ci#define AZX_DCAPS_PRESET_ATI_HDMI_NS \
3408c2ecf20Sopenharmony_ci	(AZX_DCAPS_PRESET_ATI_HDMI | AZX_DCAPS_SNOOP_OFF)
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci/* quirks for AMD SB */
3438c2ecf20Sopenharmony_ci#define AZX_DCAPS_PRESET_AMD_SB \
3448c2ecf20Sopenharmony_ci	(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_AMD_WORKAROUND |\
3458c2ecf20Sopenharmony_ci	 AZX_DCAPS_SNOOP_TYPE(ATI) | AZX_DCAPS_PM_RUNTIME |\
3468c2ecf20Sopenharmony_ci	 AZX_DCAPS_RETRY_PROBE)
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci/* quirks for Nvidia */
3498c2ecf20Sopenharmony_ci#define AZX_DCAPS_PRESET_NVIDIA \
3508c2ecf20Sopenharmony_ci	(AZX_DCAPS_NO_MSI | AZX_DCAPS_CORBRP_SELF_CLEAR |\
3518c2ecf20Sopenharmony_ci	 AZX_DCAPS_SNOOP_TYPE(NVIDIA))
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci#define AZX_DCAPS_PRESET_CTHDA \
3548c2ecf20Sopenharmony_ci	(AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB |\
3558c2ecf20Sopenharmony_ci	 AZX_DCAPS_NO_64BIT |\
3568c2ecf20Sopenharmony_ci	 AZX_DCAPS_4K_BDLE_BOUNDARY | AZX_DCAPS_SNOOP_OFF)
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci/*
3598c2ecf20Sopenharmony_ci * vga_switcheroo support
3608c2ecf20Sopenharmony_ci */
3618c2ecf20Sopenharmony_ci#ifdef SUPPORT_VGA_SWITCHEROO
3628c2ecf20Sopenharmony_ci#define use_vga_switcheroo(chip)	((chip)->use_vga_switcheroo)
3638c2ecf20Sopenharmony_ci#define needs_eld_notify_link(chip)	((chip)->bus.keep_power)
3648c2ecf20Sopenharmony_ci#else
3658c2ecf20Sopenharmony_ci#define use_vga_switcheroo(chip)	0
3668c2ecf20Sopenharmony_ci#define needs_eld_notify_link(chip)	false
3678c2ecf20Sopenharmony_ci#endif
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci#define CONTROLLER_IN_GPU(pci) (((pci)->vendor == 0x8086) &&         \
3708c2ecf20Sopenharmony_ci				       (((pci)->device == 0x0a0c) || \
3718c2ecf20Sopenharmony_ci					((pci)->device == 0x0c0c) || \
3728c2ecf20Sopenharmony_ci					((pci)->device == 0x0d0c) || \
3738c2ecf20Sopenharmony_ci					((pci)->device == 0x160c) || \
3748c2ecf20Sopenharmony_ci					((pci)->device == 0x490d) || \
3758c2ecf20Sopenharmony_ci					((pci)->device == 0x4f90) || \
3768c2ecf20Sopenharmony_ci					((pci)->device == 0x4f91) || \
3778c2ecf20Sopenharmony_ci					((pci)->device == 0x4f92)))
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic const char * const driver_short_names[] = {
3828c2ecf20Sopenharmony_ci	[AZX_DRIVER_ICH] = "HDA Intel",
3838c2ecf20Sopenharmony_ci	[AZX_DRIVER_PCH] = "HDA Intel PCH",
3848c2ecf20Sopenharmony_ci	[AZX_DRIVER_SCH] = "HDA Intel MID",
3858c2ecf20Sopenharmony_ci	[AZX_DRIVER_SKL] = "HDA Intel PCH", /* kept old name for compatibility */
3868c2ecf20Sopenharmony_ci	[AZX_DRIVER_HDMI] = "HDA Intel HDMI",
3878c2ecf20Sopenharmony_ci	[AZX_DRIVER_ATI] = "HDA ATI SB",
3888c2ecf20Sopenharmony_ci	[AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
3898c2ecf20Sopenharmony_ci	[AZX_DRIVER_ATIHDMI_NS] = "HDA ATI HDMI",
3908c2ecf20Sopenharmony_ci	[AZX_DRIVER_GFHDMI] = "HDA GF HDMI",
3918c2ecf20Sopenharmony_ci	[AZX_DRIVER_VIA] = "HDA VIA VT82xx",
3928c2ecf20Sopenharmony_ci	[AZX_DRIVER_SIS] = "HDA SIS966",
3938c2ecf20Sopenharmony_ci	[AZX_DRIVER_ULI] = "HDA ULI M5461",
3948c2ecf20Sopenharmony_ci	[AZX_DRIVER_NVIDIA] = "HDA NVidia",
3958c2ecf20Sopenharmony_ci	[AZX_DRIVER_TERA] = "HDA Teradici",
3968c2ecf20Sopenharmony_ci	[AZX_DRIVER_CTX] = "HDA Creative",
3978c2ecf20Sopenharmony_ci	[AZX_DRIVER_CTHDA] = "HDA Creative",
3988c2ecf20Sopenharmony_ci	[AZX_DRIVER_CMEDIA] = "HDA C-Media",
3998c2ecf20Sopenharmony_ci	[AZX_DRIVER_ZHAOXIN] = "HDA Zhaoxin",
4008c2ecf20Sopenharmony_ci	[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
4018c2ecf20Sopenharmony_ci};
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic int azx_acquire_irq(struct azx *chip, int do_disconnect);
4048c2ecf20Sopenharmony_cistatic void set_default_power_save(struct azx *chip);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci/*
4078c2ecf20Sopenharmony_ci * initialize the PCI registers
4088c2ecf20Sopenharmony_ci */
4098c2ecf20Sopenharmony_ci/* update bits in a PCI register byte */
4108c2ecf20Sopenharmony_cistatic void update_pci_byte(struct pci_dev *pci, unsigned int reg,
4118c2ecf20Sopenharmony_ci			    unsigned char mask, unsigned char val)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	unsigned char data;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	pci_read_config_byte(pci, reg, &data);
4168c2ecf20Sopenharmony_ci	data &= ~mask;
4178c2ecf20Sopenharmony_ci	data |= (val & mask);
4188c2ecf20Sopenharmony_ci	pci_write_config_byte(pci, reg, data);
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic void azx_init_pci(struct azx *chip)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	int snoop_type = azx_get_snoop_type(chip);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	/* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
4268c2ecf20Sopenharmony_ci	 * TCSEL == Traffic Class Select Register, which sets PCI express QOS
4278c2ecf20Sopenharmony_ci	 * Ensuring these bits are 0 clears playback static on some HD Audio
4288c2ecf20Sopenharmony_ci	 * codecs.
4298c2ecf20Sopenharmony_ci	 * The PCI register TCSEL is defined in the Intel manuals.
4308c2ecf20Sopenharmony_ci	 */
4318c2ecf20Sopenharmony_ci	if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) {
4328c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "Clearing TCSEL\n");
4338c2ecf20Sopenharmony_ci		update_pci_byte(chip->pci, AZX_PCIREG_TCSEL, 0x07, 0);
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	/* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio,
4378c2ecf20Sopenharmony_ci	 * we need to enable snoop.
4388c2ecf20Sopenharmony_ci	 */
4398c2ecf20Sopenharmony_ci	if (snoop_type == AZX_SNOOP_TYPE_ATI) {
4408c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "Setting ATI snoop: %d\n",
4418c2ecf20Sopenharmony_ci			azx_snoop(chip));
4428c2ecf20Sopenharmony_ci		update_pci_byte(chip->pci,
4438c2ecf20Sopenharmony_ci				ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07,
4448c2ecf20Sopenharmony_ci				azx_snoop(chip) ? ATI_SB450_HDAUDIO_ENABLE_SNOOP : 0);
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	/* For NVIDIA HDA, enable snoop */
4488c2ecf20Sopenharmony_ci	if (snoop_type == AZX_SNOOP_TYPE_NVIDIA) {
4498c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "Setting Nvidia snoop: %d\n",
4508c2ecf20Sopenharmony_ci			azx_snoop(chip));
4518c2ecf20Sopenharmony_ci		update_pci_byte(chip->pci,
4528c2ecf20Sopenharmony_ci				NVIDIA_HDA_TRANSREG_ADDR,
4538c2ecf20Sopenharmony_ci				0x0f, NVIDIA_HDA_ENABLE_COHBITS);
4548c2ecf20Sopenharmony_ci		update_pci_byte(chip->pci,
4558c2ecf20Sopenharmony_ci				NVIDIA_HDA_ISTRM_COH,
4568c2ecf20Sopenharmony_ci				0x01, NVIDIA_HDA_ENABLE_COHBIT);
4578c2ecf20Sopenharmony_ci		update_pci_byte(chip->pci,
4588c2ecf20Sopenharmony_ci				NVIDIA_HDA_OSTRM_COH,
4598c2ecf20Sopenharmony_ci				0x01, NVIDIA_HDA_ENABLE_COHBIT);
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	/* Enable SCH/PCH snoop if needed */
4638c2ecf20Sopenharmony_ci	if (snoop_type == AZX_SNOOP_TYPE_SCH) {
4648c2ecf20Sopenharmony_ci		unsigned short snoop;
4658c2ecf20Sopenharmony_ci		pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
4668c2ecf20Sopenharmony_ci		if ((!azx_snoop(chip) && !(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)) ||
4678c2ecf20Sopenharmony_ci		    (azx_snoop(chip) && (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP))) {
4688c2ecf20Sopenharmony_ci			snoop &= ~INTEL_SCH_HDA_DEVC_NOSNOOP;
4698c2ecf20Sopenharmony_ci			if (!azx_snoop(chip))
4708c2ecf20Sopenharmony_ci				snoop |= INTEL_SCH_HDA_DEVC_NOSNOOP;
4718c2ecf20Sopenharmony_ci			pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, snoop);
4728c2ecf20Sopenharmony_ci			pci_read_config_word(chip->pci,
4738c2ecf20Sopenharmony_ci				INTEL_SCH_HDA_DEVC, &snoop);
4748c2ecf20Sopenharmony_ci		}
4758c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "SCH snoop: %s\n",
4768c2ecf20Sopenharmony_ci			(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) ?
4778c2ecf20Sopenharmony_ci			"Disabled" : "Enabled");
4788c2ecf20Sopenharmony_ci        }
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci/*
4828c2ecf20Sopenharmony_ci * In BXT-P A0, HD-Audio DMA requests is later than expected,
4838c2ecf20Sopenharmony_ci * and makes an audio stream sensitive to system latencies when
4848c2ecf20Sopenharmony_ci * 24/32 bits are playing.
4858c2ecf20Sopenharmony_ci * Adjusting threshold of DMA fifo to force the DMA request
4868c2ecf20Sopenharmony_ci * sooner to improve latency tolerance at the expense of power.
4878c2ecf20Sopenharmony_ci */
4888c2ecf20Sopenharmony_cistatic void bxt_reduce_dma_latency(struct azx *chip)
4898c2ecf20Sopenharmony_ci{
4908c2ecf20Sopenharmony_ci	u32 val;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	val = azx_readl(chip, VS_EM4L);
4938c2ecf20Sopenharmony_ci	val &= (0x3 << 20);
4948c2ecf20Sopenharmony_ci	azx_writel(chip, VS_EM4L, val);
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci/*
4988c2ecf20Sopenharmony_ci * ML_LCAP bits:
4998c2ecf20Sopenharmony_ci *  bit 0: 6 MHz Supported
5008c2ecf20Sopenharmony_ci *  bit 1: 12 MHz Supported
5018c2ecf20Sopenharmony_ci *  bit 2: 24 MHz Supported
5028c2ecf20Sopenharmony_ci *  bit 3: 48 MHz Supported
5038c2ecf20Sopenharmony_ci *  bit 4: 96 MHz Supported
5048c2ecf20Sopenharmony_ci *  bit 5: 192 MHz Supported
5058c2ecf20Sopenharmony_ci */
5068c2ecf20Sopenharmony_cistatic int intel_get_lctl_scf(struct azx *chip)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
5098c2ecf20Sopenharmony_ci	static const int preferred_bits[] = { 2, 3, 1, 4, 5 };
5108c2ecf20Sopenharmony_ci	u32 val, t;
5118c2ecf20Sopenharmony_ci	int i;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCAP);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(preferred_bits); i++) {
5168c2ecf20Sopenharmony_ci		t = preferred_bits[i];
5178c2ecf20Sopenharmony_ci		if (val & (1 << t))
5188c2ecf20Sopenharmony_ci			return t;
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	dev_warn(chip->card->dev, "set audio clock frequency to 6MHz");
5228c2ecf20Sopenharmony_ci	return 0;
5238c2ecf20Sopenharmony_ci}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_cistatic int intel_ml_lctl_set_power(struct azx *chip, int state)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
5288c2ecf20Sopenharmony_ci	u32 val;
5298c2ecf20Sopenharmony_ci	int timeout;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	/*
5328c2ecf20Sopenharmony_ci	 * the codecs are sharing the first link setting by default
5338c2ecf20Sopenharmony_ci	 * If other links are enabled for stream, they need similar fix
5348c2ecf20Sopenharmony_ci	 */
5358c2ecf20Sopenharmony_ci	val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
5368c2ecf20Sopenharmony_ci	val &= ~AZX_MLCTL_SPA;
5378c2ecf20Sopenharmony_ci	val |= state << AZX_MLCTL_SPA_SHIFT;
5388c2ecf20Sopenharmony_ci	writel(val, bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
5398c2ecf20Sopenharmony_ci	/* wait for CPA */
5408c2ecf20Sopenharmony_ci	timeout = 50;
5418c2ecf20Sopenharmony_ci	while (timeout) {
5428c2ecf20Sopenharmony_ci		if (((readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL)) &
5438c2ecf20Sopenharmony_ci		    AZX_MLCTL_CPA) == (state << AZX_MLCTL_CPA_SHIFT))
5448c2ecf20Sopenharmony_ci			return 0;
5458c2ecf20Sopenharmony_ci		timeout--;
5468c2ecf20Sopenharmony_ci		udelay(10);
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	return -1;
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_cistatic void intel_init_lctl(struct azx *chip)
5538c2ecf20Sopenharmony_ci{
5548c2ecf20Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
5558c2ecf20Sopenharmony_ci	u32 val;
5568c2ecf20Sopenharmony_ci	int ret;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	/* 0. check lctl register value is correct or not */
5598c2ecf20Sopenharmony_ci	val = readl(bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
5608c2ecf20Sopenharmony_ci	/* if SCF is already set, let's use it */
5618c2ecf20Sopenharmony_ci	if ((val & ML_LCTL_SCF_MASK) != 0)
5628c2ecf20Sopenharmony_ci		return;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	/*
5658c2ecf20Sopenharmony_ci	 * Before operating on SPA, CPA must match SPA.
5668c2ecf20Sopenharmony_ci	 * Any deviation may result in undefined behavior.
5678c2ecf20Sopenharmony_ci	 */
5688c2ecf20Sopenharmony_ci	if (((val & AZX_MLCTL_SPA) >> AZX_MLCTL_SPA_SHIFT) !=
5698c2ecf20Sopenharmony_ci		((val & AZX_MLCTL_CPA) >> AZX_MLCTL_CPA_SHIFT))
5708c2ecf20Sopenharmony_ci		return;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	/* 1. turn link down: set SPA to 0 and wait CPA to 0 */
5738c2ecf20Sopenharmony_ci	ret = intel_ml_lctl_set_power(chip, 0);
5748c2ecf20Sopenharmony_ci	udelay(100);
5758c2ecf20Sopenharmony_ci	if (ret)
5768c2ecf20Sopenharmony_ci		goto set_spa;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	/* 2. update SCF to select a properly audio clock*/
5798c2ecf20Sopenharmony_ci	val &= ~ML_LCTL_SCF_MASK;
5808c2ecf20Sopenharmony_ci	val |= intel_get_lctl_scf(chip);
5818c2ecf20Sopenharmony_ci	writel(val, bus->mlcap + AZX_ML_BASE + AZX_REG_ML_LCTL);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ciset_spa:
5848c2ecf20Sopenharmony_ci	/* 4. turn link up: set SPA to 1 and wait CPA to 1 */
5858c2ecf20Sopenharmony_ci	intel_ml_lctl_set_power(chip, 1);
5868c2ecf20Sopenharmony_ci	udelay(100);
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_cistatic void hda_intel_init_chip(struct azx *chip, bool full_reset)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
5928c2ecf20Sopenharmony_ci	struct pci_dev *pci = chip->pci;
5938c2ecf20Sopenharmony_ci	u32 val;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	snd_hdac_set_codec_wakeup(bus, true);
5968c2ecf20Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_SKL) {
5978c2ecf20Sopenharmony_ci		pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val);
5988c2ecf20Sopenharmony_ci		val = val & ~INTEL_HDA_CGCTL_MISCBDCGE;
5998c2ecf20Sopenharmony_ci		pci_write_config_dword(pci, INTEL_HDA_CGCTL, val);
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci	azx_init_chip(chip, full_reset);
6028c2ecf20Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_SKL) {
6038c2ecf20Sopenharmony_ci		pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val);
6048c2ecf20Sopenharmony_ci		val = val | INTEL_HDA_CGCTL_MISCBDCGE;
6058c2ecf20Sopenharmony_ci		pci_write_config_dword(pci, INTEL_HDA_CGCTL, val);
6068c2ecf20Sopenharmony_ci	}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	snd_hdac_set_codec_wakeup(bus, false);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	/* reduce dma latency to avoid noise */
6118c2ecf20Sopenharmony_ci	if (IS_BXT(pci))
6128c2ecf20Sopenharmony_ci		bxt_reduce_dma_latency(chip);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	if (bus->mlcap != NULL)
6158c2ecf20Sopenharmony_ci		intel_init_lctl(chip);
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci/* calculate runtime delay from LPIB */
6198c2ecf20Sopenharmony_cistatic int azx_get_delay_from_lpib(struct azx *chip, struct azx_dev *azx_dev,
6208c2ecf20Sopenharmony_ci				   unsigned int pos)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream = azx_dev->core.substream;
6238c2ecf20Sopenharmony_ci	int stream = substream->stream;
6248c2ecf20Sopenharmony_ci	unsigned int lpib_pos = azx_get_pos_lpib(chip, azx_dev);
6258c2ecf20Sopenharmony_ci	int delay;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
6288c2ecf20Sopenharmony_ci		delay = pos - lpib_pos;
6298c2ecf20Sopenharmony_ci	else
6308c2ecf20Sopenharmony_ci		delay = lpib_pos - pos;
6318c2ecf20Sopenharmony_ci	if (delay < 0) {
6328c2ecf20Sopenharmony_ci		if (delay >= azx_dev->core.delay_negative_threshold)
6338c2ecf20Sopenharmony_ci			delay = 0;
6348c2ecf20Sopenharmony_ci		else
6358c2ecf20Sopenharmony_ci			delay += azx_dev->core.bufsize;
6368c2ecf20Sopenharmony_ci	}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	if (delay >= azx_dev->core.period_bytes) {
6398c2ecf20Sopenharmony_ci		dev_info(chip->card->dev,
6408c2ecf20Sopenharmony_ci			 "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n",
6418c2ecf20Sopenharmony_ci			 delay, azx_dev->core.period_bytes);
6428c2ecf20Sopenharmony_ci		delay = 0;
6438c2ecf20Sopenharmony_ci		chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY;
6448c2ecf20Sopenharmony_ci		chip->get_delay[stream] = NULL;
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	return bytes_to_frames(substream->runtime, delay);
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_cistatic int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci/* called from IRQ */
6538c2ecf20Sopenharmony_cistatic int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
6568c2ecf20Sopenharmony_ci	int ok;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	ok = azx_position_ok(chip, azx_dev);
6598c2ecf20Sopenharmony_ci	if (ok == 1) {
6608c2ecf20Sopenharmony_ci		azx_dev->irq_pending = 0;
6618c2ecf20Sopenharmony_ci		return ok;
6628c2ecf20Sopenharmony_ci	} else if (ok == 0) {
6638c2ecf20Sopenharmony_ci		/* bogus IRQ, process it later */
6648c2ecf20Sopenharmony_ci		azx_dev->irq_pending = 1;
6658c2ecf20Sopenharmony_ci		schedule_work(&hda->irq_pending_work);
6668c2ecf20Sopenharmony_ci	}
6678c2ecf20Sopenharmony_ci	return 0;
6688c2ecf20Sopenharmony_ci}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci#define display_power(chip, enable) \
6718c2ecf20Sopenharmony_ci	snd_hdac_display_power(azx_bus(chip), HDA_CODEC_IDX_CONTROLLER, enable)
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci/*
6748c2ecf20Sopenharmony_ci * Check whether the current DMA position is acceptable for updating
6758c2ecf20Sopenharmony_ci * periods.  Returns non-zero if it's OK.
6768c2ecf20Sopenharmony_ci *
6778c2ecf20Sopenharmony_ci * Many HD-audio controllers appear pretty inaccurate about
6788c2ecf20Sopenharmony_ci * the update-IRQ timing.  The IRQ is issued before actually the
6798c2ecf20Sopenharmony_ci * data is processed.  So, we need to process it afterwords in a
6808c2ecf20Sopenharmony_ci * workqueue.
6818c2ecf20Sopenharmony_ci *
6828c2ecf20Sopenharmony_ci * Returns 1 if OK to proceed, 0 for delay handling, -1 for skipping update
6838c2ecf20Sopenharmony_ci */
6848c2ecf20Sopenharmony_cistatic int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
6858c2ecf20Sopenharmony_ci{
6868c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream = azx_dev->core.substream;
6878c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
6888c2ecf20Sopenharmony_ci	int stream = substream->stream;
6898c2ecf20Sopenharmony_ci	u32 wallclk;
6908c2ecf20Sopenharmony_ci	unsigned int pos;
6918c2ecf20Sopenharmony_ci	snd_pcm_uframes_t hwptr, target;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	wallclk = azx_readl(chip, WALLCLK) - azx_dev->core.start_wallclk;
6948c2ecf20Sopenharmony_ci	if (wallclk < (azx_dev->core.period_wallclk * 2) / 3)
6958c2ecf20Sopenharmony_ci		return -1;	/* bogus (too early) interrupt */
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	if (chip->get_position[stream])
6988c2ecf20Sopenharmony_ci		pos = chip->get_position[stream](chip, azx_dev);
6998c2ecf20Sopenharmony_ci	else { /* use the position buffer as default */
7008c2ecf20Sopenharmony_ci		pos = azx_get_pos_posbuf(chip, azx_dev);
7018c2ecf20Sopenharmony_ci		if (!pos || pos == (u32)-1) {
7028c2ecf20Sopenharmony_ci			dev_info(chip->card->dev,
7038c2ecf20Sopenharmony_ci				 "Invalid position buffer, using LPIB read method instead.\n");
7048c2ecf20Sopenharmony_ci			chip->get_position[stream] = azx_get_pos_lpib;
7058c2ecf20Sopenharmony_ci			if (chip->get_position[0] == azx_get_pos_lpib &&
7068c2ecf20Sopenharmony_ci			    chip->get_position[1] == azx_get_pos_lpib)
7078c2ecf20Sopenharmony_ci				azx_bus(chip)->use_posbuf = false;
7088c2ecf20Sopenharmony_ci			pos = azx_get_pos_lpib(chip, azx_dev);
7098c2ecf20Sopenharmony_ci			chip->get_delay[stream] = NULL;
7108c2ecf20Sopenharmony_ci		} else {
7118c2ecf20Sopenharmony_ci			chip->get_position[stream] = azx_get_pos_posbuf;
7128c2ecf20Sopenharmony_ci			if (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)
7138c2ecf20Sopenharmony_ci				chip->get_delay[stream] = azx_get_delay_from_lpib;
7148c2ecf20Sopenharmony_ci		}
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	if (pos >= azx_dev->core.bufsize)
7188c2ecf20Sopenharmony_ci		pos = 0;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	if (WARN_ONCE(!azx_dev->core.period_bytes,
7218c2ecf20Sopenharmony_ci		      "hda-intel: zero azx_dev->period_bytes"))
7228c2ecf20Sopenharmony_ci		return -1; /* this shouldn't happen! */
7238c2ecf20Sopenharmony_ci	if (wallclk < (azx_dev->core.period_wallclk * 5) / 4 &&
7248c2ecf20Sopenharmony_ci	    pos % azx_dev->core.period_bytes > azx_dev->core.period_bytes / 2)
7258c2ecf20Sopenharmony_ci		/* NG - it's below the first next period boundary */
7268c2ecf20Sopenharmony_ci		return chip->bdl_pos_adj ? 0 : -1;
7278c2ecf20Sopenharmony_ci	azx_dev->core.start_wallclk += wallclk;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	if (azx_dev->core.no_period_wakeup)
7308c2ecf20Sopenharmony_ci		return 1; /* OK, no need to check period boundary */
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	if (runtime->hw_ptr_base != runtime->hw_ptr_interrupt)
7338c2ecf20Sopenharmony_ci		return 1; /* OK, already in hwptr updating process */
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	/* check whether the period gets really elapsed */
7368c2ecf20Sopenharmony_ci	pos = bytes_to_frames(runtime, pos);
7378c2ecf20Sopenharmony_ci	hwptr = runtime->hw_ptr_base + pos;
7388c2ecf20Sopenharmony_ci	if (hwptr < runtime->status->hw_ptr)
7398c2ecf20Sopenharmony_ci		hwptr += runtime->buffer_size;
7408c2ecf20Sopenharmony_ci	target = runtime->hw_ptr_interrupt + runtime->period_size;
7418c2ecf20Sopenharmony_ci	if (hwptr < target) {
7428c2ecf20Sopenharmony_ci		/* too early wakeup, process it later */
7438c2ecf20Sopenharmony_ci		return chip->bdl_pos_adj ? 0 : -1;
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	return 1; /* OK, it's fine */
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci/*
7508c2ecf20Sopenharmony_ci * The work for pending PCM period updates.
7518c2ecf20Sopenharmony_ci */
7528c2ecf20Sopenharmony_cistatic void azx_irq_pending_work(struct work_struct *work)
7538c2ecf20Sopenharmony_ci{
7548c2ecf20Sopenharmony_ci	struct hda_intel *hda = container_of(work, struct hda_intel, irq_pending_work);
7558c2ecf20Sopenharmony_ci	struct azx *chip = &hda->chip;
7568c2ecf20Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
7578c2ecf20Sopenharmony_ci	struct hdac_stream *s;
7588c2ecf20Sopenharmony_ci	int pending, ok;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	if (!hda->irq_pending_warned) {
7618c2ecf20Sopenharmony_ci		dev_info(chip->card->dev,
7628c2ecf20Sopenharmony_ci			 "IRQ timing workaround is activated for card #%d. Suggest a bigger bdl_pos_adj.\n",
7638c2ecf20Sopenharmony_ci			 chip->card->number);
7648c2ecf20Sopenharmony_ci		hda->irq_pending_warned = 1;
7658c2ecf20Sopenharmony_ci	}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	for (;;) {
7688c2ecf20Sopenharmony_ci		pending = 0;
7698c2ecf20Sopenharmony_ci		spin_lock_irq(&bus->reg_lock);
7708c2ecf20Sopenharmony_ci		list_for_each_entry(s, &bus->stream_list, list) {
7718c2ecf20Sopenharmony_ci			struct azx_dev *azx_dev = stream_to_azx_dev(s);
7728c2ecf20Sopenharmony_ci			if (!azx_dev->irq_pending ||
7738c2ecf20Sopenharmony_ci			    !s->substream ||
7748c2ecf20Sopenharmony_ci			    !s->running)
7758c2ecf20Sopenharmony_ci				continue;
7768c2ecf20Sopenharmony_ci			ok = azx_position_ok(chip, azx_dev);
7778c2ecf20Sopenharmony_ci			if (ok > 0) {
7788c2ecf20Sopenharmony_ci				azx_dev->irq_pending = 0;
7798c2ecf20Sopenharmony_ci				spin_unlock(&bus->reg_lock);
7808c2ecf20Sopenharmony_ci				snd_pcm_period_elapsed(s->substream);
7818c2ecf20Sopenharmony_ci				spin_lock(&bus->reg_lock);
7828c2ecf20Sopenharmony_ci			} else if (ok < 0) {
7838c2ecf20Sopenharmony_ci				pending = 0;	/* too early */
7848c2ecf20Sopenharmony_ci			} else
7858c2ecf20Sopenharmony_ci				pending++;
7868c2ecf20Sopenharmony_ci		}
7878c2ecf20Sopenharmony_ci		spin_unlock_irq(&bus->reg_lock);
7888c2ecf20Sopenharmony_ci		if (!pending)
7898c2ecf20Sopenharmony_ci			return;
7908c2ecf20Sopenharmony_ci		msleep(1);
7918c2ecf20Sopenharmony_ci	}
7928c2ecf20Sopenharmony_ci}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci/* clear irq_pending flags and assure no on-going workq */
7958c2ecf20Sopenharmony_cistatic void azx_clear_irq_pending(struct azx *chip)
7968c2ecf20Sopenharmony_ci{
7978c2ecf20Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
7988c2ecf20Sopenharmony_ci	struct hdac_stream *s;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	spin_lock_irq(&bus->reg_lock);
8018c2ecf20Sopenharmony_ci	list_for_each_entry(s, &bus->stream_list, list) {
8028c2ecf20Sopenharmony_ci		struct azx_dev *azx_dev = stream_to_azx_dev(s);
8038c2ecf20Sopenharmony_ci		azx_dev->irq_pending = 0;
8048c2ecf20Sopenharmony_ci	}
8058c2ecf20Sopenharmony_ci	spin_unlock_irq(&bus->reg_lock);
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_cistatic int azx_acquire_irq(struct azx *chip, int do_disconnect)
8098c2ecf20Sopenharmony_ci{
8108c2ecf20Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	if (request_irq(chip->pci->irq, azx_interrupt,
8138c2ecf20Sopenharmony_ci			chip->msi ? 0 : IRQF_SHARED,
8148c2ecf20Sopenharmony_ci			chip->card->irq_descr, chip)) {
8158c2ecf20Sopenharmony_ci		dev_err(chip->card->dev,
8168c2ecf20Sopenharmony_ci			"unable to grab IRQ %d, disabling device\n",
8178c2ecf20Sopenharmony_ci			chip->pci->irq);
8188c2ecf20Sopenharmony_ci		if (do_disconnect)
8198c2ecf20Sopenharmony_ci			snd_card_disconnect(chip->card);
8208c2ecf20Sopenharmony_ci		return -1;
8218c2ecf20Sopenharmony_ci	}
8228c2ecf20Sopenharmony_ci	bus->irq = chip->pci->irq;
8238c2ecf20Sopenharmony_ci	chip->card->sync_irq = bus->irq;
8248c2ecf20Sopenharmony_ci	pci_intx(chip->pci, !chip->msi);
8258c2ecf20Sopenharmony_ci	return 0;
8268c2ecf20Sopenharmony_ci}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci/* get the current DMA position with correction on VIA chips */
8298c2ecf20Sopenharmony_cistatic unsigned int azx_via_get_position(struct azx *chip,
8308c2ecf20Sopenharmony_ci					 struct azx_dev *azx_dev)
8318c2ecf20Sopenharmony_ci{
8328c2ecf20Sopenharmony_ci	unsigned int link_pos, mini_pos, bound_pos;
8338c2ecf20Sopenharmony_ci	unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos;
8348c2ecf20Sopenharmony_ci	unsigned int fifo_size;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	link_pos = snd_hdac_stream_get_pos_lpib(azx_stream(azx_dev));
8378c2ecf20Sopenharmony_ci	if (azx_dev->core.substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
8388c2ecf20Sopenharmony_ci		/* Playback, no problem using link position */
8398c2ecf20Sopenharmony_ci		return link_pos;
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	/* Capture */
8438c2ecf20Sopenharmony_ci	/* For new chipset,
8448c2ecf20Sopenharmony_ci	 * use mod to get the DMA position just like old chipset
8458c2ecf20Sopenharmony_ci	 */
8468c2ecf20Sopenharmony_ci	mod_dma_pos = le32_to_cpu(*azx_dev->core.posbuf);
8478c2ecf20Sopenharmony_ci	mod_dma_pos %= azx_dev->core.period_bytes;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	fifo_size = azx_stream(azx_dev)->fifo_size - 1;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	if (azx_dev->insufficient) {
8528c2ecf20Sopenharmony_ci		/* Link position never gather than FIFO size */
8538c2ecf20Sopenharmony_ci		if (link_pos <= fifo_size)
8548c2ecf20Sopenharmony_ci			return 0;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci		azx_dev->insufficient = 0;
8578c2ecf20Sopenharmony_ci	}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	if (link_pos <= fifo_size)
8608c2ecf20Sopenharmony_ci		mini_pos = azx_dev->core.bufsize + link_pos - fifo_size;
8618c2ecf20Sopenharmony_ci	else
8628c2ecf20Sopenharmony_ci		mini_pos = link_pos - fifo_size;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	/* Find nearest previous boudary */
8658c2ecf20Sopenharmony_ci	mod_mini_pos = mini_pos % azx_dev->core.period_bytes;
8668c2ecf20Sopenharmony_ci	mod_link_pos = link_pos % azx_dev->core.period_bytes;
8678c2ecf20Sopenharmony_ci	if (mod_link_pos >= fifo_size)
8688c2ecf20Sopenharmony_ci		bound_pos = link_pos - mod_link_pos;
8698c2ecf20Sopenharmony_ci	else if (mod_dma_pos >= mod_mini_pos)
8708c2ecf20Sopenharmony_ci		bound_pos = mini_pos - mod_mini_pos;
8718c2ecf20Sopenharmony_ci	else {
8728c2ecf20Sopenharmony_ci		bound_pos = mini_pos - mod_mini_pos + azx_dev->core.period_bytes;
8738c2ecf20Sopenharmony_ci		if (bound_pos >= azx_dev->core.bufsize)
8748c2ecf20Sopenharmony_ci			bound_pos = 0;
8758c2ecf20Sopenharmony_ci	}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	/* Calculate real DMA position we want */
8788c2ecf20Sopenharmony_ci	return bound_pos + mod_dma_pos;
8798c2ecf20Sopenharmony_ci}
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci#define AMD_FIFO_SIZE	32
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci/* get the current DMA position with FIFO size correction */
8848c2ecf20Sopenharmony_cistatic unsigned int azx_get_pos_fifo(struct azx *chip, struct azx_dev *azx_dev)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream = azx_dev->core.substream;
8878c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
8888c2ecf20Sopenharmony_ci	unsigned int pos, delay;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	pos = snd_hdac_stream_get_pos_lpib(azx_stream(azx_dev));
8918c2ecf20Sopenharmony_ci	if (!runtime)
8928c2ecf20Sopenharmony_ci		return pos;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	runtime->delay = AMD_FIFO_SIZE;
8958c2ecf20Sopenharmony_ci	delay = frames_to_bytes(runtime, AMD_FIFO_SIZE);
8968c2ecf20Sopenharmony_ci	if (azx_dev->insufficient) {
8978c2ecf20Sopenharmony_ci		if (pos < delay) {
8988c2ecf20Sopenharmony_ci			delay = pos;
8998c2ecf20Sopenharmony_ci			runtime->delay = bytes_to_frames(runtime, pos);
9008c2ecf20Sopenharmony_ci		} else {
9018c2ecf20Sopenharmony_ci			azx_dev->insufficient = 0;
9028c2ecf20Sopenharmony_ci		}
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	/* correct the DMA position for capture stream */
9068c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
9078c2ecf20Sopenharmony_ci		if (pos < delay)
9088c2ecf20Sopenharmony_ci			pos += azx_dev->core.bufsize;
9098c2ecf20Sopenharmony_ci		pos -= delay;
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	return pos;
9138c2ecf20Sopenharmony_ci}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_cistatic int azx_get_delay_from_fifo(struct azx *chip, struct azx_dev *azx_dev,
9168c2ecf20Sopenharmony_ci				   unsigned int pos)
9178c2ecf20Sopenharmony_ci{
9188c2ecf20Sopenharmony_ci	struct snd_pcm_substream *substream = azx_dev->core.substream;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	/* just read back the calculated value in the above */
9218c2ecf20Sopenharmony_ci	return substream->runtime->delay;
9228c2ecf20Sopenharmony_ci}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_cistatic void __azx_shutdown_chip(struct azx *chip, bool skip_link_reset)
9258c2ecf20Sopenharmony_ci{
9268c2ecf20Sopenharmony_ci	azx_stop_chip(chip);
9278c2ecf20Sopenharmony_ci	if (!skip_link_reset)
9288c2ecf20Sopenharmony_ci		azx_enter_link_reset(chip);
9298c2ecf20Sopenharmony_ci	azx_clear_irq_pending(chip);
9308c2ecf20Sopenharmony_ci	display_power(chip, false);
9318c2ecf20Sopenharmony_ci}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
9348c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(card_list_lock);
9358c2ecf20Sopenharmony_cistatic LIST_HEAD(card_list);
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_cistatic void azx_shutdown_chip(struct azx *chip)
9388c2ecf20Sopenharmony_ci{
9398c2ecf20Sopenharmony_ci	__azx_shutdown_chip(chip, false);
9408c2ecf20Sopenharmony_ci}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_cistatic void azx_add_card_list(struct azx *chip)
9438c2ecf20Sopenharmony_ci{
9448c2ecf20Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
9458c2ecf20Sopenharmony_ci	mutex_lock(&card_list_lock);
9468c2ecf20Sopenharmony_ci	list_add(&hda->list, &card_list);
9478c2ecf20Sopenharmony_ci	mutex_unlock(&card_list_lock);
9488c2ecf20Sopenharmony_ci}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_cistatic void azx_del_card_list(struct azx *chip)
9518c2ecf20Sopenharmony_ci{
9528c2ecf20Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
9538c2ecf20Sopenharmony_ci	mutex_lock(&card_list_lock);
9548c2ecf20Sopenharmony_ci	list_del_init(&hda->list);
9558c2ecf20Sopenharmony_ci	mutex_unlock(&card_list_lock);
9568c2ecf20Sopenharmony_ci}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci/* trigger power-save check at writing parameter */
9598c2ecf20Sopenharmony_cistatic int param_set_xint(const char *val, const struct kernel_param *kp)
9608c2ecf20Sopenharmony_ci{
9618c2ecf20Sopenharmony_ci	struct hda_intel *hda;
9628c2ecf20Sopenharmony_ci	struct azx *chip;
9638c2ecf20Sopenharmony_ci	int prev = power_save;
9648c2ecf20Sopenharmony_ci	int ret = param_set_int(val, kp);
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	if (ret || prev == power_save)
9678c2ecf20Sopenharmony_ci		return ret;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	mutex_lock(&card_list_lock);
9708c2ecf20Sopenharmony_ci	list_for_each_entry(hda, &card_list, list) {
9718c2ecf20Sopenharmony_ci		chip = &hda->chip;
9728c2ecf20Sopenharmony_ci		if (!hda->probe_continued || chip->disabled)
9738c2ecf20Sopenharmony_ci			continue;
9748c2ecf20Sopenharmony_ci		snd_hda_set_power_save(&chip->bus, power_save * 1000);
9758c2ecf20Sopenharmony_ci	}
9768c2ecf20Sopenharmony_ci	mutex_unlock(&card_list_lock);
9778c2ecf20Sopenharmony_ci	return 0;
9788c2ecf20Sopenharmony_ci}
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci/*
9818c2ecf20Sopenharmony_ci * power management
9828c2ecf20Sopenharmony_ci */
9838c2ecf20Sopenharmony_cistatic bool azx_is_pm_ready(struct snd_card *card)
9848c2ecf20Sopenharmony_ci{
9858c2ecf20Sopenharmony_ci	struct azx *chip;
9868c2ecf20Sopenharmony_ci	struct hda_intel *hda;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	if (!card)
9898c2ecf20Sopenharmony_ci		return false;
9908c2ecf20Sopenharmony_ci	chip = card->private_data;
9918c2ecf20Sopenharmony_ci	hda = container_of(chip, struct hda_intel, chip);
9928c2ecf20Sopenharmony_ci	if (chip->disabled || hda->init_failed || !chip->running)
9938c2ecf20Sopenharmony_ci		return false;
9948c2ecf20Sopenharmony_ci	return true;
9958c2ecf20Sopenharmony_ci}
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_cistatic void __azx_runtime_resume(struct azx *chip)
9988c2ecf20Sopenharmony_ci{
9998c2ecf20Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
10008c2ecf20Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
10018c2ecf20Sopenharmony_ci	struct hda_codec *codec;
10028c2ecf20Sopenharmony_ci	int status;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	display_power(chip, true);
10058c2ecf20Sopenharmony_ci	if (hda->need_i915_power)
10068c2ecf20Sopenharmony_ci		snd_hdac_i915_set_bclk(bus);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	/* Read STATESTS before controller reset */
10098c2ecf20Sopenharmony_ci	status = azx_readw(chip, STATESTS);
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	azx_init_pci(chip);
10128c2ecf20Sopenharmony_ci	hda_intel_init_chip(chip, true);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	/* Avoid codec resume if runtime resume is for system suspend */
10158c2ecf20Sopenharmony_ci	if (!chip->pm_prepared) {
10168c2ecf20Sopenharmony_ci		list_for_each_codec(codec, &chip->bus) {
10178c2ecf20Sopenharmony_ci			if (codec->relaxed_resume)
10188c2ecf20Sopenharmony_ci				continue;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci			if (codec->forced_resume || (status & (1 << codec->addr)))
10218c2ecf20Sopenharmony_ci				pm_request_resume(hda_codec_dev(codec));
10228c2ecf20Sopenharmony_ci		}
10238c2ecf20Sopenharmony_ci	}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	/* power down again for link-controlled chips */
10268c2ecf20Sopenharmony_ci	if (!hda->need_i915_power)
10278c2ecf20Sopenharmony_ci		display_power(chip, false);
10288c2ecf20Sopenharmony_ci}
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
10318c2ecf20Sopenharmony_cistatic int azx_prepare(struct device *dev)
10328c2ecf20Sopenharmony_ci{
10338c2ecf20Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
10348c2ecf20Sopenharmony_ci	struct azx *chip;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	if (!azx_is_pm_ready(card))
10378c2ecf20Sopenharmony_ci		return 0;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	chip = card->private_data;
10408c2ecf20Sopenharmony_ci	chip->pm_prepared = 1;
10418c2ecf20Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	flush_work(&azx_bus(chip)->unsol_work);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	/* HDA controller always requires different WAKEEN for runtime suspend
10468c2ecf20Sopenharmony_ci	 * and system suspend, so don't use direct-complete here.
10478c2ecf20Sopenharmony_ci	 */
10488c2ecf20Sopenharmony_ci	return 0;
10498c2ecf20Sopenharmony_ci}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_cistatic void azx_complete(struct device *dev)
10528c2ecf20Sopenharmony_ci{
10538c2ecf20Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
10548c2ecf20Sopenharmony_ci	struct azx *chip;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	if (!azx_is_pm_ready(card))
10578c2ecf20Sopenharmony_ci		return;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	chip = card->private_data;
10608c2ecf20Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
10618c2ecf20Sopenharmony_ci	chip->pm_prepared = 0;
10628c2ecf20Sopenharmony_ci}
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_cistatic int azx_suspend(struct device *dev)
10658c2ecf20Sopenharmony_ci{
10668c2ecf20Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
10678c2ecf20Sopenharmony_ci	struct azx *chip;
10688c2ecf20Sopenharmony_ci	struct hdac_bus *bus;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	if (!azx_is_pm_ready(card))
10718c2ecf20Sopenharmony_ci		return 0;
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	chip = card->private_data;
10748c2ecf20Sopenharmony_ci	bus = azx_bus(chip);
10758c2ecf20Sopenharmony_ci	azx_shutdown_chip(chip);
10768c2ecf20Sopenharmony_ci	if (bus->irq >= 0) {
10778c2ecf20Sopenharmony_ci		free_irq(bus->irq, chip);
10788c2ecf20Sopenharmony_ci		bus->irq = -1;
10798c2ecf20Sopenharmony_ci		chip->card->sync_irq = -1;
10808c2ecf20Sopenharmony_ci	}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	if (chip->msi)
10838c2ecf20Sopenharmony_ci		pci_disable_msi(chip->pci);
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	trace_azx_suspend(chip);
10868c2ecf20Sopenharmony_ci	return 0;
10878c2ecf20Sopenharmony_ci}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_cistatic int azx_resume(struct device *dev)
10908c2ecf20Sopenharmony_ci{
10918c2ecf20Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
10928c2ecf20Sopenharmony_ci	struct azx *chip;
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	if (!azx_is_pm_ready(card))
10958c2ecf20Sopenharmony_ci		return 0;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	chip = card->private_data;
10988c2ecf20Sopenharmony_ci	if (chip->msi)
10998c2ecf20Sopenharmony_ci		if (pci_enable_msi(chip->pci) < 0)
11008c2ecf20Sopenharmony_ci			chip->msi = 0;
11018c2ecf20Sopenharmony_ci	if (azx_acquire_irq(chip, 1) < 0)
11028c2ecf20Sopenharmony_ci		return -EIO;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	__azx_runtime_resume(chip);
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	trace_azx_resume(chip);
11078c2ecf20Sopenharmony_ci	return 0;
11088c2ecf20Sopenharmony_ci}
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci/* put codec down to D3 at hibernation for Intel SKL+;
11118c2ecf20Sopenharmony_ci * otherwise BIOS may still access the codec and screw up the driver
11128c2ecf20Sopenharmony_ci */
11138c2ecf20Sopenharmony_cistatic int azx_freeze_noirq(struct device *dev)
11148c2ecf20Sopenharmony_ci{
11158c2ecf20Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
11168c2ecf20Sopenharmony_ci	struct azx *chip = card->private_data;
11178c2ecf20Sopenharmony_ci	struct pci_dev *pci = to_pci_dev(dev);
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	if (!azx_is_pm_ready(card))
11208c2ecf20Sopenharmony_ci		return 0;
11218c2ecf20Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_SKL)
11228c2ecf20Sopenharmony_ci		pci_set_power_state(pci, PCI_D3hot);
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	return 0;
11258c2ecf20Sopenharmony_ci}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_cistatic int azx_thaw_noirq(struct device *dev)
11288c2ecf20Sopenharmony_ci{
11298c2ecf20Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
11308c2ecf20Sopenharmony_ci	struct azx *chip = card->private_data;
11318c2ecf20Sopenharmony_ci	struct pci_dev *pci = to_pci_dev(dev);
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	if (!azx_is_pm_ready(card))
11348c2ecf20Sopenharmony_ci		return 0;
11358c2ecf20Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_SKL)
11368c2ecf20Sopenharmony_ci		pci_set_power_state(pci, PCI_D0);
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	return 0;
11398c2ecf20Sopenharmony_ci}
11408c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_cistatic int azx_runtime_suspend(struct device *dev)
11438c2ecf20Sopenharmony_ci{
11448c2ecf20Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
11458c2ecf20Sopenharmony_ci	struct azx *chip;
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	if (!azx_is_pm_ready(card))
11488c2ecf20Sopenharmony_ci		return 0;
11498c2ecf20Sopenharmony_ci	chip = card->private_data;
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	/* enable controller wake up event */
11528c2ecf20Sopenharmony_ci	azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | STATESTS_INT_MASK);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	azx_shutdown_chip(chip);
11558c2ecf20Sopenharmony_ci	trace_azx_runtime_suspend(chip);
11568c2ecf20Sopenharmony_ci	return 0;
11578c2ecf20Sopenharmony_ci}
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_cistatic int azx_runtime_resume(struct device *dev)
11608c2ecf20Sopenharmony_ci{
11618c2ecf20Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
11628c2ecf20Sopenharmony_ci	struct azx *chip;
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	if (!azx_is_pm_ready(card))
11658c2ecf20Sopenharmony_ci		return 0;
11668c2ecf20Sopenharmony_ci	chip = card->private_data;
11678c2ecf20Sopenharmony_ci	__azx_runtime_resume(chip);
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	/* disable controller Wake Up event*/
11708c2ecf20Sopenharmony_ci	azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & ~STATESTS_INT_MASK);
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	trace_azx_runtime_resume(chip);
11738c2ecf20Sopenharmony_ci	return 0;
11748c2ecf20Sopenharmony_ci}
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_cistatic int azx_runtime_idle(struct device *dev)
11778c2ecf20Sopenharmony_ci{
11788c2ecf20Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
11798c2ecf20Sopenharmony_ci	struct azx *chip;
11808c2ecf20Sopenharmony_ci	struct hda_intel *hda;
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	if (!card)
11838c2ecf20Sopenharmony_ci		return 0;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	chip = card->private_data;
11868c2ecf20Sopenharmony_ci	hda = container_of(chip, struct hda_intel, chip);
11878c2ecf20Sopenharmony_ci	if (chip->disabled || hda->init_failed)
11888c2ecf20Sopenharmony_ci		return 0;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	if (!power_save_controller || !azx_has_pm_runtime(chip) ||
11918c2ecf20Sopenharmony_ci	    azx_bus(chip)->codec_powered || !chip->running)
11928c2ecf20Sopenharmony_ci		return -EBUSY;
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	/* ELD notification gets broken when HD-audio bus is off */
11958c2ecf20Sopenharmony_ci	if (needs_eld_notify_link(chip))
11968c2ecf20Sopenharmony_ci		return -EBUSY;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	return 0;
11998c2ecf20Sopenharmony_ci}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_cistatic const struct dev_pm_ops azx_pm = {
12028c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume)
12038c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
12048c2ecf20Sopenharmony_ci	.prepare = azx_prepare,
12058c2ecf20Sopenharmony_ci	.complete = azx_complete,
12068c2ecf20Sopenharmony_ci	.freeze_noirq = azx_freeze_noirq,
12078c2ecf20Sopenharmony_ci	.thaw_noirq = azx_thaw_noirq,
12088c2ecf20Sopenharmony_ci#endif
12098c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle)
12108c2ecf20Sopenharmony_ci};
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci#define AZX_PM_OPS	&azx_pm
12138c2ecf20Sopenharmony_ci#else
12148c2ecf20Sopenharmony_ci#define azx_add_card_list(chip) /* NOP */
12158c2ecf20Sopenharmony_ci#define azx_del_card_list(chip) /* NOP */
12168c2ecf20Sopenharmony_ci#define AZX_PM_OPS	NULL
12178c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_cistatic int azx_probe_continue(struct azx *chip);
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci#ifdef SUPPORT_VGA_SWITCHEROO
12238c2ecf20Sopenharmony_cistatic struct pci_dev *get_bound_vga(struct pci_dev *pci);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_cistatic void azx_vs_set_state(struct pci_dev *pci,
12268c2ecf20Sopenharmony_ci			     enum vga_switcheroo_state state)
12278c2ecf20Sopenharmony_ci{
12288c2ecf20Sopenharmony_ci	struct snd_card *card = pci_get_drvdata(pci);
12298c2ecf20Sopenharmony_ci	struct azx *chip = card->private_data;
12308c2ecf20Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
12318c2ecf20Sopenharmony_ci	struct hda_codec *codec;
12328c2ecf20Sopenharmony_ci	bool disabled;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	wait_for_completion(&hda->probe_wait);
12358c2ecf20Sopenharmony_ci	if (hda->init_failed)
12368c2ecf20Sopenharmony_ci		return;
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	disabled = (state == VGA_SWITCHEROO_OFF);
12398c2ecf20Sopenharmony_ci	if (chip->disabled == disabled)
12408c2ecf20Sopenharmony_ci		return;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	if (!hda->probe_continued) {
12438c2ecf20Sopenharmony_ci		chip->disabled = disabled;
12448c2ecf20Sopenharmony_ci		if (!disabled) {
12458c2ecf20Sopenharmony_ci			dev_info(chip->card->dev,
12468c2ecf20Sopenharmony_ci				 "Start delayed initialization\n");
12478c2ecf20Sopenharmony_ci			if (azx_probe_continue(chip) < 0)
12488c2ecf20Sopenharmony_ci				dev_err(chip->card->dev, "initialization error\n");
12498c2ecf20Sopenharmony_ci		}
12508c2ecf20Sopenharmony_ci	} else {
12518c2ecf20Sopenharmony_ci		dev_info(chip->card->dev, "%s via vga_switcheroo\n",
12528c2ecf20Sopenharmony_ci			 disabled ? "Disabling" : "Enabling");
12538c2ecf20Sopenharmony_ci		if (disabled) {
12548c2ecf20Sopenharmony_ci			list_for_each_codec(codec, &chip->bus) {
12558c2ecf20Sopenharmony_ci				pm_runtime_suspend(hda_codec_dev(codec));
12568c2ecf20Sopenharmony_ci				pm_runtime_disable(hda_codec_dev(codec));
12578c2ecf20Sopenharmony_ci			}
12588c2ecf20Sopenharmony_ci			pm_runtime_suspend(card->dev);
12598c2ecf20Sopenharmony_ci			pm_runtime_disable(card->dev);
12608c2ecf20Sopenharmony_ci			/* when we get suspended by vga_switcheroo we end up in D3cold,
12618c2ecf20Sopenharmony_ci			 * however we have no ACPI handle, so pci/acpi can't put us there,
12628c2ecf20Sopenharmony_ci			 * put ourselves there */
12638c2ecf20Sopenharmony_ci			pci->current_state = PCI_D3cold;
12648c2ecf20Sopenharmony_ci			chip->disabled = true;
12658c2ecf20Sopenharmony_ci			if (snd_hda_lock_devices(&chip->bus))
12668c2ecf20Sopenharmony_ci				dev_warn(chip->card->dev,
12678c2ecf20Sopenharmony_ci					 "Cannot lock devices!\n");
12688c2ecf20Sopenharmony_ci		} else {
12698c2ecf20Sopenharmony_ci			snd_hda_unlock_devices(&chip->bus);
12708c2ecf20Sopenharmony_ci			chip->disabled = false;
12718c2ecf20Sopenharmony_ci			pm_runtime_enable(card->dev);
12728c2ecf20Sopenharmony_ci			list_for_each_codec(codec, &chip->bus) {
12738c2ecf20Sopenharmony_ci				pm_runtime_enable(hda_codec_dev(codec));
12748c2ecf20Sopenharmony_ci				pm_runtime_resume(hda_codec_dev(codec));
12758c2ecf20Sopenharmony_ci			}
12768c2ecf20Sopenharmony_ci		}
12778c2ecf20Sopenharmony_ci	}
12788c2ecf20Sopenharmony_ci}
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_cistatic bool azx_vs_can_switch(struct pci_dev *pci)
12818c2ecf20Sopenharmony_ci{
12828c2ecf20Sopenharmony_ci	struct snd_card *card = pci_get_drvdata(pci);
12838c2ecf20Sopenharmony_ci	struct azx *chip = card->private_data;
12848c2ecf20Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	wait_for_completion(&hda->probe_wait);
12878c2ecf20Sopenharmony_ci	if (hda->init_failed)
12888c2ecf20Sopenharmony_ci		return false;
12898c2ecf20Sopenharmony_ci	if (chip->disabled || !hda->probe_continued)
12908c2ecf20Sopenharmony_ci		return true;
12918c2ecf20Sopenharmony_ci	if (snd_hda_lock_devices(&chip->bus))
12928c2ecf20Sopenharmony_ci		return false;
12938c2ecf20Sopenharmony_ci	snd_hda_unlock_devices(&chip->bus);
12948c2ecf20Sopenharmony_ci	return true;
12958c2ecf20Sopenharmony_ci}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci/*
12988c2ecf20Sopenharmony_ci * The discrete GPU cannot power down unless the HDA controller runtime
12998c2ecf20Sopenharmony_ci * suspends, so activate runtime PM on codecs even if power_save == 0.
13008c2ecf20Sopenharmony_ci */
13018c2ecf20Sopenharmony_cistatic void setup_vga_switcheroo_runtime_pm(struct azx *chip)
13028c2ecf20Sopenharmony_ci{
13038c2ecf20Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
13048c2ecf20Sopenharmony_ci	struct hda_codec *codec;
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	if (hda->use_vga_switcheroo && !needs_eld_notify_link(chip)) {
13078c2ecf20Sopenharmony_ci		list_for_each_codec(codec, &chip->bus)
13088c2ecf20Sopenharmony_ci			codec->auto_runtime_pm = 1;
13098c2ecf20Sopenharmony_ci		/* reset the power save setup */
13108c2ecf20Sopenharmony_ci		if (chip->running)
13118c2ecf20Sopenharmony_ci			set_default_power_save(chip);
13128c2ecf20Sopenharmony_ci	}
13138c2ecf20Sopenharmony_ci}
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_cistatic void azx_vs_gpu_bound(struct pci_dev *pci,
13168c2ecf20Sopenharmony_ci			     enum vga_switcheroo_client_id client_id)
13178c2ecf20Sopenharmony_ci{
13188c2ecf20Sopenharmony_ci	struct snd_card *card = pci_get_drvdata(pci);
13198c2ecf20Sopenharmony_ci	struct azx *chip = card->private_data;
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	if (client_id == VGA_SWITCHEROO_DIS)
13228c2ecf20Sopenharmony_ci		chip->bus.keep_power = 0;
13238c2ecf20Sopenharmony_ci	setup_vga_switcheroo_runtime_pm(chip);
13248c2ecf20Sopenharmony_ci}
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_cistatic void init_vga_switcheroo(struct azx *chip)
13278c2ecf20Sopenharmony_ci{
13288c2ecf20Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
13298c2ecf20Sopenharmony_ci	struct pci_dev *p = get_bound_vga(chip->pci);
13308c2ecf20Sopenharmony_ci	struct pci_dev *parent;
13318c2ecf20Sopenharmony_ci	if (p) {
13328c2ecf20Sopenharmony_ci		dev_info(chip->card->dev,
13338c2ecf20Sopenharmony_ci			 "Handle vga_switcheroo audio client\n");
13348c2ecf20Sopenharmony_ci		hda->use_vga_switcheroo = 1;
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci		/* cleared in either gpu_bound op or codec probe, or when its
13378c2ecf20Sopenharmony_ci		 * upstream port has _PR3 (i.e. dGPU).
13388c2ecf20Sopenharmony_ci		 */
13398c2ecf20Sopenharmony_ci		parent = pci_upstream_bridge(p);
13408c2ecf20Sopenharmony_ci		chip->bus.keep_power = parent ? !pci_pr3_present(parent) : 1;
13418c2ecf20Sopenharmony_ci		chip->driver_caps |= AZX_DCAPS_PM_RUNTIME;
13428c2ecf20Sopenharmony_ci		pci_dev_put(p);
13438c2ecf20Sopenharmony_ci	}
13448c2ecf20Sopenharmony_ci}
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_cistatic const struct vga_switcheroo_client_ops azx_vs_ops = {
13478c2ecf20Sopenharmony_ci	.set_gpu_state = azx_vs_set_state,
13488c2ecf20Sopenharmony_ci	.can_switch = azx_vs_can_switch,
13498c2ecf20Sopenharmony_ci	.gpu_bound = azx_vs_gpu_bound,
13508c2ecf20Sopenharmony_ci};
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_cistatic int register_vga_switcheroo(struct azx *chip)
13538c2ecf20Sopenharmony_ci{
13548c2ecf20Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
13558c2ecf20Sopenharmony_ci	struct pci_dev *p;
13568c2ecf20Sopenharmony_ci	int err;
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	if (!hda->use_vga_switcheroo)
13598c2ecf20Sopenharmony_ci		return 0;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	p = get_bound_vga(chip->pci);
13628c2ecf20Sopenharmony_ci	err = vga_switcheroo_register_audio_client(chip->pci, &azx_vs_ops, p);
13638c2ecf20Sopenharmony_ci	pci_dev_put(p);
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	if (err < 0)
13668c2ecf20Sopenharmony_ci		return err;
13678c2ecf20Sopenharmony_ci	hda->vga_switcheroo_registered = 1;
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	return 0;
13708c2ecf20Sopenharmony_ci}
13718c2ecf20Sopenharmony_ci#else
13728c2ecf20Sopenharmony_ci#define init_vga_switcheroo(chip)		/* NOP */
13738c2ecf20Sopenharmony_ci#define register_vga_switcheroo(chip)		0
13748c2ecf20Sopenharmony_ci#define check_hdmi_disabled(pci)	false
13758c2ecf20Sopenharmony_ci#define setup_vga_switcheroo_runtime_pm(chip)	/* NOP */
13768c2ecf20Sopenharmony_ci#endif /* SUPPORT_VGA_SWITCHER */
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci/*
13798c2ecf20Sopenharmony_ci * destructor
13808c2ecf20Sopenharmony_ci */
13818c2ecf20Sopenharmony_cistatic void azx_free(struct azx *chip)
13828c2ecf20Sopenharmony_ci{
13838c2ecf20Sopenharmony_ci	struct pci_dev *pci = chip->pci;
13848c2ecf20Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
13858c2ecf20Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	if (hda->freed)
13888c2ecf20Sopenharmony_ci		return;
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci	if (azx_has_pm_runtime(chip) && chip->running)
13918c2ecf20Sopenharmony_ci		pm_runtime_get_noresume(&pci->dev);
13928c2ecf20Sopenharmony_ci	chip->running = 0;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	azx_del_card_list(chip);
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	hda->init_failed = 1; /* to be sure */
13978c2ecf20Sopenharmony_ci	complete_all(&hda->probe_wait);
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	if (use_vga_switcheroo(hda)) {
14008c2ecf20Sopenharmony_ci		if (chip->disabled && hda->probe_continued)
14018c2ecf20Sopenharmony_ci			snd_hda_unlock_devices(&chip->bus);
14028c2ecf20Sopenharmony_ci		if (hda->vga_switcheroo_registered)
14038c2ecf20Sopenharmony_ci			vga_switcheroo_unregister_client(chip->pci);
14048c2ecf20Sopenharmony_ci	}
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	if (bus->chip_init) {
14078c2ecf20Sopenharmony_ci		azx_clear_irq_pending(chip);
14088c2ecf20Sopenharmony_ci		azx_stop_all_streams(chip);
14098c2ecf20Sopenharmony_ci		azx_stop_chip(chip);
14108c2ecf20Sopenharmony_ci	}
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	if (bus->irq >= 0)
14138c2ecf20Sopenharmony_ci		free_irq(bus->irq, (void*)chip);
14148c2ecf20Sopenharmony_ci	if (chip->msi)
14158c2ecf20Sopenharmony_ci		pci_disable_msi(chip->pci);
14168c2ecf20Sopenharmony_ci	iounmap(bus->remap_addr);
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	azx_free_stream_pages(chip);
14198c2ecf20Sopenharmony_ci	azx_free_streams(chip);
14208c2ecf20Sopenharmony_ci	snd_hdac_bus_exit(bus);
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci	if (chip->region_requested)
14238c2ecf20Sopenharmony_ci		pci_release_regions(chip->pci);
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	pci_disable_device(chip->pci);
14268c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_HDA_PATCH_LOADER
14278c2ecf20Sopenharmony_ci	release_firmware(chip->fw);
14288c2ecf20Sopenharmony_ci#endif
14298c2ecf20Sopenharmony_ci	display_power(chip, false);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT)
14328c2ecf20Sopenharmony_ci		snd_hdac_i915_exit(bus);
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	hda->freed = 1;
14358c2ecf20Sopenharmony_ci}
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_cistatic int azx_dev_disconnect(struct snd_device *device)
14388c2ecf20Sopenharmony_ci{
14398c2ecf20Sopenharmony_ci	struct azx *chip = device->device_data;
14408c2ecf20Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	chip->bus.shutdown = 1;
14438c2ecf20Sopenharmony_ci	cancel_work_sync(&bus->unsol_work);
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	return 0;
14468c2ecf20Sopenharmony_ci}
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_cistatic int azx_dev_free(struct snd_device *device)
14498c2ecf20Sopenharmony_ci{
14508c2ecf20Sopenharmony_ci	azx_free(device->device_data);
14518c2ecf20Sopenharmony_ci	return 0;
14528c2ecf20Sopenharmony_ci}
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci#ifdef SUPPORT_VGA_SWITCHEROO
14558c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
14568c2ecf20Sopenharmony_ci/* ATPX is in the integrated GPU's namespace */
14578c2ecf20Sopenharmony_cistatic bool atpx_present(void)
14588c2ecf20Sopenharmony_ci{
14598c2ecf20Sopenharmony_ci	struct pci_dev *pdev = NULL;
14608c2ecf20Sopenharmony_ci	acpi_handle dhandle, atpx_handle;
14618c2ecf20Sopenharmony_ci	acpi_status status;
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
14648c2ecf20Sopenharmony_ci		dhandle = ACPI_HANDLE(&pdev->dev);
14658c2ecf20Sopenharmony_ci		if (dhandle) {
14668c2ecf20Sopenharmony_ci			status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
14678c2ecf20Sopenharmony_ci			if (!ACPI_FAILURE(status)) {
14688c2ecf20Sopenharmony_ci				pci_dev_put(pdev);
14698c2ecf20Sopenharmony_ci				return true;
14708c2ecf20Sopenharmony_ci			}
14718c2ecf20Sopenharmony_ci		}
14728c2ecf20Sopenharmony_ci	}
14738c2ecf20Sopenharmony_ci	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
14748c2ecf20Sopenharmony_ci		dhandle = ACPI_HANDLE(&pdev->dev);
14758c2ecf20Sopenharmony_ci		if (dhandle) {
14768c2ecf20Sopenharmony_ci			status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
14778c2ecf20Sopenharmony_ci			if (!ACPI_FAILURE(status)) {
14788c2ecf20Sopenharmony_ci				pci_dev_put(pdev);
14798c2ecf20Sopenharmony_ci				return true;
14808c2ecf20Sopenharmony_ci			}
14818c2ecf20Sopenharmony_ci		}
14828c2ecf20Sopenharmony_ci	}
14838c2ecf20Sopenharmony_ci	return false;
14848c2ecf20Sopenharmony_ci}
14858c2ecf20Sopenharmony_ci#else
14868c2ecf20Sopenharmony_cistatic bool atpx_present(void)
14878c2ecf20Sopenharmony_ci{
14888c2ecf20Sopenharmony_ci	return false;
14898c2ecf20Sopenharmony_ci}
14908c2ecf20Sopenharmony_ci#endif
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci/*
14938c2ecf20Sopenharmony_ci * Check of disabled HDMI controller by vga_switcheroo
14948c2ecf20Sopenharmony_ci */
14958c2ecf20Sopenharmony_cistatic struct pci_dev *get_bound_vga(struct pci_dev *pci)
14968c2ecf20Sopenharmony_ci{
14978c2ecf20Sopenharmony_ci	struct pci_dev *p;
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	/* check only discrete GPU */
15008c2ecf20Sopenharmony_ci	switch (pci->vendor) {
15018c2ecf20Sopenharmony_ci	case PCI_VENDOR_ID_ATI:
15028c2ecf20Sopenharmony_ci	case PCI_VENDOR_ID_AMD:
15038c2ecf20Sopenharmony_ci		if (pci->devfn == 1) {
15048c2ecf20Sopenharmony_ci			p = pci_get_domain_bus_and_slot(pci_domain_nr(pci->bus),
15058c2ecf20Sopenharmony_ci							pci->bus->number, 0);
15068c2ecf20Sopenharmony_ci			if (p) {
15078c2ecf20Sopenharmony_ci				/* ATPX is in the integrated GPU's ACPI namespace
15088c2ecf20Sopenharmony_ci				 * rather than the dGPU's namespace. However,
15098c2ecf20Sopenharmony_ci				 * the dGPU is the one who is involved in
15108c2ecf20Sopenharmony_ci				 * vgaswitcheroo.
15118c2ecf20Sopenharmony_ci				 */
15128c2ecf20Sopenharmony_ci				if (((p->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
15138c2ecf20Sopenharmony_ci				    atpx_present())
15148c2ecf20Sopenharmony_ci					return p;
15158c2ecf20Sopenharmony_ci				pci_dev_put(p);
15168c2ecf20Sopenharmony_ci			}
15178c2ecf20Sopenharmony_ci		}
15188c2ecf20Sopenharmony_ci		break;
15198c2ecf20Sopenharmony_ci	case PCI_VENDOR_ID_NVIDIA:
15208c2ecf20Sopenharmony_ci		if (pci->devfn == 1) {
15218c2ecf20Sopenharmony_ci			p = pci_get_domain_bus_and_slot(pci_domain_nr(pci->bus),
15228c2ecf20Sopenharmony_ci							pci->bus->number, 0);
15238c2ecf20Sopenharmony_ci			if (p) {
15248c2ecf20Sopenharmony_ci				if ((p->class >> 16) == PCI_BASE_CLASS_DISPLAY)
15258c2ecf20Sopenharmony_ci					return p;
15268c2ecf20Sopenharmony_ci				pci_dev_put(p);
15278c2ecf20Sopenharmony_ci			}
15288c2ecf20Sopenharmony_ci		}
15298c2ecf20Sopenharmony_ci		break;
15308c2ecf20Sopenharmony_ci	}
15318c2ecf20Sopenharmony_ci	return NULL;
15328c2ecf20Sopenharmony_ci}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_cistatic bool check_hdmi_disabled(struct pci_dev *pci)
15358c2ecf20Sopenharmony_ci{
15368c2ecf20Sopenharmony_ci	bool vga_inactive = false;
15378c2ecf20Sopenharmony_ci	struct pci_dev *p = get_bound_vga(pci);
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	if (p) {
15408c2ecf20Sopenharmony_ci		if (vga_switcheroo_get_client_state(p) == VGA_SWITCHEROO_OFF)
15418c2ecf20Sopenharmony_ci			vga_inactive = true;
15428c2ecf20Sopenharmony_ci		pci_dev_put(p);
15438c2ecf20Sopenharmony_ci	}
15448c2ecf20Sopenharmony_ci	return vga_inactive;
15458c2ecf20Sopenharmony_ci}
15468c2ecf20Sopenharmony_ci#endif /* SUPPORT_VGA_SWITCHEROO */
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci/*
15498c2ecf20Sopenharmony_ci * allow/deny-listing for position_fix
15508c2ecf20Sopenharmony_ci */
15518c2ecf20Sopenharmony_cistatic const struct snd_pci_quirk position_fix_list[] = {
15528c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
15538c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
15548c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
15558c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
15568c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
15578c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
15588c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
15598c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x10de, 0xcb89, "Macbook Pro 7,1", POS_FIX_LPIB),
15608c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB),
15618c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB),
15628c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
15638c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB),
15648c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB),
15658c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB),
15668c2ecf20Sopenharmony_ci	{}
15678c2ecf20Sopenharmony_ci};
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_cistatic int check_position_fix(struct azx *chip, int fix)
15708c2ecf20Sopenharmony_ci{
15718c2ecf20Sopenharmony_ci	const struct snd_pci_quirk *q;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	switch (fix) {
15748c2ecf20Sopenharmony_ci	case POS_FIX_AUTO:
15758c2ecf20Sopenharmony_ci	case POS_FIX_LPIB:
15768c2ecf20Sopenharmony_ci	case POS_FIX_POSBUF:
15778c2ecf20Sopenharmony_ci	case POS_FIX_VIACOMBO:
15788c2ecf20Sopenharmony_ci	case POS_FIX_COMBO:
15798c2ecf20Sopenharmony_ci	case POS_FIX_SKL:
15808c2ecf20Sopenharmony_ci	case POS_FIX_FIFO:
15818c2ecf20Sopenharmony_ci		return fix;
15828c2ecf20Sopenharmony_ci	}
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
15858c2ecf20Sopenharmony_ci	if (q) {
15868c2ecf20Sopenharmony_ci		dev_info(chip->card->dev,
15878c2ecf20Sopenharmony_ci			 "position_fix set to %d for device %04x:%04x\n",
15888c2ecf20Sopenharmony_ci			 q->value, q->subvendor, q->subdevice);
15898c2ecf20Sopenharmony_ci		return q->value;
15908c2ecf20Sopenharmony_ci	}
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	/* Check VIA/ATI HD Audio Controller exist */
15938c2ecf20Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_VIA) {
15948c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n");
15958c2ecf20Sopenharmony_ci		return POS_FIX_VIACOMBO;
15968c2ecf20Sopenharmony_ci	}
15978c2ecf20Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_AMD_WORKAROUND) {
15988c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "Using FIFO position fix\n");
15998c2ecf20Sopenharmony_ci		return POS_FIX_FIFO;
16008c2ecf20Sopenharmony_ci	}
16018c2ecf20Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) {
16028c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "Using LPIB position fix\n");
16038c2ecf20Sopenharmony_ci		return POS_FIX_LPIB;
16048c2ecf20Sopenharmony_ci	}
16058c2ecf20Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_SKL) {
16068c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "Using SKL position fix\n");
16078c2ecf20Sopenharmony_ci		return POS_FIX_SKL;
16088c2ecf20Sopenharmony_ci	}
16098c2ecf20Sopenharmony_ci	return POS_FIX_AUTO;
16108c2ecf20Sopenharmony_ci}
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_cistatic void assign_position_fix(struct azx *chip, int fix)
16138c2ecf20Sopenharmony_ci{
16148c2ecf20Sopenharmony_ci	static const azx_get_pos_callback_t callbacks[] = {
16158c2ecf20Sopenharmony_ci		[POS_FIX_AUTO] = NULL,
16168c2ecf20Sopenharmony_ci		[POS_FIX_LPIB] = azx_get_pos_lpib,
16178c2ecf20Sopenharmony_ci		[POS_FIX_POSBUF] = azx_get_pos_posbuf,
16188c2ecf20Sopenharmony_ci		[POS_FIX_VIACOMBO] = azx_via_get_position,
16198c2ecf20Sopenharmony_ci		[POS_FIX_COMBO] = azx_get_pos_lpib,
16208c2ecf20Sopenharmony_ci		[POS_FIX_SKL] = azx_get_pos_posbuf,
16218c2ecf20Sopenharmony_ci		[POS_FIX_FIFO] = azx_get_pos_fifo,
16228c2ecf20Sopenharmony_ci	};
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	chip->get_position[0] = chip->get_position[1] = callbacks[fix];
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	/* combo mode uses LPIB only for playback */
16278c2ecf20Sopenharmony_ci	if (fix == POS_FIX_COMBO)
16288c2ecf20Sopenharmony_ci		chip->get_position[1] = NULL;
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	if ((fix == POS_FIX_POSBUF || fix == POS_FIX_SKL) &&
16318c2ecf20Sopenharmony_ci	    (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) {
16328c2ecf20Sopenharmony_ci		chip->get_delay[0] = chip->get_delay[1] =
16338c2ecf20Sopenharmony_ci			azx_get_delay_from_lpib;
16348c2ecf20Sopenharmony_ci	}
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	if (fix == POS_FIX_FIFO)
16378c2ecf20Sopenharmony_ci		chip->get_delay[0] = chip->get_delay[1] =
16388c2ecf20Sopenharmony_ci			azx_get_delay_from_fifo;
16398c2ecf20Sopenharmony_ci}
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci/*
16428c2ecf20Sopenharmony_ci * deny-lists for probe_mask
16438c2ecf20Sopenharmony_ci */
16448c2ecf20Sopenharmony_cistatic const struct snd_pci_quirk probe_mask_list[] = {
16458c2ecf20Sopenharmony_ci	/* Thinkpad often breaks the controller communication when accessing
16468c2ecf20Sopenharmony_ci	 * to the non-working (or non-existing) modem codec slot.
16478c2ecf20Sopenharmony_ci	 */
16488c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01),
16498c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01),
16508c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01),
16518c2ecf20Sopenharmony_ci	/* broken BIOS */
16528c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01),
16538c2ecf20Sopenharmony_ci	/* including bogus ALC268 in slot#2 that conflicts with ALC888 */
16548c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01),
16558c2ecf20Sopenharmony_ci	/* forced codec slots */
16568c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x1262, "ASUS W5Fm", 0x103),
16578c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103),
16588c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1558, 0x0351, "Schenker Dock 15", 0x105),
16598c2ecf20Sopenharmony_ci	/* WinFast VP200 H (Teradici) user reported broken communication */
16608c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x3a21, 0x040d, "WinFast VP200 H", 0x101),
16618c2ecf20Sopenharmony_ci	{}
16628c2ecf20Sopenharmony_ci};
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci#define AZX_FORCE_CODEC_MASK	0x100
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_cistatic void check_probe_mask(struct azx *chip, int dev)
16678c2ecf20Sopenharmony_ci{
16688c2ecf20Sopenharmony_ci	const struct snd_pci_quirk *q;
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	chip->codec_probe_mask = probe_mask[dev];
16718c2ecf20Sopenharmony_ci	if (chip->codec_probe_mask == -1) {
16728c2ecf20Sopenharmony_ci		q = snd_pci_quirk_lookup(chip->pci, probe_mask_list);
16738c2ecf20Sopenharmony_ci		if (q) {
16748c2ecf20Sopenharmony_ci			dev_info(chip->card->dev,
16758c2ecf20Sopenharmony_ci				 "probe_mask set to 0x%x for device %04x:%04x\n",
16768c2ecf20Sopenharmony_ci				 q->value, q->subvendor, q->subdevice);
16778c2ecf20Sopenharmony_ci			chip->codec_probe_mask = q->value;
16788c2ecf20Sopenharmony_ci		}
16798c2ecf20Sopenharmony_ci	}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	/* check forced option */
16828c2ecf20Sopenharmony_ci	if (chip->codec_probe_mask != -1 &&
16838c2ecf20Sopenharmony_ci	    (chip->codec_probe_mask & AZX_FORCE_CODEC_MASK)) {
16848c2ecf20Sopenharmony_ci		azx_bus(chip)->codec_mask = chip->codec_probe_mask & 0xff;
16858c2ecf20Sopenharmony_ci		dev_info(chip->card->dev, "codec_mask forced to 0x%x\n",
16868c2ecf20Sopenharmony_ci			 (int)azx_bus(chip)->codec_mask);
16878c2ecf20Sopenharmony_ci	}
16888c2ecf20Sopenharmony_ci}
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci/*
16918c2ecf20Sopenharmony_ci * allow/deny-list for enable_msi
16928c2ecf20Sopenharmony_ci */
16938c2ecf20Sopenharmony_cistatic const struct snd_pci_quirk msi_deny_list[] = {
16948c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x103c, 0x2191, "HP", 0), /* AMD Hudson */
16958c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x103c, 0x2192, "HP", 0), /* AMD Hudson */
16968c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x103c, 0x21f7, "HP", 0), /* AMD Hudson */
16978c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x103c, 0x21fa, "HP", 0), /* AMD Hudson */
16988c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */
16998c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x81f6, "ASUS", 0), /* nvidia */
17008c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x822d, "ASUS", 0), /* Athlon64 X2 + nvidia MCP55 */
17018c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1179, 0xfb44, "Toshiba Satellite C870", 0), /* AMD Hudson */
17028c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1849, 0x0888, "ASRock", 0), /* Athlon64 X2 + nvidia */
17038c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0xa0a0, 0x0575, "Aopen MZ915-M", 0), /* ICH6 */
17048c2ecf20Sopenharmony_ci	{}
17058c2ecf20Sopenharmony_ci};
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_cistatic void check_msi(struct azx *chip)
17088c2ecf20Sopenharmony_ci{
17098c2ecf20Sopenharmony_ci	const struct snd_pci_quirk *q;
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	if (enable_msi >= 0) {
17128c2ecf20Sopenharmony_ci		chip->msi = !!enable_msi;
17138c2ecf20Sopenharmony_ci		return;
17148c2ecf20Sopenharmony_ci	}
17158c2ecf20Sopenharmony_ci	chip->msi = 1;	/* enable MSI as default */
17168c2ecf20Sopenharmony_ci	q = snd_pci_quirk_lookup(chip->pci, msi_deny_list);
17178c2ecf20Sopenharmony_ci	if (q) {
17188c2ecf20Sopenharmony_ci		dev_info(chip->card->dev,
17198c2ecf20Sopenharmony_ci			 "msi for device %04x:%04x set to %d\n",
17208c2ecf20Sopenharmony_ci			 q->subvendor, q->subdevice, q->value);
17218c2ecf20Sopenharmony_ci		chip->msi = q->value;
17228c2ecf20Sopenharmony_ci		return;
17238c2ecf20Sopenharmony_ci	}
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci	/* NVidia chipsets seem to cause troubles with MSI */
17268c2ecf20Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_NO_MSI) {
17278c2ecf20Sopenharmony_ci		dev_info(chip->card->dev, "Disabling MSI\n");
17288c2ecf20Sopenharmony_ci		chip->msi = 0;
17298c2ecf20Sopenharmony_ci	}
17308c2ecf20Sopenharmony_ci}
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci/* check the snoop mode availability */
17338c2ecf20Sopenharmony_cistatic void azx_check_snoop_available(struct azx *chip)
17348c2ecf20Sopenharmony_ci{
17358c2ecf20Sopenharmony_ci	int snoop = hda_snoop;
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	if (snoop >= 0) {
17388c2ecf20Sopenharmony_ci		dev_info(chip->card->dev, "Force to %s mode by module option\n",
17398c2ecf20Sopenharmony_ci			 snoop ? "snoop" : "non-snoop");
17408c2ecf20Sopenharmony_ci		chip->snoop = snoop;
17418c2ecf20Sopenharmony_ci		chip->uc_buffer = !snoop;
17428c2ecf20Sopenharmony_ci		return;
17438c2ecf20Sopenharmony_ci	}
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	snoop = true;
17468c2ecf20Sopenharmony_ci	if (azx_get_snoop_type(chip) == AZX_SNOOP_TYPE_NONE &&
17478c2ecf20Sopenharmony_ci	    chip->driver_type == AZX_DRIVER_VIA) {
17488c2ecf20Sopenharmony_ci		/* force to non-snoop mode for a new VIA controller
17498c2ecf20Sopenharmony_ci		 * when BIOS is set
17508c2ecf20Sopenharmony_ci		 */
17518c2ecf20Sopenharmony_ci		u8 val;
17528c2ecf20Sopenharmony_ci		pci_read_config_byte(chip->pci, 0x42, &val);
17538c2ecf20Sopenharmony_ci		if (!(val & 0x80) && (chip->pci->revision == 0x30 ||
17548c2ecf20Sopenharmony_ci				      chip->pci->revision == 0x20))
17558c2ecf20Sopenharmony_ci			snoop = false;
17568c2ecf20Sopenharmony_ci	}
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_SNOOP_OFF)
17598c2ecf20Sopenharmony_ci		snoop = false;
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	chip->snoop = snoop;
17628c2ecf20Sopenharmony_ci	if (!snoop) {
17638c2ecf20Sopenharmony_ci		dev_info(chip->card->dev, "Force to non-snoop mode\n");
17648c2ecf20Sopenharmony_ci		/* C-Media requires non-cached pages only for CORB/RIRB */
17658c2ecf20Sopenharmony_ci		if (chip->driver_type != AZX_DRIVER_CMEDIA)
17668c2ecf20Sopenharmony_ci			chip->uc_buffer = true;
17678c2ecf20Sopenharmony_ci	}
17688c2ecf20Sopenharmony_ci}
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_cistatic void azx_probe_work(struct work_struct *work)
17718c2ecf20Sopenharmony_ci{
17728c2ecf20Sopenharmony_ci	struct hda_intel *hda = container_of(work, struct hda_intel, probe_work.work);
17738c2ecf20Sopenharmony_ci	azx_probe_continue(&hda->chip);
17748c2ecf20Sopenharmony_ci}
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_cistatic int default_bdl_pos_adj(struct azx *chip)
17778c2ecf20Sopenharmony_ci{
17788c2ecf20Sopenharmony_ci	/* some exceptions: Atoms seem problematic with value 1 */
17798c2ecf20Sopenharmony_ci	if (chip->pci->vendor == PCI_VENDOR_ID_INTEL) {
17808c2ecf20Sopenharmony_ci		switch (chip->pci->device) {
17818c2ecf20Sopenharmony_ci		case 0x0f04: /* Baytrail */
17828c2ecf20Sopenharmony_ci		case 0x2284: /* Braswell */
17838c2ecf20Sopenharmony_ci			return 32;
17848c2ecf20Sopenharmony_ci		}
17858c2ecf20Sopenharmony_ci	}
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	switch (chip->driver_type) {
17888c2ecf20Sopenharmony_ci	/*
17898c2ecf20Sopenharmony_ci	 * increase the bdl size for Glenfly Gpus for hardware
17908c2ecf20Sopenharmony_ci	 * limitation on hdac interrupt interval
17918c2ecf20Sopenharmony_ci	 */
17928c2ecf20Sopenharmony_ci	case AZX_DRIVER_GFHDMI:
17938c2ecf20Sopenharmony_ci		return 128;
17948c2ecf20Sopenharmony_ci	case AZX_DRIVER_ICH:
17958c2ecf20Sopenharmony_ci	case AZX_DRIVER_PCH:
17968c2ecf20Sopenharmony_ci		return 1;
17978c2ecf20Sopenharmony_ci	default:
17988c2ecf20Sopenharmony_ci		return 32;
17998c2ecf20Sopenharmony_ci	}
18008c2ecf20Sopenharmony_ci}
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci/*
18038c2ecf20Sopenharmony_ci * constructor
18048c2ecf20Sopenharmony_ci */
18058c2ecf20Sopenharmony_cistatic const struct hda_controller_ops pci_hda_ops;
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_cistatic int azx_create(struct snd_card *card, struct pci_dev *pci,
18088c2ecf20Sopenharmony_ci		      int dev, unsigned int driver_caps,
18098c2ecf20Sopenharmony_ci		      struct azx **rchip)
18108c2ecf20Sopenharmony_ci{
18118c2ecf20Sopenharmony_ci	static const struct snd_device_ops ops = {
18128c2ecf20Sopenharmony_ci		.dev_disconnect = azx_dev_disconnect,
18138c2ecf20Sopenharmony_ci		.dev_free = azx_dev_free,
18148c2ecf20Sopenharmony_ci	};
18158c2ecf20Sopenharmony_ci	struct hda_intel *hda;
18168c2ecf20Sopenharmony_ci	struct azx *chip;
18178c2ecf20Sopenharmony_ci	int err;
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	*rchip = NULL;
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci	err = pci_enable_device(pci);
18228c2ecf20Sopenharmony_ci	if (err < 0)
18238c2ecf20Sopenharmony_ci		return err;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci	hda = devm_kzalloc(&pci->dev, sizeof(*hda), GFP_KERNEL);
18268c2ecf20Sopenharmony_ci	if (!hda) {
18278c2ecf20Sopenharmony_ci		pci_disable_device(pci);
18288c2ecf20Sopenharmony_ci		return -ENOMEM;
18298c2ecf20Sopenharmony_ci	}
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci	chip = &hda->chip;
18328c2ecf20Sopenharmony_ci	mutex_init(&chip->open_mutex);
18338c2ecf20Sopenharmony_ci	chip->card = card;
18348c2ecf20Sopenharmony_ci	chip->pci = pci;
18358c2ecf20Sopenharmony_ci	chip->ops = &pci_hda_ops;
18368c2ecf20Sopenharmony_ci	chip->driver_caps = driver_caps;
18378c2ecf20Sopenharmony_ci	chip->driver_type = driver_caps & 0xff;
18388c2ecf20Sopenharmony_ci	check_msi(chip);
18398c2ecf20Sopenharmony_ci	chip->dev_index = dev;
18408c2ecf20Sopenharmony_ci	if (jackpoll_ms[dev] >= 50 && jackpoll_ms[dev] <= 60000)
18418c2ecf20Sopenharmony_ci		chip->jackpoll_interval = msecs_to_jiffies(jackpoll_ms[dev]);
18428c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&chip->pcm_list);
18438c2ecf20Sopenharmony_ci	INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work);
18448c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&hda->list);
18458c2ecf20Sopenharmony_ci	init_vga_switcheroo(chip);
18468c2ecf20Sopenharmony_ci	init_completion(&hda->probe_wait);
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci	assign_position_fix(chip, check_position_fix(chip, position_fix[dev]));
18498c2ecf20Sopenharmony_ci
18508c2ecf20Sopenharmony_ci	if (single_cmd < 0) /* allow fallback to single_cmd at errors */
18518c2ecf20Sopenharmony_ci		chip->fallback_to_single_cmd = 1;
18528c2ecf20Sopenharmony_ci	else /* explicitly set to single_cmd or not */
18538c2ecf20Sopenharmony_ci		chip->single_cmd = single_cmd;
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	azx_check_snoop_available(chip);
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	if (bdl_pos_adj[dev] < 0)
18588c2ecf20Sopenharmony_ci		chip->bdl_pos_adj = default_bdl_pos_adj(chip);
18598c2ecf20Sopenharmony_ci	else
18608c2ecf20Sopenharmony_ci		chip->bdl_pos_adj = bdl_pos_adj[dev];
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci	err = azx_bus_init(chip, model[dev]);
18638c2ecf20Sopenharmony_ci	if (err < 0) {
18648c2ecf20Sopenharmony_ci		pci_disable_device(pci);
18658c2ecf20Sopenharmony_ci		return err;
18668c2ecf20Sopenharmony_ci	}
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	/* use the non-cached pages in non-snoop mode */
18698c2ecf20Sopenharmony_ci	if (!azx_snoop(chip))
18708c2ecf20Sopenharmony_ci		azx_bus(chip)->dma_type = SNDRV_DMA_TYPE_DEV_UC;
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_NVIDIA) {
18738c2ecf20Sopenharmony_ci		dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n");
18748c2ecf20Sopenharmony_ci		chip->bus.core.needs_damn_long_delay = 1;
18758c2ecf20Sopenharmony_ci	}
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	check_probe_mask(chip, dev);
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
18808c2ecf20Sopenharmony_ci	if (err < 0) {
18818c2ecf20Sopenharmony_ci		dev_err(card->dev, "Error creating device [card]!\n");
18828c2ecf20Sopenharmony_ci		azx_free(chip);
18838c2ecf20Sopenharmony_ci		return err;
18848c2ecf20Sopenharmony_ci	}
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci	/* continue probing in work context as may trigger request module */
18878c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&hda->probe_work, azx_probe_work);
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	*rchip = chip;
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	return 0;
18928c2ecf20Sopenharmony_ci}
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_cistatic int azx_first_init(struct azx *chip)
18958c2ecf20Sopenharmony_ci{
18968c2ecf20Sopenharmony_ci	int dev = chip->dev_index;
18978c2ecf20Sopenharmony_ci	struct pci_dev *pci = chip->pci;
18988c2ecf20Sopenharmony_ci	struct snd_card *card = chip->card;
18998c2ecf20Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
19008c2ecf20Sopenharmony_ci	int err;
19018c2ecf20Sopenharmony_ci	unsigned short gcap;
19028c2ecf20Sopenharmony_ci	unsigned int dma_bits = 64;
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_ci#if BITS_PER_LONG != 64
19058c2ecf20Sopenharmony_ci	/* Fix up base address on ULI M5461 */
19068c2ecf20Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_ULI) {
19078c2ecf20Sopenharmony_ci		u16 tmp3;
19088c2ecf20Sopenharmony_ci		pci_read_config_word(pci, 0x40, &tmp3);
19098c2ecf20Sopenharmony_ci		pci_write_config_word(pci, 0x40, tmp3 | 0x10);
19108c2ecf20Sopenharmony_ci		pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, 0);
19118c2ecf20Sopenharmony_ci	}
19128c2ecf20Sopenharmony_ci#endif
19138c2ecf20Sopenharmony_ci	/*
19148c2ecf20Sopenharmony_ci	 * Fix response write request not synced to memory when handle
19158c2ecf20Sopenharmony_ci	 * hdac interrupt on Glenfly Gpus
19168c2ecf20Sopenharmony_ci	 */
19178c2ecf20Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_GFHDMI)
19188c2ecf20Sopenharmony_ci		bus->polling_mode = 1;
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci	err = pci_request_regions(pci, "ICH HD audio");
19218c2ecf20Sopenharmony_ci	if (err < 0)
19228c2ecf20Sopenharmony_ci		return err;
19238c2ecf20Sopenharmony_ci	chip->region_requested = 1;
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	bus->addr = pci_resource_start(pci, 0);
19268c2ecf20Sopenharmony_ci	bus->remap_addr = pci_ioremap_bar(pci, 0);
19278c2ecf20Sopenharmony_ci	if (bus->remap_addr == NULL) {
19288c2ecf20Sopenharmony_ci		dev_err(card->dev, "ioremap error\n");
19298c2ecf20Sopenharmony_ci		return -ENXIO;
19308c2ecf20Sopenharmony_ci	}
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	if (chip->driver_type == AZX_DRIVER_SKL)
19338c2ecf20Sopenharmony_ci		snd_hdac_bus_parse_capabilities(bus);
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	/*
19368c2ecf20Sopenharmony_ci	 * Some Intel CPUs has always running timer (ART) feature and
19378c2ecf20Sopenharmony_ci	 * controller may have Global time sync reporting capability, so
19388c2ecf20Sopenharmony_ci	 * check both of these before declaring synchronized time reporting
19398c2ecf20Sopenharmony_ci	 * capability SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME
19408c2ecf20Sopenharmony_ci	 */
19418c2ecf20Sopenharmony_ci	chip->gts_present = false;
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
19448c2ecf20Sopenharmony_ci	if (bus->ppcap && boot_cpu_has(X86_FEATURE_ART))
19458c2ecf20Sopenharmony_ci		chip->gts_present = true;
19468c2ecf20Sopenharmony_ci#endif
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	if (chip->msi) {
19498c2ecf20Sopenharmony_ci		if (chip->driver_caps & AZX_DCAPS_NO_MSI64) {
19508c2ecf20Sopenharmony_ci			dev_dbg(card->dev, "Disabling 64bit MSI\n");
19518c2ecf20Sopenharmony_ci			pci->no_64bit_msi = true;
19528c2ecf20Sopenharmony_ci		}
19538c2ecf20Sopenharmony_ci		if (pci_enable_msi(pci) < 0)
19548c2ecf20Sopenharmony_ci			chip->msi = 0;
19558c2ecf20Sopenharmony_ci	}
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	pci_set_master(pci);
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci	gcap = azx_readw(chip, GCAP);
19608c2ecf20Sopenharmony_ci	dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap);
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci	/* AMD devices support 40 or 48bit DMA, take the safe one */
19638c2ecf20Sopenharmony_ci	if (chip->pci->vendor == PCI_VENDOR_ID_AMD)
19648c2ecf20Sopenharmony_ci		dma_bits = 40;
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_ci	/* disable SB600 64bit support for safety */
19678c2ecf20Sopenharmony_ci	if (chip->pci->vendor == PCI_VENDOR_ID_ATI) {
19688c2ecf20Sopenharmony_ci		struct pci_dev *p_smbus;
19698c2ecf20Sopenharmony_ci		dma_bits = 40;
19708c2ecf20Sopenharmony_ci		p_smbus = pci_get_device(PCI_VENDOR_ID_ATI,
19718c2ecf20Sopenharmony_ci					 PCI_DEVICE_ID_ATI_SBX00_SMBUS,
19728c2ecf20Sopenharmony_ci					 NULL);
19738c2ecf20Sopenharmony_ci		if (p_smbus) {
19748c2ecf20Sopenharmony_ci			if (p_smbus->revision < 0x30)
19758c2ecf20Sopenharmony_ci				gcap &= ~AZX_GCAP_64OK;
19768c2ecf20Sopenharmony_ci			pci_dev_put(p_smbus);
19778c2ecf20Sopenharmony_ci		}
19788c2ecf20Sopenharmony_ci	}
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci	/* NVidia hardware normally only supports up to 40 bits of DMA */
19818c2ecf20Sopenharmony_ci	if (chip->pci->vendor == PCI_VENDOR_ID_NVIDIA)
19828c2ecf20Sopenharmony_ci		dma_bits = 40;
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	/* disable 64bit DMA address on some devices */
19858c2ecf20Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_NO_64BIT) {
19868c2ecf20Sopenharmony_ci		dev_dbg(card->dev, "Disabling 64bit DMA\n");
19878c2ecf20Sopenharmony_ci		gcap &= ~AZX_GCAP_64OK;
19888c2ecf20Sopenharmony_ci	}
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_ci	/* disable buffer size rounding to 128-byte multiples if supported */
19918c2ecf20Sopenharmony_ci	if (align_buffer_size >= 0)
19928c2ecf20Sopenharmony_ci		chip->align_buffer_size = !!align_buffer_size;
19938c2ecf20Sopenharmony_ci	else {
19948c2ecf20Sopenharmony_ci		if (chip->driver_caps & AZX_DCAPS_NO_ALIGN_BUFSIZE)
19958c2ecf20Sopenharmony_ci			chip->align_buffer_size = 0;
19968c2ecf20Sopenharmony_ci		else
19978c2ecf20Sopenharmony_ci			chip->align_buffer_size = 1;
19988c2ecf20Sopenharmony_ci	}
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci	/* allow 64bit DMA address if supported by H/W */
20018c2ecf20Sopenharmony_ci	if (!(gcap & AZX_GCAP_64OK))
20028c2ecf20Sopenharmony_ci		dma_bits = 32;
20038c2ecf20Sopenharmony_ci	if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
20048c2ecf20Sopenharmony_ci		dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
20058c2ecf20Sopenharmony_ci	} else {
20068c2ecf20Sopenharmony_ci		dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
20078c2ecf20Sopenharmony_ci		dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
20088c2ecf20Sopenharmony_ci	}
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci	/* read number of streams from GCAP register instead of using
20118c2ecf20Sopenharmony_ci	 * hardcoded value
20128c2ecf20Sopenharmony_ci	 */
20138c2ecf20Sopenharmony_ci	chip->capture_streams = (gcap >> 8) & 0x0f;
20148c2ecf20Sopenharmony_ci	chip->playback_streams = (gcap >> 12) & 0x0f;
20158c2ecf20Sopenharmony_ci	if (!chip->playback_streams && !chip->capture_streams) {
20168c2ecf20Sopenharmony_ci		/* gcap didn't give any info, switching to old method */
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci		switch (chip->driver_type) {
20198c2ecf20Sopenharmony_ci		case AZX_DRIVER_ULI:
20208c2ecf20Sopenharmony_ci			chip->playback_streams = ULI_NUM_PLAYBACK;
20218c2ecf20Sopenharmony_ci			chip->capture_streams = ULI_NUM_CAPTURE;
20228c2ecf20Sopenharmony_ci			break;
20238c2ecf20Sopenharmony_ci		case AZX_DRIVER_ATIHDMI:
20248c2ecf20Sopenharmony_ci		case AZX_DRIVER_ATIHDMI_NS:
20258c2ecf20Sopenharmony_ci			chip->playback_streams = ATIHDMI_NUM_PLAYBACK;
20268c2ecf20Sopenharmony_ci			chip->capture_streams = ATIHDMI_NUM_CAPTURE;
20278c2ecf20Sopenharmony_ci			break;
20288c2ecf20Sopenharmony_ci		case AZX_DRIVER_GFHDMI:
20298c2ecf20Sopenharmony_ci		case AZX_DRIVER_GENERIC:
20308c2ecf20Sopenharmony_ci		default:
20318c2ecf20Sopenharmony_ci			chip->playback_streams = ICH6_NUM_PLAYBACK;
20328c2ecf20Sopenharmony_ci			chip->capture_streams = ICH6_NUM_CAPTURE;
20338c2ecf20Sopenharmony_ci			break;
20348c2ecf20Sopenharmony_ci		}
20358c2ecf20Sopenharmony_ci	}
20368c2ecf20Sopenharmony_ci	chip->capture_index_offset = 0;
20378c2ecf20Sopenharmony_ci	chip->playback_index_offset = chip->capture_streams;
20388c2ecf20Sopenharmony_ci	chip->num_streams = chip->playback_streams + chip->capture_streams;
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci	/* sanity check for the SDxCTL.STRM field overflow */
20418c2ecf20Sopenharmony_ci	if (chip->num_streams > 15 &&
20428c2ecf20Sopenharmony_ci	    (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG) == 0) {
20438c2ecf20Sopenharmony_ci		dev_warn(chip->card->dev, "number of I/O streams is %d, "
20448c2ecf20Sopenharmony_ci			 "forcing separate stream tags", chip->num_streams);
20458c2ecf20Sopenharmony_ci		chip->driver_caps |= AZX_DCAPS_SEPARATE_STREAM_TAG;
20468c2ecf20Sopenharmony_ci	}
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	/* initialize streams */
20498c2ecf20Sopenharmony_ci	err = azx_init_streams(chip);
20508c2ecf20Sopenharmony_ci	if (err < 0)
20518c2ecf20Sopenharmony_ci		return err;
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	err = azx_alloc_stream_pages(chip);
20548c2ecf20Sopenharmony_ci	if (err < 0)
20558c2ecf20Sopenharmony_ci		return err;
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci	/* initialize chip */
20588c2ecf20Sopenharmony_ci	azx_init_pci(chip);
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	snd_hdac_i915_set_bclk(bus);
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci	hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0);
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci	/* codec detection */
20658c2ecf20Sopenharmony_ci	if (!azx_bus(chip)->codec_mask) {
20668c2ecf20Sopenharmony_ci		dev_err(card->dev, "no codecs found!\n");
20678c2ecf20Sopenharmony_ci		/* keep running the rest for the runtime PM */
20688c2ecf20Sopenharmony_ci	}
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci	if (azx_acquire_irq(chip, 0) < 0)
20718c2ecf20Sopenharmony_ci		return -EBUSY;
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci	strcpy(card->driver, "HDA-Intel");
20748c2ecf20Sopenharmony_ci	strlcpy(card->shortname, driver_short_names[chip->driver_type],
20758c2ecf20Sopenharmony_ci		sizeof(card->shortname));
20768c2ecf20Sopenharmony_ci	snprintf(card->longname, sizeof(card->longname),
20778c2ecf20Sopenharmony_ci		 "%s at 0x%lx irq %i",
20788c2ecf20Sopenharmony_ci		 card->shortname, bus->addr, bus->irq);
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci	return 0;
20818c2ecf20Sopenharmony_ci}
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_HDA_PATCH_LOADER
20848c2ecf20Sopenharmony_ci/* callback from request_firmware_nowait() */
20858c2ecf20Sopenharmony_cistatic void azx_firmware_cb(const struct firmware *fw, void *context)
20868c2ecf20Sopenharmony_ci{
20878c2ecf20Sopenharmony_ci	struct snd_card *card = context;
20888c2ecf20Sopenharmony_ci	struct azx *chip = card->private_data;
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci	if (fw)
20918c2ecf20Sopenharmony_ci		chip->fw = fw;
20928c2ecf20Sopenharmony_ci	else
20938c2ecf20Sopenharmony_ci		dev_err(card->dev, "Cannot load firmware, continue without patching\n");
20948c2ecf20Sopenharmony_ci	if (!chip->disabled) {
20958c2ecf20Sopenharmony_ci		/* continue probing */
20968c2ecf20Sopenharmony_ci		azx_probe_continue(chip);
20978c2ecf20Sopenharmony_ci	}
20988c2ecf20Sopenharmony_ci}
20998c2ecf20Sopenharmony_ci#endif
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_cistatic int disable_msi_reset_irq(struct azx *chip)
21028c2ecf20Sopenharmony_ci{
21038c2ecf20Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
21048c2ecf20Sopenharmony_ci	int err;
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci	free_irq(bus->irq, chip);
21078c2ecf20Sopenharmony_ci	bus->irq = -1;
21088c2ecf20Sopenharmony_ci	chip->card->sync_irq = -1;
21098c2ecf20Sopenharmony_ci	pci_disable_msi(chip->pci);
21108c2ecf20Sopenharmony_ci	chip->msi = 0;
21118c2ecf20Sopenharmony_ci	err = azx_acquire_irq(chip, 1);
21128c2ecf20Sopenharmony_ci	if (err < 0)
21138c2ecf20Sopenharmony_ci		return err;
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci	return 0;
21168c2ecf20Sopenharmony_ci}
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_cistatic void pcm_mmap_prepare(struct snd_pcm_substream *substream,
21198c2ecf20Sopenharmony_ci			     struct vm_area_struct *area)
21208c2ecf20Sopenharmony_ci{
21218c2ecf20Sopenharmony_ci#ifdef CONFIG_X86
21228c2ecf20Sopenharmony_ci	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
21238c2ecf20Sopenharmony_ci	struct azx *chip = apcm->chip;
21248c2ecf20Sopenharmony_ci	if (chip->uc_buffer)
21258c2ecf20Sopenharmony_ci		area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
21268c2ecf20Sopenharmony_ci#endif
21278c2ecf20Sopenharmony_ci}
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci/* Denylist for skipping the whole probe:
21308c2ecf20Sopenharmony_ci * some HD-audio PCI entries are exposed without any codecs, and such devices
21318c2ecf20Sopenharmony_ci * should be ignored from the beginning.
21328c2ecf20Sopenharmony_ci */
21338c2ecf20Sopenharmony_cistatic const struct pci_device_id driver_denylist[] = {
21348c2ecf20Sopenharmony_ci	{ PCI_DEVICE_SUB(0x1022, 0x1487, 0x1043, 0x874f) }, /* ASUS ROG Zenith II / Strix */
21358c2ecf20Sopenharmony_ci	{ PCI_DEVICE_SUB(0x1022, 0x1487, 0x1462, 0xcb59) }, /* MSI TRX40 Creator */
21368c2ecf20Sopenharmony_ci	{ PCI_DEVICE_SUB(0x1022, 0x1487, 0x1462, 0xcb60) }, /* MSI TRX40 */
21378c2ecf20Sopenharmony_ci	{}
21388c2ecf20Sopenharmony_ci};
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_cistatic const struct hda_controller_ops pci_hda_ops = {
21418c2ecf20Sopenharmony_ci	.disable_msi_reset_irq = disable_msi_reset_irq,
21428c2ecf20Sopenharmony_ci	.pcm_mmap_prepare = pcm_mmap_prepare,
21438c2ecf20Sopenharmony_ci	.position_check = azx_position_check,
21448c2ecf20Sopenharmony_ci};
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_cistatic int azx_probe(struct pci_dev *pci,
21478c2ecf20Sopenharmony_ci		     const struct pci_device_id *pci_id)
21488c2ecf20Sopenharmony_ci{
21498c2ecf20Sopenharmony_ci	static int dev;
21508c2ecf20Sopenharmony_ci	struct snd_card *card;
21518c2ecf20Sopenharmony_ci	struct hda_intel *hda;
21528c2ecf20Sopenharmony_ci	struct azx *chip;
21538c2ecf20Sopenharmony_ci	bool schedule_probe;
21548c2ecf20Sopenharmony_ci	int err;
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci	if (pci_match_id(driver_denylist, pci)) {
21578c2ecf20Sopenharmony_ci		dev_info(&pci->dev, "Skipping the device on the denylist\n");
21588c2ecf20Sopenharmony_ci		return -ENODEV;
21598c2ecf20Sopenharmony_ci	}
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci	if (dev >= SNDRV_CARDS)
21628c2ecf20Sopenharmony_ci		return -ENODEV;
21638c2ecf20Sopenharmony_ci	if (!enable[dev]) {
21648c2ecf20Sopenharmony_ci		dev++;
21658c2ecf20Sopenharmony_ci		return -ENOENT;
21668c2ecf20Sopenharmony_ci	}
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci	/*
21698c2ecf20Sopenharmony_ci	 * stop probe if another Intel's DSP driver should be activated
21708c2ecf20Sopenharmony_ci	 */
21718c2ecf20Sopenharmony_ci	if (dmic_detect) {
21728c2ecf20Sopenharmony_ci		err = snd_intel_dsp_driver_probe(pci);
21738c2ecf20Sopenharmony_ci		if (err != SND_INTEL_DSP_DRIVER_ANY && err != SND_INTEL_DSP_DRIVER_LEGACY) {
21748c2ecf20Sopenharmony_ci			dev_dbg(&pci->dev, "HDAudio driver not selected, aborting probe\n");
21758c2ecf20Sopenharmony_ci			return -ENODEV;
21768c2ecf20Sopenharmony_ci		}
21778c2ecf20Sopenharmony_ci	} else {
21788c2ecf20Sopenharmony_ci		dev_warn(&pci->dev, "dmic_detect option is deprecated, pass snd-intel-dspcfg.dsp_driver=1 option instead\n");
21798c2ecf20Sopenharmony_ci	}
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci	err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
21828c2ecf20Sopenharmony_ci			   0, &card);
21838c2ecf20Sopenharmony_ci	if (err < 0) {
21848c2ecf20Sopenharmony_ci		dev_err(&pci->dev, "Error creating card!\n");
21858c2ecf20Sopenharmony_ci		return err;
21868c2ecf20Sopenharmony_ci	}
21878c2ecf20Sopenharmony_ci
21888c2ecf20Sopenharmony_ci	err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
21898c2ecf20Sopenharmony_ci	if (err < 0)
21908c2ecf20Sopenharmony_ci		goto out_free;
21918c2ecf20Sopenharmony_ci	card->private_data = chip;
21928c2ecf20Sopenharmony_ci	hda = container_of(chip, struct hda_intel, chip);
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	pci_set_drvdata(pci, card);
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci	err = register_vga_switcheroo(chip);
21978c2ecf20Sopenharmony_ci	if (err < 0) {
21988c2ecf20Sopenharmony_ci		dev_err(card->dev, "Error registering vga_switcheroo client\n");
21998c2ecf20Sopenharmony_ci		goto out_free;
22008c2ecf20Sopenharmony_ci	}
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci	if (check_hdmi_disabled(pci)) {
22038c2ecf20Sopenharmony_ci		dev_info(card->dev, "VGA controller is disabled\n");
22048c2ecf20Sopenharmony_ci		dev_info(card->dev, "Delaying initialization\n");
22058c2ecf20Sopenharmony_ci		chip->disabled = true;
22068c2ecf20Sopenharmony_ci	}
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci	schedule_probe = !chip->disabled;
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_HDA_PATCH_LOADER
22118c2ecf20Sopenharmony_ci	if (patch[dev] && *patch[dev]) {
22128c2ecf20Sopenharmony_ci		dev_info(card->dev, "Applying patch firmware '%s'\n",
22138c2ecf20Sopenharmony_ci			 patch[dev]);
22148c2ecf20Sopenharmony_ci		err = request_firmware_nowait(THIS_MODULE, true, patch[dev],
22158c2ecf20Sopenharmony_ci					      &pci->dev, GFP_KERNEL, card,
22168c2ecf20Sopenharmony_ci					      azx_firmware_cb);
22178c2ecf20Sopenharmony_ci		if (err < 0)
22188c2ecf20Sopenharmony_ci			goto out_free;
22198c2ecf20Sopenharmony_ci		schedule_probe = false; /* continued in azx_firmware_cb() */
22208c2ecf20Sopenharmony_ci	}
22218c2ecf20Sopenharmony_ci#endif /* CONFIG_SND_HDA_PATCH_LOADER */
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci#ifndef CONFIG_SND_HDA_I915
22248c2ecf20Sopenharmony_ci	if (CONTROLLER_IN_GPU(pci))
22258c2ecf20Sopenharmony_ci		dev_err(card->dev, "Haswell/Broadwell HDMI/DP must build in CONFIG_SND_HDA_I915\n");
22268c2ecf20Sopenharmony_ci#endif
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci	if (schedule_probe)
22298c2ecf20Sopenharmony_ci		schedule_delayed_work(&hda->probe_work, 0);
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci	dev++;
22328c2ecf20Sopenharmony_ci	if (chip->disabled)
22338c2ecf20Sopenharmony_ci		complete_all(&hda->probe_wait);
22348c2ecf20Sopenharmony_ci	return 0;
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ciout_free:
22378c2ecf20Sopenharmony_ci	snd_card_free(card);
22388c2ecf20Sopenharmony_ci	return err;
22398c2ecf20Sopenharmony_ci}
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
22428c2ecf20Sopenharmony_ci/* On some boards setting power_save to a non 0 value leads to clicking /
22438c2ecf20Sopenharmony_ci * popping sounds when ever we enter/leave powersaving mode. Ideally we would
22448c2ecf20Sopenharmony_ci * figure out how to avoid these sounds, but that is not always feasible.
22458c2ecf20Sopenharmony_ci * So we keep a list of devices where we disable powersaving as its known
22468c2ecf20Sopenharmony_ci * to causes problems on these devices.
22478c2ecf20Sopenharmony_ci */
22488c2ecf20Sopenharmony_cistatic const struct snd_pci_quirk power_save_denylist[] = {
22498c2ecf20Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
22508c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1849, 0xc892, "Asrock B85M-ITX", 0),
22518c2ecf20Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
22528c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1849, 0x0397, "Asrock N68C-S UCC", 0),
22538c2ecf20Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
22548c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1849, 0x7662, "Asrock H81M-HDS", 0),
22558c2ecf20Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
22568c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1043, 0x8733, "Asus Prime X370-Pro", 0),
22578c2ecf20Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
22588c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1558, 0x6504, "Clevo W65_67SB", 0),
22598c2ecf20Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
22608c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1028, 0x0497, "Dell Precision T3600", 0),
22618c2ecf20Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
22628c2ecf20Sopenharmony_ci	/* Note the P55A-UD3 and Z87-D3HP share the subsys id for the HDA dev */
22638c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P55A-UD3 / Z87-D3HP", 0),
22648c2ecf20Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
22658c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x8086, 0x2040, "Intel DZ77BH-55K", 0),
22668c2ecf20Sopenharmony_ci	/* https://bugzilla.kernel.org/show_bug.cgi?id=199607 */
22678c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x8086, 0x2057, "Intel NUC5i7RYB", 0),
22688c2ecf20Sopenharmony_ci	/* https://bugs.launchpad.net/bugs/1821663 */
22698c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x8086, 0x2064, "Intel SDP 8086:2064", 0),
22708c2ecf20Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1520902 */
22718c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x8086, 0x2068, "Intel NUC7i3BNB", 0),
22728c2ecf20Sopenharmony_ci	/* https://bugzilla.kernel.org/show_bug.cgi?id=198611 */
22738c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x17aa, 0x2227, "Lenovo X1 Carbon 3rd Gen", 0),
22748c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x17aa, 0x316e, "Lenovo ThinkCentre M70q", 0),
22758c2ecf20Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1689623 */
22768c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x17aa, 0x367b, "Lenovo IdeaCentre B550", 0),
22778c2ecf20Sopenharmony_ci	/* https://bugzilla.redhat.com/show_bug.cgi?id=1572975 */
22788c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x17aa, 0x36a7, "Lenovo C50 All in one", 0),
22798c2ecf20Sopenharmony_ci	/* https://bugs.launchpad.net/bugs/1821663 */
22808c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1631, 0xe017, "Packard Bell NEC IMEDIA 5204", 0),
22818c2ecf20Sopenharmony_ci	/* KONTRON SinglePC may cause a stall at runtime resume */
22828c2ecf20Sopenharmony_ci	SND_PCI_QUIRK(0x1734, 0x1232, "KONTRON SinglePC", 0),
22838c2ecf20Sopenharmony_ci	{}
22848c2ecf20Sopenharmony_ci};
22858c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_cistatic void set_default_power_save(struct azx *chip)
22888c2ecf20Sopenharmony_ci{
22898c2ecf20Sopenharmony_ci	int val = power_save;
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
22928c2ecf20Sopenharmony_ci	if (pm_blacklist) {
22938c2ecf20Sopenharmony_ci		const struct snd_pci_quirk *q;
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ci		q = snd_pci_quirk_lookup(chip->pci, power_save_denylist);
22968c2ecf20Sopenharmony_ci		if (q && val) {
22978c2ecf20Sopenharmony_ci			dev_info(chip->card->dev, "device %04x:%04x is on the power_save denylist, forcing power_save to 0\n",
22988c2ecf20Sopenharmony_ci				 q->subvendor, q->subdevice);
22998c2ecf20Sopenharmony_ci			val = 0;
23008c2ecf20Sopenharmony_ci		}
23018c2ecf20Sopenharmony_ci	}
23028c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */
23038c2ecf20Sopenharmony_ci	snd_hda_set_power_save(&chip->bus, val * 1000);
23048c2ecf20Sopenharmony_ci}
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
23078c2ecf20Sopenharmony_cistatic const unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = {
23088c2ecf20Sopenharmony_ci	[AZX_DRIVER_NVIDIA] = 8,
23098c2ecf20Sopenharmony_ci	[AZX_DRIVER_TERA] = 1,
23108c2ecf20Sopenharmony_ci};
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_cistatic int azx_probe_continue(struct azx *chip)
23138c2ecf20Sopenharmony_ci{
23148c2ecf20Sopenharmony_ci	struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
23158c2ecf20Sopenharmony_ci	struct hdac_bus *bus = azx_bus(chip);
23168c2ecf20Sopenharmony_ci	struct pci_dev *pci = chip->pci;
23178c2ecf20Sopenharmony_ci	int dev = chip->dev_index;
23188c2ecf20Sopenharmony_ci	int err;
23198c2ecf20Sopenharmony_ci
23208c2ecf20Sopenharmony_ci	if (chip->disabled || hda->init_failed)
23218c2ecf20Sopenharmony_ci		return -EIO;
23228c2ecf20Sopenharmony_ci	if (hda->probe_retry)
23238c2ecf20Sopenharmony_ci		goto probe_retry;
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci	to_hda_bus(bus)->bus_probing = 1;
23268c2ecf20Sopenharmony_ci	hda->probe_continued = 1;
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci	/* bind with i915 if needed */
23298c2ecf20Sopenharmony_ci	if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) {
23308c2ecf20Sopenharmony_ci		err = snd_hdac_i915_init(bus);
23318c2ecf20Sopenharmony_ci		if (err < 0) {
23328c2ecf20Sopenharmony_ci			/* if the controller is bound only with HDMI/DP
23338c2ecf20Sopenharmony_ci			 * (for HSW and BDW), we need to abort the probe;
23348c2ecf20Sopenharmony_ci			 * for other chips, still continue probing as other
23358c2ecf20Sopenharmony_ci			 * codecs can be on the same link.
23368c2ecf20Sopenharmony_ci			 */
23378c2ecf20Sopenharmony_ci			if (CONTROLLER_IN_GPU(pci)) {
23388c2ecf20Sopenharmony_ci				dev_err(chip->card->dev,
23398c2ecf20Sopenharmony_ci					"HSW/BDW HD-audio HDMI/DP requires binding with gfx driver\n");
23408c2ecf20Sopenharmony_ci				goto out_free;
23418c2ecf20Sopenharmony_ci			} else {
23428c2ecf20Sopenharmony_ci				/* don't bother any longer */
23438c2ecf20Sopenharmony_ci				chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT;
23448c2ecf20Sopenharmony_ci			}
23458c2ecf20Sopenharmony_ci		}
23468c2ecf20Sopenharmony_ci
23478c2ecf20Sopenharmony_ci		/* HSW/BDW controllers need this power */
23488c2ecf20Sopenharmony_ci		if (CONTROLLER_IN_GPU(pci))
23498c2ecf20Sopenharmony_ci			hda->need_i915_power = 1;
23508c2ecf20Sopenharmony_ci	}
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_ci	/* Request display power well for the HDA controller or codec. For
23538c2ecf20Sopenharmony_ci	 * Haswell/Broadwell, both the display HDA controller and codec need
23548c2ecf20Sopenharmony_ci	 * this power. For other platforms, like Baytrail/Braswell, only the
23558c2ecf20Sopenharmony_ci	 * display codec needs the power and it can be released after probe.
23568c2ecf20Sopenharmony_ci	 */
23578c2ecf20Sopenharmony_ci	display_power(chip, true);
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_ci	err = azx_first_init(chip);
23608c2ecf20Sopenharmony_ci	if (err < 0)
23618c2ecf20Sopenharmony_ci		goto out_free;
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_HDA_INPUT_BEEP
23648c2ecf20Sopenharmony_ci	chip->beep_mode = beep_mode[dev];
23658c2ecf20Sopenharmony_ci#endif
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci	/* create codec instances */
23688c2ecf20Sopenharmony_ci	if (bus->codec_mask) {
23698c2ecf20Sopenharmony_ci		err = azx_probe_codecs(chip, azx_max_codecs[chip->driver_type]);
23708c2ecf20Sopenharmony_ci		if (err < 0)
23718c2ecf20Sopenharmony_ci			goto out_free;
23728c2ecf20Sopenharmony_ci	}
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_HDA_PATCH_LOADER
23758c2ecf20Sopenharmony_ci	if (chip->fw) {
23768c2ecf20Sopenharmony_ci		err = snd_hda_load_patch(&chip->bus, chip->fw->size,
23778c2ecf20Sopenharmony_ci					 chip->fw->data);
23788c2ecf20Sopenharmony_ci		if (err < 0)
23798c2ecf20Sopenharmony_ci			goto out_free;
23808c2ecf20Sopenharmony_ci#ifndef CONFIG_PM
23818c2ecf20Sopenharmony_ci		release_firmware(chip->fw); /* no longer needed */
23828c2ecf20Sopenharmony_ci		chip->fw = NULL;
23838c2ecf20Sopenharmony_ci#endif
23848c2ecf20Sopenharmony_ci	}
23858c2ecf20Sopenharmony_ci#endif
23868c2ecf20Sopenharmony_ci
23878c2ecf20Sopenharmony_ci probe_retry:
23888c2ecf20Sopenharmony_ci	if (bus->codec_mask && !(probe_only[dev] & 1)) {
23898c2ecf20Sopenharmony_ci		err = azx_codec_configure(chip);
23908c2ecf20Sopenharmony_ci		if (err) {
23918c2ecf20Sopenharmony_ci			if ((chip->driver_caps & AZX_DCAPS_RETRY_PROBE) &&
23928c2ecf20Sopenharmony_ci			    ++hda->probe_retry < 60) {
23938c2ecf20Sopenharmony_ci				schedule_delayed_work(&hda->probe_work,
23948c2ecf20Sopenharmony_ci						      msecs_to_jiffies(1000));
23958c2ecf20Sopenharmony_ci				return 0; /* keep things up */
23968c2ecf20Sopenharmony_ci			}
23978c2ecf20Sopenharmony_ci			dev_err(chip->card->dev, "Cannot probe codecs, giving up\n");
23988c2ecf20Sopenharmony_ci			goto out_free;
23998c2ecf20Sopenharmony_ci		}
24008c2ecf20Sopenharmony_ci	}
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	err = snd_card_register(chip->card);
24038c2ecf20Sopenharmony_ci	if (err < 0)
24048c2ecf20Sopenharmony_ci		goto out_free;
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_ci	setup_vga_switcheroo_runtime_pm(chip);
24078c2ecf20Sopenharmony_ci
24088c2ecf20Sopenharmony_ci	chip->running = 1;
24098c2ecf20Sopenharmony_ci	azx_add_card_list(chip);
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci	set_default_power_save(chip);
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci	if (azx_has_pm_runtime(chip)) {
24148c2ecf20Sopenharmony_ci		pm_runtime_use_autosuspend(&pci->dev);
24158c2ecf20Sopenharmony_ci		pm_runtime_allow(&pci->dev);
24168c2ecf20Sopenharmony_ci		pm_runtime_put_autosuspend(&pci->dev);
24178c2ecf20Sopenharmony_ci	}
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_ciout_free:
24208c2ecf20Sopenharmony_ci	if (err < 0) {
24218c2ecf20Sopenharmony_ci		pci_set_drvdata(pci, NULL);
24228c2ecf20Sopenharmony_ci		snd_card_free(chip->card);
24238c2ecf20Sopenharmony_ci		return err;
24248c2ecf20Sopenharmony_ci	}
24258c2ecf20Sopenharmony_ci
24268c2ecf20Sopenharmony_ci	if (!hda->need_i915_power)
24278c2ecf20Sopenharmony_ci		display_power(chip, false);
24288c2ecf20Sopenharmony_ci	complete_all(&hda->probe_wait);
24298c2ecf20Sopenharmony_ci	to_hda_bus(bus)->bus_probing = 0;
24308c2ecf20Sopenharmony_ci	hda->probe_retry = 0;
24318c2ecf20Sopenharmony_ci	return 0;
24328c2ecf20Sopenharmony_ci}
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_cistatic void azx_remove(struct pci_dev *pci)
24358c2ecf20Sopenharmony_ci{
24368c2ecf20Sopenharmony_ci	struct snd_card *card = pci_get_drvdata(pci);
24378c2ecf20Sopenharmony_ci	struct azx *chip;
24388c2ecf20Sopenharmony_ci	struct hda_intel *hda;
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci	if (card) {
24418c2ecf20Sopenharmony_ci		/* cancel the pending probing work */
24428c2ecf20Sopenharmony_ci		chip = card->private_data;
24438c2ecf20Sopenharmony_ci		hda = container_of(chip, struct hda_intel, chip);
24448c2ecf20Sopenharmony_ci		/* FIXME: below is an ugly workaround.
24458c2ecf20Sopenharmony_ci		 * Both device_release_driver() and driver_probe_device()
24468c2ecf20Sopenharmony_ci		 * take *both* the device's and its parent's lock before
24478c2ecf20Sopenharmony_ci		 * calling the remove() and probe() callbacks.  The codec
24488c2ecf20Sopenharmony_ci		 * probe takes the locks of both the codec itself and its
24498c2ecf20Sopenharmony_ci		 * parent, i.e. the PCI controller dev.  Meanwhile, when
24508c2ecf20Sopenharmony_ci		 * the PCI controller is unbound, it takes its lock, too
24518c2ecf20Sopenharmony_ci		 * ==> ouch, a deadlock!
24528c2ecf20Sopenharmony_ci		 * As a workaround, we unlock temporarily here the controller
24538c2ecf20Sopenharmony_ci		 * device during cancel_work_sync() call.
24548c2ecf20Sopenharmony_ci		 */
24558c2ecf20Sopenharmony_ci		device_unlock(&pci->dev);
24568c2ecf20Sopenharmony_ci		cancel_delayed_work_sync(&hda->probe_work);
24578c2ecf20Sopenharmony_ci		device_lock(&pci->dev);
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci		snd_card_free(card);
24608c2ecf20Sopenharmony_ci	}
24618c2ecf20Sopenharmony_ci}
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_cistatic void azx_shutdown(struct pci_dev *pci)
24648c2ecf20Sopenharmony_ci{
24658c2ecf20Sopenharmony_ci	struct snd_card *card = pci_get_drvdata(pci);
24668c2ecf20Sopenharmony_ci	struct azx *chip;
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci	if (!card)
24698c2ecf20Sopenharmony_ci		return;
24708c2ecf20Sopenharmony_ci	chip = card->private_data;
24718c2ecf20Sopenharmony_ci	if (chip && chip->running)
24728c2ecf20Sopenharmony_ci		__azx_shutdown_chip(chip, true);
24738c2ecf20Sopenharmony_ci}
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci/* PCI IDs */
24768c2ecf20Sopenharmony_cistatic const struct pci_device_id azx_ids[] = {
24778c2ecf20Sopenharmony_ci	/* CPT */
24788c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x1c20),
24798c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
24808c2ecf20Sopenharmony_ci	/* PBG */
24818c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x1d20),
24828c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
24838c2ecf20Sopenharmony_ci	/* Panther Point */
24848c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x1e20),
24858c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
24868c2ecf20Sopenharmony_ci	/* Lynx Point */
24878c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x8c20),
24888c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
24898c2ecf20Sopenharmony_ci	/* 9 Series */
24908c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x8ca0),
24918c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
24928c2ecf20Sopenharmony_ci	/* Wellsburg */
24938c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x8d20),
24948c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
24958c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x8d21),
24968c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
24978c2ecf20Sopenharmony_ci	/* Lewisburg */
24988c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0xa1f0),
24998c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
25008c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0xa270),
25018c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
25028c2ecf20Sopenharmony_ci	/* Lynx Point-LP */
25038c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x9c20),
25048c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
25058c2ecf20Sopenharmony_ci	/* Lynx Point-LP */
25068c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x9c21),
25078c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
25088c2ecf20Sopenharmony_ci	/* Wildcat Point-LP */
25098c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x9ca0),
25108c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
25118c2ecf20Sopenharmony_ci	/* Sunrise Point */
25128c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0xa170),
25138c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
25148c2ecf20Sopenharmony_ci	/* Sunrise Point-LP */
25158c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x9d70),
25168c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
25178c2ecf20Sopenharmony_ci	/* Kabylake */
25188c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0xa171),
25198c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
25208c2ecf20Sopenharmony_ci	/* Kabylake-LP */
25218c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x9d71),
25228c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
25238c2ecf20Sopenharmony_ci	/* Kabylake-H */
25248c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0xa2f0),
25258c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE },
25268c2ecf20Sopenharmony_ci	/* Coffelake */
25278c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0xa348),
25288c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25298c2ecf20Sopenharmony_ci	/* Cannonlake */
25308c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x9dc8),
25318c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25328c2ecf20Sopenharmony_ci	/* CometLake-LP */
25338c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x02C8),
25348c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25358c2ecf20Sopenharmony_ci	/* CometLake-H */
25368c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x06C8),
25378c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25388c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0xf1c8),
25398c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25408c2ecf20Sopenharmony_ci	/* CometLake-S */
25418c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0xa3f0),
25428c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25438c2ecf20Sopenharmony_ci	/* CometLake-R */
25448c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0xf0c8),
25458c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25468c2ecf20Sopenharmony_ci	/* Icelake */
25478c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x34c8),
25488c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25498c2ecf20Sopenharmony_ci	/* Icelake-H */
25508c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x3dc8),
25518c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25528c2ecf20Sopenharmony_ci	/* Jasperlake */
25538c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x38c8),
25548c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25558c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x4dc8),
25568c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25578c2ecf20Sopenharmony_ci	/* Tigerlake */
25588c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0xa0c8),
25598c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25608c2ecf20Sopenharmony_ci	/* Tigerlake-H */
25618c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x43c8),
25628c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25638c2ecf20Sopenharmony_ci	/* DG1 */
25648c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x490d),
25658c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25668c2ecf20Sopenharmony_ci	/* DG2 */
25678c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x4f90),
25688c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25698c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x4f91),
25708c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25718c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x4f92),
25728c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25738c2ecf20Sopenharmony_ci	/* Alderlake-S */
25748c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x7ad0),
25758c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25768c2ecf20Sopenharmony_ci	/* Alderlake-P */
25778c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x51c8),
25788c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25798c2ecf20Sopenharmony_ci	/* Elkhart Lake */
25808c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x4b55),
25818c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25828c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x4b58),
25838c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
25848c2ecf20Sopenharmony_ci	/* Arrow Lake */
25858c2ecf20Sopenharmony_ci	{ PCI_DEVICE_DATA(INTEL, HDA_ARL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
25868c2ecf20Sopenharmony_ci	/* Broxton-P(Apollolake) */
25878c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x5a98),
25888c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
25898c2ecf20Sopenharmony_ci	/* Broxton-T */
25908c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x1a98),
25918c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
25928c2ecf20Sopenharmony_ci	/* Gemini-Lake */
25938c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x3198),
25948c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON },
25958c2ecf20Sopenharmony_ci	/* Haswell */
25968c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x0a0c),
25978c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
25988c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x0c0c),
25998c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
26008c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x0d0c),
26018c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
26028c2ecf20Sopenharmony_ci	/* Broadwell */
26038c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x160c),
26048c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_BROADWELL },
26058c2ecf20Sopenharmony_ci	/* 5 Series/3400 */
26068c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x3b56),
26078c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
26088c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x3b57),
26098c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
26108c2ecf20Sopenharmony_ci	/* Poulsbo */
26118c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x811b),
26128c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE |
26138c2ecf20Sopenharmony_ci	  AZX_DCAPS_POSFIX_LPIB },
26148c2ecf20Sopenharmony_ci	/* Oaktrail */
26158c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x080a),
26168c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE },
26178c2ecf20Sopenharmony_ci	/* BayTrail */
26188c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x0f04),
26198c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL },
26208c2ecf20Sopenharmony_ci	/* Braswell */
26218c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x2284),
26228c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BRASWELL },
26238c2ecf20Sopenharmony_ci	/* ICH6 */
26248c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x2668),
26258c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
26268c2ecf20Sopenharmony_ci	/* ICH7 */
26278c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x27d8),
26288c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
26298c2ecf20Sopenharmony_ci	/* ESB2 */
26308c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x269a),
26318c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
26328c2ecf20Sopenharmony_ci	/* ICH8 */
26338c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x284b),
26348c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
26358c2ecf20Sopenharmony_ci	/* ICH9 */
26368c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x293e),
26378c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
26388c2ecf20Sopenharmony_ci	/* ICH9 */
26398c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x293f),
26408c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
26418c2ecf20Sopenharmony_ci	/* ICH10 */
26428c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x3a3e),
26438c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
26448c2ecf20Sopenharmony_ci	/* ICH10 */
26458c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x8086, 0x3a6e),
26468c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
26478c2ecf20Sopenharmony_ci	/* Generic Intel */
26488c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
26498c2ecf20Sopenharmony_ci	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
26508c2ecf20Sopenharmony_ci	  .class_mask = 0xffffff,
26518c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_NO_ALIGN_BUFSIZE },
26528c2ecf20Sopenharmony_ci	/* ATI SB 450/600/700/800/900 */
26538c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0x437b),
26548c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
26558c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0x4383),
26568c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
26578c2ecf20Sopenharmony_ci	/* AMD Hudson */
26588c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1022, 0x780d),
26598c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
26608c2ecf20Sopenharmony_ci	/* AMD, X370 & co */
26618c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1022, 0x1457),
26628c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
26638c2ecf20Sopenharmony_ci	/* AMD, X570 & co */
26648c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1022, 0x1487),
26658c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
26668c2ecf20Sopenharmony_ci	/* AMD Stoney */
26678c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1022, 0x157a),
26688c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB |
26698c2ecf20Sopenharmony_ci			 AZX_DCAPS_PM_RUNTIME },
26708c2ecf20Sopenharmony_ci	/* AMD Raven */
26718c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1022, 0x15e3),
26728c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
26738c2ecf20Sopenharmony_ci	/* ATI HDMI */
26748c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0x0002),
26758c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
26768c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0x1308),
26778c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
26788c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0x157a),
26798c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
26808c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0x15b3),
26818c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
26828c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0x793b),
26838c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
26848c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0x7919),
26858c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
26868c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0x960f),
26878c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
26888c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0x970f),
26898c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
26908c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0x9840),
26918c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
26928c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa00),
26938c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
26948c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa08),
26958c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
26968c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa10),
26978c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
26988c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa18),
26998c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27008c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa20),
27018c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27028c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa28),
27038c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27048c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa30),
27058c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27068c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa38),
27078c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27088c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa40),
27098c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27108c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa48),
27118c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27128c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa50),
27138c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27148c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa58),
27158c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27168c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa60),
27178c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27188c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa68),
27198c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27208c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa80),
27218c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27228c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa88),
27238c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27248c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa90),
27258c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27268c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaa98),
27278c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
27288c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0x9902),
27298c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
27308c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaaa0),
27318c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
27328c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaaa8),
27338c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
27348c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaab0),
27358c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
27368c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaac0),
27378c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
27388c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaac8),
27398c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
27408c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaad8),
27418c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
27428c2ecf20Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
27438c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaae0),
27448c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
27458c2ecf20Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
27468c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaae8),
27478c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
27488c2ecf20Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
27498c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaaf0),
27508c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
27518c2ecf20Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
27528c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xaaf8),
27538c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
27548c2ecf20Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
27558c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xab00),
27568c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
27578c2ecf20Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
27588c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xab08),
27598c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
27608c2ecf20Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
27618c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xab10),
27628c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
27638c2ecf20Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
27648c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xab18),
27658c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
27668c2ecf20Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
27678c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xab20),
27688c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
27698c2ecf20Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
27708c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xab28),
27718c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
27728c2ecf20Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
27738c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xab30),
27748c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
27758c2ecf20Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
27768c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1002, 0xab38),
27778c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
27788c2ecf20Sopenharmony_ci	  AZX_DCAPS_PM_RUNTIME },
27798c2ecf20Sopenharmony_ci	/* GLENFLY */
27808c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x6766, PCI_ANY_ID),
27818c2ecf20Sopenharmony_ci	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
27828c2ecf20Sopenharmony_ci	  .class_mask = 0xffffff,
27838c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_GFHDMI | AZX_DCAPS_POSFIX_LPIB |
27848c2ecf20Sopenharmony_ci	  AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT },
27858c2ecf20Sopenharmony_ci	/* VIA VT8251/VT8237A */
27868c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA },
27878c2ecf20Sopenharmony_ci	/* VIA GFX VT7122/VX900 */
27888c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1106, 0x9170), .driver_data = AZX_DRIVER_GENERIC },
27898c2ecf20Sopenharmony_ci	/* VIA GFX VT6122/VX11 */
27908c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1106, 0x9140), .driver_data = AZX_DRIVER_GENERIC },
27918c2ecf20Sopenharmony_ci	/* SIS966 */
27928c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1039, 0x7502), .driver_data = AZX_DRIVER_SIS },
27938c2ecf20Sopenharmony_ci	/* ULI M5461 */
27948c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI },
27958c2ecf20Sopenharmony_ci	/* NVIDIA MCP */
27968c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
27978c2ecf20Sopenharmony_ci	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
27988c2ecf20Sopenharmony_ci	  .class_mask = 0xffffff,
27998c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_NVIDIA | AZX_DCAPS_PRESET_NVIDIA },
28008c2ecf20Sopenharmony_ci	/* Teradici */
28018c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x6549, 0x1200),
28028c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT },
28038c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x6549, 0x2200),
28048c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT },
28058c2ecf20Sopenharmony_ci	/* Creative X-Fi (CA0110-IBG) */
28068c2ecf20Sopenharmony_ci	/* CTHDA chips */
28078c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1102, 0x0010),
28088c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
28098c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1102, 0x0012),
28108c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
28118c2ecf20Sopenharmony_ci#if !IS_ENABLED(CONFIG_SND_CTXFI)
28128c2ecf20Sopenharmony_ci	/* the following entry conflicts with snd-ctxfi driver,
28138c2ecf20Sopenharmony_ci	 * as ctxfi driver mutates from HD-audio to native mode with
28148c2ecf20Sopenharmony_ci	 * a special command sequence.
28158c2ecf20Sopenharmony_ci	 */
28168c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID),
28178c2ecf20Sopenharmony_ci	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
28188c2ecf20Sopenharmony_ci	  .class_mask = 0xffffff,
28198c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
28208c2ecf20Sopenharmony_ci	  AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB },
28218c2ecf20Sopenharmony_ci#else
28228c2ecf20Sopenharmony_ci	/* this entry seems still valid -- i.e. without emu20kx chip */
28238c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1102, 0x0009),
28248c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
28258c2ecf20Sopenharmony_ci	  AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB },
28268c2ecf20Sopenharmony_ci#endif
28278c2ecf20Sopenharmony_ci	/* CM8888 */
28288c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x13f6, 0x5011),
28298c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_CMEDIA |
28308c2ecf20Sopenharmony_ci	  AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_SNOOP_OFF },
28318c2ecf20Sopenharmony_ci	/* Vortex86MX */
28328c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
28338c2ecf20Sopenharmony_ci	/* VMware HDAudio */
28348c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x15ad, 0x1977), .driver_data = AZX_DRIVER_GENERIC },
28358c2ecf20Sopenharmony_ci	/* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
28368c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
28378c2ecf20Sopenharmony_ci	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
28388c2ecf20Sopenharmony_ci	  .class_mask = 0xffffff,
28398c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
28408c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_ANY_ID),
28418c2ecf20Sopenharmony_ci	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
28428c2ecf20Sopenharmony_ci	  .class_mask = 0xffffff,
28438c2ecf20Sopenharmony_ci	  .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_HDMI },
28448c2ecf20Sopenharmony_ci	/* Zhaoxin */
28458c2ecf20Sopenharmony_ci	{ PCI_DEVICE(0x1d17, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN },
28468c2ecf20Sopenharmony_ci	{ 0, }
28478c2ecf20Sopenharmony_ci};
28488c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, azx_ids);
28498c2ecf20Sopenharmony_ci
28508c2ecf20Sopenharmony_ci/* pci_driver definition */
28518c2ecf20Sopenharmony_cistatic struct pci_driver azx_driver = {
28528c2ecf20Sopenharmony_ci	.name = KBUILD_MODNAME,
28538c2ecf20Sopenharmony_ci	.id_table = azx_ids,
28548c2ecf20Sopenharmony_ci	.probe = azx_probe,
28558c2ecf20Sopenharmony_ci	.remove = azx_remove,
28568c2ecf20Sopenharmony_ci	.shutdown = azx_shutdown,
28578c2ecf20Sopenharmony_ci	.driver = {
28588c2ecf20Sopenharmony_ci		.pm = AZX_PM_OPS,
28598c2ecf20Sopenharmony_ci	},
28608c2ecf20Sopenharmony_ci};
28618c2ecf20Sopenharmony_ci
28628c2ecf20Sopenharmony_cimodule_pci_driver(azx_driver);
2863