linux/sound/pci/hda/hda_intel.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *
 *  hda_intel.c - Implementation of primary alsa driver code base
 *                for Intel HD Audio.
 *
 *  Copyright(c) 2004 Intel Corporation
 *
 *  Copyright (c) 2004 Takashi Iwai <[email protected]>
 *                     PeiSen Hou <[email protected]>
 *
 *  CONTACTS:
 *
 *  Matt Jared		[email protected]
 *  Andy Kopp		[email protected]
 *  Dan Kogan		[email protected]
 *
 *  CHANGES:
 *
 *  2004.12.01	Major rewrite by tiwai, merged the work of pshou
 */

#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <linux/clocksource.h>
#include <linux/time.h>
#include <linux/completion.h>
#include <linux/acpi.h>
#include <linux/pgtable.h>

#ifdef CONFIG_X86
/* for snoop control */
#include <linux/dma-map-ops.h>
#include <asm/set_memory.h>
#include <asm/cpufeature.h>
#endif
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/hdaudio.h>
#include <sound/hda_i915.h>
#include <sound/intel-dsp-config.h>
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>
#include <linux/apple-gmux.h>
#include <linux/firmware.h>
#include <sound/hda_codec.h>
#include "hda_controller.h"
#include "hda_intel.h"

#define CREATE_TRACE_POINTS
#include "hda_intel_trace.h"

/* position fix mode */
enum {};

/* Defines for ATI HD Audio support in SB450 south bridge */
#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR
#define ATI_SB450_HDAUDIO_ENABLE_SNOOP

/* Defines for Nvidia HDA support */
#define NVIDIA_HDA_TRANSREG_ADDR
#define NVIDIA_HDA_ENABLE_COHBITS
#define NVIDIA_HDA_ISTRM_COH
#define NVIDIA_HDA_OSTRM_COH
#define NVIDIA_HDA_ENABLE_COHBIT

/* Defines for Intel SCH HDA snoop control */
#define INTEL_HDA_CGCTL
#define INTEL_HDA_CGCTL_MISCBDCGE
#define INTEL_SCH_HDA_DEVC
#define INTEL_SCH_HDA_DEVC_NOSNOOP

/* max number of SDs */
/* ICH, ATI and VIA have 4 playback and 4 capture */
#define ICH6_NUM_CAPTURE
#define ICH6_NUM_PLAYBACK

/* ULI has 6 playback and 5 capture */
#define ULI_NUM_CAPTURE
#define ULI_NUM_PLAYBACK

/* ATI HDMI may have up to 8 playbacks and 0 capture */
#define ATIHDMI_NUM_CAPTURE
#define ATIHDMI_NUM_PLAYBACK


static int index[SNDRV_CARDS] =;
static char *id[SNDRV_CARDS] =;
static bool enable[SNDRV_CARDS] =;
static char *model[SNDRV_CARDS];
static int position_fix[SNDRV_CARDS] =;
static int bdl_pos_adj[SNDRV_CARDS] =;
static int probe_mask[SNDRV_CARDS] =;
static int probe_only[SNDRV_CARDS];
static int jackpoll_ms[SNDRV_CARDS];
static int single_cmd =;
static int enable_msi =;
#ifdef CONFIG_SND_HDA_PATCH_LOADER
static char *patch[SNDRV_CARDS];
#endif
#ifdef CONFIG_SND_HDA_INPUT_BEEP
static bool beep_mode[SNDRV_CARDS] =;
#endif
static bool dmic_detect =;
static bool ctl_dev_id =;

module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();
module_param(single_cmd, bint, 0444);
MODULE_PARM_DESC();
module_param(enable_msi, bint, 0444);
MODULE_PARM_DESC();
#ifdef CONFIG_SND_HDA_PATCH_LOADER
module_param_array();
MODULE_PARM_DESC();
#endif
#ifdef CONFIG_SND_HDA_INPUT_BEEP
module_param_array();
MODULE_PARM_DESC();
#endif
module_param(dmic_detect, bool, 0444);
MODULE_PARM_DESC();
module_param(ctl_dev_id, bool, 0444);
MODULE_PARM_DESC();

#ifdef CONFIG_PM
static int param_set_xint(const char *val, const struct kernel_param *kp);
static const struct kernel_param_ops param_ops_xint =;
#define param_check_xint

static int power_save =;
module_param(power_save, xint, 0644);
MODULE_PARM_DESC();

static bool pm_blacklist =;
module_param(pm_blacklist, bool, 0644);
MODULE_PARM_DESC();

/* reset the HD-audio controller in power save mode.
 * this may give more power-saving, but will take longer time to
 * wake up.
 */
static bool power_save_controller =;
module_param(power_save_controller, bool, 0644);
MODULE_PARM_DESC();
#else /* CONFIG_PM */
#define power_save
#define pm_blacklist
#define power_save_controller
#endif /* CONFIG_PM */

static int align_buffer_size =;
module_param(align_buffer_size, bint, 0644);
MODULE_PARM_DESC();

#ifdef CONFIG_X86
static int hda_snoop =;
module_param_named(snoop, hda_snoop, bint, 0444);
MODULE_PARM_DESC();
#else
#define hda_snoop
#endif


MODULE_LICENSE();
MODULE_DESCRIPTION();

#if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO)
#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
#define SUPPORT_VGA_SWITCHEROO
#endif
#endif


/*
 */

/* driver types */
enum {};

#define azx_get_snoop_type(chip)
#define AZX_DCAPS_SNOOP_TYPE(type)

/* quirks for old Intel chipsets */
#define AZX_DCAPS_INTEL_ICH

/* quirks for Intel PCH */
#define AZX_DCAPS_INTEL_PCH_BASE

/* PCH up to IVB; no runtime PM; bind with i915 gfx */
#define AZX_DCAPS_INTEL_PCH_NOPM

/* PCH for HSW/BDW; with runtime PM */
/* no i915 binding for this as HSW/BDW has another controller for HDMI */
#define AZX_DCAPS_INTEL_PCH

/* HSW HDMI */
#define AZX_DCAPS_INTEL_HASWELL

/* Broadwell HDMI can't use position buffer reliably, force to use LPIB */
#define AZX_DCAPS_INTEL_BROADWELL

#define AZX_DCAPS_INTEL_BAYTRAIL

#define AZX_DCAPS_INTEL_BRASWELL

#define AZX_DCAPS_INTEL_SKYLAKE

#define AZX_DCAPS_INTEL_BROXTON

#define AZX_DCAPS_INTEL_LNL

/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB

/* quirks for ATI/AMD HDMI */
#define AZX_DCAPS_PRESET_ATI_HDMI

/* quirks for ATI HDMI with snoop off */
#define AZX_DCAPS_PRESET_ATI_HDMI_NS

/* quirks for AMD SB */
#define AZX_DCAPS_PRESET_AMD_SB

/* quirks for Nvidia */
#define AZX_DCAPS_PRESET_NVIDIA

#define AZX_DCAPS_PRESET_CTHDA

/*
 * vga_switcheroo support
 */
#ifdef SUPPORT_VGA_SWITCHEROO
#define use_vga_switcheroo(chip)
#define needs_eld_notify_link(chip)
#else
#define use_vga_switcheroo
#define needs_eld_notify_link
#endif

static const char * const driver_short_names[] =;

static int azx_acquire_irq(struct azx *chip, int do_disconnect);
static void set_default_power_save(struct azx *chip);

/*
 * initialize the PCI registers
 */
/* update bits in a PCI register byte */
static void update_pci_byte(struct pci_dev *pci, unsigned int reg,
			    unsigned char mask, unsigned char val)
{}

static void azx_init_pci(struct azx *chip)
{}

/*
 * In BXT-P A0, HD-Audio DMA requests is later than expected,
 * and makes an audio stream sensitive to system latencies when
 * 24/32 bits are playing.
 * Adjusting threshold of DMA fifo to force the DMA request
 * sooner to improve latency tolerance at the expense of power.
 */
static void bxt_reduce_dma_latency(struct azx *chip)
{}

/*
 * ML_LCAP bits:
 *  bit 0: 6 MHz Supported
 *  bit 1: 12 MHz Supported
 *  bit 2: 24 MHz Supported
 *  bit 3: 48 MHz Supported
 *  bit 4: 96 MHz Supported
 *  bit 5: 192 MHz Supported
 */
static int intel_get_lctl_scf(struct azx *chip)
{}

static int intel_ml_lctl_set_power(struct azx *chip, int state)
{}

static void intel_init_lctl(struct azx *chip)
{}

static void hda_intel_init_chip(struct azx *chip, bool full_reset)
{}

/* calculate runtime delay from LPIB */
static int azx_get_delay_from_lpib(struct azx *chip, struct azx_dev *azx_dev,
				   unsigned int pos)
{}

static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev);

/* called from IRQ */
static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev)
{}

#define display_power(chip, enable)

/*
 * Check whether the current DMA position is acceptable for updating
 * periods.  Returns non-zero if it's OK.
 *
 * Many HD-audio controllers appear pretty inaccurate about
 * the update-IRQ timing.  The IRQ is issued before actually the
 * data is processed.  So, we need to process it afterwords in a
 * workqueue.
 *
 * Returns 1 if OK to proceed, 0 for delay handling, -1 for skipping update
 */
static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
{}

/*
 * The work for pending PCM period updates.
 */
static void azx_irq_pending_work(struct work_struct *work)
{}

/* clear irq_pending flags and assure no on-going workq */
static void azx_clear_irq_pending(struct azx *chip)
{}

static int azx_acquire_irq(struct azx *chip, int do_disconnect)
{}

/* get the current DMA position with correction on VIA chips */
static unsigned int azx_via_get_position(struct azx *chip,
					 struct azx_dev *azx_dev)
{}

#define AMD_FIFO_SIZE

/* get the current DMA position with FIFO size correction */
static unsigned int azx_get_pos_fifo(struct azx *chip, struct azx_dev *azx_dev)
{}

static int azx_get_delay_from_fifo(struct azx *chip, struct azx_dev *azx_dev,
				   unsigned int pos)
{}

static void __azx_shutdown_chip(struct azx *chip, bool skip_link_reset)
{}

static DEFINE_MUTEX(card_list_lock);
static LIST_HEAD(card_list);

static void azx_shutdown_chip(struct azx *chip)
{}

static void azx_add_card_list(struct azx *chip)
{}

static void azx_del_card_list(struct azx *chip)
{}

/* trigger power-save check at writing parameter */
static int __maybe_unused param_set_xint(const char *val, const struct kernel_param *kp)
{}

/*
 * power management
 */
static bool azx_is_pm_ready(struct snd_card *card)
{}

static void __azx_runtime_resume(struct azx *chip)
{}

static int azx_prepare(struct device *dev)
{}

static void azx_complete(struct device *dev)
{}

static int azx_suspend(struct device *dev)
{}

static int __maybe_unused azx_resume(struct device *dev)
{}

/* put codec down to D3 at hibernation for Intel SKL+;
 * otherwise BIOS may still access the codec and screw up the driver
 */
static int azx_freeze_noirq(struct device *dev)
{}

static int azx_thaw_noirq(struct device *dev)
{}

static int __maybe_unused azx_runtime_suspend(struct device *dev)
{}

static int __maybe_unused azx_runtime_resume(struct device *dev)
{}

static int __maybe_unused azx_runtime_idle(struct device *dev)
{}

static const struct dev_pm_ops azx_pm =;


static int azx_probe_continue(struct azx *chip);

#ifdef SUPPORT_VGA_SWITCHEROO
static struct pci_dev *get_bound_vga(struct pci_dev *pci);

static void azx_vs_set_state(struct pci_dev *pci,
			     enum vga_switcheroo_state state)
{}

static bool azx_vs_can_switch(struct pci_dev *pci)
{}

/*
 * The discrete GPU cannot power down unless the HDA controller runtime
 * suspends, so activate runtime PM on codecs even if power_save == 0.
 */
static void setup_vga_switcheroo_runtime_pm(struct azx *chip)
{}

static void azx_vs_gpu_bound(struct pci_dev *pci,
			     enum vga_switcheroo_client_id client_id)
{}

static void init_vga_switcheroo(struct azx *chip)
{}

static const struct vga_switcheroo_client_ops azx_vs_ops =;

static int register_vga_switcheroo(struct azx *chip)
{}
#else
#define init_vga_switcheroo
#define register_vga_switcheroo
#define check_hdmi_disabled
#define setup_vga_switcheroo_runtime_pm
#endif /* SUPPORT_VGA_SWITCHER */

/*
 * destructor
 */
static void azx_free(struct azx *chip)
{}

static int azx_dev_disconnect(struct snd_device *device)
{}

static int azx_dev_free(struct snd_device *device)
{}

#ifdef SUPPORT_VGA_SWITCHEROO
#ifdef CONFIG_ACPI
/* ATPX is in the integrated GPU's namespace */
static bool atpx_present(void)
{}
#else
static bool atpx_present(void)
{
	return false;
}
#endif

/*
 * Check of disabled HDMI controller by vga_switcheroo
 */
static struct pci_dev *get_bound_vga(struct pci_dev *pci)
{}

static bool check_hdmi_disabled(struct pci_dev *pci)
{}
#endif /* SUPPORT_VGA_SWITCHEROO */

/*
 * allow/deny-listing for position_fix
 */
static const struct snd_pci_quirk position_fix_list[] =;

static int check_position_fix(struct azx *chip, int fix)
{}

static void assign_position_fix(struct azx *chip, int fix)
{}

/*
 * deny-lists for probe_mask
 */
static const struct snd_pci_quirk probe_mask_list[] =;

#define AZX_FORCE_CODEC_MASK

static void check_probe_mask(struct azx *chip, int dev)
{}

/*
 * allow/deny-list for enable_msi
 */
static const struct snd_pci_quirk msi_deny_list[] =;

static void check_msi(struct azx *chip)
{}

/* check the snoop mode availability */
static void azx_check_snoop_available(struct azx *chip)
{}

static void azx_probe_work(struct work_struct *work)
{}

static int default_bdl_pos_adj(struct azx *chip)
{}

/*
 * constructor
 */
static const struct hda_controller_ops pci_hda_ops;

static int azx_create(struct snd_card *card, struct pci_dev *pci,
		      int dev, unsigned int driver_caps,
		      struct azx **rchip)
{}

static int azx_first_init(struct azx *chip)
{}

#ifdef CONFIG_SND_HDA_PATCH_LOADER
/* callback from request_firmware_nowait() */
static void azx_firmware_cb(const struct firmware *fw, void *context)
{}
#endif

static int disable_msi_reset_irq(struct azx *chip)
{}

/* Denylist for skipping the whole probe:
 * some HD-audio PCI entries are exposed without any codecs, and such devices
 * should be ignored from the beginning.
 */
static const struct pci_device_id driver_denylist[] =;

static const struct hda_controller_ops pci_hda_ops =;

static DECLARE_BITMAP(probed_devs, SNDRV_CARDS);

static int azx_probe(struct pci_dev *pci,
		     const struct pci_device_id *pci_id)
{}

/* On some boards setting power_save to a non 0 value leads to clicking /
 * popping sounds when ever we enter/leave powersaving mode. Ideally we would
 * figure out how to avoid these sounds, but that is not always feasible.
 * So we keep a list of devices where we disable powersaving as its known
 * to causes problems on these devices.
 */
static const struct snd_pci_quirk power_save_denylist[] =;

static void set_default_power_save(struct azx *chip)
{}

/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
static const unsigned int azx_max_codecs[AZX_NUM_DRIVERS] =;

static int azx_probe_continue(struct azx *chip)
{}

static void azx_remove(struct pci_dev *pci)
{}

static void azx_shutdown(struct pci_dev *pci)
{}

/* PCI IDs */
static const struct pci_device_id azx_ids[] =;
MODULE_DEVICE_TABLE(pci, azx_ids);

/* pci_driver definition */
static struct pci_driver azx_driver =;

module_pci_driver();