Module Name:    src
Committed By:   jmcneill
Date:           Sun Jul 26 19:06:26 UTC 2015

Modified Files:
        src/sys/dev/hdaudio: hdafg.c

Log Message:
- Support multi-channel (> 2) output to HDMI sinks.
- Fix a bug in hdafg_set_params that could program converters using the
  wrong audio_params_t if auconv is in use
- Force Tegra124 HDMI codec to a fixed rate 44.1kHz


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/hdaudio/hdafg.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/hdaudio/hdafg.c
diff -u src/sys/dev/hdaudio/hdafg.c:1.2 src/sys/dev/hdaudio/hdafg.c:1.3
--- src/sys/dev/hdaudio/hdafg.c:1.2	Sat Mar 28 14:50:20 2015
+++ src/sys/dev/hdaudio/hdafg.c	Sun Jul 26 19:06:26 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: hdafg.c,v 1.2 2015/03/28 14:50:20 jmcneill Exp $ */
+/* $NetBSD: hdafg.c,v 1.3 2015/07/26 19:06:26 jmcneill Exp $ */
 
 /*
  * Copyright (c) 2009 Precedence Technologies Ltd <supp...@precedence.co.uk>
@@ -60,7 +60,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hdafg.c,v 1.2 2015/03/28 14:50:20 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hdafg.c,v 1.3 2015/07/26 19:06:26 jmcneill Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -327,6 +327,8 @@ struct hdafg_softc {
 	} sc_p;
 
 	struct hdaudio_audiodev		sc_audiodev;
+
+	uint16_t			sc_fixed_rate;
 };
 
 static int	hdafg_match(device_t, cfdata_t, void *);
@@ -3041,7 +3043,7 @@ hdafg_commit(struct hdafg_softc *sc)
 
 static void
 hdafg_stream_connect_hdmi(struct hdafg_softc *sc, struct hdaudio_assoc *as,
-    struct hdaudio_widget *w, int maxchan)
+    struct hdaudio_widget *w, const audio_params_t *params)
 {
 	struct hdmi_audio_infoframe hdmi;
 	/* TODO struct displayport_audio_infoframe dp; */
@@ -3069,7 +3071,12 @@ hdafg_stream_connect_hdmi(struct hdafg_s
 		hdmi.header.packet_type = HDMI_AI_PACKET_TYPE;
 		hdmi.header.version = HDMI_AI_VERSION;
 		hdmi.header.length = HDMI_AI_LENGTH;
-		hdmi.ct_cc = maxchan - 1;
+		hdmi.ct_cc = params->channels - 1;
+		if (params->channels > 2) {
+			hdmi.ca = 0x1f;
+		} else {
+			hdmi.ca = 0x00;
+		}
 		hdafg_dd_hdmi_ai_cksum(&hdmi);
 	}
 	/* update data island with new audio infoframe */
@@ -3092,19 +3099,22 @@ hdafg_stream_connect(struct hdafg_softc 
 {
 	struct hdaudio_assoc *as = sc->sc_assocs;
 	struct hdaudio_widget *w;
+	const audio_params_t *params;
 	uint16_t fmt, dfmt;
 	int tag, chn, maxchan, c;
 	int i, j, k;
 
 	KASSERT(mode == AUMODE_PLAY || mode == AUMODE_RECORD);
 
-	if (mode == AUMODE_PLAY)
+	if (mode == AUMODE_PLAY) {
 		fmt = hdaudio_stream_param(sc->sc_audiodev.ad_playback,
 		    &sc->sc_pparam);
-	else
+		params = &sc->sc_pparam;
+	} else {
 		fmt = hdaudio_stream_param(sc->sc_audiodev.ad_capture,
 		    &sc->sc_rparam);
-
+		params = &sc->sc_rparam;
+	}
 
 	for (i = 0; i < sc->sc_nassocs; i++) {
 		if (as[i].as_enable == false)
@@ -3177,6 +3187,8 @@ hdafg_stream_connect(struct hdafg_softc 
 					dfmt |= COP_DIGITAL_CONVCTRL1_NAUDIO;
 				else
 					dfmt &= ~COP_DIGITAL_CONVCTRL1_NAUDIO;
+				if (sc->sc_vendor == HDAUDIO_VENDOR_NVIDIA)
+					dfmt |= COP_DIGITAL_CONVCTRL1_COPY;
 				hdaudio_command(sc->sc_codec, w->w_nid,
 				    CORB_SET_DIGITAL_CONVERTER_CONTROL_1, dfmt);
 			}
@@ -3203,7 +3215,7 @@ hdafg_stream_connect(struct hdafg_softc 
 				continue;
 			if (w->w_pin.cap & (COP_PINCAP_HDMI|COP_PINCAP_DP))
 				hdafg_stream_connect_hdmi(sc, &as[i],
-				    w, maxchan);
+				    w, params);
 		}
 	}
 }
@@ -3237,6 +3249,9 @@ hdafg_rate_supported(struct hdafg_softc 
 {
 	uint32_t caps = sc->sc_p.pcm_size_rate;
 
+	if (sc->sc_fixed_rate)
+		return frequency == sc->sc_fixed_rate;
+
 #define ISFREQOK(shift)	((caps & (1 << (shift))) ? true : false)
 	switch (frequency) {
 	case 8000:
@@ -3251,6 +3266,7 @@ hdafg_rate_supported(struct hdafg_softc 
 		return ISFREQOK(4);
 	case 44100:
 		return ISFREQOK(5);
+		return true;
 	case 48000:
 		return true;	/* Must be supported by all codecs */
 	case 88200:
@@ -3433,7 +3449,8 @@ hdafg_configure_encodings(struct hdafg_s
 		f.channels = 2;
 		f.channel_mask = AUFMT_STEREO;
 		f.frequency_type = 0;
-		f.frequency[0] = f.frequency[1] = 48000;
+		f.frequency[0] = f.frequency[1] = sc->sc_fixed_rate ?
+		    sc->sc_fixed_rate : 48000;
 		f.mode = AUMODE_PLAY|AUMODE_RECORD;
 		hdafg_append_formats(&sc->sc_audiodev, &f);
 	}
@@ -3625,6 +3642,16 @@ hdafg_attach(device_t parent, device_t s
 	hda_print1(sc, ": %s %s%s\n", vendor, product,
 	    sc->sc_config ? " (custom configuration)" : "");
 
+	switch (sc->sc_vendor) {
+	case HDAUDIO_VENDOR_NVIDIA:
+		switch (sc->sc_product) {
+		case HDAUDIO_PRODUCT_NVIDIA_TEGRA124_HDMI:
+			sc->sc_fixed_rate = 44100;
+			break;
+		}
+		break;
+	}
+
 	rv = prop_dictionary_get_uint64(args, "function-group", &fgptr);
 	if (rv == false || fgptr == 0) {
 		hda_error(sc, "missing function-group property\n");
@@ -3715,7 +3742,7 @@ hdafg_attach(device_t parent, device_t s
 
 	hda_debug(sc, "connecting streams\n");
 	defparams.channels = 2;
-	defparams.sample_rate = 48000;
+	defparams.sample_rate = sc->sc_fixed_rate ? sc->sc_fixed_rate : 48000;
 	defparams.precision = defparams.validbits = 16;
 	defparams.encoding = AUDIO_ENCODING_SLINEAR_LE;
 	sc->sc_pparam = sc->sc_rparam = defparams;
@@ -3862,7 +3889,8 @@ hdafg_set_params(void *opaque, int setmo
 		    AUMODE_PLAY, play, TRUE, pfil);
 		if (index < 0)
 			return EINVAL;
-		ad->ad_sc->sc_pparam = *play;
+		ad->ad_sc->sc_pparam = pfil->req_size > 0 ?
+		    pfil->filters[0].param : *play;
 		hdafg_stream_connect(ad->ad_sc, AUMODE_PLAY);
 	}
 	if (rec && (setmode & AUMODE_RECORD)) {
@@ -3870,7 +3898,8 @@ hdafg_set_params(void *opaque, int setmo
 		    AUMODE_RECORD, rec, TRUE, rfil);
 		if (index < 0)
 			return EINVAL;
-		ad->ad_sc->sc_rparam = *rec;
+		ad->ad_sc->sc_rparam = rfil->req_size > 0 ?
+		    rfil->filters[0].param : *rec;
 		hdafg_stream_connect(ad->ad_sc, AUMODE_RECORD);
 	}
 	return 0;
@@ -4215,9 +4244,9 @@ hdafg_trigger_output(void *opaque, void 
 	ad->ad_playbackintrarg = intrarg;
 
 	dmasize = (char *)end - (char *)start;
-	ad->ad_sc->sc_pparam = *param;
 	hdafg_stream_connect(ad->ad_sc, AUMODE_PLAY);
-	hdaudio_stream_start(ad->ad_playback, blksize, dmasize, param);
+	hdaudio_stream_start(ad->ad_playback, blksize, dmasize,
+	    &ad->ad_sc->sc_pparam);
 
 	return 0;
 }
@@ -4238,9 +4267,9 @@ hdafg_trigger_input(void *opaque, void *
 	ad->ad_captureintrarg = intrarg;
 
 	dmasize = (char *)end - (char *)start;
-	ad->ad_sc->sc_rparam = *param;
 	hdafg_stream_connect(ad->ad_sc, AUMODE_RECORD);
-	hdaudio_stream_start(ad->ad_capture, blksize, dmasize, param);
+	hdaudio_stream_start(ad->ad_capture, blksize, dmasize,
+	    &ad->ad_sc->sc_rparam);
 
 	return 0;
 }

Reply via email to