From a687bfb7343b33992f92e86c234718c3e21144a0 Mon Sep 17 00:00:00 2001 From: Konstantin Kozhevnikov 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 --- 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