From 8e8646698a0b1c2269966bee2b416163109fc443 Mon Sep 17 00:00:00 2001 From: jmcneill Date: Sun, 26 Jul 2015 19:06:26 +0000 Subject: [PATCH] - 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 --- sys/dev/hdaudio/hdafg.c | 61 ++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/sys/dev/hdaudio/hdafg.c b/sys/dev/hdaudio/hdafg.c index b273e406c0b5..b4145b6fc70e 100644 --- a/sys/dev/hdaudio/hdafg.c +++ b/sys/dev/hdaudio/hdafg.c @@ -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 @@ -60,7 +60,7 @@ */ #include -__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 #include @@ -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_softc *sc, struct hdaudio_assoc *as, 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 *sc, int mode) { 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 *sc, int mode) 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 *sc, int mode) 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 *sc, u_int frequency) { 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 *sc, u_int frequency) 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_softc *sc) 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 self, void *opaque) 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 self, void *opaque) 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 setmode, int usemode, 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 setmode, int usemode, 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 *start, void *end, int blksize, 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 *start, void *end, int blksize, 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; }