/* * The HDA codec on NVIDIA Tegra contains two scratch registers that are * accessed using vendor-defined verbs. These registers can be used for * interoperability between the HDA and HDMI drivers.
*/
/* Audio Function Group node */ #define NVIDIA_AFG_NID 0x01
/* * The SCRATCH0 register is used to notify the HDMI codec of changes in audio * format. On Tegra, bit 31 is used as a trigger that causes an interrupt to * be raised in the HDMI codec. The remainder of the bits is arbitrary. This * implementation stores the HDA format (see AC_FMT_*) in bits [15:0] and an * additional bit (at position 30) to signal the validity of the format. * * | 31 | 30 | 29 16 | 15 0 | * +---------+-------+--------+--------+ * | TRIGGER | VALID | UNUSED | FORMAT | * +-----------------------------------| * * Note that for the trigger bit to take effect it needs to change value * (i.e. it needs to be toggled). The trigger bit is not applicable from * TEGRA234 chip onwards, as new verb id 0xf80 will be used for interrupt * trigger to hdmi.
*/ #define NVIDIA_SET_HOST_INTR 0xf80 #define NVIDIA_GET_SCRATCH0 0xfa6 #define NVIDIA_SET_SCRATCH0_BYTE0 0xfa7 #define NVIDIA_SET_SCRATCH0_BYTE1 0xfa8 #define NVIDIA_SET_SCRATCH0_BYTE2 0xfa9 #define NVIDIA_SET_SCRATCH0_BYTE3 0xfaa #define NVIDIA_SCRATCH_TRIGGER (1 << 7) #define NVIDIA_SCRATCH_VALID (1 << 6)
/* * The format parameter is the HDA audio format (see AC_FMT_*). If set to 0, * the format is invalidated so that the HDMI codec can be disabled.
*/ staticvoid tegra_hdmi_set_format(struct hda_codec *codec,
hda_nid_t cvt_nid, unsignedint format)
{ unsignedint value; unsignedint nid = NVIDIA_AFG_NID; struct hdmi_spec *spec = codec->spec;
/* * Tegra HDA codec design from TEGRA234 chip onwards support DP MST. * This resulted in moving scratch registers from audio function * group to converter widget context. So CVT NID should be used for * scratch register read/write for DP MST supported Tegra HDA codec.
*/ if (codec->dp_mst)
nid = cvt_nid;
/* bits [31:30] contain the trigger and valid bits */
value = snd_hda_codec_read(codec, nid, 0,
NVIDIA_GET_SCRATCH0, 0);
value = (value >> 24) & 0xff;
/* bits [15:0] are used to store the HDA format */
snd_hda_codec_write(codec, nid, 0,
NVIDIA_SET_SCRATCH0_BYTE0,
(format >> 0) & 0xff);
snd_hda_codec_write(codec, nid, 0,
NVIDIA_SET_SCRATCH0_BYTE1,
(format >> 8) & 0xff);
/* * Bit 30 signals that the data is valid and hence that HDMI audio can * be enabled.
*/ if (format == 0)
value &= ~NVIDIA_SCRATCH_VALID; else
value |= NVIDIA_SCRATCH_VALID;
if (spec->hdmi_intr_trig_ctrl) { /* * For Tegra HDA Codec design from TEGRA234 onwards, the * Interrupt to hdmi driver is triggered by writing * non-zero values to verb 0xF80 instead of 31st bit of * scratch register.
*/
snd_hda_codec_write(codec, nid, 0,
NVIDIA_SET_SCRATCH0_BYTE3, value);
snd_hda_codec_write(codec, nid, 0,
NVIDIA_SET_HOST_INTR, 0x1);
} else { /* * Whenever the 31st trigger bit is toggled, an interrupt is raised * in the HDMI codec. The HDMI driver will use that as trigger * to update its configuration.
*/
value ^= NVIDIA_SCRATCH_TRIGGER;
err = snd_hda_hdmi_generic_build_pcms(codec); if (err < 0) return err;
pcm = hda_find_pcm_by_type(codec, HDA_PCM_TYPE_HDMI); if (!pcm) return -ENODEV;
/* * Override ->prepare() and ->cleanup() operations to notify the HDMI * codec about format changes.
*/
stream = &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK];
stream->ops.prepare = tegra_hdmi_pcm_prepare;
stream->ops.cleanup = tegra_hdmi_pcm_cleanup;
return 0;
}
/* * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on: * - 0x10de0015 * - 0x10de0040
*/ staticint nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, struct hdac_cea_channel_speaker_allocation *cap, int channels)
{ if (cap->ca_index == 0x00 && channels == 2) return SNDRV_CTL_TLVT_CHMAP_FIXED;
/* If the speaker allocation matches the channel count, it is OK. */ if (cap->channels != channels) return -1;
/* all channels are remappable freely */ return SNDRV_CTL_TLVT_CHMAP_VAR;
}
staticint nvhdmi_chmap_validate(struct hdac_chmap *chmap, int ca, int chs, unsignedchar *map)
{ if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR)) return -EINVAL;
return 0;
}
staticint tegra_hdmi_init(struct hda_codec *codec)
{ struct hdmi_spec *spec = codec->spec; int i, err;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.