mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-28 00:19:36 +00:00

Now that all patch_ops usage have been converted to the new hda_codec_ops probe, we can drop patch_ops from the hda_codec, together with the calls of patch_ops callbacks. The hda_codec_ops.free callback is removed as all have been replaced with the new remove callback. Also, correct comments mentioning "patch"; it's replaced with "codec driver". Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20250709160434.1859-25-tiwai@suse.de
303 lines
9.2 KiB
C
303 lines
9.2 KiB
C
// 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 */
|