diff options
Diffstat (limited to 'sound/hda/codecs/hdmi/hdmi_local.h')
-rw-r--r-- | sound/hda/codecs/hdmi/hdmi_local.h | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/sound/hda/codecs/hdmi/hdmi_local.h b/sound/hda/codecs/hdmi/hdmi_local.h new file mode 100644 index 000000000000..548241ad3fa9 --- /dev/null +++ b/sound/hda/codecs/hdmi/hdmi_local.h @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HD-audio HDMI codec driver + */ + +#ifndef __HDA_HDMI_LOCAL_H +#define __HDA_HDMI_LOCAL_H + +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/hdaudio.h> +#include <sound/hda_i915.h> +#include <sound/hda_chmap.h> +#include <sound/hda_codec.h> +#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 */ |