root/sound/hda/codecs/hdmi/hdmi_local.h
// 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 */