From 67a755cc6ef9d7ffc36073922610ffab9f3c8dfe Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Tue, 13 Nov 2018 20:36:36 +0300 Subject: [PATCH 175/211] gpu: drm: rcar-du: Extend VSP1-DRM interface This is based on the original "Extend VSP1-DRM interface" patch by Konstantin Kozhevnikov which adds alpha plane and color key properties to DRM planes. Signed-off-by: Valentine Barshak --- drivers/gpu/drm/drm_fourcc.c | 1 + drivers/gpu/drm/rcar-du/rcar_du_drv.h | 5 + drivers/gpu/drm/rcar-du/rcar_du_kms.c | 38 ++++++ drivers/gpu/drm/rcar-du/rcar_du_plane.c | 2 + drivers/gpu/drm/rcar-du/rcar_du_plane.h | 5 + drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 229 ++++++++++++++++++++++++++------ drivers/gpu/drm/rcar-du/rcar_du_vsp.h | 7 +- 7 files changed, 249 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c index 9c0152d..5f1a175 100644 --- a/drivers/gpu/drm/drm_fourcc.c +++ b/drivers/gpu/drm/drm_fourcc.c @@ -106,6 +106,7 @@ const struct drm_format_info *__drm_format_info(u32 format) { static const struct drm_format_info formats[] = { { .format = DRM_FORMAT_C8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, + { .format = DRM_FORMAT_R8, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, { .format = DRM_FORMAT_RGB332, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, { .format = DRM_FORMAT_BGR233, .depth = 8, .num_planes = 1, .cpp = { 1, 0, 0 }, .hsub = 1, .vsub = 1 }, { .format = DRM_FORMAT_XRGB4444, .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 1, .vsub = 1 }, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 504a188..dc20ebb 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -99,6 +99,11 @@ struct rcar_du_device { struct drm_property *alpha; struct drm_property *colorkey; struct drm_property *colorkey_alpha; + struct drm_property *alphaplane; + struct drm_property *blend; + struct drm_property *ckey; + struct drm_property *ckey_set0; + struct drm_property *ckey_set1; } props; unsigned int dpad0_source; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index d66ae53..f74bc6a 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -11,6 +11,7 @@ * (at your option) any later version. */ +//#define DEBUG #include #include #include @@ -96,6 +97,12 @@ static const struct rcar_du_format_info rcar_du_format_infos[] = { .planes = 2, .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC, .edf = PnDDCR4_EDF_NONE, + }, { + .fourcc = DRM_FORMAT_R8, + .bpp = 8, + .planes = 1, + .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_8BPP, + .edf = PnDDCR4_EDF_NONE, }, /* * The following formats are not supported on Gen2 and thus have no @@ -543,6 +550,37 @@ static int rcar_du_properties_init(struct rcar_du_device *rcdu) return -ENOMEM; } + rcdu->props.alphaplane = + drm_property_create(rcdu->ddev, DRM_MODE_PROP_OBJECT, "alphaplane", 1); + if (rcdu->props.alphaplane == NULL) + return -ENOMEM; + + rcdu->props.alphaplane->values[0] = DRM_MODE_OBJECT_FB; + + rcdu->props.blend = + drm_property_create_range(rcdu->ddev, 0, "blend", + 0, 0xffffffff); + if (rcdu->props.blend == NULL) + return -ENOMEM; + + rcdu->props.ckey = + drm_property_create_range(rcdu->ddev, 0, "ckey", + 0, 0xffffffff); + if (rcdu->props.ckey == NULL) + return -ENOMEM; + + rcdu->props.ckey_set0 = + drm_property_create_range(rcdu->ddev, 0, "ckey_set0", + 0, 0xffffffff); + if (rcdu->props.ckey_set0 == NULL) + return -ENOMEM; + + rcdu->props.ckey_set1 = + drm_property_create_range(rcdu->ddev, 0, "ckey_set1", + 0, 0xffffffff); + if (rcdu->props.ckey_set1 == NULL) + return -ENOMEM; + return 0; } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 5818c59..74e0bb1 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -11,6 +11,7 @@ * (at your option) any later version. */ +//#define DEBUG #include #include #include @@ -790,6 +791,7 @@ static const uint32_t formats[] = { DRM_FORMAT_NV12, DRM_FORMAT_NV21, DRM_FORMAT_NV16, + DRM_FORMAT_R8, }; int rcar_du_planes_init(struct rcar_du_group *rgrp) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.h b/drivers/gpu/drm/rcar-du/rcar_du_plane.h index e0ddecf..3e9dfdb 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.h @@ -70,6 +70,11 @@ struct rcar_du_plane_state { unsigned int alpha; unsigned int colorkey; unsigned int colorkey_alpha; + struct drm_framebuffer *alphaplane; + unsigned int blend; + unsigned int ckey; + unsigned int ckey_set0; + unsigned int ckey_set1; }; static inline struct rcar_du_plane_state * diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c index 0c352a0..e53c20e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c @@ -11,6 +11,7 @@ * (at your option) any later version. */ +//#define DEBUG #include #include #include @@ -96,6 +97,16 @@ void rcar_du_vsp_enable(struct rcar_du_crtc *crtc) void rcar_du_vsp_disable(struct rcar_du_crtc *crtc) { + struct rcar_du_vsp *vsp = crtc->vsp; + struct rcar_du_vsp_plane *primary = &vsp->planes[0]; + struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(primary->plane.state); + + /* ...drop alpha-plane associated with primary plane (why only primary? - tbd) */ + if (rstate->alphaplane) { + drm_framebuffer_unreference(rstate->alphaplane); + rstate->alphaplane = NULL; + } + vsp1_du_setup_lif(crtc->vsp->vsp, crtc->vsp_pipe, NULL); } @@ -142,6 +153,7 @@ static const u32 formats_kms[] = { DRM_FORMAT_YVU422, DRM_FORMAT_YUV444, DRM_FORMAT_YVU444, + DRM_FORMAT_R8, }; static const u32 formats_v4l2[] = { @@ -170,6 +182,7 @@ static const u32 formats_v4l2[] = { V4L2_PIX_FMT_YVU422M, V4L2_PIX_FMT_YUV444M, V4L2_PIX_FMT_YVU444M, + V4L2_PIX_FMT_GREY, }; static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane) @@ -217,6 +230,28 @@ static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane) } } + /* ...add alpha-plane as needed */ + if (state->alphaplane) { + i = state->format->planes; + cfg.alpha_mem = sg_dma_address(state->sg_tables[i].sgl); + cfg.alpha_pitch = state->alphaplane->pitches[0]; + pr_debug("alpha-%d: set alpha-mem address: %llx, pitch=%d\n", + i, (unsigned long long)cfg.alpha_mem, cfg.alpha_pitch); + } + + /* ...add blending formula as needed */ + if (state->blend) { + cfg.blend = state->blend; + pr_debug("set blending formula: %X\n", cfg.blend); + } + + /* ...add color key property as needed */ + if (state->ckey) { + cfg.ckey = state->ckey; + cfg.ckey_set0 = state->ckey_set0; + cfg.ckey_set1 = state->ckey_set1; + } + vsp1_du_atomic_update(plane->vsp->vsp, crtc->vsp_pipe, plane->index, &cfg); } @@ -285,6 +320,23 @@ static int rcar_du_vsp_plane_prepare_fb(struct drm_plane *plane, if (ret) goto fail; + /* ...check if we have alpha-plane attached */ + if (rstate->alphaplane) { + struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(rstate->alphaplane, 0); + struct sg_table *sgt = &rstate->sg_tables[i++]; + + ret = dma_get_sgtable(rcdu->dev, sgt, gem->vaddr, gem->paddr, gem->base.size); + if (ret) + goto fail; + + ret = vsp1_du_map_sg(vsp->vsp, sgt); + if (!ret) { + sg_free_table(sgt); + ret = -ENOMEM; + goto fail; + } + } + return 0; fail: @@ -314,6 +366,14 @@ static void rcar_du_vsp_plane_cleanup_fb(struct drm_plane *plane, vsp1_du_unmap_sg(vsp->vsp, sgt); sg_free_table(sgt); } + + if (rstate->alphaplane) { + struct sg_table *sgt = &rstate->sg_tables[i]; + + vsp1_du_unmap_sg(vsp->vsp, sgt); + sg_free_table(sgt); + pr_debug("unmap alpha-plane\n"); + } } static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane, @@ -356,6 +416,13 @@ rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane) if (copy == NULL) return NULL; + if (copy->alphaplane) { + drm_framebuffer_reference(copy->alphaplane); + pr_debug("duplicate alpha-plane '%p' (refcount=%d)\n", + copy->alphaplane, + drm_framebuffer_read_refcount(copy->alphaplane)); + } + __drm_atomic_helper_plane_duplicate_state(plane, ©->state); copy->alpha = to_rcar_vsp_plane_state(plane->state)->alpha; copy->colorkey = to_rcar_vsp_plane_state(plane->state)->colorkey; @@ -367,8 +434,17 @@ rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane) static void rcar_du_vsp_plane_atomic_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { + struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state); + + if (rstate->alphaplane) { + pr_debug("unref alpha-plane '%p' (refcount=%d)\n", + rstate->alphaplane, + drm_framebuffer_read_refcount(rstate->alphaplane)); + drm_framebuffer_unreference(rstate->alphaplane); + } + __drm_atomic_helper_plane_destroy_state(state); - kfree(to_rcar_vsp_plane_state(state)); + kfree(rstate); } static void rcar_du_vsp_plane_reset(struct drm_plane *plane) @@ -376,6 +452,8 @@ static void rcar_du_vsp_plane_reset(struct drm_plane *plane) struct rcar_du_vsp_plane_state *state; if (plane->state) { + pr_debug("reset plane '%p'\n", + to_rcar_vsp_plane_state(plane->state)->alphaplane); rcar_du_vsp_plane_atomic_destroy_state(plane, plane->state); plane->state = NULL; } @@ -403,9 +481,10 @@ int rcar_du_vsp_write_back(struct drm_device *dev, void *data, struct rcar_du_crtc *rcrtc; struct rcar_du_device *rcdu; const struct drm_display_mode *mode; - u32 pixelformat, bpp; - unsigned int pitch; + struct drm_framebuffer *fb; dma_addr_t mem[3]; + struct sg_table sg_tables[3]; + int i = 0; obj = drm_mode_object_find(dev, sh->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) @@ -416,65 +495,89 @@ int rcar_du_vsp_write_back(struct drm_device *dev, void *data, rcdu = rcrtc->group->dev; mode = &rcrtc->crtc.state->adjusted_mode; - switch (sh->fmt) { - case DRM_FORMAT_RGB565: - bpp = 16; - pixelformat = V4L2_PIX_FMT_RGB565; - break; - case DRM_FORMAT_ARGB1555: - bpp = 16; - pixelformat = V4L2_PIX_FMT_ARGB555; - break; - case DRM_FORMAT_ARGB8888: - bpp = 32; - pixelformat = V4L2_PIX_FMT_ABGR32; - break; - default: - dev_err(rcdu->dev, "specified format is not supported.\n"); + fb = drm_framebuffer_lookup(dev, sh->buff); + if (!fb) { + dev_err(dev->dev, + "failed to lookup destination framebuffer '%lu'\n", + sh->buff); return -EINVAL; } - pitch = mode->hdisplay * bpp / 8; + /* ...check framebuffer is okay */ + if ((fb->width != (mode->hdisplay)) || + (fb->height != (mode->vdisplay))) { + dev_err(dev->dev, "wrong fb mode: %d*%d vs %d*%d\n", + fb->width, fb->height, mode->hdisplay, mode->vdisplay); + ret = -EINVAL; + goto done; + } - mem[0] = sh->buff; - mem[1] = 0; - mem[2] = 0; + /* ...need to verify compatibility of output format, I guess - tbd */ - if (sh->width != mode->hdisplay || - sh->height != mode->vdisplay) - return -EINVAL; + /* ...fill memory planes addresses */ + for (i = 0; i < 3; i++) { + struct drm_gem_cma_object *gem; + struct sg_table *sgt = &sg_tables[i]; - if ((pitch * mode->vdisplay) > sh->buff_len) - return -EINVAL; + gem = drm_fb_cma_get_gem_obj(fb, i); + if (!gem) + break; + + ret = dma_get_sgtable(rcdu->dev, sgt, gem->vaddr, gem->paddr, + gem->base.size); + if (ret) + goto done; + + ret = vsp1_du_map_sg(rcrtc->vsp->vsp, sgt); + if (!ret) { + sg_free_table(sgt); + ret = -ENOMEM; + goto done; + } + mem[i] = sg_dma_address(sg_tables[i].sgl) + fb->offsets[i]; + } - ret = vsp1_du_setup_wb(rcrtc->vsp->vsp, pixelformat, pitch, mem, - rcrtc->vsp_pipe); + dev_info(dev->dev, "setup write-back (pixfmt=%X, %u*%u, planes: %d)\n", + fb->format->format, fb->width, fb->height, i); + + ret = vsp1_du_setup_wb(rcrtc->vsp->vsp, fb->format->format, + fb->pitches[0], mem, rcrtc->vsp_pipe); if (ret != 0) - return ret; + goto done; ret = vsp1_du_wait_wb(rcrtc->vsp->vsp, WB_STAT_CATP_SET, rcrtc->vsp_pipe); if (ret != 0) - return ret; + goto done; ret = rcar_du_async_commit(dev, crtc); if (ret != 0) - return ret; + goto done; ret = vsp1_du_wait_wb(rcrtc->vsp->vsp, WB_STAT_CATP_START, rcrtc->vsp_pipe); if (ret != 0) - return ret; + goto done; ret = rcar_du_async_commit(dev, crtc); if (ret != 0) - return ret; + goto done; ret = vsp1_du_wait_wb(rcrtc->vsp->vsp, WB_STAT_CATP_DONE, rcrtc->vsp_pipe); if (ret != 0) - return ret; + goto done; + +done: + /* ...unmap all tables */ + while (i--) { + struct sg_table *sgt = &sg_tables[i]; + + vsp1_du_unmap_sg(rcrtc->vsp->vsp, sgt); + sg_free_table(sgt); + } + drm_framebuffer_unreference(fb); return ret; } @@ -518,7 +621,38 @@ static int rcar_du_vsp_plane_atomic_set_property(struct drm_plane *plane, rstate->colorkey = val; else if (property == rcdu->props.colorkey_alpha) rstate->colorkey_alpha = val; - else + else if (property == rcdu->props.blend) + rstate->blend = val; + else if (property == rcdu->props.ckey) + rstate->ckey = val; + else if (property == rcdu->props.ckey_set0) + rstate->ckey_set0 = val; + else if (property == rcdu->props.ckey_set1) + rstate->ckey_set1 = val; + else if (property == rcdu->props.alphaplane) { + if (rstate->alphaplane) { + pr_debug("unref alpha-plane '%p' (refcount=%d)\n", + rstate->alphaplane, + drm_framebuffer_read_refcount(rstate->alphaplane)); + drm_framebuffer_unreference(rstate->alphaplane); + } + rstate->alphaplane = drm_framebuffer_lookup(plane->dev, val); + if (rstate->alphaplane) { + pr_debug("use alpha-plane '%p' (refcount=%d)\n", + rstate->alphaplane, + drm_framebuffer_read_refcount(rstate->alphaplane)); + /* ...the way how we handle this leads to a "loss" + * of plane reference (it is acquired within + * "drm_property_change_valid_get" but not returned + * in symmetric "drm_property_change_valid_put") + * Whether it is a bug or was done intentionally, + * I don't know. For a moment just drop that + * extra reference right here. + */ + if (0) + drm_framebuffer_unreference(rstate->alphaplane); + } + } else return -EINVAL; return 0; @@ -538,6 +672,16 @@ static int rcar_du_vsp_plane_atomic_get_property(struct drm_plane *plane, *val = rstate->colorkey; else if (property == rcdu->props.colorkey_alpha) *val = rstate->colorkey_alpha; + else if (property == rcdu->props.alphaplane) + *val = (rstate->alphaplane ? rstate->alphaplane->base.id : 0); + else if (property == rcdu->props.blend) + *val = rstate->blend; + else if (property == rcdu->props.ckey) + *val = rstate->ckey; + else if (property == rcdu->props.ckey_set0) + *val = rstate->ckey_set0; + else if (property == rcdu->props.ckey_set1) + *val = rstate->ckey_set1; else return -EINVAL; @@ -633,7 +777,8 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np, drm_plane_helper_add(&plane->plane, &rcar_du_vsp_plane_helper_funcs); - if (type == DRM_PLANE_TYPE_PRIMARY) { + // ...use same set of properties for all planes + if (0 && type == DRM_PLANE_TYPE_PRIMARY) { drm_plane_create_zpos_immutable_property(&plane->plane, 0); } else { @@ -648,6 +793,16 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np, 0); drm_plane_create_zpos_property(&plane->plane, 1, 1, vsp->num_planes - 1); + drm_object_attach_property(&plane->plane.base, + rcdu->props.alphaplane, 0); + drm_object_attach_property(&plane->plane.base, + rcdu->props.blend, 0); + drm_object_attach_property(&plane->plane.base, + rcdu->props.ckey, 0); + drm_object_attach_property(&plane->plane.base, + rcdu->props.ckey_set0, 0); + drm_object_attach_property(&plane->plane.base, + rcdu->props.ckey_set1, 0); } } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h index 93dbb9e..083d065 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h @@ -55,11 +55,16 @@ struct rcar_du_vsp_plane_state { struct drm_plane_state state; const struct rcar_du_format_info *format; - struct sg_table sg_tables[3]; + struct sg_table sg_tables[4]; unsigned int alpha; u32 colorkey; u32 colorkey_alpha; + struct drm_framebuffer *alphaplane; + unsigned int blend; + unsigned int ckey; + unsigned int ckey_set0; + unsigned int ckey_set1; }; static inline struct rcar_du_vsp_plane_state * -- 2.7.4