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