diff options
Diffstat (limited to 'meta-rcar-gen3-adas/recipes-kernel/linux')
4 files changed, 1457 insertions, 0 deletions
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0103-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0103-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch new file mode 100644 index 0000000..e3f24a6 --- /dev/null +++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0103-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch @@ -0,0 +1,546 @@ +From b6176e313aea415b83d5762db275b2f364f08820 Mon Sep 17 00:00:00 2001 +From: Konstantin Kozhevnikov <Konstantin.Kozhevnikov@cogentembedded.com> +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 <Konstantin.Kozhevnikov@cogentembedded.com> +--- + 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 <drm/drmP.h> + #include <drm/drm_atomic.h> + #include <drm/drm_atomic_helper.h> +@@ -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 <drm/drmP.h> + #include <drm/drm_atomic.h> + #include <drm/drm_atomic_helper.h> +@@ -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 <drm/drmP.h> + #include <drm/drm_atomic.h> + #include <drm/drm_atomic_helper.h> +@@ -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 + diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0104-media-vsp1-extend-DRM-VSP1-interface.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0104-media-vsp1-extend-DRM-VSP1-interface.patch new file mode 100644 index 0000000..2f6fa35 --- /dev/null +++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0104-media-vsp1-extend-DRM-VSP1-interface.patch @@ -0,0 +1,367 @@ +From 0cbfce87c1a16b80111cdcecdd703ad5f75cc6e7 Mon Sep 17 00:00:00 2001 +From: Konstantin Kozhevnikov <Konstantin.Kozhevnikov@cogentembedded.com> +Date: Tue, 14 Nov 2017 01:41:06 -0800 +Subject: [PATCH] media: platform: vsp1: extend DRM-VSP1 interface + +- Extend DRM-VSP1 interface +- Add alpha-plane support for VSP1 + +Signed-off-by: Konstantin Kozhevnikov <Konstantin.Kozhevnikov@cogentembedded.com> +--- + drivers/media/platform/vsp1/vsp1_bru.c | 13 ++++++++++++- + drivers/media/platform/vsp1/vsp1_dl.c | 5 +++++ + drivers/media/platform/vsp1/vsp1_drm.c | 34 ++++++++++++++++++++++++++------- + drivers/media/platform/vsp1/vsp1_lif.c | 2 +- + drivers/media/platform/vsp1/vsp1_pipe.c | 4 ++++ + drivers/media/platform/vsp1/vsp1_rpf.c | 24 ++++++++++++++++++++--- + drivers/media/platform/vsp1/vsp1_rwpf.c | 2 +- + drivers/media/platform/vsp1/vsp1_rwpf.h | 6 ++++++ + drivers/media/platform/vsp1/vsp1_wpf.c | 4 +++- + include/media/vsp1.h | 6 ++++++ + 10 files changed, 86 insertions(+), 14 deletions(-) + +diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c +index 8b3164a..2c131be 100644 +--- a/drivers/media/platform/vsp1/vsp1_bru.c ++++ b/drivers/media/platform/vsp1/vsp1_bru.c +@@ -387,6 +387,16 @@ static void bru_configure(struct vsp1_entity *entity, + ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i); + + vsp1_bru_write(bru, dl, VI6_BRU_CTRL(i), ctrl); ++ dev_dbg(entity->vsp1->dev, "bru#%d: ctrl=%X\n", i, ctrl); ++ ++ /* ...set blending formula as defined by the input RPF */ ++ if (bru->inputs[i].rpf) { ++ if (bru->inputs[i].rpf->blend) { ++ vsp1_bru_write(bru, dl, VI6_BRU_BLD(i), bru->inputs[i].rpf->blend); ++ dev_dbg(entity->vsp1->dev, "bru#%d(#%d): setup blending formula: %X\n", i, bru->inputs[i].rpf->entity.index, bru->inputs[i].rpf->blend); ++ continue; ++ } ++ } + + /* Harcode the blending formula to + * +@@ -441,7 +451,8 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1) + v4l2_ctrl_new_std(&bru->ctrls, &bru_ctrl_ops, V4L2_CID_BG_COLOR, + 0, 0xffffff, 1, 0); + +- bru->bgcolor = 0; ++ /* ...for YUV, set black background */ ++ bru->bgcolor = 0x00800080; + + bru->entity.subdev.ctrl_handler = &bru->ctrls; + +diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c +index 478e093..f9c6d09 100644 +--- a/drivers/media/platform/vsp1/vsp1_dl.c ++++ b/drivers/media/platform/vsp1/vsp1_dl.c +@@ -272,6 +272,7 @@ void vsp1_dl_set_addr_auto_fld(struct vsp1_dl_list *dl, struct vsp1_rwpf *rpf) + u32 y_top_index, y_bot_index; + u32 u_top_index, u_bot_index; + u32 v_top_index, v_bot_index; ++ u32 alpha_index; + dma_addr_t y_top_addr, y_bot_addr; + dma_addr_t u_top_addr, u_bot_addr; + dma_addr_t v_top_addr, v_bot_addr; +@@ -287,6 +288,7 @@ void vsp1_dl_set_addr_auto_fld(struct vsp1_dl_list *dl, struct vsp1_rwpf *rpf) + u_bot_index = rpf->entity.index * 8 + 3; + v_top_index = rpf->entity.index * 8 + 4; + v_bot_index = rpf->entity.index * 8 + 5; ++ alpha_index = rpf->entity.index * 8 + 6; + + switch (rpf->fmtinfo->fourcc) { + case V4L2_PIX_FMT_YUV420M: +@@ -359,6 +361,9 @@ void vsp1_dl_set_addr_auto_fld(struct vsp1_dl_list *dl, struct vsp1_rwpf *rpf) + dl->src_dst_addr[u_bot_index].addr = u_bot_addr; + dl->src_dst_addr[v_top_index].addr = v_top_addr; + dl->src_dst_addr[v_bot_index].addr = v_bot_addr; ++ ++ /* ...set alpha-plane address as needed */ ++ dl->src_dst_addr[alpha_index].addr = rpf->mem.alpha; + } + + static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm) +diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c +index 2681c8a..542ca5a 100644 +--- a/drivers/media/platform/vsp1/vsp1_drm.c ++++ b/drivers/media/platform/vsp1/vsp1_drm.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 <linux/device.h> + #include <linux/dma-mapping.h> + #include <linux/slab.h> +@@ -201,7 +201,9 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg, + + format.format.width = cfg->width; + format.format.height = cfg->height; +- format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32; ++ //format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32; ++ /* ...always blend in YUV colorspace; apply conversion as needed */ ++ format.format.code = MEDIA_BUS_FMT_AYUV8_1X32; + format.format.field = V4L2_FIELD_NONE; + + ret = v4l2_subdev_call(&brs->entity.subdev, pad, +@@ -222,7 +224,9 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg, + + format.format.width = cfg->width; + format.format.height = cfg->height; +- format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32; ++ //format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32; ++ /* ...always blend in YUV colorspace; apply conversion as needed */ ++ format.format.code = MEDIA_BUS_FMT_AYUV8_1X32; + format.format.field = V4L2_FIELD_NONE; + + ret = v4l2_subdev_call(&bru->entity.subdev, pad, +@@ -241,7 +245,8 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg, + + format.format.width = cfg->width; + format.format.height = cfg->height; +- format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32; ++ //format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32; ++ format.format.code = MEDIA_BUS_FMT_AYUV8_1X32; + format.format.field = V4L2_FIELD_NONE; + + if (lif_index == 1) { +@@ -275,6 +280,13 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg, + format.format.code, lif_index); + + format.pad = RWPF_PAD_SOURCE; ++ /* ...force conversion back to ARGB at the output */ ++ format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32; ++ ret = v4l2_subdev_call(&vsp1->wpf[0]->entity.subdev, pad, set_fmt, NULL, ++ &format); ++ if (ret < 0) ++ return ret; ++ + ret = v4l2_subdev_call(&vsp1->wpf[lif_index]->entity.subdev, + pad, get_fmt, NULL, &format); + if (ret < 0) +@@ -402,12 +414,12 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, + } + + dev_dbg(vsp1->dev, +- "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad, %pad } zpos %u\n", ++ "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad, %pad } zpos %u, alpha %pad, ckey %x/%x/%x\n", + __func__, rpf_index, + cfg->src.left, cfg->src.top, cfg->src.width, cfg->src.height, + cfg->dst.left, cfg->dst.top, cfg->dst.width, cfg->dst.height, + cfg->pixelformat, cfg->pitch, &cfg->mem[0], &cfg->mem[1], +- &cfg->mem[2], cfg->zpos); ++ &cfg->mem[2], cfg->zpos, &cfg->alpha_mem, cfg->ckey, cfg->ckey_set0, cfg->ckey_set1); + + /* + * Store the format, stride, memory buffer address, crop and compose +@@ -432,6 +444,11 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, + rpf->format.plane_fmt[1].bytesperline = cfg->pitch; + rpf->alpha = cfg->alpha; + rpf->interlaced = cfg->interlaced; ++ rpf->alpha_pitch = cfg->alpha_pitch; ++ rpf->ckey = cfg->ckey; ++ rpf->ckey_set0 = cfg->ckey_set0; ++ rpf->ckey_set1 = cfg->ckey_set1; ++ rpf->blend = cfg->blend; + + if ((vsp1->ths_quirks & VSP1_AUTO_FLD_NOT_SUPPORT) && + rpf->interlaced) { +@@ -443,6 +460,7 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, + rpf->mem.addr[0] = cfg->mem[0]; + rpf->mem.addr[1] = cfg->mem[1]; + rpf->mem.addr[2] = cfg->mem[2]; ++ rpf->mem.alpha = cfg->alpha_mem; + + vsp1->drm->inputs[rpf_index].crop = cfg->src; + vsp1->drm->inputs[rpf_index].compose = cfg->dst; +@@ -517,7 +535,9 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, + __func__, format.format.width, format.format.height, + format.format.code, rpf->entity.index); + +- format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32; ++ //format.format.code = MEDIA_BUS_FMT_ARGB8888_1X32; ++ /* ...do blending in YUV color-space; apply conversion as needed */ ++ format.format.code = MEDIA_BUS_FMT_AYUV8_1X32; + + ret = v4l2_subdev_call(&rpf->entity.subdev, pad, set_fmt, NULL, + &format); +diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c +index e79f9e6..753763d 100644 +--- a/drivers/media/platform/vsp1/vsp1_lif.c ++++ b/drivers/media/platform/vsp1/vsp1_lif.c +@@ -162,7 +162,7 @@ static void lif_configure(struct vsp1_entity *entity, + + vsp1_lif_write(lif, dl, VI6_LIF_CTRL(lif->entity.index), + (obth << VI6_LIF_CTRL_OBTH_SHIFT) | +- (format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) | ++ (format->code != MEDIA_BUS_FMT_ARGB8888_1X32 ? VI6_LIF_CTRL_CFMT : 0) | + VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN); + + if (soc_device_match(r8a7797)) +diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c +index 8379962..86d4a85 100644 +--- a/drivers/media/platform/vsp1/vsp1_pipe.c ++++ b/drivers/media/platform/vsp1/vsp1_pipe.c +@@ -137,6 +137,10 @@ static const struct vsp1_format_info vsp1_video_formats[] = { + VI6_FMT_Y_U_V_444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, + 3, { 8, 8, 8 }, false, false, 1, 1, false }, ++ { V4L2_PIX_FMT_GREY, MEDIA_BUS_FMT_Y8_1X8, ++ /*VI6_FMT_Y_U_V_444*/0xDEAD, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | ++ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, ++ 1, { 8, 0, 0 }, false, false, 0, 0, false }, + }; + + /** +diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c +index ff25470..2cce294 100644 +--- a/drivers/media/platform/vsp1/vsp1_rpf.c ++++ b/drivers/media/platform/vsp1/vsp1_rpf.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 <linux/device.h> + + #include <media/v4l2-subdev.h> +@@ -253,8 +253,10 @@ static void rpf_configure(struct vsp1_entity *entity, + if (sink_format->code != source_format->code) + infmt |= VI6_RPF_INFMT_CSC; + ++ dev_dbg(vsp1->dev, "rpf#%d: infmt=%x (csc=%d)\n", rpf->entity.index, infmt, !!(infmt & VI6_RPF_INFMT_CSC)); ++ + vsp1_rpf_write(rpf, dl, VI6_RPF_INFMT, infmt); +- vsp1_rpf_write(rpf, dl, VI6_RPF_DSWAP, fmtinfo->swap); ++ vsp1_rpf_write(rpf, dl, VI6_RPF_DSWAP, fmtinfo->swap | 0xF00); + + /* Output location */ + if (pipe->bru) { +@@ -288,6 +290,15 @@ static void rpf_configure(struct vsp1_entity *entity, + (left << VI6_RPF_LOC_HCOORD_SHIFT) | + (top << VI6_RPF_LOC_VCOORD_SHIFT)); + ++ // ...setup alpha-plane as required ++ if (rpf->mem.alpha) { ++ vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_AI, rpf->mem.alpha); ++ vsp1_rpf_write(rpf, dl, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_ASEL_8B_PLANE); ++ vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ASTRIDE, rpf->alpha_pitch); ++ dev_dbg(vsp1->dev, "rpf#%d: setup alpha-plane: buffer=%pad, stride=%u\n", rpf->entity.index, &rpf->mem.alpha, rpf->alpha_pitch); ++ goto out; ++ } ++ + /* On Gen2 use the alpha channel (extended to 8 bits) when available or + * a fixed alpha value set through the V4L2_CID_ALPHA_COMPONENT control + * otherwise. +@@ -342,7 +353,9 @@ static void rpf_configure(struct vsp1_entity *entity, + if (entity->vsp1->info->gen == 3) { + u32 mult; + +- if ((fmtinfo->alpha) && ++ dev_dbg(vsp1->dev, "rpf#%d: alpha=%x, fourcc=%x\n", rpf->entity.index, fmtinfo->alpha, fmtinfo->fourcc); ++ ++ if (0 && (fmtinfo->alpha) && + (fmtinfo->fourcc != V4L2_PIX_FMT_ARGB555)) { + /* When the input contains an alpha channel enable the + * alpha multiplier. If the input is premultiplied we +@@ -371,9 +384,14 @@ static void rpf_configure(struct vsp1_entity *entity, + rpf->mult_alpha = mult; + } + ++out: + vsp1_rpf_write(rpf, dl, VI6_RPF_MSK_CTRL, 0); + vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_CTRL, 0); + ++ /* ...set up color keying */ ++ vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_CTRL, rpf->ckey); ++ vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_SET0, rpf->ckey_set0); ++ vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_SET1, rpf->ckey_set1); + } + + static const struct vsp1_entity_operations rpf_entity_ops = { +diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c +index 66e4d7e..d7e730f 100644 +--- a/drivers/media/platform/vsp1/vsp1_rwpf.c ++++ b/drivers/media/platform/vsp1/vsp1_rwpf.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 <media/v4l2-subdev.h> + + #include "vsp1.h" +diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h +index fbe6aa6..7553f2b 100644 +--- a/drivers/media/platform/vsp1/vsp1_rwpf.h ++++ b/drivers/media/platform/vsp1/vsp1_rwpf.h +@@ -33,6 +33,7 @@ struct vsp1_video; + + struct vsp1_rwpf_memory { + dma_addr_t addr[3]; ++ dma_addr_t alpha; + }; + + struct vsp1_rwpf { +@@ -72,6 +73,11 @@ struct vsp1_rwpf { + + int write_back; + dma_addr_t buf_addr[3]; ++ unsigned int alpha_pitch; ++ unsigned int ckey; ++ unsigned int ckey_set0; ++ unsigned int ckey_set1; ++ unsigned int blend; + }; + + static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev) +diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c +index e8b3cfb..cb81848 100644 +--- a/drivers/media/platform/vsp1/vsp1_wpf.c ++++ b/drivers/media/platform/vsp1/vsp1_wpf.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 <linux/device.h> + + #include <media/v4l2-subdev.h> +@@ -358,6 +358,8 @@ static void wpf_configure(struct vsp1_entity *entity, + + wpf->outfmt = outfmt; + ++ dev_dbg(vsp1->dev, "wpf#%d: outfmt=%x (csc=%d)\n", wpf->entity.index, outfmt, !!(outfmt & VI6_WPF_OUTFMT_CSC)); ++ + vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index), + VI6_DPR_WPF_FPORCH_FP_WPFN); + +diff --git a/include/media/vsp1.h b/include/media/vsp1.h +index d5d93ed..c1c3201 100644 +--- a/include/media/vsp1.h ++++ b/include/media/vsp1.h +@@ -53,11 +53,17 @@ struct vsp1_du_atomic_config { + u32 pixelformat; + unsigned int pitch; + dma_addr_t mem[3]; ++ dma_addr_t alpha_mem; ++ unsigned int alpha_pitch; ++ unsigned int ckey; ++ unsigned int ckey_set0; ++ unsigned int ckey_set1; + struct v4l2_rect src; + struct v4l2_rect dst; + unsigned int alpha; + unsigned int zpos; + bool interlaced; ++ unsigned int blend; + }; + + void vsp1_du_atomic_begin(struct device *dev, unsigned int lif_index); +-- +2.7.4 + diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0105-media-rcar-imr-IMR-driver-updates-for-raw-DL.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0105-media-rcar-imr-IMR-driver-updates-for-raw-DL.patch new file mode 100644 index 0000000..42d2e32 --- /dev/null +++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0105-media-rcar-imr-IMR-driver-updates-for-raw-DL.patch @@ -0,0 +1,538 @@ +From a687bfb7343b33992f92e86c234718c3e21144a0 Mon Sep 17 00:00:00 2001 +From: Konstantin Kozhevnikov <Konstantin.Kozhevnikov@cogentembedded.com> +Date: Tue, 14 Nov 2017 01:47:11 -0800 +Subject: [PATCH] media: rcar-imr: IMR driver updates for raw DL + +IMR driver updates for raw DL + +Signed-off-by: Konstantin Kozhevnikov <Konstantin.Kozhevnikov@cogentembedded.com> +--- + drivers/media/platform/rcar_imr.c | 209 ++++++++++++++++++++++++++++++-------- + include/uapi/linux/rcar-imr.h | 16 +-- + 2 files changed, 175 insertions(+), 50 deletions(-) + +diff --git a/drivers/media/platform/rcar_imr.c b/drivers/media/platform/rcar_imr.c +index 30c6742..9b601da 100644 +--- a/drivers/media/platform/rcar_imr.c ++++ b/drivers/media/platform/rcar_imr.c +@@ -94,6 +94,7 @@ struct imr_device { + struct v4l2_device v4l2_dev; + struct video_device video_dev; + struct v4l2_m2m_dev *m2m_dev; ++ struct device *alloc_dev; + + /* ...do we need that counter really? framework counts fh structures for us - tbd */ + int refcount; +@@ -117,6 +118,9 @@ struct imr_ctx { + /* ...cropping parameters (in pixels) */ + u16 crop[4]; + ++ /* ...solid color code */ ++ u32 color; ++ + /* ...number of active configurations (debugging) */ + u32 cfg_num; + }; +@@ -192,6 +196,7 @@ struct imr_ctx { + + #define IMR_TRICR 0x6C + #define IMR_TRIC_YCFORM (1 << 31) ++#define IMR_TRICR2 0xA0 + + #define IMR_UVDPOR 0x70 + #define IMR_SUSR 0x74 +@@ -212,6 +217,8 @@ struct imr_ctx { + #define IMR_CPDP_UBDPO_SHIFT 4 + #define IMR_CPDP_VRDPO_SHIFT 0 + ++#define IMR_TPOR 0xF0 ++ + /******************************************************************************* + * Auxiliary helpers + ******************************************************************************/ +@@ -404,11 +411,16 @@ static int imr_queue_setup(struct vb2_queue *vq, + return -EINVAL; + } + ++ /* ...specify default allocator */ ++ alloc_devs[0] = ctx->imr->alloc_dev; ++ + return 0; + } + + static int imr_buf_prepare(struct vb2_buffer *vb) + { ++ struct imr_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); ++ + /* ...unclear yet if we want to prepare a buffer somehow (cache invalidation? - tbd) */ + return 0; + } +@@ -441,9 +453,10 @@ static void imr_buf_finish(struct vb2_buffer *vb) + WARN_ON(!mutex_is_locked(&ctx->imr->mutex)); + + /* ...any special processing of completed buffer? - tbd */ +- v4l2_dbg(3, debug, &ctx->imr->v4l2_dev, "%sput buffer <0x%08llx> done\n", ++ v4l2_dbg(3, debug, &ctx->imr->v4l2_dev, "%sput buffer <0x%08llx> done (err: %d) (ctx=%p)\n", + q->is_output ? "in" : "out", +- vb2_dma_contig_plane_dma_addr(vb, 0)); ++ vb2_dma_contig_plane_dma_addr(vb, 0), ++ vb->state, ctx); + + /* ...unref configuration pointer as needed */ + if (q->is_output) +@@ -568,6 +581,11 @@ static inline u16 __imr_auto_sg_dg_tcm(u32 type) + (type & IMR_MAP_TCM ? IMR_TRIM_TCM : 0); + } + ++static inline u16 __imr_bfe_tme(u32 type) ++{ ++ return (type & IMR_MAP_TME ? IMR_TRIM_TME : 0) | (type & IMR_MAP_BFE ? IMR_TRIM_BFE : 0); ++} ++ + static inline u16 __imr_uvdp(u32 type) + { + return __IMR_MAP_UVDPOR(type) | (type & IMR_MAP_DDP ? (1 << 8) : 0); +@@ -674,15 +692,14 @@ static inline u32 * imr_tri_set_type_b(u32 *dl, void *map, struct imr_mesh *mesh + ******************************************************************************/ + + /* ...calculate length of a type "c" mapping */ +-static inline u32 imr_tri_type_c_get_length(struct imr_vbo *vbo, int item_size) ++static inline u32 imr_tri_type_c_get_length(int num, int item_size) + { +- return ((4 + 3 * item_size) * vbo->num + 4); ++ return ((4 + 3 * item_size) * num + 4); + } + + /* ...set a VBO mapping using absolute coordinates */ +-static inline u32 * imr_tri_set_type_c(u32 *dl, void *map, struct imr_vbo *vbo, int item_size) ++static inline u32 * imr_tri_set_type_c(u32 *dl, void *map, int num, int item_size) + { +- int num = vbo->num; + int i; + + /* ...prepare list of triangles to draw */ +@@ -732,6 +749,7 @@ static inline void imr_dl_program_setup(struct imr_ctx *ctx, struct imr_cfg *cfg + int h = ctx->queue[0].fmt.height; + int W = ctx->queue[1].fmt.width; + int H = ctx->queue[1].fmt.height; ++ u32 tricr = ctx->color & 0xFFFFFF; + + v4l2_dbg(2, debug, &ctx->imr->v4l2_dev, "setup %u*%u -> %u*%u mapping (type=%x)\n", w, h, W, H, type); + +@@ -739,11 +757,17 @@ static inline void imr_dl_program_setup(struct imr_ctx *ctx, struct imr_cfg *cfg + *dl++ = IMR_OP_WTS(IMR_TRIMCR, 0xFFFF); + + /* ...set automatic source / destination coordinates generation flags */ +- *dl++ = IMR_OP_WTS(IMR_TRIMSR, __imr_auto_sg_dg_tcm(type) | IMR_TRIM_BFE | IMR_TRIM_TME); ++ *dl++ = IMR_OP_WTS(IMR_TRIMSR, __imr_auto_sg_dg_tcm(type) | __imr_bfe_tme(type)); ++ ++ /* ...that's probably not needed? - tbd */ ++ *dl++ = IMR_OP_SYNCM; + + /* ...set source / destination coordinate precision */ + *dl++ = IMR_OP_WTS(IMR_UVDPOR, __imr_uvdp(type)); + ++ /* ...that's probably not needed? - tbd */ ++ *dl++ = IMR_OP_SYNCM; ++ + /* ...set luminance/chromacity correction parameters precision */ + *dl++ = IMR_OP_WTS(IMR_CPDPOR, __imr_cpdp(type)); + +@@ -776,14 +800,12 @@ static inline void imr_dl_program_setup(struct imr_ctx *ctx, struct imr_cfg *cfg + } + } else { + u16 src_fmt = (iflags & IMR_F_UV_SWAP ? IMR_CMR2_UVFORM : 0) | (iflags & IMR_F_YUV_SWAP ? IMR_CMR2_YUV422FORM : 0); +- u32 dst_fmt = (oflags & IMR_F_YUV_SWAP ? IMR_TRIC_YCFORM : 0); + + /* ...interleaved input; output is either interleaved or planar */ + *dl++ = IMR_OP_WTS(IMR_CMRCSR2, IMR_CMR2_YUV422E | src_fmt); + + /* ...destination is always YUYV or UYVY */ +- *dl++ = IMR_OP_WTL(IMR_TRICR, 1); +- *dl++ = dst_fmt; ++ tricr |= (oflags & IMR_F_YUV_SWAP ? IMR_TRIC_YCFORM : 0); + + /* ...set precision of Y/UV planes and required correction */ + *dl++ = IMR_OP_WTS(IMR_CMRCSR, src_y_fmt | src_uv_fmt | dst_y_fmt | dst_uv_fmt | __imr_clce(type) | __imr_luce(type)); +@@ -810,6 +832,10 @@ static inline void imr_dl_program_setup(struct imr_ctx *ctx, struct imr_cfg *cfg + *dl++ = ((w - 2) << 16) | (w - 1); + *dl++ = h - 1; + ++ /* ...set triangle single color */ ++ *dl++ = IMR_OP_WTL(IMR_TRICR, 1); ++ *dl++ = tricr; ++ + /* ...invoke subroutine for triangles drawing */ + *dl++ = IMR_OP_GOSUB; + *dl++ = subaddr; +@@ -852,7 +878,7 @@ static int imr_ioctl_map(struct imr_ctx *ctx, struct imr_map_desc *desc) + { + struct imr_device *imr = ctx->imr; + struct imr_mesh *mesh; +- struct imr_vbo *vbo; ++ int vbo_num; + struct imr_cfg *cfg; + void *buf, *map; + u32 type; +@@ -925,13 +951,6 @@ static int imr_ioctl_map(struct imr_ctx *ctx, struct imr_map_desc *desc) + tri_length = imr_tri_type_a_get_length(mesh, item_size); + } + } else { +- /* ...assure we have proper VBO descriptor */ +- if (length < sizeof(struct imr_vbo)) { +- v4l2_err(&imr->v4l2_dev, "invalid vbo specification size: %u\n", length); +- ret = -EINVAL; +- goto out; +- } +- + /* ...make sure there is no automatic-generation flags */ + if (type & (IMR_MAP_AUTODG | IMR_MAP_AUTOSG)) { + v4l2_err(&imr->v4l2_dev, "invalid auto-dg/sg flags: 0x%x\n", type); +@@ -939,22 +958,23 @@ static int imr_ioctl_map(struct imr_ctx *ctx, struct imr_map_desc *desc) + goto out; + } + +- vbo = (struct imr_vbo *)buf; +- length -= sizeof(struct imr_vbo); +- map = buf + sizeof(struct imr_vbo); ++ map = buf; + + /* ...vertex is given with absolute coordinates */ + item_size += 8; + ++ /* ...calculate total number of triangles */ ++ vbo_num = length / (3 * item_size); ++ + /* ...check the length is sane */ +- if (length != vbo->num * 3 * item_size) { +- v4l2_err(&imr->v4l2_dev, "invalid vbo size: %u*%u*3 != %u\n", vbo->num, item_size, length); ++ if (length != vbo_num * 3 * item_size) { ++ v4l2_err(&imr->v4l2_dev, "invalid vbo size: %u*%u*3 != %u\n", vbo_num, item_size, length); + ret = -EINVAL; + goto out; + } + + /* ...calculate size of trangles drawing subroutine */ +- tri_length = imr_tri_type_c_get_length(vbo, item_size); ++ tri_length = imr_tri_type_c_get_length(vbo_num, item_size); + } + + /* ...DL main program shall start with 8-byte aligned address */ +@@ -975,13 +995,16 @@ static int imr_ioctl_map(struct imr_ctx *ctx, struct imr_map_desc *desc) + imr_cfg_unref(ctx, ctx->cfg); + + /* ...create new configuration */ +- ctx->cfg = cfg = imr_cfg_create(ctx, dl_size, dl_start_offset); ++ cfg = imr_cfg_create(ctx, dl_size, dl_start_offset); + if (IS_ERR(cfg)) { + ret = PTR_ERR(cfg); ++ ctx->cfg = NULL; + v4l2_err(&imr->v4l2_dev, "failed to create configuration: %d\n", ret); + goto out; + } + ++ ctx->cfg = cfg; ++ + /* ...get pointer to the new display list */ + dl_vaddr = cfg->dl_vaddr; + dl_dma_addr = cfg->dl_dma_addr; +@@ -994,7 +1017,7 @@ static int imr_ioctl_map(struct imr_ctx *ctx, struct imr_map_desc *desc) + imr_tri_set_type_a(dl_vaddr, map, mesh, item_size); + } + } else { +- imr_tri_set_type_c(dl_vaddr, map, vbo, item_size); ++ imr_tri_set_type_c(dl_vaddr, map, vbo_num, item_size); + } + + /* ...prepare main DL-program */ +@@ -1020,6 +1043,66 @@ static int imr_ioctl_map(struct imr_ctx *ctx, struct imr_map_desc *desc) + return ret; + } + ++/* ...set mapping data (function called with video device lock held) */ ++static int imr_ioctl_map_raw(struct imr_ctx *ctx, struct imr_map_desc *desc) ++{ ++ struct imr_device *imr = ctx->imr; ++ u32 type = desc->type; ++ u32 length = desc->size; ++ struct imr_cfg *cfg; ++ void *dl_vaddr; ++ u32 dl_size; ++ u32 dl_start_offset; ++ dma_addr_t dl_dma_addr; ++ ++ /* ...calculate main routine length */ ++ dl_size = imr_dl_program_length(ctx); ++ if (!dl_size) { ++ v4l2_err(&imr->v4l2_dev, "format configuration error\n"); ++ return -EINVAL; ++ } ++ ++ /* ...unref current configuration (will not be used by subsequent jobs) */ ++ imr_cfg_unref(ctx, ctx->cfg); ++ ++ /* ...create new configuration (starts with zero offset) */ ++ cfg = imr_cfg_create(ctx, dl_size, 0); ++ if (IS_ERR(cfg)) { ++ ctx->cfg = NULL; ++ v4l2_err(&imr->v4l2_dev, "failed to create configuration: %ld\n", PTR_ERR(cfg)); ++ return PTR_ERR(cfg); ++ } ++ ++ ctx->cfg = cfg; ++ ++ /* ...get pointer to the new display list */ ++ dl_vaddr = cfg->dl_vaddr; ++ ++ /* ...prepare main DL-program */ ++ imr_dl_program_setup(ctx, cfg, type, dl_vaddr, (u32)(uintptr_t)desc->data); ++ ++ /* ...update cropping parameters */ ++ cfg->dst_subpixel = (type & IMR_MAP_DDP ? 2 : 0); ++ ++ /* ...display list updated successfully */ ++ v4l2_dbg(2, debug, &ctx->imr->v4l2_dev, "display-list created: #%u[%08X]:%u[%u]\n", ++ cfg->id, (u32)dl_dma_addr, dl_size, 0); ++ ++ if (debug >= 4) ++ print_hex_dump_bytes("DL-", DUMP_PREFIX_OFFSET, dl_vaddr + dl_start_offset, dl_size - dl_start_offset); ++ ++ /* ...success */ ++ return 0; ++} ++ ++/* ...set mapping data (function called with video device lock held) */ ++static int imr_ioctl_color(struct imr_ctx *ctx, u32 color) ++{ ++ ctx->color = color; ++ ++ return 0; ++} ++ + /******************************************************************************* + * V4L2 I/O controls + ******************************************************************************/ +@@ -1183,7 +1266,7 @@ static int imr_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) + WARN_ON(!mutex_is_locked(&ctx->imr->mutex)); + + /* ...verify the configuration is complete */ +- if (!V4L2_TYPE_IS_OUTPUT(buf->type) && !ctx->cfg) { ++ if (!ctx->cfg) { + v4l2_err(&ctx->imr->v4l2_dev, "stream configuration is not complete\n"); + return -EINVAL; + } +@@ -1265,6 +1348,14 @@ static long imr_default(struct file *file, void *fh, bool valid_prio, unsigned i + /* ...set mesh data */ + return imr_ioctl_map(ctx, (struct imr_map_desc *)arg); + ++ case VIDIOC_IMR_MESH_RAW: ++ /* ...set mesh data */ ++ return imr_ioctl_map_raw(ctx, (struct imr_map_desc *)arg); ++ ++ case VIDIOC_IMR_COLOR: ++ /* ...set solid color code */ ++ return imr_ioctl_color(ctx, *(u32 *)arg); ++ + default: + return -ENOIOCTLCMD; + } +@@ -1326,6 +1417,9 @@ static int imr_open(struct file *file) + /* ...set default cropping parameters */ + ctx->crop[1] = ctx->crop[3] = 0x3FF; + ++ /* ...set default color */ ++ ctx->color = 0x808080; ++ + /* ...initialize M2M processing context */ + ctx->m2m_ctx = v4l2_m2m_ctx_init(imr->m2m_dev, ctx, imr_queue_init); + if (IS_ERR(ctx->m2m_ctx)) { +@@ -1418,8 +1512,11 @@ static unsigned int imr_poll(struct file *file, struct poll_table_struct *wait) + return -ERESTARTSYS; + + res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); ++ + mutex_unlock(&imr->mutex); + ++ v4l2_dbg(3, debug, &imr->v4l2_dev, "poll result: %X (ctx=%p)\n", res, ctx); ++ + return res; + } + +@@ -1453,7 +1550,6 @@ static const struct v4l2_file_operations imr_fops = { + * M2M device interface + ******************************************************************************/ + +-#if 0 + /* ...job cleanup function */ + static void imr_cleanup(struct imr_ctx *ctx) + { +@@ -1473,17 +1569,16 @@ static void imr_cleanup(struct imr_ctx *ctx) + /* ...release lock before we mark current job as finished */ + spin_unlock_irqrestore(&imr->lock, flags); + } +-#endif + + /* ...job execution function */ + static void imr_device_run(void *priv) + { +- struct imr_ctx *ctx = priv; +- struct imr_device *imr = ctx->imr; +- struct imr_cfg *cfg; +- struct vb2_buffer *src_buf, *dst_buf; +- u32 src_addr, dst_addr; +- unsigned long flags; ++ struct imr_ctx *ctx = priv; ++ struct imr_device *imr = ctx->imr; ++ struct imr_cfg *cfg; ++ struct vb2_v4l2_buffer *src_buf, *dst_buf; ++ u32 src_addr, dst_addr; ++ unsigned long flags; + + v4l2_dbg(3, debug, &imr->v4l2_dev, "run next job...\n"); + +@@ -1494,8 +1589,11 @@ static void imr_device_run(void *priv) + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + ++ /* ...put source/destination buffers sequence numbers */ ++ dst_buf->sequence = src_buf->sequence = ctx->sequence++; ++ + /* ...take configuration pointer associated with input buffer */ +- cfg = to_imr_buffer(to_vb2_v4l2_buffer(src_buf))->cfg; ++ cfg = to_imr_buffer(src_buf)->cfg; + + /* ...cancel software reset state as needed */ + iowrite32(0, imr->mmio + IMR_CR); +@@ -1507,8 +1605,8 @@ static void imr_device_run(void *priv) + iowrite32(ctx->crop[3] << cfg->dst_subpixel, imr->mmio + IMR_YMAXR); + + /* ...adjust source/destination parameters of the program (interleaved / semiplanar) */ +- *cfg->src_pa_ptr[0] = src_addr = (u32)vb2_dma_contig_plane_dma_addr(src_buf, 0); +- *cfg->dst_pa_ptr[0] = dst_addr = (u32)vb2_dma_contig_plane_dma_addr(dst_buf, 0); ++ *cfg->src_pa_ptr[0] = src_addr = (u32)vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); ++ *cfg->dst_pa_ptr[0] = dst_addr = (u32)vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + + /* ...adjust source/destination parameters of the UV-plane as needed */ + if (cfg->src_pa_ptr[1] && cfg->dst_pa_ptr[1]) { +@@ -1529,6 +1627,9 @@ static void imr_device_run(void *priv) + /* ...set display list address */ + iowrite32(cfg->dl_dma_addr + cfg->dl_start_offset, imr->mmio + IMR_DLSAR); + ++ /* ...enable texture prefetching */ ++ iowrite32(0xACCE5501, imr->mmio + IMR_TPOR); ++ + /* ...explicitly flush any pending write operations (don't need that, I guess) */ + wmb(); + +@@ -1536,7 +1637,7 @@ static void imr_device_run(void *priv) + iowrite32(IMR_CR_RS, imr->mmio + IMR_CR); + + /* ...timestamp input buffer */ +- src_buf->timestamp = ktime_get_ns(); ++ src_buf->vb2_buf.timestamp = ktime_get_ns(); + + /* ...unlock device access */ + spin_unlock_irqrestore(&imr->lock, flags); +@@ -1633,13 +1734,14 @@ static irqreturn_t imr_irq_handler(int irq, void *data) + dst_buf->timecode = src_buf->timecode; + dst_buf->flags = src_buf->flags & (V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_KEYFRAME | + V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME | V4L2_BUF_FLAG_TSTAMP_SRC_MASK); +- dst_buf->sequence = src_buf->sequence = ctx->sequence++; ++ //dst_buf->sequence = src_buf->sequence = ctx->sequence++; ++ + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + +- v4l2_dbg(3, debug, &imr->v4l2_dev, "buffers <0x%08x,0x%08x> done\n", ++ v4l2_dbg(3, debug, &imr->v4l2_dev, "buffers <0x%08x,0x%08x> done (ctx=%p)\n", + (u32)vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0), +- (u32)vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0)); ++ (u32)vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0), ctx); + } else { + /* ...operation completed in error; no way to understand what exactly went wrong */ + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); +@@ -1668,6 +1770,8 @@ static irqreturn_t imr_irq_handler(int irq, void *data) + * Device probing / removal interface + ******************************************************************************/ + ++static struct class *imr_alloc_class; ++ + static int imr_probe(struct platform_device *pdev) + { + struct imr_device *imr; +@@ -1727,6 +1831,26 @@ static int imr_probe(struct platform_device *pdev) + goto device_register_rollback; + } + ++ if (!imr_alloc_class) { ++ imr_alloc_class = class_create(THIS_MODULE, "imr-alloc"); ++ if (IS_ERR(imr_alloc_class)) { ++ v4l2_err(&imr->v4l2_dev, "Failed to create alloc-device class\n"); ++ ret = PTR_ERR(imr_alloc_class); ++ goto m2m_init_rollback; ++ } ++ } ++ ++ struct device *adev = device_create(imr_alloc_class, imr->dev, MKDEV(0, 0), NULL, "%s_alloc", dev_name(&pdev->dev)); ++ if (IS_ERR(adev)) { ++ v4l2_err(&imr->v4l2_dev, "Failed to create alloc-device\n"); ++ ret = PTR_ERR(adev); ++ goto m2m_init_rollback; ++ } ++ adev->dma_mask = &adev->coherent_dma_mask; ++ adev->coherent_dma_mask = DMA_BIT_MASK(32); ++ arch_setup_dma_ops(adev, 0, DMA_BIT_MASK(32) + 1, NULL, true); ++ imr->alloc_dev = adev; ++ + strlcpy(imr->video_dev.name, dev_name(&pdev->dev), sizeof(imr->video_dev.name)); + imr->video_dev.fops = &imr_fops; + imr->video_dev.ioctl_ops = &imr_ioctl_ops; +@@ -1765,6 +1889,7 @@ static int imr_remove(struct platform_device *pdev) + + //pm_runtime_disable(imr->v4l2_dev.dev); + video_unregister_device(&imr->video_dev); ++ //device_destroy(imr->alloc_dev, MKDEV(0, 0)); + v4l2_m2m_release(imr->m2m_dev); + v4l2_device_unregister(&imr->v4l2_dev); + +diff --git a/include/uapi/linux/rcar-imr.h b/include/uapi/linux/rcar-imr.h +index d02082f..7b8ed0c 100644 +--- a/include/uapi/linux/rcar-imr.h ++++ b/include/uapi/linux/rcar-imr.h +@@ -48,6 +48,12 @@ struct imr_map_desc { + /* ...vertex clockwise-mode order */ + #define IMR_MAP_TCM (1 << 5) + ++/* ...texture mapping enable flag */ ++#define IMR_MAP_TME (1 << 6) ++ ++/* ...bilinear filtration enable flag */ ++#define IMR_MAP_BFE (1 << 7) ++ + /* ...source coordinate decimal point position bit index */ + #define __IMR_MAP_UVDPOR_SHIFT 8 + #define __IMR_MAP_UVDPOR(v) (((v) >> __IMR_MAP_UVDPOR_SHIFT) & 0x7) +@@ -81,18 +87,12 @@ struct imr_mesh { + + } __attribute__((packed)); + +-/* ...VBO descriptor */ +-struct imr_vbo { +- /* ...number of triangles */ +- u16 num; +- +-} __attribute__((packed)); +- +- + /******************************************************************************* + * Private IOCTL codes + ******************************************************************************/ + + #define VIDIOC_IMR_MESH _IOW('V', BASE_VIDIOC_PRIVATE + 0, struct imr_map_desc) ++#define VIDIOC_IMR_MESH_RAW _IOW('V', BASE_VIDIOC_PRIVATE + 1, struct imr_map_desc) ++#define VIDIOC_IMR_COLOR _IOW('V', BASE_VIDIOC_PRIVATE + 2, u32) + + #endif /* RCAR_IMR_USER_H */ +-- +2.7.4 + diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas_4.9.bbappend b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas_4.9.bbappend index 57a1ee6..d73c1e3 100644 --- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas_4.9.bbappend +++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas_4.9.bbappend @@ -69,6 +69,12 @@ SRC_URI_append = " \ file://0079-ASoC-fix-pcm-creation-regression.patch \ " +SRC_URI_append_r8a7797 = " \ + file://0103-gpu-drm-rcar-du-Extend-VSP1-DRM-interface.patch \ + file://0104-media-vsp1-extend-DRM-VSP1-interface.patch \ + file://0105-media-rcar-imr-IMR-driver-updates-for-raw-DL.patch \ +" + SRC_URI_append_h3ulcb = " file://ulcb.cfg" SRC_URI_append_m3ulcb = " file://ulcb.cfg" SRC_URI_append_salvator-x = " file://salvator-x.cfg" |