1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2020 BayLibre, SAS
4 * Author: Neil Armstrong <narmstrong@baylibre.com>
8 #include <linux/delay.h>
9 #include <linux/bitfield.h>
10 #include <linux/interrupt.h>
11 #include <linux/module.h>
13 #include <linux/reset.h>
14 #include <linux/sched.h>
15 #include <linux/slab.h>
16 #include <linux/timer.h>
17 #include <linux/regmap.h>
19 #include <linux/platform_device.h>
20 #include <media/v4l2-device.h>
21 #include <media/v4l2-event.h>
22 #include <media/v4l2-ioctl.h>
23 #include <media/v4l2-mem2mem.h>
24 #include <media/v4l2-ctrls.h>
25 #include <media/videobuf2-v4l2.h>
26 #include <media/videobuf2-dma-contig.h>
28 #include "ge2d-regs.h"
30 #define GE2D_NAME "meson-ge2d"
32 #define DEFAULT_WIDTH 128
33 #define DEFAULT_HEIGHT 128
34 #define DEFAULT_STRIDE 512
36 #define MAX_WIDTH 8191
37 #define MAX_HEIGHT 8191
42 * - Simple 1/2 vertical scaling
44 * - Source global alpha
45 * - Colorspace conversion
58 struct vb2_v4l2_buffer
*buf
;
61 struct v4l2_pix_format pix_fmt
;
64 struct v4l2_rect crop
;
67 const struct ge2d_fmt
*fmt
;
72 struct meson_ge2d
*ge2d
;
74 struct ge2d_frame out
;
75 struct v4l2_ctrl_handler ctrl_handler
;
77 unsigned long sequence_out
, sequence_cap
;
86 struct v4l2_device v4l2_dev
;
87 struct v4l2_m2m_dev
*m2m_dev
;
88 struct video_device
*vfd
;
97 struct ge2d_ctx
*curr
;
100 #define FMT(_fourcc, _alpha, _depth, _map) \
105 .hw_fmt = GE2D_FORMAT_ ## _depth ## BIT, \
106 .hw_map = GE2D_COLOR_MAP_ ## _map, \
109 /* TOFIX Handle the YUV input formats */
110 static const struct ge2d_fmt formats
[] = {
111 /* FOURCC Alpha HW FMT HW MAP */
112 FMT(V4L2_PIX_FMT_XRGB32
, false, 32, BGRA8888
),
113 FMT(V4L2_PIX_FMT_RGB32
, true, 32, BGRA8888
),
114 FMT(V4L2_PIX_FMT_ARGB32
, true, 32, BGRA8888
),
115 FMT(V4L2_PIX_FMT_RGBX32
, false, 32, ABGR8888
),
116 FMT(V4L2_PIX_FMT_RGBA32
, true, 32, ABGR8888
),
117 FMT(V4L2_PIX_FMT_BGRX32
, false, 32, RGBA8888
),
118 FMT(V4L2_PIX_FMT_BGRA32
, true, 32, RGBA8888
),
119 FMT(V4L2_PIX_FMT_BGR32
, true, 32, ARGB8888
),
120 FMT(V4L2_PIX_FMT_ABGR32
, true, 32, ARGB8888
),
121 FMT(V4L2_PIX_FMT_XBGR32
, false, 32, ARGB8888
),
123 FMT(V4L2_PIX_FMT_RGB24
, false, 24, BGR888
),
124 FMT(V4L2_PIX_FMT_BGR24
, false, 24, RGB888
),
126 FMT(V4L2_PIX_FMT_XRGB555X
, false, 16, ARGB1555
),
127 FMT(V4L2_PIX_FMT_ARGB555X
, true, 16, ARGB1555
),
128 FMT(V4L2_PIX_FMT_RGB565
, false, 16, RGB565
),
129 FMT(V4L2_PIX_FMT_RGBX444
, false, 16, RGBA4444
),
130 FMT(V4L2_PIX_FMT_RGBA444
, true, 16, RGBA4444
),
131 FMT(V4L2_PIX_FMT_XRGB444
, false, 16, ARGB4444
),
132 FMT(V4L2_PIX_FMT_ARGB444
, true, 16, ARGB4444
),
135 #define NUM_FORMATS ARRAY_SIZE(formats)
137 static const struct ge2d_fmt
*find_fmt(struct v4l2_format
*f
)
141 for (i
= 0; i
< NUM_FORMATS
; i
++) {
142 if (formats
[i
].fourcc
== f
->fmt
.pix
.pixelformat
)
147 * TRY_FMT/S_FMT should never return an error when the requested format
148 * is not supported. Drivers should always return a valid format,
149 * preferably a format that is as widely supported by applications as
155 static struct ge2d_frame
*get_frame(struct ge2d_ctx
*ctx
,
156 enum v4l2_buf_type type
)
159 case V4L2_BUF_TYPE_VIDEO_OUTPUT
:
161 case V4L2_BUF_TYPE_VIDEO_CAPTURE
:
164 /* This should never happen, warn and return OUTPUT frame */
165 dev_warn(ctx
->ge2d
->dev
, "%s: invalid buffer type\n", __func__
);
170 static void ge2d_hw_start(struct meson_ge2d
*ge2d
)
172 struct ge2d_ctx
*ctx
= ge2d
->curr
;
176 regmap_update_bits(ge2d
->map
, GE2D_GEN_CTRL1
,
177 GE2D_SOFT_RST
, GE2D_SOFT_RST
);
178 regmap_update_bits(ge2d
->map
, GE2D_GEN_CTRL1
,
181 usleep_range(100, 200);
183 /* Implement CANVAS for non-AXG */
184 regmap_write(ge2d
->map
, GE2D_SRC1_BADDR_CTRL
,
185 (vb2_dma_contig_plane_dma_addr(&ctx
->in
.buf
->vb2_buf
, 0) + 7) >> 3);
186 regmap_write(ge2d
->map
, GE2D_SRC1_STRIDE_CTRL
,
187 (ctx
->in
.pix_fmt
.bytesperline
+ 7) >> 3);
188 regmap_write(ge2d
->map
, GE2D_SRC2_BADDR_CTRL
,
189 (vb2_dma_contig_plane_dma_addr(&ctx
->out
.buf
->vb2_buf
, 0) + 7) >> 3);
190 regmap_write(ge2d
->map
, GE2D_SRC2_STRIDE_CTRL
,
191 (ctx
->out
.pix_fmt
.bytesperline
+ 7) >> 3);
192 regmap_write(ge2d
->map
, GE2D_DST1_BADDR_CTRL
,
193 (vb2_dma_contig_plane_dma_addr(&ctx
->out
.buf
->vb2_buf
, 0) + 7) >> 3);
194 regmap_write(ge2d
->map
, GE2D_DST1_STRIDE_CTRL
,
195 (ctx
->out
.pix_fmt
.bytesperline
+ 7) >> 3);
197 regmap_write(ge2d
->map
, GE2D_GEN_CTRL0
, 0);
198 regmap_write(ge2d
->map
, GE2D_GEN_CTRL1
,
199 FIELD_PREP(GE2D_INTERRUPT_CTRL
, 2) |
200 FIELD_PREP(GE2D_SRC2_BURST_SIZE_CTRL
, 3) |
201 FIELD_PREP(GE2D_SRC1_BURST_SIZE_CTRL
, 0x3f));
203 regmap_write(ge2d
->map
, GE2D_GEN_CTRL2
,
204 GE2D_SRC1_LITTLE_ENDIAN
|
205 GE2D_SRC2_LITTLE_ENDIAN
|
206 GE2D_DST_LITTLE_ENDIAN
|
207 FIELD_PREP(GE2D_DST1_COLOR_MAP
, ctx
->out
.fmt
->hw_map
) |
208 FIELD_PREP(GE2D_DST1_FORMAT
, ctx
->out
.fmt
->hw_fmt
) |
209 FIELD_PREP(GE2D_SRC2_COLOR_MAP
, ctx
->out
.fmt
->hw_map
) |
210 FIELD_PREP(GE2D_SRC2_FORMAT
, ctx
->out
.fmt
->hw_fmt
) |
211 FIELD_PREP(GE2D_SRC1_COLOR_MAP
, ctx
->in
.fmt
->hw_map
) |
212 FIELD_PREP(GE2D_SRC1_FORMAT
, ctx
->in
.fmt
->hw_fmt
));
213 regmap_write(ge2d
->map
, GE2D_GEN_CTRL3
,
216 regmap_write(ge2d
->map
, GE2D_SRC1_CLIPY_START_END
,
217 FIELD_PREP(GE2D_START
, ctx
->in
.crop
.top
) |
218 FIELD_PREP(GE2D_END
, ctx
->in
.crop
.top
+ ctx
->in
.crop
.height
- 1));
219 regmap_write(ge2d
->map
, GE2D_SRC1_CLIPX_START_END
,
220 FIELD_PREP(GE2D_START
, ctx
->in
.crop
.left
) |
221 FIELD_PREP(GE2D_END
, ctx
->in
.crop
.left
+ ctx
->in
.crop
.width
- 1));
222 regmap_write(ge2d
->map
, GE2D_SRC2_CLIPY_START_END
,
223 FIELD_PREP(GE2D_START
, ctx
->out
.crop
.top
) |
224 FIELD_PREP(GE2D_END
, ctx
->out
.crop
.top
+ ctx
->out
.crop
.height
- 1));
225 regmap_write(ge2d
->map
, GE2D_SRC2_CLIPX_START_END
,
226 FIELD_PREP(GE2D_START
, ctx
->out
.crop
.left
) |
227 FIELD_PREP(GE2D_END
, ctx
->out
.crop
.left
+ ctx
->out
.crop
.width
- 1));
228 regmap_write(ge2d
->map
, GE2D_DST_CLIPY_START_END
,
229 FIELD_PREP(GE2D_START
, ctx
->out
.crop
.top
) |
230 FIELD_PREP(GE2D_END
, ctx
->out
.crop
.top
+ ctx
->out
.crop
.height
- 1));
231 regmap_write(ge2d
->map
, GE2D_DST_CLIPX_START_END
,
232 FIELD_PREP(GE2D_START
, ctx
->out
.crop
.left
) |
233 FIELD_PREP(GE2D_END
, ctx
->out
.crop
.left
+ ctx
->out
.crop
.width
- 1));
235 regmap_write(ge2d
->map
, GE2D_SRC1_Y_START_END
,
236 FIELD_PREP(GE2D_END
, ctx
->in
.pix_fmt
.height
- 1));
237 regmap_write(ge2d
->map
, GE2D_SRC1_X_START_END
,
238 FIELD_PREP(GE2D_END
, ctx
->in
.pix_fmt
.width
- 1));
239 regmap_write(ge2d
->map
, GE2D_SRC2_Y_START_END
,
240 FIELD_PREP(GE2D_END
, ctx
->out
.pix_fmt
.height
- 1));
241 regmap_write(ge2d
->map
, GE2D_SRC2_X_START_END
,
242 FIELD_PREP(GE2D_END
, ctx
->out
.pix_fmt
.width
- 1));
243 regmap_write(ge2d
->map
, GE2D_DST_Y_START_END
,
244 FIELD_PREP(GE2D_END
, ctx
->out
.pix_fmt
.height
- 1));
245 regmap_write(ge2d
->map
, GE2D_DST_X_START_END
,
246 FIELD_PREP(GE2D_END
, ctx
->out
.pix_fmt
.width
- 1));
248 /* Color, no blend, use source color */
249 reg
= GE2D_ALU_DO_COLOR_OPERATION_LOGIC(LOGIC_OPERATION_COPY
,
250 COLOR_FACTOR_SRC_COLOR
);
252 if (ctx
->in
.fmt
->alpha
&& ctx
->out
.fmt
->alpha
)
253 /* Take source alpha */
254 reg
|= GE2D_ALU_DO_ALPHA_OPERATION_LOGIC(LOGIC_OPERATION_COPY
,
255 COLOR_FACTOR_SRC_ALPHA
);
256 else if (!ctx
->out
.fmt
->alpha
)
258 reg
|= GE2D_ALU_DO_ALPHA_OPERATION_LOGIC(LOGIC_OPERATION_SET
,
261 /* Keep original alpha */
262 reg
|= GE2D_ALU_DO_ALPHA_OPERATION_LOGIC(LOGIC_OPERATION_COPY
,
263 COLOR_FACTOR_DST_ALPHA
);
265 regmap_write(ge2d
->map
, GE2D_ALU_OP_CTRL
, reg
);
268 regmap_write(ge2d
->map
, GE2D_CMD_CTRL
,
269 (ctx
->xy_swap
? GE2D_DST_XY_SWAP
: 0) |
270 (ctx
->hflip
? GE2D_SRC1_Y_REV
: 0) |
271 (ctx
->vflip
? GE2D_SRC1_X_REV
: 0) |
275 static void device_run(void *priv
)
277 struct ge2d_ctx
*ctx
= priv
;
278 struct meson_ge2d
*ge2d
= ctx
->ge2d
;
282 ctx
->in
.buf
= v4l2_m2m_next_src_buf(ctx
->fh
.m2m_ctx
);
283 ctx
->out
.buf
= v4l2_m2m_next_dst_buf(ctx
->fh
.m2m_ctx
);
288 static irqreturn_t
ge2d_isr(int irq
, void *priv
)
290 struct meson_ge2d
*ge2d
= priv
;
293 regmap_read(ge2d
->map
, GE2D_STATUS0
, &intr
);
295 if (!(intr
& GE2D_GE2D_BUSY
)) {
296 struct vb2_v4l2_buffer
*src
, *dst
;
297 struct ge2d_ctx
*ctx
= ge2d
->curr
;
301 src
= v4l2_m2m_src_buf_remove(ctx
->fh
.m2m_ctx
);
302 dst
= v4l2_m2m_dst_buf_remove(ctx
->fh
.m2m_ctx
);
304 src
->sequence
= ctx
->sequence_out
++;
305 dst
->sequence
= ctx
->sequence_cap
++;
307 dst
->timecode
= src
->timecode
;
308 dst
->vb2_buf
.timestamp
= src
->vb2_buf
.timestamp
;
309 dst
->flags
= src
->flags
;
311 v4l2_m2m_buf_done(src
, VB2_BUF_STATE_DONE
);
312 v4l2_m2m_buf_done(dst
, VB2_BUF_STATE_DONE
);
313 v4l2_m2m_job_finish(ge2d
->m2m_dev
, ctx
->fh
.m2m_ctx
);
319 static const struct v4l2_m2m_ops ge2d_m2m_ops
= {
320 .device_run
= device_run
,
323 static int ge2d_queue_setup(struct vb2_queue
*vq
,
324 unsigned int *nbuffers
, unsigned int *nplanes
,
325 unsigned int sizes
[], struct device
*alloc_devs
[])
327 struct ge2d_ctx
*ctx
= vb2_get_drv_priv(vq
);
328 struct ge2d_frame
*f
= get_frame(ctx
, vq
->type
);
331 return sizes
[0] < f
->pix_fmt
.sizeimage
? -EINVAL
: 0;
333 sizes
[0] = f
->pix_fmt
.sizeimage
;
339 static int ge2d_buf_prepare(struct vb2_buffer
*vb
)
341 struct ge2d_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
342 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb
);
343 struct ge2d_frame
*f
= get_frame(ctx
, vb
->vb2_queue
->type
);
345 vbuf
->field
= V4L2_FIELD_NONE
;
347 vb2_set_plane_payload(vb
, 0, f
->pix_fmt
.sizeimage
);
352 static void ge2d_buf_queue(struct vb2_buffer
*vb
)
354 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb
);
355 struct ge2d_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
357 v4l2_m2m_buf_queue(ctx
->fh
.m2m_ctx
, vbuf
);
360 static int ge2d_start_streaming(struct vb2_queue
*vq
, unsigned int count
)
362 struct ge2d_ctx
*ctx
= vb2_get_drv_priv(vq
);
364 if (V4L2_TYPE_IS_OUTPUT(vq
->type
))
365 ctx
->sequence_out
= 0;
367 ctx
->sequence_cap
= 0;
372 static void ge2d_stop_streaming(struct vb2_queue
*vq
)
374 struct ge2d_ctx
*ctx
= vb2_get_drv_priv(vq
);
375 struct vb2_v4l2_buffer
*vbuf
;
378 if (V4L2_TYPE_IS_OUTPUT(vq
->type
))
379 vbuf
= v4l2_m2m_src_buf_remove(ctx
->fh
.m2m_ctx
);
381 vbuf
= v4l2_m2m_dst_buf_remove(ctx
->fh
.m2m_ctx
);
384 v4l2_m2m_buf_done(vbuf
, VB2_BUF_STATE_ERROR
);
388 static const struct vb2_ops ge2d_qops
= {
389 .queue_setup
= ge2d_queue_setup
,
390 .buf_prepare
= ge2d_buf_prepare
,
391 .buf_queue
= ge2d_buf_queue
,
392 .start_streaming
= ge2d_start_streaming
,
393 .stop_streaming
= ge2d_stop_streaming
,
397 queue_init(void *priv
, struct vb2_queue
*src_vq
, struct vb2_queue
*dst_vq
)
399 struct ge2d_ctx
*ctx
= priv
;
402 src_vq
->type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
403 src_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
404 src_vq
->drv_priv
= ctx
;
405 src_vq
->ops
= &ge2d_qops
;
406 src_vq
->mem_ops
= &vb2_dma_contig_memops
;
407 src_vq
->buf_struct_size
= sizeof(struct v4l2_m2m_buffer
);
408 src_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
409 src_vq
->lock
= &ctx
->ge2d
->mutex
;
410 src_vq
->dev
= ctx
->ge2d
->v4l2_dev
.dev
;
412 ret
= vb2_queue_init(src_vq
);
416 dst_vq
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
417 dst_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
418 dst_vq
->drv_priv
= ctx
;
419 dst_vq
->ops
= &ge2d_qops
;
420 dst_vq
->mem_ops
= &vb2_dma_contig_memops
;
421 dst_vq
->buf_struct_size
= sizeof(struct v4l2_m2m_buffer
);
422 dst_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
423 dst_vq
->lock
= &ctx
->ge2d
->mutex
;
424 dst_vq
->dev
= ctx
->ge2d
->v4l2_dev
.dev
;
426 return vb2_queue_init(dst_vq
);
430 vidioc_querycap(struct file
*file
, void *priv
, struct v4l2_capability
*cap
)
432 strscpy(cap
->driver
, GE2D_NAME
, sizeof(cap
->driver
));
433 strscpy(cap
->card
, GE2D_NAME
, sizeof(cap
->card
));
434 strscpy(cap
->bus_info
, "platform:" GE2D_NAME
, sizeof(cap
->bus_info
));
439 static int vidioc_enum_fmt(struct file
*file
, void *priv
, struct v4l2_fmtdesc
*f
)
441 const struct ge2d_fmt
*fmt
;
443 if (f
->index
>= NUM_FORMATS
)
446 fmt
= &formats
[f
->index
];
447 f
->pixelformat
= fmt
->fourcc
;
452 static int vidioc_g_selection(struct file
*file
, void *priv
,
453 struct v4l2_selection
*s
)
455 struct ge2d_ctx
*ctx
= priv
;
456 struct ge2d_frame
*f
;
457 bool use_frame
= false;
459 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_OUTPUT
&&
460 s
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
463 f
= get_frame(ctx
, s
->type
);
466 case V4L2_SEL_TGT_COMPOSE_DEFAULT
:
467 case V4L2_SEL_TGT_COMPOSE_BOUNDS
:
468 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
471 case V4L2_SEL_TGT_CROP_DEFAULT
:
472 case V4L2_SEL_TGT_CROP_BOUNDS
:
473 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_OUTPUT
)
476 case V4L2_SEL_TGT_COMPOSE
:
477 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
481 case V4L2_SEL_TGT_CROP
:
482 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_OUTPUT
)
495 s
->r
.width
= f
->pix_fmt
.width
;
496 s
->r
.height
= f
->pix_fmt
.height
;
502 static int vidioc_s_selection(struct file
*file
, void *priv
,
503 struct v4l2_selection
*s
)
505 struct ge2d_ctx
*ctx
= priv
;
506 struct meson_ge2d
*ge2d
= ctx
->ge2d
;
507 struct ge2d_frame
*f
;
510 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_OUTPUT
&&
511 s
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
514 f
= get_frame(ctx
, s
->type
);
517 case V4L2_SEL_TGT_COMPOSE
:
519 * COMPOSE target is only valid for capture buffer type, return
520 * error for output buffer type
522 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
525 case V4L2_SEL_TGT_CROP
:
527 * CROP target is only valid for output buffer type, return
528 * error for capture buffer type
530 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_OUTPUT
)
534 * bound and default crop/compose targets are invalid targets to
541 if (s
->r
.top
< 0 || s
->r
.left
< 0) {
542 v4l2_err(&ge2d
->v4l2_dev
,
543 "doesn't support negative values for top & left.\n");
547 if (s
->r
.left
+ s
->r
.width
> f
->pix_fmt
.width
||
548 s
->r
.top
+ s
->r
.height
> f
->pix_fmt
.height
) {
549 v4l2_err(&ge2d
->v4l2_dev
, "unsupported rectangle value.\n");
558 static void vidioc_setup_cap_fmt(struct ge2d_ctx
*ctx
, struct v4l2_pix_format
*f
)
560 struct ge2d_frame
*frm_out
= get_frame(ctx
, V4L2_BUF_TYPE_VIDEO_OUTPUT
);
562 *f
= frm_out
->pix_fmt
;
565 f
->width
= frm_out
->pix_fmt
.height
;
566 f
->height
= frm_out
->pix_fmt
.width
;
570 static int vidioc_try_fmt_cap(struct file
*file
, void *priv
, struct v4l2_format
*f
)
572 const struct ge2d_fmt
*fmt
= find_fmt(f
);
573 struct ge2d_ctx
*ctx
= priv
;
574 struct v4l2_pix_format fmt_cap
;
576 vidioc_setup_cap_fmt(ctx
, &fmt_cap
);
578 fmt_cap
.pixelformat
= fmt
->fourcc
;
580 fmt_cap
.bytesperline
= max(f
->fmt
.pix
.bytesperline
,
581 ALIGN((fmt_cap
.width
* fmt
->depth
) >> 3, 8));
583 fmt_cap
.sizeimage
= max(f
->fmt
.pix
.sizeimage
,
584 fmt_cap
.height
* fmt_cap
.bytesperline
);
586 f
->fmt
.pix
= fmt_cap
;
591 static int vidioc_s_fmt_cap(struct file
*file
, void *priv
, struct v4l2_format
*f
)
593 struct ge2d_ctx
*ctx
= priv
;
594 struct meson_ge2d
*ge2d
= ctx
->ge2d
;
595 struct vb2_queue
*vq
;
596 struct ge2d_frame
*frm
;
599 /* Adjust all values accordingly to the hardware capabilities
602 ret
= vidioc_try_fmt_cap(file
, priv
, f
);
606 vq
= v4l2_m2m_get_vq(ctx
->fh
.m2m_ctx
, f
->type
);
607 if (vb2_is_busy(vq
)) {
608 v4l2_err(&ge2d
->v4l2_dev
, "queue (%d) bust\n", f
->type
);
612 frm
= get_frame(ctx
, V4L2_BUF_TYPE_VIDEO_CAPTURE
);
614 frm
->pix_fmt
= f
->fmt
.pix
;
615 frm
->fmt
= find_fmt(f
);
616 f
->fmt
.pix
.pixelformat
= frm
->fmt
->fourcc
;
618 /* Reset crop settings */
621 frm
->crop
.width
= frm
->pix_fmt
.width
;
622 frm
->crop
.height
= frm
->pix_fmt
.height
;
627 static int vidioc_g_fmt(struct file
*file
, void *priv
, struct v4l2_format
*f
)
629 struct ge2d_ctx
*ctx
= priv
;
630 struct vb2_queue
*vq
;
631 struct ge2d_frame
*frm
;
633 vq
= v4l2_m2m_get_vq(ctx
->fh
.m2m_ctx
, f
->type
);
637 frm
= get_frame(ctx
, f
->type
);
639 f
->fmt
.pix
= frm
->pix_fmt
;
640 f
->fmt
.pix
.pixelformat
= frm
->fmt
->fourcc
;
645 static int vidioc_try_fmt_out(struct file
*file
, void *priv
, struct v4l2_format
*f
)
647 const struct ge2d_fmt
*fmt
= find_fmt(f
);
649 f
->fmt
.pix
.field
= V4L2_FIELD_NONE
;
650 f
->fmt
.pix
.pixelformat
= fmt
->fourcc
;
652 if (f
->fmt
.pix
.width
> MAX_WIDTH
)
653 f
->fmt
.pix
.width
= MAX_WIDTH
;
654 if (f
->fmt
.pix
.height
> MAX_HEIGHT
)
655 f
->fmt
.pix
.height
= MAX_HEIGHT
;
657 f
->fmt
.pix
.bytesperline
= max(f
->fmt
.pix
.bytesperline
,
658 ALIGN((f
->fmt
.pix
.width
* fmt
->depth
) >> 3, 8));
660 f
->fmt
.pix
.sizeimage
= max(f
->fmt
.pix
.sizeimage
,
661 f
->fmt
.pix
.height
* f
->fmt
.pix
.bytesperline
);
666 static int vidioc_s_fmt_out(struct file
*file
, void *priv
, struct v4l2_format
*f
)
668 struct ge2d_ctx
*ctx
= priv
;
669 struct meson_ge2d
*ge2d
= ctx
->ge2d
;
670 struct vb2_queue
*vq
;
671 struct ge2d_frame
*frm
, *frm_cap
;
674 /* Adjust all values accordingly to the hardware capabilities
677 ret
= vidioc_try_fmt_out(file
, priv
, f
);
681 vq
= v4l2_m2m_get_vq(ctx
->fh
.m2m_ctx
, f
->type
);
682 if (vb2_is_busy(vq
)) {
683 v4l2_err(&ge2d
->v4l2_dev
, "queue (%d) bust\n", f
->type
);
687 frm
= get_frame(ctx
, V4L2_BUF_TYPE_VIDEO_OUTPUT
);
688 frm_cap
= get_frame(ctx
, V4L2_BUF_TYPE_VIDEO_CAPTURE
);
690 frm
->pix_fmt
= f
->fmt
.pix
;
691 frm
->fmt
= find_fmt(f
);
692 f
->fmt
.pix
.pixelformat
= frm
->fmt
->fourcc
;
694 /* Reset crop settings */
697 frm
->crop
.width
= frm
->pix_fmt
.width
;
698 frm
->crop
.height
= frm
->pix_fmt
.height
;
700 /* Propagate settings to capture */
701 vidioc_setup_cap_fmt(ctx
, &frm_cap
->pix_fmt
);
706 static const struct v4l2_ioctl_ops ge2d_ioctl_ops
= {
707 .vidioc_querycap
= vidioc_querycap
,
709 .vidioc_enum_fmt_vid_cap
= vidioc_enum_fmt
,
710 .vidioc_g_fmt_vid_cap
= vidioc_g_fmt
,
711 .vidioc_try_fmt_vid_cap
= vidioc_try_fmt_cap
,
712 .vidioc_s_fmt_vid_cap
= vidioc_s_fmt_cap
,
714 .vidioc_enum_fmt_vid_out
= vidioc_enum_fmt
,
715 .vidioc_g_fmt_vid_out
= vidioc_g_fmt
,
716 .vidioc_try_fmt_vid_out
= vidioc_try_fmt_out
,
717 .vidioc_s_fmt_vid_out
= vidioc_s_fmt_out
,
719 .vidioc_reqbufs
= v4l2_m2m_ioctl_reqbufs
,
720 .vidioc_querybuf
= v4l2_m2m_ioctl_querybuf
,
721 .vidioc_qbuf
= v4l2_m2m_ioctl_qbuf
,
722 .vidioc_dqbuf
= v4l2_m2m_ioctl_dqbuf
,
723 .vidioc_prepare_buf
= v4l2_m2m_ioctl_prepare_buf
,
724 .vidioc_create_bufs
= v4l2_m2m_ioctl_create_bufs
,
725 .vidioc_expbuf
= v4l2_m2m_ioctl_expbuf
,
727 .vidioc_subscribe_event
= v4l2_ctrl_subscribe_event
,
728 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
730 .vidioc_streamon
= v4l2_m2m_ioctl_streamon
,
731 .vidioc_streamoff
= v4l2_m2m_ioctl_streamoff
,
733 .vidioc_g_selection
= vidioc_g_selection
,
734 .vidioc_s_selection
= vidioc_s_selection
,
737 static int ge2d_s_ctrl(struct v4l2_ctrl
*ctrl
)
739 struct ge2d_ctx
*ctx
= container_of(ctrl
->handler
, struct ge2d_ctx
,
741 struct v4l2_pix_format fmt
;
742 struct vb2_queue
*vq
;
746 ctx
->hflip
= ctrl
->val
;
749 ctx
->vflip
= ctrl
->val
;
751 case V4L2_CID_ROTATE
:
752 vq
= v4l2_m2m_get_vq(ctx
->fh
.m2m_ctx
, V4L2_BUF_TYPE_VIDEO_CAPTURE
);
756 if (ctrl
->val
== 90) {
760 } else if (ctrl
->val
== 180) {
764 } else if (ctrl
->val
== 270) {
774 vidioc_setup_cap_fmt(ctx
, &fmt
);
777 * If the rotation parameter changes the OUTPUT frames
778 * parameters, take them in account
780 ctx
->out
.pix_fmt
= fmt
;
788 static const struct v4l2_ctrl_ops ge2d_ctrl_ops
= {
789 .s_ctrl
= ge2d_s_ctrl
,
792 static int ge2d_setup_ctrls(struct ge2d_ctx
*ctx
)
794 struct meson_ge2d
*ge2d
= ctx
->ge2d
;
796 v4l2_ctrl_handler_init(&ctx
->ctrl_handler
, 4);
798 v4l2_ctrl_new_std(&ctx
->ctrl_handler
, &ge2d_ctrl_ops
,
799 V4L2_CID_HFLIP
, 0, 1, 1, 0);
801 v4l2_ctrl_new_std(&ctx
->ctrl_handler
, &ge2d_ctrl_ops
,
802 V4L2_CID_VFLIP
, 0, 1, 1, 0);
804 v4l2_ctrl_new_std(&ctx
->ctrl_handler
, &ge2d_ctrl_ops
,
805 V4L2_CID_ROTATE
, 0, 270, 90, 0);
807 if (ctx
->ctrl_handler
.error
) {
808 int err
= ctx
->ctrl_handler
.error
;
810 v4l2_err(&ge2d
->v4l2_dev
, "%s failed\n", __func__
);
811 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
818 static const struct ge2d_frame def_frame
= {
820 .width
= DEFAULT_WIDTH
,
821 .height
= DEFAULT_HEIGHT
,
822 .bytesperline
= DEFAULT_STRIDE
,
823 .sizeimage
= DEFAULT_STRIDE
* DEFAULT_HEIGHT
,
824 .field
= V4L2_FIELD_NONE
,
826 .crop
.width
= DEFAULT_WIDTH
,
827 .crop
.height
= DEFAULT_HEIGHT
,
831 static int ge2d_open(struct file
*file
)
833 struct meson_ge2d
*ge2d
= video_drvdata(file
);
834 struct ge2d_ctx
*ctx
= NULL
;
837 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
842 /* Set default formats */
844 ctx
->out
= def_frame
;
846 if (mutex_lock_interruptible(&ge2d
->mutex
)) {
850 ctx
->fh
.m2m_ctx
= v4l2_m2m_ctx_init(ge2d
->m2m_dev
, ctx
, &queue_init
);
851 if (IS_ERR(ctx
->fh
.m2m_ctx
)) {
852 ret
= PTR_ERR(ctx
->fh
.m2m_ctx
);
853 mutex_unlock(&ge2d
->mutex
);
857 v4l2_fh_init(&ctx
->fh
, video_devdata(file
));
858 file
->private_data
= &ctx
->fh
;
859 v4l2_fh_add(&ctx
->fh
);
861 ge2d_setup_ctrls(ctx
);
863 /* Write the default values to the ctx struct */
864 v4l2_ctrl_handler_setup(&ctx
->ctrl_handler
);
866 ctx
->fh
.ctrl_handler
= &ctx
->ctrl_handler
;
867 mutex_unlock(&ge2d
->mutex
);
872 static int ge2d_release(struct file
*file
)
874 struct ge2d_ctx
*ctx
=
875 container_of(file
->private_data
, struct ge2d_ctx
, fh
);
876 struct meson_ge2d
*ge2d
= ctx
->ge2d
;
878 mutex_lock(&ge2d
->mutex
);
880 v4l2_m2m_ctx_release(ctx
->fh
.m2m_ctx
);
882 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
883 v4l2_fh_del(&ctx
->fh
);
884 v4l2_fh_exit(&ctx
->fh
);
887 mutex_unlock(&ge2d
->mutex
);
892 static const struct v4l2_file_operations ge2d_fops
= {
893 .owner
= THIS_MODULE
,
895 .release
= ge2d_release
,
896 .poll
= v4l2_m2m_fop_poll
,
897 .unlocked_ioctl
= video_ioctl2
,
898 .mmap
= v4l2_m2m_fop_mmap
,
901 static const struct video_device ge2d_videodev
= {
902 .name
= "meson-ge2d",
904 .ioctl_ops
= &ge2d_ioctl_ops
,
906 .release
= video_device_release
,
907 .vfl_dir
= VFL_DIR_M2M
,
908 .device_caps
= V4L2_CAP_VIDEO_M2M
| V4L2_CAP_STREAMING
,
911 static const struct regmap_config meson_ge2d_regmap_conf
= {
915 .max_register
= GE2D_SRC2_STRIDE_CTRL
,
918 static int ge2d_probe(struct platform_device
*pdev
)
920 struct reset_control
*rst
;
921 struct video_device
*vfd
;
922 struct meson_ge2d
*ge2d
;
927 if (!pdev
->dev
.of_node
)
930 ge2d
= devm_kzalloc(&pdev
->dev
, sizeof(*ge2d
), GFP_KERNEL
);
934 ge2d
->dev
= &pdev
->dev
;
935 mutex_init(&ge2d
->mutex
);
937 regs
= devm_platform_ioremap_resource(pdev
, 0);
939 return PTR_ERR(regs
);
941 ge2d
->map
= devm_regmap_init_mmio(ge2d
->dev
, regs
,
942 &meson_ge2d_regmap_conf
);
943 if (IS_ERR(ge2d
->map
))
944 return PTR_ERR(ge2d
->map
);
946 irq
= platform_get_irq(pdev
, 0);
947 ret
= devm_request_irq(ge2d
->dev
, irq
, ge2d_isr
, 0,
948 dev_name(ge2d
->dev
), ge2d
);
950 dev_err(ge2d
->dev
, "failed to request irq\n");
954 rst
= devm_reset_control_get(ge2d
->dev
, NULL
);
956 dev_err(ge2d
->dev
, "failed to get core reset controller\n");
960 ge2d
->clk
= devm_clk_get(ge2d
->dev
, NULL
);
961 if (IS_ERR(ge2d
->clk
)) {
962 dev_err(ge2d
->dev
, "failed to get clock\n");
963 return PTR_ERR(ge2d
->clk
);
966 reset_control_assert(rst
);
968 reset_control_deassert(rst
);
970 ret
= clk_prepare_enable(ge2d
->clk
);
972 dev_err(ge2d
->dev
, "Cannot enable ge2d sclk: %d\n", ret
);
976 ret
= v4l2_device_register(&pdev
->dev
, &ge2d
->v4l2_dev
);
980 vfd
= video_device_alloc();
982 v4l2_err(&ge2d
->v4l2_dev
, "Failed to allocate video device\n");
987 *vfd
= ge2d_videodev
;
988 vfd
->lock
= &ge2d
->mutex
;
989 vfd
->v4l2_dev
= &ge2d
->v4l2_dev
;
991 video_set_drvdata(vfd
, ge2d
);
994 platform_set_drvdata(pdev
, ge2d
);
995 ge2d
->m2m_dev
= v4l2_m2m_init(&ge2d_m2m_ops
);
996 if (IS_ERR(ge2d
->m2m_dev
)) {
997 v4l2_err(&ge2d
->v4l2_dev
, "Failed to init mem2mem device\n");
998 ret
= PTR_ERR(ge2d
->m2m_dev
);
1002 ret
= video_register_device(vfd
, VFL_TYPE_VIDEO
, -1);
1004 v4l2_err(&ge2d
->v4l2_dev
, "Failed to register video device\n");
1008 v4l2_info(&ge2d
->v4l2_dev
, "Registered %s as /dev/%s\n",
1009 vfd
->name
, video_device_node_name(vfd
));
1014 v4l2_m2m_release(ge2d
->m2m_dev
);
1016 video_device_release(ge2d
->vfd
);
1018 v4l2_device_unregister(&ge2d
->v4l2_dev
);
1020 clk_disable_unprepare(ge2d
->clk
);
1025 static void ge2d_remove(struct platform_device
*pdev
)
1027 struct meson_ge2d
*ge2d
= platform_get_drvdata(pdev
);
1029 video_unregister_device(ge2d
->vfd
);
1030 v4l2_m2m_release(ge2d
->m2m_dev
);
1031 v4l2_device_unregister(&ge2d
->v4l2_dev
);
1032 clk_disable_unprepare(ge2d
->clk
);
1035 static const struct of_device_id meson_ge2d_match
[] = {
1037 .compatible
= "amlogic,axg-ge2d",
1042 MODULE_DEVICE_TABLE(of
, meson_ge2d_match
);
1044 static struct platform_driver ge2d_drv
= {
1045 .probe
= ge2d_probe
,
1046 .remove
= ge2d_remove
,
1048 .name
= "meson-ge2d",
1049 .of_match_table
= meson_ge2d_match
,
1053 module_platform_driver(ge2d_drv
);
1055 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
1056 MODULE_DESCRIPTION("Amlogic 2D Graphic Acceleration Unit");
1057 MODULE_LICENSE("GPL");