From b6176e313aea415b83d5762db275b2f364f08820 Mon Sep 17 00:00:00 2001 From: Konstantin Kozhevnikov Date: Tue, 14 Nov 2017 01:38:51 -0800 Subject: [PATCH] gpu: drm: rcar-du: Extend VSP1-DRM interface Extend VSP1-DRM interface Signed-off-by: Konstantin Kozhevnikov --- drivers/gpu/drm/drm_framebuffer.c | 1 + drivers/gpu/drm/rcar-du/rcar_du_drv.h | 5 + drivers/gpu/drm/rcar-du/rcar_du_kms.c | 42 ++++++- drivers/gpu/drm/rcar-du/rcar_du_plane.c | 3 +- drivers/gpu/drm/rcar-du/rcar_du_plane.h | 5 + drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 209 ++++++++++++++++++++++++++------ drivers/gpu/drm/rcar-du/rcar_du_vsp.h | 7 +- 7 files changed, 232 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 398efd6..4a43e15 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -192,6 +192,7 @@ static int format_check(const struct drm_mode_fb_cmd2 *r) case DRM_FORMAT_YVU422: case DRM_FORMAT_YUV444: case DRM_FORMAT_YVU444: + case DRM_FORMAT_R8: return 0; default: format_name = drm_get_format_name(r->pixel_format); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 45d6e7e..bdf2612 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -104,6 +104,11 @@ struct rcar_du_device { struct { struct drm_property *alpha; struct drm_property *colorkey; + 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 e955e92..31b48bc 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -10,7 +10,7 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ - +//#define DEBUG #include #include #include @@ -101,6 +101,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, }, }; @@ -169,6 +175,10 @@ static const struct rcar_du_format_info rcar_vsp_format_infos[] = { .fourcc = DRM_FORMAT_YVU444, .bpp = 24, .planes = 3, + }, { + .fourcc = DRM_FORMAT_R8, + .bpp = 8, + .planes = 1, }, }; @@ -565,6 +575,36 @@ static int rcar_du_properties_init(struct rcar_du_device *rcdu) if (rcdu->props.colorkey == NULL) 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 e408aa3..2b57f09 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -10,7 +10,7 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ - +//#define DEBUG #include #include #include @@ -719,6 +719,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 c1de338..a6065ef 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.h @@ -66,6 +66,11 @@ struct rcar_du_plane_state { unsigned int alpha; unsigned int colorkey; + 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 770238a..910e0f0 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c @@ -10,7 +10,7 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ - +//#define DEBUG #include #include #include @@ -91,6 +91,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, NULL, crtc->lif_index, crtc->suspend); } @@ -133,6 +143,7 @@ static const u32 formats_kms[] = { DRM_FORMAT_YVU422, DRM_FORMAT_YUV444, DRM_FORMAT_YVU444, + DRM_FORMAT_R8, }; static const u32 formats_v4l2[] = { @@ -162,6 +173,7 @@ static const u32 formats_v4l2[] = { V4L2_PIX_FMT_YVU422M, V4L2_PIX_FMT_YUV444M, V4L2_PIX_FMT_YVU444M, + V4L2_PIX_FMT_GREY, }; static const u32 formats_xlate[][2] = { @@ -184,6 +196,7 @@ static const u32 formats_xlate[][2] = { { DRM_FORMAT_NV21, V4L2_PIX_FMT_NV21M }, { DRM_FORMAT_NV16, V4L2_PIX_FMT_NV16M }, { DRM_FORMAT_NV61, V4L2_PIX_FMT_NV61M }, + { DRM_FORMAT_R8, V4L2_PIX_FMT_GREY }, }; static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane) @@ -226,6 +239,27 @@ 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, plane->index, &cfg); } @@ -259,6 +293,23 @@ static int rcar_du_vsp_plane_prepare_fb(struct drm_plane *plane, } } + /* ...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: @@ -288,6 +339,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, @@ -369,6 +428,11 @@ 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); return ©->state; @@ -377,8 +441,15 @@ 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) @@ -386,6 +457,7 @@ 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; } @@ -410,7 +482,30 @@ static int rcar_du_vsp_plane_atomic_set_property(struct drm_plane *plane, if (property == rcdu->props.alpha) rstate->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; @@ -426,6 +521,16 @@ static int rcar_du_vsp_plane_atomic_get_property(struct drm_plane *plane, if (property == rcdu->props.alpha) *val = rstate->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; @@ -442,9 +547,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) @@ -455,62 +561,79 @@ 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]; + 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; - if ((pitch * mode->vdisplay) > sh->buff_len) - return -EINVAL; + 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]; + } + + dev_info(dev->dev, "setup write-back (pixfmt=%X, %u*%u, planes: %d)\n", fb->pixel_format, fb->width, fb->height, i); + + vsp1_du_setup_wb(rcrtc->vsp->vsp, fb->pixel_format, fb->pitches[0], mem, rcrtc->lif_index); - vsp1_du_setup_wb(rcrtc->vsp->vsp, pixelformat, pitch, mem, - rcrtc->lif_index); ret = vsp1_du_wait_wb(rcrtc->vsp->vsp, WB_STAT_CATP_SET, rcrtc->lif_index); 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->lif_index); 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->lif_index); 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; } @@ -574,6 +697,7 @@ static const uint32_t formats[] = { DRM_FORMAT_NV21, DRM_FORMAT_NV16, DRM_FORMAT_NV61, + DRM_FORMAT_R8, }; int rcar_du_vsp_init(struct rcar_du_vsp *vsp) @@ -653,13 +777,24 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp) drm_plane_helper_add(&plane->plane, &rcar_du_vsp_plane_helper_funcs); +#if 0 // ...use same set of properties for all planes if (type == DRM_PLANE_TYPE_PRIMARY) continue; - +#endif drm_object_attach_property(&plane->plane.base, rcdu->props.alpha, 255); 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); } return 0; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h index 3fd9cef..2f4aa41 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h @@ -52,10 +52,15 @@ 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; unsigned int zpos; + 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