• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Samsung S5P G2D - 2D Graphics Accelerator Driver
3  *
4  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
5  * Kamil Debski, <k.debski@samsung.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by the
9  * Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version
11  */
12 
13 #include <linux/module.h>
14 #include <linux/fs.h>
15 #include <linux/version.h>
16 #include <linux/timer.h>
17 #include <linux/sched.h>
18 #include <linux/slab.h>
19 #include <linux/clk.h>
20 #include <linux/interrupt.h>
21 #include <linux/of.h>
22 
23 #include <linux/platform_device.h>
24 #include <media/v4l2-mem2mem.h>
25 #include <media/v4l2-device.h>
26 #include <media/v4l2-ioctl.h>
27 #include <media/videobuf2-core.h>
28 #include <media/videobuf2-dma-contig.h>
29 
30 #include "g2d.h"
31 #include "g2d-regs.h"
32 
33 #define fh2ctx(__fh) container_of(__fh, struct g2d_ctx, fh)
34 
35 static struct g2d_fmt formats[] = {
36 	{
37 		.name	= "XRGB_8888",
38 		.fourcc	= V4L2_PIX_FMT_RGB32,
39 		.depth	= 32,
40 		.hw	= COLOR_MODE(ORDER_XRGB, MODE_XRGB_8888),
41 	},
42 	{
43 		.name	= "RGB_565",
44 		.fourcc	= V4L2_PIX_FMT_RGB565X,
45 		.depth	= 16,
46 		.hw	= COLOR_MODE(ORDER_XRGB, MODE_RGB_565),
47 	},
48 	{
49 		.name	= "XRGB_1555",
50 		.fourcc	= V4L2_PIX_FMT_RGB555X,
51 		.depth	= 16,
52 		.hw	= COLOR_MODE(ORDER_XRGB, MODE_XRGB_1555),
53 	},
54 	{
55 		.name	= "XRGB_4444",
56 		.fourcc	= V4L2_PIX_FMT_RGB444,
57 		.depth	= 16,
58 		.hw	= COLOR_MODE(ORDER_XRGB, MODE_XRGB_4444),
59 	},
60 	{
61 		.name	= "PACKED_RGB_888",
62 		.fourcc	= V4L2_PIX_FMT_RGB24,
63 		.depth	= 24,
64 		.hw	= COLOR_MODE(ORDER_XRGB, MODE_PACKED_RGB_888),
65 	},
66 };
67 #define NUM_FORMATS ARRAY_SIZE(formats)
68 
69 static struct g2d_frame def_frame = {
70 	.width		= DEFAULT_WIDTH,
71 	.height		= DEFAULT_HEIGHT,
72 	.c_width	= DEFAULT_WIDTH,
73 	.c_height	= DEFAULT_HEIGHT,
74 	.o_width	= 0,
75 	.o_height	= 0,
76 	.fmt		= &formats[0],
77 	.right		= DEFAULT_WIDTH,
78 	.bottom		= DEFAULT_HEIGHT,
79 };
80 
find_fmt(struct v4l2_format * f)81 static struct g2d_fmt *find_fmt(struct v4l2_format *f)
82 {
83 	unsigned int i;
84 	for (i = 0; i < NUM_FORMATS; i++) {
85 		if (formats[i].fourcc == f->fmt.pix.pixelformat)
86 			return &formats[i];
87 	}
88 	return NULL;
89 }
90 
91 
get_frame(struct g2d_ctx * ctx,enum v4l2_buf_type type)92 static struct g2d_frame *get_frame(struct g2d_ctx *ctx,
93 							enum v4l2_buf_type type)
94 {
95 	switch (type) {
96 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
97 		return &ctx->in;
98 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
99 		return &ctx->out;
100 	default:
101 		return ERR_PTR(-EINVAL);
102 	}
103 }
104 
g2d_queue_setup(struct vb2_queue * vq,const struct v4l2_format * fmt,unsigned int * nbuffers,unsigned int * nplanes,unsigned int sizes[],void * alloc_ctxs[])105 static int g2d_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
106 			   unsigned int *nbuffers, unsigned int *nplanes,
107 			   unsigned int sizes[], void *alloc_ctxs[])
108 {
109 	struct g2d_ctx *ctx = vb2_get_drv_priv(vq);
110 	struct g2d_frame *f = get_frame(ctx, vq->type);
111 
112 	if (IS_ERR(f))
113 		return PTR_ERR(f);
114 
115 	sizes[0] = f->size;
116 	*nplanes = 1;
117 	alloc_ctxs[0] = ctx->dev->alloc_ctx;
118 
119 	if (*nbuffers == 0)
120 		*nbuffers = 1;
121 
122 	return 0;
123 }
124 
g2d_buf_prepare(struct vb2_buffer * vb)125 static int g2d_buf_prepare(struct vb2_buffer *vb)
126 {
127 	struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
128 	struct g2d_frame *f = get_frame(ctx, vb->vb2_queue->type);
129 
130 	if (IS_ERR(f))
131 		return PTR_ERR(f);
132 	vb2_set_plane_payload(vb, 0, f->size);
133 	return 0;
134 }
135 
g2d_buf_queue(struct vb2_buffer * vb)136 static void g2d_buf_queue(struct vb2_buffer *vb)
137 {
138 	struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
139 	v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
140 }
141 
142 
143 static struct vb2_ops g2d_qops = {
144 	.queue_setup	= g2d_queue_setup,
145 	.buf_prepare	= g2d_buf_prepare,
146 	.buf_queue	= g2d_buf_queue,
147 };
148 
queue_init(void * priv,struct vb2_queue * src_vq,struct vb2_queue * dst_vq)149 static int queue_init(void *priv, struct vb2_queue *src_vq,
150 						struct vb2_queue *dst_vq)
151 {
152 	struct g2d_ctx *ctx = priv;
153 	int ret;
154 
155 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
156 	src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
157 	src_vq->drv_priv = ctx;
158 	src_vq->ops = &g2d_qops;
159 	src_vq->mem_ops = &vb2_dma_contig_memops;
160 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
161 	src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
162 
163 	ret = vb2_queue_init(src_vq);
164 	if (ret)
165 		return ret;
166 
167 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
168 	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
169 	dst_vq->drv_priv = ctx;
170 	dst_vq->ops = &g2d_qops;
171 	dst_vq->mem_ops = &vb2_dma_contig_memops;
172 	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
173 	dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
174 
175 	return vb2_queue_init(dst_vq);
176 }
177 
g2d_s_ctrl(struct v4l2_ctrl * ctrl)178 static int g2d_s_ctrl(struct v4l2_ctrl *ctrl)
179 {
180 	struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx,
181 								ctrl_handler);
182 	unsigned long flags;
183 
184 	spin_lock_irqsave(&ctx->dev->ctrl_lock, flags);
185 	switch (ctrl->id) {
186 	case V4L2_CID_COLORFX:
187 		if (ctrl->val == V4L2_COLORFX_NEGATIVE)
188 			ctx->rop = ROP4_INVERT;
189 		else
190 			ctx->rop = ROP4_COPY;
191 		break;
192 
193 	case V4L2_CID_HFLIP:
194 		ctx->flip = ctx->ctrl_hflip->val | (ctx->ctrl_vflip->val << 1);
195 		break;
196 
197 	}
198 	spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags);
199 	return 0;
200 }
201 
202 static const struct v4l2_ctrl_ops g2d_ctrl_ops = {
203 	.s_ctrl		= g2d_s_ctrl,
204 };
205 
g2d_setup_ctrls(struct g2d_ctx * ctx)206 static int g2d_setup_ctrls(struct g2d_ctx *ctx)
207 {
208 	struct g2d_dev *dev = ctx->dev;
209 
210 	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
211 
212 	ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops,
213 						V4L2_CID_HFLIP, 0, 1, 1, 0);
214 
215 	ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops,
216 						V4L2_CID_VFLIP, 0, 1, 1, 0);
217 
218 	v4l2_ctrl_new_std_menu(
219 		&ctx->ctrl_handler,
220 		&g2d_ctrl_ops,
221 		V4L2_CID_COLORFX,
222 		V4L2_COLORFX_NEGATIVE,
223 		~((1 << V4L2_COLORFX_NONE) | (1 << V4L2_COLORFX_NEGATIVE)),
224 		V4L2_COLORFX_NONE);
225 
226 	if (ctx->ctrl_handler.error) {
227 		int err = ctx->ctrl_handler.error;
228 		v4l2_err(&dev->v4l2_dev, "g2d_setup_ctrls failed\n");
229 		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
230 		return err;
231 	}
232 
233 	v4l2_ctrl_cluster(2, &ctx->ctrl_hflip);
234 
235 	return 0;
236 }
237 
g2d_open(struct file * file)238 static int g2d_open(struct file *file)
239 {
240 	struct g2d_dev *dev = video_drvdata(file);
241 	struct g2d_ctx *ctx = NULL;
242 	int ret = 0;
243 
244 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
245 	if (!ctx)
246 		return -ENOMEM;
247 	ctx->dev = dev;
248 	/* Set default formats */
249 	ctx->in		= def_frame;
250 	ctx->out	= def_frame;
251 
252 	if (mutex_lock_interruptible(&dev->mutex)) {
253 		kfree(ctx);
254 		return -ERESTARTSYS;
255 	}
256 	ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
257 	if (IS_ERR(ctx->m2m_ctx)) {
258 		ret = PTR_ERR(ctx->m2m_ctx);
259 		mutex_unlock(&dev->mutex);
260 		kfree(ctx);
261 		return ret;
262 	}
263 	v4l2_fh_init(&ctx->fh, video_devdata(file));
264 	file->private_data = &ctx->fh;
265 	v4l2_fh_add(&ctx->fh);
266 
267 	g2d_setup_ctrls(ctx);
268 
269 	/* Write the default values to the ctx struct */
270 	v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
271 
272 	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
273 	mutex_unlock(&dev->mutex);
274 
275 	v4l2_info(&dev->v4l2_dev, "instance opened\n");
276 	return 0;
277 }
278 
g2d_release(struct file * file)279 static int g2d_release(struct file *file)
280 {
281 	struct g2d_dev *dev = video_drvdata(file);
282 	struct g2d_ctx *ctx = fh2ctx(file->private_data);
283 
284 	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
285 	v4l2_fh_del(&ctx->fh);
286 	v4l2_fh_exit(&ctx->fh);
287 	kfree(ctx);
288 	v4l2_info(&dev->v4l2_dev, "instance closed\n");
289 	return 0;
290 }
291 
292 
vidioc_querycap(struct file * file,void * priv,struct v4l2_capability * cap)293 static int vidioc_querycap(struct file *file, void *priv,
294 				struct v4l2_capability *cap)
295 {
296 	strncpy(cap->driver, G2D_NAME, sizeof(cap->driver) - 1);
297 	strncpy(cap->card, G2D_NAME, sizeof(cap->card) - 1);
298 	cap->bus_info[0] = 0;
299 	cap->version = KERNEL_VERSION(1, 0, 0);
300 	/*
301 	 * This is only a mem-to-mem video device. The capture and output
302 	 * device capability flags are left only for backward compatibility
303 	 * and are scheduled for removal.
304 	 */
305 	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
306 			    V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
307 	return 0;
308 }
309 
vidioc_enum_fmt(struct file * file,void * prv,struct v4l2_fmtdesc * f)310 static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f)
311 {
312 	struct g2d_fmt *fmt;
313 	if (f->index >= NUM_FORMATS)
314 		return -EINVAL;
315 	fmt = &formats[f->index];
316 	f->pixelformat = fmt->fourcc;
317 	strncpy(f->description, fmt->name, sizeof(f->description) - 1);
318 	return 0;
319 }
320 
vidioc_g_fmt(struct file * file,void * prv,struct v4l2_format * f)321 static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
322 {
323 	struct g2d_ctx *ctx = prv;
324 	struct vb2_queue *vq;
325 	struct g2d_frame *frm;
326 
327 	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
328 	if (!vq)
329 		return -EINVAL;
330 	frm = get_frame(ctx, f->type);
331 	if (IS_ERR(frm))
332 		return PTR_ERR(frm);
333 
334 	f->fmt.pix.width		= frm->width;
335 	f->fmt.pix.height		= frm->height;
336 	f->fmt.pix.field		= V4L2_FIELD_NONE;
337 	f->fmt.pix.pixelformat		= frm->fmt->fourcc;
338 	f->fmt.pix.bytesperline		= (frm->width * frm->fmt->depth) >> 3;
339 	f->fmt.pix.sizeimage		= frm->size;
340 	return 0;
341 }
342 
vidioc_try_fmt(struct file * file,void * prv,struct v4l2_format * f)343 static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f)
344 {
345 	struct g2d_fmt *fmt;
346 	enum v4l2_field *field;
347 
348 	fmt = find_fmt(f);
349 	if (!fmt)
350 		return -EINVAL;
351 
352 	field = &f->fmt.pix.field;
353 	if (*field == V4L2_FIELD_ANY)
354 		*field = V4L2_FIELD_NONE;
355 	else if (*field != V4L2_FIELD_NONE)
356 		return -EINVAL;
357 
358 	if (f->fmt.pix.width > MAX_WIDTH)
359 		f->fmt.pix.width = MAX_WIDTH;
360 	if (f->fmt.pix.height > MAX_HEIGHT)
361 		f->fmt.pix.height = MAX_HEIGHT;
362 
363 	if (f->fmt.pix.width < 1)
364 		f->fmt.pix.width = 1;
365 	if (f->fmt.pix.height < 1)
366 		f->fmt.pix.height = 1;
367 
368 	f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
369 	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
370 	return 0;
371 }
372 
vidioc_s_fmt(struct file * file,void * prv,struct v4l2_format * f)373 static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
374 {
375 	struct g2d_ctx *ctx = prv;
376 	struct g2d_dev *dev = ctx->dev;
377 	struct vb2_queue *vq;
378 	struct g2d_frame *frm;
379 	struct g2d_fmt *fmt;
380 	int ret = 0;
381 
382 	/* Adjust all values accordingly to the hardware capabilities
383 	 * and chosen format. */
384 	ret = vidioc_try_fmt(file, prv, f);
385 	if (ret)
386 		return ret;
387 	vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
388 	if (vb2_is_busy(vq)) {
389 		v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type);
390 		return -EBUSY;
391 	}
392 	frm = get_frame(ctx, f->type);
393 	if (IS_ERR(frm))
394 		return PTR_ERR(frm);
395 	fmt = find_fmt(f);
396 	if (!fmt)
397 		return -EINVAL;
398 	frm->width	= f->fmt.pix.width;
399 	frm->height	= f->fmt.pix.height;
400 	frm->size	= f->fmt.pix.sizeimage;
401 	/* Reset crop settings */
402 	frm->o_width	= 0;
403 	frm->o_height	= 0;
404 	frm->c_width	= frm->width;
405 	frm->c_height	= frm->height;
406 	frm->right	= frm->width;
407 	frm->bottom	= frm->height;
408 	frm->fmt	= fmt;
409 	frm->stride	= f->fmt.pix.bytesperline;
410 	return 0;
411 }
412 
g2d_poll(struct file * file,struct poll_table_struct * wait)413 static unsigned int g2d_poll(struct file *file, struct poll_table_struct *wait)
414 {
415 	struct g2d_ctx *ctx = fh2ctx(file->private_data);
416 	struct g2d_dev *dev = ctx->dev;
417 	unsigned int res;
418 
419 	mutex_lock(&dev->mutex);
420 	res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
421 	mutex_unlock(&dev->mutex);
422 	return res;
423 }
424 
g2d_mmap(struct file * file,struct vm_area_struct * vma)425 static int g2d_mmap(struct file *file, struct vm_area_struct *vma)
426 {
427 	struct g2d_ctx *ctx = fh2ctx(file->private_data);
428 	struct g2d_dev *dev = ctx->dev;
429 	int ret;
430 
431 	if (mutex_lock_interruptible(&dev->mutex))
432 		return -ERESTARTSYS;
433 	ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
434 	mutex_unlock(&dev->mutex);
435 	return ret;
436 }
437 
vidioc_reqbufs(struct file * file,void * priv,struct v4l2_requestbuffers * reqbufs)438 static int vidioc_reqbufs(struct file *file, void *priv,
439 			struct v4l2_requestbuffers *reqbufs)
440 {
441 	struct g2d_ctx *ctx = priv;
442 	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
443 }
444 
vidioc_querybuf(struct file * file,void * priv,struct v4l2_buffer * buf)445 static int vidioc_querybuf(struct file *file, void *priv,
446 			struct v4l2_buffer *buf)
447 {
448 	struct g2d_ctx *ctx = priv;
449 	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
450 }
451 
vidioc_qbuf(struct file * file,void * priv,struct v4l2_buffer * buf)452 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
453 {
454 	struct g2d_ctx *ctx = priv;
455 	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
456 }
457 
vidioc_dqbuf(struct file * file,void * priv,struct v4l2_buffer * buf)458 static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
459 {
460 	struct g2d_ctx *ctx = priv;
461 	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
462 }
463 
464 
vidioc_streamon(struct file * file,void * priv,enum v4l2_buf_type type)465 static int vidioc_streamon(struct file *file, void *priv,
466 					enum v4l2_buf_type type)
467 {
468 	struct g2d_ctx *ctx = priv;
469 	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
470 }
471 
vidioc_streamoff(struct file * file,void * priv,enum v4l2_buf_type type)472 static int vidioc_streamoff(struct file *file, void *priv,
473 					enum v4l2_buf_type type)
474 {
475 	struct g2d_ctx *ctx = priv;
476 	return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
477 }
478 
vidioc_cropcap(struct file * file,void * priv,struct v4l2_cropcap * cr)479 static int vidioc_cropcap(struct file *file, void *priv,
480 					struct v4l2_cropcap *cr)
481 {
482 	struct g2d_ctx *ctx = priv;
483 	struct g2d_frame *f;
484 
485 	f = get_frame(ctx, cr->type);
486 	if (IS_ERR(f))
487 		return PTR_ERR(f);
488 
489 	cr->bounds.left		= 0;
490 	cr->bounds.top		= 0;
491 	cr->bounds.width	= f->width;
492 	cr->bounds.height	= f->height;
493 	cr->defrect		= cr->bounds;
494 	return 0;
495 }
496 
vidioc_g_crop(struct file * file,void * prv,struct v4l2_crop * cr)497 static int vidioc_g_crop(struct file *file, void *prv, struct v4l2_crop *cr)
498 {
499 	struct g2d_ctx *ctx = prv;
500 	struct g2d_frame *f;
501 
502 	f = get_frame(ctx, cr->type);
503 	if (IS_ERR(f))
504 		return PTR_ERR(f);
505 
506 	cr->c.left	= f->o_height;
507 	cr->c.top	= f->o_width;
508 	cr->c.width	= f->c_width;
509 	cr->c.height	= f->c_height;
510 	return 0;
511 }
512 
vidioc_try_crop(struct file * file,void * prv,const struct v4l2_crop * cr)513 static int vidioc_try_crop(struct file *file, void *prv, const struct v4l2_crop *cr)
514 {
515 	struct g2d_ctx *ctx = prv;
516 	struct g2d_dev *dev = ctx->dev;
517 	struct g2d_frame *f;
518 
519 	f = get_frame(ctx, cr->type);
520 	if (IS_ERR(f))
521 		return PTR_ERR(f);
522 
523 	if (cr->c.top < 0 || cr->c.left < 0) {
524 		v4l2_err(&dev->v4l2_dev,
525 			"doesn't support negative values for top & left\n");
526 		return -EINVAL;
527 	}
528 
529 	return 0;
530 }
531 
vidioc_s_crop(struct file * file,void * prv,const struct v4l2_crop * cr)532 static int vidioc_s_crop(struct file *file, void *prv, const struct v4l2_crop *cr)
533 {
534 	struct g2d_ctx *ctx = prv;
535 	struct g2d_frame *f;
536 	int ret;
537 
538 	ret = vidioc_try_crop(file, prv, cr);
539 	if (ret)
540 		return ret;
541 	f = get_frame(ctx, cr->type);
542 	if (IS_ERR(f))
543 		return PTR_ERR(f);
544 
545 	f->c_width	= cr->c.width;
546 	f->c_height	= cr->c.height;
547 	f->o_width	= cr->c.left;
548 	f->o_height	= cr->c.top;
549 	f->bottom	= f->o_height + f->c_height;
550 	f->right	= f->o_width + f->c_width;
551 	return 0;
552 }
553 
g2d_lock(void * prv)554 static void g2d_lock(void *prv)
555 {
556 	struct g2d_ctx *ctx = prv;
557 	struct g2d_dev *dev = ctx->dev;
558 	mutex_lock(&dev->mutex);
559 }
560 
g2d_unlock(void * prv)561 static void g2d_unlock(void *prv)
562 {
563 	struct g2d_ctx *ctx = prv;
564 	struct g2d_dev *dev = ctx->dev;
565 	mutex_unlock(&dev->mutex);
566 }
567 
job_abort(void * prv)568 static void job_abort(void *prv)
569 {
570 	struct g2d_ctx *ctx = prv;
571 	struct g2d_dev *dev = ctx->dev;
572 	int ret;
573 
574 	if (dev->curr == NULL) /* No job currently running */
575 		return;
576 
577 	ret = wait_event_timeout(dev->irq_queue,
578 		dev->curr == NULL,
579 		msecs_to_jiffies(G2D_TIMEOUT));
580 }
581 
device_run(void * prv)582 static void device_run(void *prv)
583 {
584 	struct g2d_ctx *ctx = prv;
585 	struct g2d_dev *dev = ctx->dev;
586 	struct vb2_buffer *src, *dst;
587 	unsigned long flags;
588 	u32 cmd = 0;
589 
590 	dev->curr = ctx;
591 
592 	src = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
593 	dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
594 
595 	clk_enable(dev->gate);
596 	g2d_reset(dev);
597 
598 	spin_lock_irqsave(&dev->ctrl_lock, flags);
599 
600 	g2d_set_src_size(dev, &ctx->in);
601 	g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0));
602 
603 	g2d_set_dst_size(dev, &ctx->out);
604 	g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0));
605 
606 	g2d_set_rop4(dev, ctx->rop);
607 	g2d_set_flip(dev, ctx->flip);
608 
609 	if (ctx->in.c_width != ctx->out.c_width ||
610 		ctx->in.c_height != ctx->out.c_height) {
611 		if (dev->variant->hw_rev == TYPE_G2D_3X)
612 			cmd |= CMD_V3_ENABLE_STRETCH;
613 		else
614 			g2d_set_v41_stretch(dev, &ctx->in, &ctx->out);
615 	}
616 
617 	g2d_set_cmd(dev, cmd);
618 	g2d_start(dev);
619 
620 	spin_unlock_irqrestore(&dev->ctrl_lock, flags);
621 }
622 
g2d_isr(int irq,void * prv)623 static irqreturn_t g2d_isr(int irq, void *prv)
624 {
625 	struct g2d_dev *dev = prv;
626 	struct g2d_ctx *ctx = dev->curr;
627 	struct vb2_buffer *src, *dst;
628 
629 	g2d_clear_int(dev);
630 	clk_disable(dev->gate);
631 
632 	BUG_ON(ctx == NULL);
633 
634 	src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
635 	dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
636 
637 	BUG_ON(src == NULL);
638 	BUG_ON(dst == NULL);
639 
640 	dst->v4l2_buf.timecode = src->v4l2_buf.timecode;
641 	dst->v4l2_buf.timestamp = src->v4l2_buf.timestamp;
642 
643 	v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
644 	v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
645 	v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
646 
647 	dev->curr = NULL;
648 	wake_up(&dev->irq_queue);
649 	return IRQ_HANDLED;
650 }
651 
652 static const struct v4l2_file_operations g2d_fops = {
653 	.owner		= THIS_MODULE,
654 	.open		= g2d_open,
655 	.release	= g2d_release,
656 	.poll		= g2d_poll,
657 	.unlocked_ioctl	= video_ioctl2,
658 	.mmap		= g2d_mmap,
659 };
660 
661 static const struct v4l2_ioctl_ops g2d_ioctl_ops = {
662 	.vidioc_querycap	= vidioc_querycap,
663 
664 	.vidioc_enum_fmt_vid_cap	= vidioc_enum_fmt,
665 	.vidioc_g_fmt_vid_cap		= vidioc_g_fmt,
666 	.vidioc_try_fmt_vid_cap		= vidioc_try_fmt,
667 	.vidioc_s_fmt_vid_cap		= vidioc_s_fmt,
668 
669 	.vidioc_enum_fmt_vid_out	= vidioc_enum_fmt,
670 	.vidioc_g_fmt_vid_out		= vidioc_g_fmt,
671 	.vidioc_try_fmt_vid_out		= vidioc_try_fmt,
672 	.vidioc_s_fmt_vid_out		= vidioc_s_fmt,
673 
674 	.vidioc_reqbufs			= vidioc_reqbufs,
675 	.vidioc_querybuf		= vidioc_querybuf,
676 
677 	.vidioc_qbuf			= vidioc_qbuf,
678 	.vidioc_dqbuf			= vidioc_dqbuf,
679 
680 	.vidioc_streamon		= vidioc_streamon,
681 	.vidioc_streamoff		= vidioc_streamoff,
682 
683 	.vidioc_g_crop			= vidioc_g_crop,
684 	.vidioc_s_crop			= vidioc_s_crop,
685 	.vidioc_cropcap			= vidioc_cropcap,
686 };
687 
688 static struct video_device g2d_videodev = {
689 	.name		= G2D_NAME,
690 	.fops		= &g2d_fops,
691 	.ioctl_ops	= &g2d_ioctl_ops,
692 	.minor		= -1,
693 	.release	= video_device_release,
694 	.vfl_dir	= VFL_DIR_M2M,
695 };
696 
697 static struct v4l2_m2m_ops g2d_m2m_ops = {
698 	.device_run	= device_run,
699 	.job_abort	= job_abort,
700 	.lock		= g2d_lock,
701 	.unlock		= g2d_unlock,
702 };
703 
704 static const struct of_device_id exynos_g2d_match[];
705 
g2d_probe(struct platform_device * pdev)706 static int g2d_probe(struct platform_device *pdev)
707 {
708 	struct g2d_dev *dev;
709 	struct video_device *vfd;
710 	struct resource *res;
711 	const struct of_device_id *of_id;
712 	int ret = 0;
713 
714 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
715 	if (!dev)
716 		return -ENOMEM;
717 
718 	spin_lock_init(&dev->ctrl_lock);
719 	mutex_init(&dev->mutex);
720 	atomic_set(&dev->num_inst, 0);
721 	init_waitqueue_head(&dev->irq_queue);
722 
723 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
724 
725 	dev->regs = devm_ioremap_resource(&pdev->dev, res);
726 	if (IS_ERR(dev->regs))
727 		return PTR_ERR(dev->regs);
728 
729 	dev->clk = clk_get(&pdev->dev, "sclk_fimg2d");
730 	if (IS_ERR(dev->clk)) {
731 		dev_err(&pdev->dev, "failed to get g2d clock\n");
732 		return -ENXIO;
733 	}
734 
735 	ret = clk_prepare(dev->clk);
736 	if (ret) {
737 		dev_err(&pdev->dev, "failed to prepare g2d clock\n");
738 		goto put_clk;
739 	}
740 
741 	dev->gate = clk_get(&pdev->dev, "fimg2d");
742 	if (IS_ERR(dev->gate)) {
743 		dev_err(&pdev->dev, "failed to get g2d clock gate\n");
744 		ret = -ENXIO;
745 		goto unprep_clk;
746 	}
747 
748 	ret = clk_prepare(dev->gate);
749 	if (ret) {
750 		dev_err(&pdev->dev, "failed to prepare g2d clock gate\n");
751 		goto put_clk_gate;
752 	}
753 
754 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
755 	if (!res) {
756 		dev_err(&pdev->dev, "failed to find IRQ\n");
757 		ret = -ENXIO;
758 		goto unprep_clk_gate;
759 	}
760 
761 	dev->irq = res->start;
762 
763 	ret = devm_request_irq(&pdev->dev, dev->irq, g2d_isr,
764 						0, pdev->name, dev);
765 	if (ret) {
766 		dev_err(&pdev->dev, "failed to install IRQ\n");
767 		goto put_clk_gate;
768 	}
769 
770 	dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
771 	if (IS_ERR(dev->alloc_ctx)) {
772 		ret = PTR_ERR(dev->alloc_ctx);
773 		goto unprep_clk_gate;
774 	}
775 
776 	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
777 	if (ret)
778 		goto alloc_ctx_cleanup;
779 	vfd = video_device_alloc();
780 	if (!vfd) {
781 		v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
782 		ret = -ENOMEM;
783 		goto unreg_v4l2_dev;
784 	}
785 	*vfd = g2d_videodev;
786 	vfd->lock = &dev->mutex;
787 	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
788 	if (ret) {
789 		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
790 		goto rel_vdev;
791 	}
792 	video_set_drvdata(vfd, dev);
793 	snprintf(vfd->name, sizeof(vfd->name), "%s", g2d_videodev.name);
794 	dev->vfd = vfd;
795 	v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n",
796 								vfd->num);
797 	platform_set_drvdata(pdev, dev);
798 	dev->m2m_dev = v4l2_m2m_init(&g2d_m2m_ops);
799 	if (IS_ERR(dev->m2m_dev)) {
800 		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
801 		ret = PTR_ERR(dev->m2m_dev);
802 		goto unreg_video_dev;
803 	}
804 
805 	def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
806 
807 	if (!pdev->dev.of_node) {
808 		dev->variant = g2d_get_drv_data(pdev);
809 	} else {
810 		of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node);
811 		if (!of_id) {
812 			ret = -ENODEV;
813 			goto unreg_video_dev;
814 		}
815 		dev->variant = (struct g2d_variant *)of_id->data;
816 	}
817 
818 	return 0;
819 
820 unreg_video_dev:
821 	video_unregister_device(dev->vfd);
822 rel_vdev:
823 	video_device_release(vfd);
824 unreg_v4l2_dev:
825 	v4l2_device_unregister(&dev->v4l2_dev);
826 alloc_ctx_cleanup:
827 	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
828 unprep_clk_gate:
829 	clk_unprepare(dev->gate);
830 put_clk_gate:
831 	clk_put(dev->gate);
832 unprep_clk:
833 	clk_unprepare(dev->clk);
834 put_clk:
835 	clk_put(dev->clk);
836 
837 	return ret;
838 }
839 
g2d_remove(struct platform_device * pdev)840 static int g2d_remove(struct platform_device *pdev)
841 {
842 	struct g2d_dev *dev = (struct g2d_dev *)platform_get_drvdata(pdev);
843 
844 	v4l2_info(&dev->v4l2_dev, "Removing " G2D_NAME);
845 	v4l2_m2m_release(dev->m2m_dev);
846 	video_unregister_device(dev->vfd);
847 	v4l2_device_unregister(&dev->v4l2_dev);
848 	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
849 	clk_unprepare(dev->gate);
850 	clk_put(dev->gate);
851 	clk_unprepare(dev->clk);
852 	clk_put(dev->clk);
853 	return 0;
854 }
855 
856 static struct g2d_variant g2d_drvdata_v3x = {
857 	.hw_rev = TYPE_G2D_3X, /* Revision 3.0 for S5PV210 and Exynos4210 */
858 };
859 
860 static struct g2d_variant g2d_drvdata_v4x = {
861 	.hw_rev = TYPE_G2D_4X, /* Revision 4.1 for Exynos4X12 and Exynos5 */
862 };
863 
864 static const struct of_device_id exynos_g2d_match[] = {
865 	{
866 		.compatible = "samsung,s5pv210-g2d",
867 		.data = &g2d_drvdata_v3x,
868 	}, {
869 		.compatible = "samsung,exynos4212-g2d",
870 		.data = &g2d_drvdata_v4x,
871 	},
872 	{},
873 };
874 MODULE_DEVICE_TABLE(of, exynos_g2d_match);
875 
876 static struct platform_device_id g2d_driver_ids[] = {
877 	{
878 		.name = "s5p-g2d",
879 		.driver_data = (unsigned long)&g2d_drvdata_v3x,
880 	}, {
881 		.name = "s5p-g2d-v4x",
882 		.driver_data = (unsigned long)&g2d_drvdata_v4x,
883 	},
884 	{},
885 };
886 MODULE_DEVICE_TABLE(platform, g2d_driver_ids);
887 
888 static struct platform_driver g2d_pdrv = {
889 	.probe		= g2d_probe,
890 	.remove		= g2d_remove,
891 	.id_table	= g2d_driver_ids,
892 	.driver		= {
893 		.name = G2D_NAME,
894 		.owner = THIS_MODULE,
895 		.of_match_table = exynos_g2d_match,
896 	},
897 };
898 
899 module_platform_driver(g2d_pdrv);
900 
901 MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
902 MODULE_DESCRIPTION("S5P G2D 2d graphics accelerator driver");
903 MODULE_LICENSE("GPL");
904