Commit a9f5d772 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/disp: move HDA ELD method

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Reviewed-by: default avatarLyude Paul <lyude@redhat.com>
parent f530bc60
......@@ -673,29 +673,33 @@ nv50_audio_component_fini(struct nouveau_drm *drm)
/******************************************************************************
* Audio
*****************************************************************************/
static bool
nv50_audio_supported(struct drm_encoder *encoder)
{
struct nv50_disp *disp = nv50_disp(encoder->dev);
if (disp->disp->object.oclass <= GT200_DISP ||
disp->disp->object.oclass == GT206_DISP)
return false;
return true;
}
static void
nv50_audio_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
{
struct nouveau_drm *drm = nouveau_drm(encoder->dev);
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nv50_disp *disp = nv50_disp(encoder->dev);
struct nvif_outp *outp = &nv_encoder->outp;
struct {
struct nv50_disp_mthd_v1 base;
struct nv50_disp_sor_hda_eld_v0 eld;
} args = {
.base.version = 1,
.base.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
.base.hasht = nv_encoder->dcb->hasht,
.base.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
(0x0100 << nv_crtc->index),
};
if (!nv50_audio_supported(encoder))
return;
mutex_lock(&drm->audio.lock);
if (nv_encoder->audio.enabled) {
nv_encoder->audio.enabled = false;
nv_encoder->audio.connector = NULL;
nvif_mthd(&disp->disp->object, 0, &args, sizeof(args));
nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, NULL, 0);
}
mutex_unlock(&drm->audio.lock);
......@@ -709,31 +713,15 @@ nv50_audio_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
{
struct nouveau_drm *drm = nouveau_drm(encoder->dev);
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nv50_disp *disp = nv50_disp(encoder->dev);
struct nvif_outp *outp = &nv_encoder->outp;
struct __packed {
struct {
struct nv50_disp_mthd_v1 mthd;
struct nv50_disp_sor_hda_eld_v0 eld;
} base;
u8 data[sizeof(nv_connector->base.eld)];
} args = {
.base.mthd.version = 1,
.base.mthd.method = NV50_DISP_MTHD_V1_SOR_HDA_ELD,
.base.mthd.hasht = nv_encoder->dcb->hasht,
.base.mthd.hashm = (0xf0ff & nv_encoder->dcb->hashm) |
(0x0100 << nv_crtc->index),
};
if (!drm_detect_monitor_audio(nv_connector->edid))
if (!nv50_audio_supported(encoder) || !drm_detect_monitor_audio(nv_connector->edid))
return;
mutex_lock(&drm->audio.lock);
memcpy(args.data, nv_connector->base.eld, sizeof(args.data));
nvif_mthd(&disp->disp->object, 0, &args,
sizeof(args.base) + drm_eld_size(args.data));
nvif_outp_hda_eld(&nv_encoder->outp, nv_crtc->index, nv_connector->base.eld,
drm_eld_size(nv_connector->base.eld));
nv_encoder->audio.enabled = true;
nv_encoder->audio.connector = &nv_connector->base;
......
......@@ -28,7 +28,6 @@ struct nv50_disp_scanoutpos_v0 {
struct nv50_disp_mthd_v1 {
__u8 version;
#define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21
#define NV50_DISP_MTHD_V1_SOR_DP_MST_LINK 0x25
#define NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI 0x26
__u8 method;
......@@ -37,12 +36,6 @@ struct nv50_disp_mthd_v1 {
__u8 pad06[2];
};
struct nv50_disp_sor_hda_eld_v0 {
__u8 version;
__u8 pad01[7];
__u8 data[];
};
struct nv50_disp_sor_dp_mst_link_v0 {
__u8 version;
__u8 state;
......
......@@ -14,6 +14,7 @@ union nvif_outp_args {
#define NVIF_OUTP_V0_ACQUIRE 0x01
#define NVIF_OUTP_V0_RELEASE 0x02
#define NVIF_OUTP_V0_INFOFRAME 0x03
#define NVIF_OUTP_V0_HDA_ELD 0x04
union nvif_outp_load_detect_args {
struct nvif_outp_load_detect_v0 {
......@@ -77,4 +78,13 @@ union nvif_outp_infoframe_args {
__u8 data[];
} v0;
};
union nvif_outp_hda_eld_args {
struct nvif_outp_hda_eld_v0 {
__u8 version;
__u8 head;
__u8 pad02[6];
__u8 data[];
} v0;
};
#endif
......@@ -24,4 +24,5 @@ int nvif_outp_acquire_lvds(struct nvif_outp *, bool dual, bool bpc8);
int nvif_outp_acquire_dp(struct nvif_outp *, bool hda);
void nvif_outp_release(struct nvif_outp *);
int nvif_outp_infoframe(struct nvif_outp *, u8 type, struct nvif_outp_infoframe_v0 *, u32 size);
int nvif_outp_hda_eld(struct nvif_outp *, int head, void *data, u32 size);
#endif
......@@ -25,6 +25,27 @@
#include <nvif/class.h>
int
nvif_outp_hda_eld(struct nvif_outp *outp, int head, void *data, u32 size)
{
struct {
struct nvif_outp_hda_eld_v0 mthd;
u8 data[128];
} args;
int ret;
if (WARN_ON(size > ARRAY_SIZE(args.data)))
return -EINVAL;
args.mthd.version = 0;
args.mthd.head = head;
memcpy(args.data, data, size);
ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_HDA_ELD, &args, sizeof(args.mthd) + size);
NVIF_ERRON(ret, &outp->object, "[HDA_ELD head:%d size:%d]", head, size);
return ret;
}
int
nvif_outp_infoframe(struct nvif_outp *outp, u8 type, struct nvif_outp_infoframe_v0 *args, u32 size)
{
......
......@@ -91,39 +91,6 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
}
switch (mthd * !!outp) {
case NV50_DISP_MTHD_V1_SOR_HDA_ELD: {
union {
struct nv50_disp_sor_hda_eld_v0 v0;
} *args = data;
struct nvkm_ior *ior = outp->ior;
int ret = -ENOSYS;
nvif_ioctl(object, "disp sor hda eld size %d\n", size);
if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(object, "disp sor hda eld vers %d\n",
args->v0.version);
if (size > 0x60)
return -E2BIG;
} else
return ret;
if (!ior->hda)
return -ENODEV;
if (size && args->v0.data[0]) {
if (outp->info.type == DCB_OUTPUT_DP)
ior->func->dp->audio(ior, hidx, true);
ior->func->hda->hpd(ior, hidx, true);
ior->func->hda->eld(ior, hidx, data, size);
} else {
if (outp->info.type == DCB_OUTPUT_DP)
ior->func->dp->audio(ior, hidx, false);
ior->func->hda->hpd(ior, hidx, false);
}
return 0;
}
break;
case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK: {
union {
struct nv50_disp_sor_dp_mst_link_v0 v0;
......
......@@ -26,6 +26,35 @@
#include <nvif/if0012.h>
static int
nvkm_uoutp_mthd_hda_eld(struct nvkm_outp *outp, void *argv, u32 argc)
{
struct nvkm_ior *ior = outp->ior;
union nvif_outp_hda_eld_args *args = argv;
if (argc < sizeof(args->v0) || args->v0.version != 0)
return -ENOSYS;
argc -= sizeof(args->v0);
if (!ior->hda || !nvkm_head_find(outp->disp, args->v0.head))
return -EINVAL;
if (argc > 0x60)
return -E2BIG;
if (argc && args->v0.data[0]) {
if (outp->info.type == DCB_OUTPUT_DP)
ior->func->dp->audio(ior, args->v0.head, true);
ior->func->hda->hpd(ior, args->v0.head, true);
ior->func->hda->eld(ior, args->v0.head, args->v0.data, argc);
} else {
if (outp->info.type == DCB_OUTPUT_DP)
ior->func->dp->audio(ior, args->v0.head, false);
ior->func->hda->hpd(ior, args->v0.head, false);
}
return 0;
}
static int
nvkm_uoutp_mthd_infoframe(struct nvkm_outp *outp, void *argv, u32 argc)
{
......@@ -184,6 +213,7 @@ nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc)
switch (mthd) {
case NVIF_OUTP_V0_RELEASE : return nvkm_uoutp_mthd_release (outp, argv, argc);
case NVIF_OUTP_V0_INFOFRAME : return nvkm_uoutp_mthd_infoframe (outp, argv, argc);
case NVIF_OUTP_V0_HDA_ELD : return nvkm_uoutp_mthd_hda_eld (outp, argv, argc);
default:
break;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment