// SPDX-License-Identifier: GPL-2.0-or-later /* * HD-audio HDMI codec driver */ #ifndef __HDA_HDMI_LOCAL_H #define __HDA_HDMI_LOCAL_H #include #include #include #include #include #include #include "hda_local.h" struct hdmi_spec_per_cvt { hda_nid_t cvt_nid; bool assigned; /* the stream has been assigned */ bool silent_stream; /* silent stream activated */ unsigned int channels_min; unsigned int channels_max; u32 rates; u64 formats; unsigned int maxbps; }; /* max. connections to a widget */ #define HDA_MAX_CONNECTIONS 32 struct hdmi_spec_per_pin { hda_nid_t pin_nid; int dev_id; /* pin idx, different device entries on the same pin use the same idx */ int pin_nid_idx; int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; int mux_idx; hda_nid_t cvt_nid; struct hda_codec *codec; struct hdmi_eld sink_eld; struct mutex lock; struct delayed_work work; struct hdmi_pcm *pcm; /* pointer to spec->pcm_rec[n] dynamically*/ int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */ int prev_pcm_idx; /* previously assigned pcm index */ int repoll_count; bool setup; /* the stream has been set up by prepare callback */ bool silent_stream; int channels; /* current number of channels */ bool non_pcm; bool chmap_set; /* channel-map override by ALSA API? */ unsigned char chmap[8]; /* ALSA API channel-map */ #ifdef CONFIG_SND_PROC_FS struct snd_info_entry *proc_entry; #endif }; /* operations used by generic code that can be overridden by codec drivers */ struct hdmi_ops { int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid, int dev_id, unsigned char *buf, int *eld_size); void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid, int dev_id, int ca, int active_channels, int conn_type); /* enable/disable HBR (HD passthrough) */ int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid, int dev_id, bool hbr); int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid, hda_nid_t pin_nid, int dev_id, u32 stream_tag, int format); void (*pin_cvt_fixup)(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin, hda_nid_t cvt_nid); void (*silent_stream)(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin, bool enable); }; struct hdmi_pcm { struct hda_pcm *pcm; struct snd_jack *jack; struct snd_kcontrol *eld_ctl; }; enum { SILENT_STREAM_OFF = 0, SILENT_STREAM_KAE, /* use standard HDA Keep-Alive */ SILENT_STREAM_I915, /* Intel i915 extension */ }; struct hdmi_spec { struct hda_codec *codec; int num_cvts; struct snd_array cvts; /* struct hdmi_spec_per_cvt */ hda_nid_t cvt_nids[4]; /* only for haswell fix */ /* * num_pins is the number of virtual pins * for example, there are 3 pins, and each pin * has 4 device entries, then the num_pins is 12 */ int num_pins; /* * num_nids is the number of real pins * In the above example, num_nids is 3 */ int num_nids; /* * dev_num is the number of device entries * on each pin. * In the above example, dev_num is 4 */ int dev_num; struct snd_array pins; /* struct hdmi_spec_per_pin */ struct hdmi_pcm pcm_rec[8]; struct mutex pcm_lock; struct mutex bind_lock; /* for audio component binding */ /* pcm_bitmap means which pcms have been assigned to pins*/ unsigned long pcm_bitmap; int pcm_used; /* counter of pcm_rec[] */ /* bitmap shows whether the pcm is opened in user space * bit 0 means the first playback PCM (PCM3); * bit 1 means the second playback PCM, and so on. */ unsigned long pcm_in_use; struct hdmi_eld temp_eld; struct hdmi_ops ops; bool dyn_pin_out; bool static_pcm_mapping; /* hdmi interrupt trigger control flag for Nvidia codec */ bool hdmi_intr_trig_ctrl; bool nv_dp_workaround; /* workaround DP audio infoframe for Nvidia */ bool intel_hsw_fixup; /* apply Intel platform-specific fixups */ /* * Non-generic VIA/NVIDIA specific */ struct hda_multi_out multiout; struct hda_pcm_stream pcm_playback; bool use_acomp_notifier; /* use eld_notify callback for hotplug */ bool acomp_registered; /* audio component registered in this driver */ bool force_connect; /* force connectivity */ struct drm_audio_component_audio_ops drm_audio_ops; int (*port2pin)(struct hda_codec *codec, int port); /* reverse port/pin mapping */ struct hdac_chmap chmap; hda_nid_t vendor_nid; const int *port_map; int port_num; int silent_stream_type; const struct snd_pcm_hw_constraint_list *hw_constraints_channels; }; #ifdef CONFIG_SND_HDA_COMPONENT static inline bool codec_has_acomp(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; return spec->use_acomp_notifier; } #else #define codec_has_acomp(codec) false #endif struct hdmi_audio_infoframe { u8 type; /* 0x84 */ u8 ver; /* 0x01 */ u8 len; /* 0x0a */ u8 checksum; u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ u8 SS01_SF24; u8 CXT04; u8 CA; u8 LFEPBL01_LSV36_DM_INH7; }; struct dp_audio_infoframe { u8 type; /* 0x84 */ u8 len; /* 0x1b */ u8 ver; /* 0x11 << 2 */ u8 CC02_CT47; /* match with HDMI infoframe from this on */ u8 SS01_SF24; u8 CXT04; u8 CA; u8 LFEPBL01_LSV36_DM_INH7; }; union audio_infoframe { struct hdmi_audio_infoframe hdmi; struct dp_audio_infoframe dp; DECLARE_FLEX_ARRAY(u8, bytes); }; #ifdef LIMITED_RATE_FMT_SUPPORT /* support only the safe format and rate */ #define SUPPORTED_RATES SNDRV_PCM_RATE_48000 #define SUPPORTED_MAXBPS 16 #define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE #else /* support all rates and formats */ #define SUPPORTED_RATES \ (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ SNDRV_PCM_RATE_192000) #define SUPPORTED_MAXBPS 24 #define SUPPORTED_FORMATS \ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) #endif /* * HDMI routines */ #define get_pin(spec, idx) \ ((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx)) #define get_cvt(spec, idx) \ ((struct hdmi_spec_per_cvt *)snd_array_elem(&spec->cvts, idx)) /* obtain hdmi_pcm object assigned to idx */ #define get_hdmi_pcm(spec, idx) (&(spec)->pcm_rec[idx]) /* obtain hda_pcm object assigned to idx */ #define get_pcm_rec(spec, idx) (get_hdmi_pcm(spec, idx)->pcm) /* Generic HDMI codec support */ int snd_hda_hdmi_generic_alloc(struct hda_codec *codec); int snd_hda_hdmi_parse_codec(struct hda_codec *codec); int snd_hda_hdmi_generic_probe(struct hda_codec *codec); void snd_hda_hdmi_generic_remove(struct hda_codec *codec); int snd_hda_hdmi_generic_build_pcms(struct hda_codec *codec); int snd_hda_hdmi_generic_build_controls(struct hda_codec *codec); int snd_hda_hdmi_generic_init(struct hda_codec *codec); int snd_hda_hdmi_generic_suspend(struct hda_codec *codec); int snd_hda_hdmi_generic_resume(struct hda_codec *codec); void snd_hda_hdmi_generic_unsol_event(struct hda_codec *codec, unsigned int res); int snd_hda_hdmi_pin_id_to_pin_index(struct hda_codec *codec, hda_nid_t pin_nid, int dev_id); #define pin_id_to_pin_index(codec, pin, dev) \ snd_hda_hdmi_pin_id_to_pin_index(codec, pin, dev) int snd_hda_hdmi_generic_init_per_pins(struct hda_codec *codec); void snd_hda_hdmi_generic_spec_free(struct hda_codec *codec); int snd_hda_hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, hda_nid_t pin_nid, int dev_id, u32 stream_tag, int format); int snd_hda_hdmi_generic_pcm_prepare(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream); int snd_hda_hdmi_generic_pcm_cleanup(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream); void snd_hda_hdmi_check_presence_and_report(struct hda_codec *codec, hda_nid_t nid, int dev_id); void snd_hda_hdmi_setup_audio_infoframe(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin, bool non_pcm); /* Audio component support */ void snd_hda_hdmi_setup_drm_audio_ops(struct hda_codec *codec, const struct drm_audio_component_audio_ops *ops); void snd_hda_hdmi_acomp_init(struct hda_codec *codec, const struct drm_audio_component_audio_ops *ops, int (*port2pin)(struct hda_codec *, int)); void snd_hda_hdmi_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id); int snd_hda_hdmi_acomp_master_bind(struct device *dev, struct drm_audio_component *acomp); void snd_hda_hdmi_acomp_master_unbind(struct device *dev, struct drm_audio_component *acomp); /* Simple / legacy HDMI codec support */ int snd_hda_hdmi_simple_probe(struct hda_codec *codec, hda_nid_t cvt_nid, hda_nid_t pin_nid); void snd_hda_hdmi_simple_remove(struct hda_codec *codec); int snd_hda_hdmi_simple_build_pcms(struct hda_codec *codec); int snd_hda_hdmi_simple_build_controls(struct hda_codec *codec); int snd_hda_hdmi_simple_init(struct hda_codec *codec); void snd_hda_hdmi_simple_unsol_event(struct hda_codec *codec, unsigned int res); int snd_hda_hdmi_simple_pcm_open(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream); #endif /* __HDA_HDMI_LOCAL_H */