From a6fd88487f2dda6f8c5ec28230129478711206fb Mon Sep 17 00:00:00 2001 From: Andrey Dolnikov Date: Tue, 6 Feb 2018 13:38:34 +0300 Subject: [PATCH] media: rcar-imr: Add RSE support This adds RSE support for V3H IMR Signed-off-by: Andrey Dolnikov --- drivers/media/platform/rcar_imr.c | 143 +++++++++++++++++++++++++++++++ include/uapi/linux/rcar-imr.h | 22 ++++- 2 files changed, 165 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/rcar_imr.c b/drivers/media/platform/rcar_imr.c index 9b601da..7b16765 100644 --- a/drivers/media/platform/rcar_imr.c +++ b/drivers/media/platform/rcar_imr.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,9 @@ MODULE_PARM_DESC(debug, "Debug level (0-4)"); * Local types definitions ******************************************************************************/ +/* Number of RSE planes on V3H (non scaled, 1/2, 1/4, 1/8) */ +#define RSE_PLANES_NUM 4 + /* ...configuration data */ struct imr_cfg { /* ...display-list main program data */ @@ -49,6 +53,21 @@ struct imr_cfg { /* ...pointers to the source/destination planes */ u32 *src_pa_ptr[2]; u32 *dst_pa_ptr[2]; + /* ...pointers to the RSE destination planes */ + u32 *dstn_pa_ptr[RSE_PLANES_NUM]; + u32 *dstr_pa_ptr[RSE_PLANES_NUM]; + + /* ...offsets to RSE destination planes */ + u32 dstnr_offsets[IMR_EXTDST_NUM]; + + /* ...RSE logical right shift data */ + u32 *rscr_ptr; + u8 rscr_sc8, rscr_sc4, rscr_sc2; + + /* ...RSE destination stride values */ + u32 dstnr_strides[IMR_EXTDST_NUM]; + u32 *striden_ptr[RSE_PLANES_NUM]; + u32 *strider_ptr[RSE_PLANES_NUM]; /* ...subpixel destination coordinates space */ int dst_subpixel; @@ -96,6 +115,8 @@ struct imr_device { struct v4l2_m2m_dev *m2m_dev; struct device *alloc_dev; + bool rse; + /* ...do we need that counter really? framework counts fh structures for us - tbd */ int refcount; @@ -219,6 +240,18 @@ struct imr_ctx { #define IMR_TPOR 0xF0 +#define IMR_RSCSR 0x204 +#define IMR_RSCCR 0x208 +#define IMR_RSCR_RSE 31 +#define IMR_RSCR_SC8 25 +#define IMR_RSCR_SC4 21 +#define IMR_RSCR_SC2 17 + +#define IMR_DSANRR0 0x210 +#define IMR_DSTNRR0 0x214 +#define IMR_DSARR0 0x218 +#define IMR_DSTRR0 0x21C + /******************************************************************************* * Auxiliary helpers ******************************************************************************/ @@ -398,6 +431,7 @@ static int imr_queue_setup(struct vb2_queue *vq, case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_Y10: + case V4L2_PIX_FMT_Y12: case V4L2_PIX_FMT_Y16: sizes[0] = w * h * 2; break; @@ -750,6 +784,7 @@ static inline void imr_dl_program_setup(struct imr_ctx *ctx, struct imr_cfg *cfg int W = ctx->queue[1].fmt.width; int H = ctx->queue[1].fmt.height; u32 tricr = ctx->color & 0xFFFFFF; + int i; v4l2_dbg(2, debug, &ctx->imr->v4l2_dev, "setup %u*%u -> %u*%u mapping (type=%x)\n", w, h, W, H, type); @@ -775,6 +810,38 @@ static inline void imr_dl_program_setup(struct imr_ctx *ctx, struct imr_cfg *cfg *dl++ = IMR_OP_WTS(IMR_CMRCCR, 0xFFFF); *dl++ = IMR_OP_WTS(IMR_CMRCCR2, 0xFFFF); + if (type & IMR_MAP_RSE) { + /* ...enable RSE */ + *dl++ = IMR_OP_WTL(IMR_RSCCR, 1); + *dl++ = 0xffffffff; + *dl++ = IMR_OP_WTL(IMR_RSCSR, 1); + cfg->rscr_ptr = dl++; + + for (i = 0; i < RSE_PLANES_NUM; i++) { + /* ...set destination planes base address and strides */ + *dl++ = IMR_OP_WTL(IMR_DSANRR0 + i * 0x10, 4); + cfg->dstn_pa_ptr[i] = dl++; + cfg->striden_ptr[i] = dl++; + cfg->dstr_pa_ptr[i] = dl++; + cfg->strider_ptr[i] = dl++; + } + + cfg->rscr_sc8 = cfg->rscr_sc4 = cfg->rscr_sc2 = 0; + memset(cfg->dstnr_offsets, 0, sizeof(cfg->dstnr_offsets)); + memset(cfg->dstnr_strides, 0, sizeof(cfg->dstnr_strides)); + } else { + /* ...disable RSE */ + *dl++ = IMR_OP_WTL(IMR_RSCCR, 1); + *dl++ = 0xffffffff; + + for (i = 0; i < RSE_PLANES_NUM; i++) { + cfg->dstn_pa_ptr[i] = NULL; + cfg->striden_ptr[i] = NULL; + cfg->dstr_pa_ptr[i] = NULL; + cfg->strider_ptr[i] = NULL; + } + cfg->rscr_ptr = NULL; + } /* ...set source/destination addresses of Y/UV plane */ *dl++ = IMR_OP_WTL(IMR_DSAR, 2); cfg->dst_pa_ptr[0] = dl++; @@ -907,6 +974,12 @@ static int imr_ioctl_map(struct imr_ctx *ctx, struct imr_map_desc *desc) type = desc->type; + /* ...check for RSE */ + if ((type & IMR_MAP_RSE) && !imr->rse) { + v4l2_err(&imr->v4l2_dev, "Rotator & Scaler extension not supported\n"); + return -EINVAL; + } + /* ...mesh item size calculation */ item_size = (type & IMR_MAP_LUCE ? 4 : 0) + (type & IMR_MAP_CLCE ? 4 : 0); @@ -1055,6 +1128,12 @@ static int imr_ioctl_map_raw(struct imr_ctx *ctx, struct imr_map_desc *desc) u32 dl_start_offset; dma_addr_t dl_dma_addr; + /* ...check RSE */ + if ((type & IMR_MAP_RSE) && !imr->rse) { + v4l2_err(&imr->v4l2_dev, "Rotator & Scaler extension not supported\n"); + return -EINVAL; + } + /* ...calculate main routine length */ dl_size = imr_dl_program_length(ctx); if (!dl_size) { @@ -1103,6 +1182,46 @@ static int imr_ioctl_color(struct imr_ctx *ctx, u32 color) return 0; } +static int imr_extdst_set(struct imr_ctx *ctx, u32 *extdst) +{ + struct imr_device *imr = ctx->imr; + struct imr_cfg *cfg = ctx->cfg; + + if (!cfg) { + v4l2_err(&imr->v4l2_dev, "failed to set V3H extension dst buffers: No active confguration.\n"); + return -EINVAL; + } + + if (copy_from_user((void *) cfg->dstnr_offsets, (void __user *) extdst, sizeof(cfg->dstnr_offsets))) { + v4l2_err(&imr->v4l2_dev, "failed to read V3H extension dst buffers\n"); + return -EFAULT; + } + + return 0; +} + +static int imr_extstride_set(struct imr_ctx *ctx, struct imr_rse_param *param) +{ + struct imr_device *imr = ctx->imr; + struct imr_cfg *cfg = ctx->cfg; + + if (!cfg) { + v4l2_err(&imr->v4l2_dev, "failed to set V3H extension buffers params: No active confguration.\n"); + return -EINVAL; + } + + cfg->rscr_sc8 = param->sc8; + cfg->rscr_sc4 = param->sc4; + cfg->rscr_sc2 = param->sc2; + + if (copy_from_user((void *) cfg->dstnr_strides, (void __user *) param->strides, sizeof(cfg->dstnr_strides))) { + v4l2_err(&imr->v4l2_dev, "failed to read V3H extension buffers strides\n"); + return -EFAULT; + } + + return 0; +} + /******************************************************************************* * V4L2 I/O controls ******************************************************************************/ @@ -1356,6 +1475,14 @@ static long imr_default(struct file *file, void *fh, bool valid_prio, unsigned i /* ...set solid color code */ return imr_ioctl_color(ctx, *(u32 *)arg); + case VIDIOC_IMR_EXTDST: + /* ...set V3H extension dst buffers */ + return imr_extdst_set(ctx, *(u32 **)arg); + + case VIDIOC_IMR_EXTSTRIDE: + /* ...set V3H extension dst strides */ + return imr_extstride_set(ctx, (struct imr_rse_param *)arg); + default: return -ENOIOCTLCMD; } @@ -1579,6 +1706,7 @@ static void imr_device_run(void *priv) struct vb2_v4l2_buffer *src_buf, *dst_buf; u32 src_addr, dst_addr; unsigned long flags; + int i; v4l2_dbg(3, debug, &imr->v4l2_dev, "run next job...\n"); @@ -1608,6 +1736,17 @@ static void imr_device_run(void *priv) *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); + for (i = 0; i < RSE_PLANES_NUM; i++) { + if (cfg->rscr_ptr) *cfg->rscr_ptr = (1 << IMR_RSCR_RSE) | (cfg->rscr_sc8 << IMR_RSCR_SC8) | + (cfg->rscr_sc4 << IMR_RSCR_SC4) |(cfg->rscr_sc2 << IMR_RSCR_SC2); + + if (cfg->dstn_pa_ptr[i]) *cfg->dstn_pa_ptr[i] = dst_addr + cfg->dstnr_offsets[i]; + if (cfg->dstr_pa_ptr[i]) *cfg->dstr_pa_ptr[i] = dst_addr + cfg->dstnr_offsets[i + RSE_PLANES_NUM]; + + if (cfg->striden_ptr[i]) *cfg->striden_ptr[i] = cfg->dstnr_strides[i]; + if (cfg->strider_ptr[i]) *cfg->strider_ptr[i] = cfg->dstnr_strides[i + RSE_PLANES_NUM]; + } + /* ...adjust source/destination parameters of the UV-plane as needed */ if (cfg->src_pa_ptr[1] && cfg->dst_pa_ptr[1]) { *cfg->src_pa_ptr[1] = src_addr + ctx->queue[0].fmt.width * ctx->queue[0].fmt.height; @@ -1776,6 +1915,7 @@ static int imr_probe(struct platform_device *pdev) { struct imr_device *imr; struct resource *res; + struct device_node *np = pdev->dev.of_node; int ret; imr = devm_kzalloc(&pdev->dev, sizeof(*imr), GFP_KERNEL); @@ -1786,6 +1926,9 @@ static int imr_probe(struct platform_device *pdev) spin_lock_init(&imr->lock); imr->dev = &pdev->dev; + /* Check RSE support */ + imr->rse = of_property_read_bool(np, "rse"); + /* ...memory-mapped registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { diff --git a/include/uapi/linux/rcar-imr.h b/include/uapi/linux/rcar-imr.h index 7b8ed0c..19fdbae 100644 --- a/include/uapi/linux/rcar-imr.h +++ b/include/uapi/linux/rcar-imr.h @@ -25,8 +25,8 @@ struct imr_map_desc { /* ...total size of the mesh structure */ u32 size; - /* ...map-specific user-pointer */ - void *data; + /* ...map-specific user-pointer */ + void *data; } __attribute__((packed)); @@ -54,6 +54,9 @@ struct imr_map_desc { /* ...bilinear filtration enable flag */ #define IMR_MAP_BFE (1 << 7) +/* ...extended functionality (rotation/scaling) enable flag */ +#define IMR_MAP_RSE (1 << 21) + /* ...source coordinate decimal point position bit index */ #define __IMR_MAP_UVDPOR_SHIFT 8 #define __IMR_MAP_UVDPOR(v) (((v) >> __IMR_MAP_UVDPOR_SHIFT) & 0x7) @@ -88,11 +91,26 @@ struct imr_mesh { } __attribute__((packed)); /******************************************************************************* + * V3H Extension destination data + ******************************************************************************/ +/* ...number of V3H extension destination buffers (rotated/non-rotated, scaled 1/1, 1/2, 1/4, 1/8) */ +#define IMR_EXTDST_NUM 8 + +struct imr_rse_param { + /* ...logical right shift data */ + u8 sc8, sc4, sc2; + /* ...destination buffers stride */ + u32 *strides; +}; + +/******************************************************************************* * 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) +#define VIDIOC_IMR_EXTDST _IOW('V', BASE_VIDIOC_PRIVATE + 3, u32 *) +#define VIDIOC_IMR_EXTSTRIDE _IOW('V', BASE_VIDIOC_PRIVATE + 4, struct imr_rse_param) #endif /* RCAR_IMR_USER_H */ -- 2.7.4