The HDMI GCP carries color depth and pixel packing phase. These fields are required for 30-, 36- and 48-bpp RGB links. Nouveau has no way to pass them from the atomic state to the display engine.
Build CD and PP using NVIDIA NVKMS's 36-bpp rule and the HDMI 48-bpp encoding. Extend the internal HDMI NVIF method and cache the values in the armed TMDS state. The following change uses that state in the generation-specific GCP writers. Signed-off-by: Daniel Campos Ramos <[email protected]> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 23 +++++++++++++++---- drivers/gpu/drm/nouveau/include/nvif/if0012.h | 3 +++ drivers/gpu/drm/nouveau/include/nvif/outp.h | 2 +- drivers/gpu/drm/nouveau/nvif/outp.c | 7 ++++-- .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 2 ++ .../gpu/drm/nouveau/nvkm/engine/disp/uoutp.c | 6 +++++ 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 6410b96b..6d8fee1b 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -809,13 +809,14 @@ nv50_audio_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, static void nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, struct nouveau_connector *nv_connector, struct drm_atomic_commit *state, - struct drm_display_mode *mode, bool hda) + struct drm_display_mode *mode, bool hda, u8 bpc) { struct nouveau_drm *drm = nouveau_drm(encoder->dev); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct drm_hdmi_info *hdmi = &nv_connector->base.display_info.hdmi; union hdmi_infoframe infoframe = { 0 }; const u8 rekey = 56; /* binary driver, and tegra, constant */ + u8 gcp_cd = 0, gcp_pp = 0; u32 max_ac_packet; DEFINE_RAW_FLEX(struct nvif_outp_infoframe_v0, args, data, 17); const u8 data_len = __member_size(args->data); @@ -826,6 +827,19 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, max_ac_packet -= 18; /* constant from tegra */ max_ac_packet /= 32; + /* Match NVIDIA's 36-bpp GCP construction and extend the same HDMI + * color-depth encoding to 48-bpp. 48-bpp groups contain one pixel, + * so their last packing phase is phase 4 (zero). + */ + if (bpc == 16) { + gcp_cd = 7; + } else if (bpc == 12) { + const u32 hbp = mode->crtc_hblank_end - mode->crtc_hsync_end; + + gcp_cd = 6; + gcp_pp = ((mode->crtc_hdisplay + hbp) & 1) ? 1 : 2; + } + if (nv_encoder->i2c && hdmi->scdc.scrambling.supported) { const bool high_tmds_clock_ratio = mode->clock > 340000; u8 scdc; @@ -850,7 +864,7 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, ret = nvif_outp_hdmi(&nv_encoder->outp, nv_crtc->index, true, max_ac_packet, rekey, mode->clock, hdmi->scdc.supported, hdmi->scdc.scrambling.supported, - hdmi->scdc.scrambling.low_rates); + hdmi->scdc.scrambling.low_rates, gcp_cd, gcp_pp); if (ret) return; @@ -1615,7 +1629,7 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_commit *s if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS && nv_encoder->hdmi.enabled) { nvif_outp_hdmi(&nv_encoder->outp, head->base.index, - false, 0, 0, 0, false, false, false); + false, 0, 0, 0, false, false, false, 0, 0); nv_encoder->hdmi.enabled = false; } @@ -1831,7 +1845,8 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_commit *st if (disp->disp->object.oclass != NV50_DISP && nv_connector->base.display_info.is_hdmi) - nv50_hdmi_enable(encoder, nv_crtc, nv_connector, state, mode, hda); + nv50_hdmi_enable(encoder, nv_crtc, nv_connector, state, mode, hda, + asyh->or.bpc); if (nv_encoder->outp.or.link & 1) { proto = NV507D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_A; diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0012.h b/drivers/gpu/drm/nouveau/include/nvif/if0012.h index bde9bfae..ebfa60f9 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/if0012.h +++ b/drivers/gpu/drm/nouveau/include/nvif/if0012.h @@ -176,6 +176,9 @@ union nvif_outp_hdmi_args { __u8 scdc_scrambling; __u8 scdc_low_rates; __u32 khz; + __u8 gcp_cd; + __u8 gcp_pp; + __u8 pad14[2]; } v0; }; diff --git a/drivers/gpu/drm/nouveau/include/nvif/outp.h b/drivers/gpu/drm/nouveau/include/nvif/outp.h index bc122a5b..3d5ed53f 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/outp.h +++ b/drivers/gpu/drm/nouveau/include/nvif/outp.h @@ -90,7 +90,7 @@ int nvif_outp_bl_set(struct nvif_outp *, int level); int nvif_outp_lvds(struct nvif_outp *, bool dual, bool bpc8); int nvif_outp_hdmi(struct nvif_outp *, int head, bool enable, u8 max_ac_packet, u8 rekey, u32 khz, - bool scdc, bool scdc_scrambling, bool scdc_low_rates); + bool scdc, bool scdc_scrambling, bool scdc_low_rates, u8 gcp_cd, u8 gcp_pp); 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); diff --git a/drivers/gpu/drm/nouveau/nvif/outp.c b/drivers/gpu/drm/nouveau/nvif/outp.c index 8cf4775a..44562645 100644 --- a/drivers/gpu/drm/nouveau/nvif/outp.c +++ b/drivers/gpu/drm/nouveau/nvif/outp.c @@ -224,9 +224,10 @@ nvif_outp_infoframe(struct nvif_outp *outp, u8 type, struct nvif_outp_infoframe_ int nvif_outp_hdmi(struct nvif_outp *outp, int head, bool enable, u8 max_ac_packet, u8 rekey, - u32 khz, bool scdc, bool scdc_scrambling, bool scdc_low_rates) + u32 khz, bool scdc, bool scdc_scrambling, bool scdc_low_rates, + u8 gcp_cd, u8 gcp_pp) { - struct nvif_outp_hdmi_v0 args; + struct nvif_outp_hdmi_v0 args = {}; int ret; args.version = 0; @@ -238,6 +239,8 @@ nvif_outp_hdmi(struct nvif_outp *outp, int head, bool enable, u8 max_ac_packet, args.scdc = scdc; args.scdc_scrambling = scdc_scrambling; args.scdc_low_rates = scdc_low_rates; + args.gcp_cd = gcp_cd; + args.gcp_pp = gcp_pp; ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_HDMI, &args, sizeof(args)); NVIF_ERRON(ret, &outp->object, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 5d682a77..fcf624cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -46,6 +46,8 @@ struct nvkm_ior { /* Armed TMDS state. */ struct { bool high_speed; + u8 gcp_cd; + u8 gcp_pp; } tmds; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c index 377d0e0c..dff75d72 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c @@ -254,16 +254,22 @@ nvkm_uoutp_mthd_hdmi(struct nvkm_outp *outp, void *argv, u32 argc) if (!ior->func->hdmi || args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f || + args->v0.gcp_cd > 0x0f || + args->v0.gcp_pp > 0x0f || (args->v0.scdc && !ior->func->hdmi->scdc)) return -EINVAL; if (!args->v0.enable) { + ior->tmds.gcp_cd = 0; + ior->tmds.gcp_pp = 0; ior->func->hdmi->infoframe_avi(ior, args->v0.head, NULL, 0); ior->func->hdmi->infoframe_vsi(ior, args->v0.head, NULL, 0); ior->func->hdmi->ctrl(ior, args->v0.head, false, 0, 0); return 0; } + ior->tmds.gcp_cd = args->v0.gcp_cd; + ior->tmds.gcp_pp = args->v0.gcp_pp; ior->func->hdmi->ctrl(ior, args->v0.head, args->v0.enable, args->v0.max_ac_packet, args->v0.rekey); if (ior->func->hdmi->scdc) -- 2.53.0
