- 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
This commit is contained in:
parent
9ac658bba2
commit
8e8646698a
|
@ -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 <support@precedence.co.uk>
|
* Copyright (c) 2009 Precedence Technologies Ltd <support@precedence.co.uk>
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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/types.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
@ -327,6 +327,8 @@ struct hdafg_softc {
|
||||||
} sc_p;
|
} sc_p;
|
||||||
|
|
||||||
struct hdaudio_audiodev sc_audiodev;
|
struct hdaudio_audiodev sc_audiodev;
|
||||||
|
|
||||||
|
uint16_t sc_fixed_rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int hdafg_match(device_t, cfdata_t, void *);
|
static int hdafg_match(device_t, cfdata_t, void *);
|
||||||
|
@ -3041,7 +3043,7 @@ hdafg_commit(struct hdafg_softc *sc)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
hdafg_stream_connect_hdmi(struct hdafg_softc *sc, struct hdaudio_assoc *as,
|
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;
|
struct hdmi_audio_infoframe hdmi;
|
||||||
/* TODO struct displayport_audio_infoframe dp; */
|
/* 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.packet_type = HDMI_AI_PACKET_TYPE;
|
||||||
hdmi.header.version = HDMI_AI_VERSION;
|
hdmi.header.version = HDMI_AI_VERSION;
|
||||||
hdmi.header.length = HDMI_AI_LENGTH;
|
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);
|
hdafg_dd_hdmi_ai_cksum(&hdmi);
|
||||||
}
|
}
|
||||||
/* update data island with new audio infoframe */
|
/* 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_assoc *as = sc->sc_assocs;
|
||||||
struct hdaudio_widget *w;
|
struct hdaudio_widget *w;
|
||||||
|
const audio_params_t *params;
|
||||||
uint16_t fmt, dfmt;
|
uint16_t fmt, dfmt;
|
||||||
int tag, chn, maxchan, c;
|
int tag, chn, maxchan, c;
|
||||||
int i, j, k;
|
int i, j, k;
|
||||||
|
|
||||||
KASSERT(mode == AUMODE_PLAY || mode == AUMODE_RECORD);
|
KASSERT(mode == AUMODE_PLAY || mode == AUMODE_RECORD);
|
||||||
|
|
||||||
if (mode == AUMODE_PLAY)
|
if (mode == AUMODE_PLAY) {
|
||||||
fmt = hdaudio_stream_param(sc->sc_audiodev.ad_playback,
|
fmt = hdaudio_stream_param(sc->sc_audiodev.ad_playback,
|
||||||
&sc->sc_pparam);
|
&sc->sc_pparam);
|
||||||
else
|
params = &sc->sc_pparam;
|
||||||
|
} else {
|
||||||
fmt = hdaudio_stream_param(sc->sc_audiodev.ad_capture,
|
fmt = hdaudio_stream_param(sc->sc_audiodev.ad_capture,
|
||||||
&sc->sc_rparam);
|
&sc->sc_rparam);
|
||||||
|
params = &sc->sc_rparam;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < sc->sc_nassocs; i++) {
|
for (i = 0; i < sc->sc_nassocs; i++) {
|
||||||
if (as[i].as_enable == false)
|
if (as[i].as_enable == false)
|
||||||
|
@ -3177,6 +3187,8 @@ hdafg_stream_connect(struct hdafg_softc *sc, int mode)
|
||||||
dfmt |= COP_DIGITAL_CONVCTRL1_NAUDIO;
|
dfmt |= COP_DIGITAL_CONVCTRL1_NAUDIO;
|
||||||
else
|
else
|
||||||
dfmt &= ~COP_DIGITAL_CONVCTRL1_NAUDIO;
|
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,
|
hdaudio_command(sc->sc_codec, w->w_nid,
|
||||||
CORB_SET_DIGITAL_CONVERTER_CONTROL_1, dfmt);
|
CORB_SET_DIGITAL_CONVERTER_CONTROL_1, dfmt);
|
||||||
}
|
}
|
||||||
|
@ -3203,7 +3215,7 @@ hdafg_stream_connect(struct hdafg_softc *sc, int mode)
|
||||||
continue;
|
continue;
|
||||||
if (w->w_pin.cap & (COP_PINCAP_HDMI|COP_PINCAP_DP))
|
if (w->w_pin.cap & (COP_PINCAP_HDMI|COP_PINCAP_DP))
|
||||||
hdafg_stream_connect_hdmi(sc, &as[i],
|
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;
|
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)
|
#define ISFREQOK(shift) ((caps & (1 << (shift))) ? true : false)
|
||||||
switch (frequency) {
|
switch (frequency) {
|
||||||
case 8000:
|
case 8000:
|
||||||
|
@ -3251,6 +3266,7 @@ hdafg_rate_supported(struct hdafg_softc *sc, u_int frequency)
|
||||||
return ISFREQOK(4);
|
return ISFREQOK(4);
|
||||||
case 44100:
|
case 44100:
|
||||||
return ISFREQOK(5);
|
return ISFREQOK(5);
|
||||||
|
return true;
|
||||||
case 48000:
|
case 48000:
|
||||||
return true; /* Must be supported by all codecs */
|
return true; /* Must be supported by all codecs */
|
||||||
case 88200:
|
case 88200:
|
||||||
|
@ -3433,7 +3449,8 @@ hdafg_configure_encodings(struct hdafg_softc *sc)
|
||||||
f.channels = 2;
|
f.channels = 2;
|
||||||
f.channel_mask = AUFMT_STEREO;
|
f.channel_mask = AUFMT_STEREO;
|
||||||
f.frequency_type = 0;
|
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;
|
f.mode = AUMODE_PLAY|AUMODE_RECORD;
|
||||||
hdafg_append_formats(&sc->sc_audiodev, &f);
|
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,
|
hda_print1(sc, ": %s %s%s\n", vendor, product,
|
||||||
sc->sc_config ? " (custom configuration)" : "");
|
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);
|
rv = prop_dictionary_get_uint64(args, "function-group", &fgptr);
|
||||||
if (rv == false || fgptr == 0) {
|
if (rv == false || fgptr == 0) {
|
||||||
hda_error(sc, "missing function-group property\n");
|
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");
|
hda_debug(sc, "connecting streams\n");
|
||||||
defparams.channels = 2;
|
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.precision = defparams.validbits = 16;
|
||||||
defparams.encoding = AUDIO_ENCODING_SLINEAR_LE;
|
defparams.encoding = AUDIO_ENCODING_SLINEAR_LE;
|
||||||
sc->sc_pparam = sc->sc_rparam = defparams;
|
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);
|
AUMODE_PLAY, play, TRUE, pfil);
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
return EINVAL;
|
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);
|
hdafg_stream_connect(ad->ad_sc, AUMODE_PLAY);
|
||||||
}
|
}
|
||||||
if (rec && (setmode & AUMODE_RECORD)) {
|
if (rec && (setmode & AUMODE_RECORD)) {
|
||||||
|
@ -3870,7 +3898,8 @@ hdafg_set_params(void *opaque, int setmode, int usemode,
|
||||||
AUMODE_RECORD, rec, TRUE, rfil);
|
AUMODE_RECORD, rec, TRUE, rfil);
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
return EINVAL;
|
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);
|
hdafg_stream_connect(ad->ad_sc, AUMODE_RECORD);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4215,9 +4244,9 @@ hdafg_trigger_output(void *opaque, void *start, void *end, int blksize,
|
||||||
ad->ad_playbackintrarg = intrarg;
|
ad->ad_playbackintrarg = intrarg;
|
||||||
|
|
||||||
dmasize = (char *)end - (char *)start;
|
dmasize = (char *)end - (char *)start;
|
||||||
ad->ad_sc->sc_pparam = *param;
|
|
||||||
hdafg_stream_connect(ad->ad_sc, AUMODE_PLAY);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -4238,9 +4267,9 @@ hdafg_trigger_input(void *opaque, void *start, void *end, int blksize,
|
||||||
ad->ad_captureintrarg = intrarg;
|
ad->ad_captureintrarg = intrarg;
|
||||||
|
|
||||||
dmasize = (char *)end - (char *)start;
|
dmasize = (char *)end - (char *)start;
|
||||||
ad->ad_sc->sc_rparam = *param;
|
|
||||||
hdafg_stream_connect(ad->ad_sc, AUMODE_RECORD);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue