This adds support on GF119:GV100 (exclusive) for CTM (aka CSC). Signed-off-by: Ilia Mirkin <imir...@alum.mit.edu> --- drivers/gpu/drm/nouveau/dispnv50/atom.h | 6 ++ drivers/gpu/drm/nouveau/dispnv50/base907c.c | 65 +++++++++++++++++++++ drivers/gpu/drm/nouveau/dispnv50/wndw.c | 13 +++++ drivers/gpu/drm/nouveau/dispnv50/wndw.h | 4 ++ 4 files changed, 88 insertions(+)
diff --git a/drivers/gpu/drm/nouveau/dispnv50/atom.h b/drivers/gpu/drm/nouveau/dispnv50/atom.h index b5fae5ab3fa8..894d1fec6f0a 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/atom.h +++ b/drivers/gpu/drm/nouveau/dispnv50/atom.h @@ -184,6 +184,11 @@ struct nv50_wndw_atom { } i; } xlut; + struct { + u32 matrix[12]; + bool valid; + } ctm; + struct { u8 mode:2; u8 interval:4; @@ -221,6 +226,7 @@ struct nv50_wndw_atom { bool ntfy:1; bool sema:1; bool xlut:1; + bool ctm:1; bool image:1; bool scale:1; bool point:1; diff --git a/drivers/gpu/drm/nouveau/dispnv50/base907c.c b/drivers/gpu/drm/nouveau/dispnv50/base907c.c index 049ce6da321c..ceadc2e3efe9 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/base907c.c +++ b/drivers/gpu/drm/nouveau/dispnv50/base907c.c @@ -83,6 +83,68 @@ base907c_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) asyw->xlut.i.load = head907d_olut_load; } +static inline u32 +ctm_drm_to_base(u64 in) +{ + /* base takes a 19-bit 2's complement value in S3.16 format */ + bool sign = in & BIT_ULL(63); + u32 integer = (in >> 32) & 0x7fffffff; + u32 fraction = in & 0xffffffff; + + if (integer >= 4) { + return (1 << 18) - (sign ? 0 : 1); + } else { + u32 ret = (integer << 16) | (fraction >> 16); + if (sign) + ret = -ret; + return ret & GENMASK(18, 0); + } +} + +static void +base907c_ctm(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, + const struct drm_color_ctm *ctm) +{ + int i, j; + + for (j = 0; j < 3; j++) { + for (i = 0; i < 4; i++) { + u32 *val = &asyw->ctm.matrix[j * 4 + i]; + /* CTM does not support constant offset, while + * HW CSC does. Skip it. */ + if (i == 3) { + *val = 0; + } else { + *val = ctm_drm_to_base(ctm->matrix[j * 3 + i]); + } + } + } +} + +static void +base907c_ctm_clr(struct nv50_wndw *wndw) +{ + u32 *push; + if ((push = evo_wait(&wndw->wndw, 2))) { + evo_mthd(push, 0x0140, 1); + evo_data(push, 0x00000000); + evo_kick(push, &wndw->wndw); + } +} + +static void +base907c_ctm_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) +{ + u32 *push, i; + if ((push = evo_wait(&wndw->wndw, 13))) { + evo_mthd(push, 0x0140, 12); + evo_data(push, asyw->ctm.matrix[0] | 0x80000000); + for (i = 1; i < 12; i++) + evo_data(push, asyw->ctm.matrix[i]); + evo_kick(push, &wndw->wndw); + } +} + const struct nv50_wndw_func base907c = { .acquire = base507c_acquire, @@ -94,6 +156,9 @@ base907c = { .ntfy_clr = base507c_ntfy_clr, .ntfy_wait_begun = base507c_ntfy_wait_begun, .ilut = base907c_ilut, + .ctm = base907c_ctm, + .ctm_set = base907c_ctm_set, + .ctm_clr = base907c_ctm_clr, .olut_core = true, .xlut_set = base907c_xlut_set, .xlut_clr = base907c_xlut_clr, diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c index 3bee1f063dfb..2ae3ca9a5968 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c @@ -118,6 +118,7 @@ nv50_wndw_flush_clr(struct nv50_wndw *wndw, u32 *interlock, bool flush, if (clr.sema ) wndw->func-> sema_clr(wndw); if (clr.ntfy ) wndw->func-> ntfy_clr(wndw); if (clr.xlut ) wndw->func-> xlut_clr(wndw); + if (clr.ctm ) wndw->func-> ctm_clr(wndw); if (clr.image) wndw->func->image_clr(wndw); interlock[wndw->interlock.type] |= wndw->interlock.data; @@ -145,6 +146,7 @@ nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 *interlock, wndw->func->xlut_set(wndw, asyw); } + if (asyw->set.ctm ) wndw->func->ctm_set (wndw, asyw); if (asyw->set.scale) wndw->func->scale_set(wndw, asyw); if (asyw->set.point) { if (asyw->set.point = false, asyw->set.mask) @@ -341,6 +343,15 @@ nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw, (!armw->visible || (armw->xlut.handle && !asyw->xlut.handle))) asyw->set.xlut = true; + if (wndw->func->ctm && asyh->state.ctm) { + const struct drm_color_ctm *ctm = asyh->state.ctm->data; + wndw->func->ctm(wndw, asyw, ctm); + asyw->ctm.valid = true; + asyw->set.ctm = true; + } else { + asyw->clr.ctm = armw->ctm.valid; + } + /* Can't do an immediate flip while changing the LUT. */ asyh->state.pageflip_flags &= ~DRM_MODE_PAGE_FLIP_ASYNC; } @@ -410,6 +421,7 @@ nv50_wndw_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) asyw->clr.ntfy = armw->ntfy.handle != 0; asyw->clr.sema = armw->sema.handle != 0; asyw->clr.xlut = armw->xlut.handle != 0; + asyw->clr.ctm = armw->ctm.valid; if (wndw->func->image_clr) asyw->clr.image = armw->image.handle[0] != 0; } @@ -501,6 +513,7 @@ nv50_wndw_atomic_duplicate_state(struct drm_plane *plane) asyw->ntfy = armw->ntfy; asyw->ilut = NULL; asyw->xlut = armw->xlut; + asyw->ctm = armw->ctm; asyw->image = armw->image; asyw->point = armw->point; asyw->clr.mask = 0; diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.h b/drivers/gpu/drm/nouveau/dispnv50/wndw.h index 03f3d8dc235a..b6bdc6617a59 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.h +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.h @@ -65,6 +65,10 @@ struct nv50_wndw_func { int (*ntfy_wait_begun)(struct nouveau_bo *, u32 offset, struct nvif_device *); void (*ilut)(struct nv50_wndw *, struct nv50_wndw_atom *); + void (*ctm)(struct nv50_wndw *, struct nv50_wndw_atom *, + const struct drm_color_ctm *); + void (*ctm_set)(struct nv50_wndw *, struct nv50_wndw_atom *); + void (*ctm_clr)(struct nv50_wndw *); bool ilut_identity; bool olut_core; void (*xlut_set)(struct nv50_wndw *, struct nv50_wndw_atom *); -- 2.21.0 _______________________________________________ Nouveau mailing list Nouveau@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/nouveau