• 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->fh.m2m_ctx, vb);
140 }
141 
142 static struct vb2_ops g2d_qops = {
143 	.queue_setup	= g2d_queue_setup,
144 	.buf_prepare	= g2d_buf_prepare,
145 	.buf_queue	= g2d_buf_queue,
146 };
147 
queue_init(void * priv,struct vb2_queue * src_vq,struct vb2_queue * dst_vq)148 static int queue_init(void *priv, struct vb2_queue *src_vq,
149 						struct vb2_queue *dst_vq)
150 {
151 	struct g2d_ctx *ctx = priv;
152 	int ret;
153 
154 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
155 	src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
156 	src_vq->drv_priv = ctx;
157 	src_vq->ops = &g2d_qops;
158 	src_vq->mem_ops = &vb2_dma_contig_memops;
159 	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
160 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
161 	src_vq->lock = &ctx->dev->mutex;
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_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
174 	dst_vq->lock = &ctx->dev->mutex;
175 
176 	return vb2_queue_init(dst_vq);
177 }
178 
g2d_s_ctrl(struct v4l2_ctrl * ctrl)179 static int g2d_s_ctrl(struct v4l2_ctrl *ctrl)
180 {
181 	struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx,
182 								ctrl_handler);
183 	unsigned long flags;
184 
185 	spin_lock_irqsave(&ctx->dev->ctrl_lock, flags);
186 	switch (ctrl->id) {
187 	case V4L2_CID_COLORFX:
188 		if (ctrl->val == V4L2_COLORFX_NEGATIVE)
189 			ctx->rop = ROP4_INVERT;
190 		else
191 			ctx->rop = ROP4_COPY;
192 		break;
193 
194 	case V4L2_CID_HFLIP:
195 		ctx->flip = ctx->ctrl_hflip->val | (ctx->ctrl_vflip->val << 1);
196 		break;
197 
198 	}
199 	spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags);
200 	return 0;
201 }
202 
203 static const struct v4l2_ctrl_ops g2d_ctrl_ops = {
204 	.s_ctrl		= g2d_s_ctrl,
205 };
206 
g2d_setup_ctrls(struct g2d_ctx * ctx)207 static int g2d_setup_ctrls(struct g2d_ctx *ctx)
208 {
209 	struct g2d_dev *dev = ctx->dev;
210 
211 	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
212 
213 	ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops,
214 						V4L2_CID_HFLIP, 0, 1, 1, 0);
215 
216 	ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops,
217 						V4L2_CID_VFLIP, 0, 1, 1, 0);
218 
219 	v4l2_ctrl_new_std_menu(
220 		&ctx->ctrl_handler,
221 		&g2d_ctrl_ops,
222 		V4L2_CID_COLORFX,
223 		V4L2_COLORFX_NEGATIVE,
224 		~((1 << V4L2_COLORFX_NONE) | (1 << V4L2_COLORFX_NEGATIVE)),
225 		V4L2_COLORFX_NONE);
226 
227 	if (ctx->ctrl_handler.error) {
228 		int err = ctx->ctrl_handler.error;
229 		v4l2_err(&dev->v4l2_dev, "g2d_setup_ctrls failed\n");
230 		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
231 		return err;
232 	}
233 
234 	v4l2_ctrl_cluster(2, &ctx->ctrl_hflip);
235 
236 	return 0;
237 }
238 
g2d_open(struct file * file)239 static int g2d_open(struct file *file)
240 {
241 	struct g2d_dev *dev = video_drvdata(file);
242 	struct g2d_ctx *ctx = NULL;
243 	int ret = 0;
244 
245 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
246 	if (!ctx)
247 		return -ENOMEM;
248 	ctx->dev = dev;
249 	/* Set default formats */
250 	ctx->in		= def_frame;
251 	ctx->out	= def_frame;
252 
253 	if (mutex_lock_interruptible(&dev->mutex)) {
254 		kfree(ctx);
255 		return -ERESTARTSYS;
256 	}
257 	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
258 	if (IS_ERR(ctx->fh.m2m_ctx)) {
259 		ret = PTR_ERR(ctx->fh.m2m_ctx);
260 		mutex_unlock(&dev->mutex);
261 		kfree(ctx);
262 		return ret;
263 	}
264 	v4l2_fh_init(&ctx->fh, video_devdata(file));
265 	file->private_data = &ctx->fh;
266 	v4l2_fh_add(&ctx->fh);
267 
268 	g2d_setup_ctrls(ctx);
269 
270 	/* Write the default values to the ctx struct */
271 	v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
272 
273 	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
274 	mutex_unlock(&dev->mutex);
275 
276 	v4l2_info(&dev->v4l2_dev, "instance opened\n");
277 	return 0;
278 }
279 
g2d_release(struct file * file)280 static int g2d_release(struct file *file)
281 {
282 	struct g2d_dev *dev = video_drvdata(file);
283 	struct g2d_ctx *ctx = fh2ctx(file->private_data);
284 
285 	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
286 	v4l2_fh_del(&ctx->fh);
287 	v4l2_fh_exit(&ctx->fh);
288 	kfree(ctx);
289 	v4l2_info(&dev->v4l2_dev, "instance closed\n");
290 	return 0;
291 }
292 
293 
vidioc_querycap(struct file * file,void * priv,struct v4l2_capability * cap)294 static int vidioc_querycap(struct file *file, void *priv,
295 				struct v4l2_capability *cap)
296 {
297 	strncpy(cap->driver, G2D_NAME, sizeof(cap->driver) - 1);
298 	strncpy(cap->card, G2D_NAME, sizeof(cap->card) - 1);
299 	cap->bus_info[0] = 0;
300 	cap->version = KERNEL_VERSION(1, 0, 0);
301 	/*
302 	 * This is only a mem-to-mem video device. The capture and output
303 	 * device capability flags are left only for backward compatibility
304 	 * and are scheduled for removal.
305 	 */
306 	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
307 			    V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
308 	return 0;
309 }
310 
vidioc_enum_fmt(struct file * file,void * prv,struct v4l2_fmtdesc * f)311 static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f)
312 {
313 	struct g2d_fmt *fmt;
314 	if (f->index >= NUM_FORMATS)
315 		return -EINVAL;
316 	fmt = &formats[f->index];
317 	f->pixelformat = fmt->fourcc;
318 	strncpy(f->description, fmt->name, sizeof(f->description) - 1);
319 	return 0;
320 }
321 
vidioc_g_fmt(struct file * file,void * prv,struct v4l2_format * f)322 static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
323 {
324 	struct g2d_ctx *ctx = prv;
325 	struct vb2_queue *vq;
326 	struct g2d_frame *frm;
327 
328 	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
329 	if (!vq)
330 		return -EINVAL;
331 	frm = get_frame(ctx, f->type);
332 	if (IS_ERR(frm))
333 		return PTR_ERR(frm);
334 
335 	f->fmt.pix.width		= frm->width;
336 	f->fmt.pix.height		= frm->height;
337 	f->fmt.pix.field		= V4L2_FIELD_NONE;
338 	f->fmt.pix.pixelformat		= frm->fmt->fourcc;
339 	f->fmt.pix.bytesperline		= (frm->width * frm->fmt->depth) >> 3;
340 	f->fmt.pix.sizeimage		= frm->size;
341 	return 0;
342 }
343 
vidioc_try_fmt(struct file * file,void * prv,struct v4l2_format * f)344 static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f)
345 {
346 	struct g2d_fmt *fmt;
347 	enum v4l2_field *field;
348 
349 	fmt = find_fmt(f);
350 	if (!fmt)
351 		return -EINVAL;
352 
353 	field = &f->fmt.pix.field;
354 	if (*field == V4L2_FIELD_ANY)
355 		*field = V4L2_FIELD_NONE;
356 	else if (*field != V4L2_FIELD_NONE)
357 		return -EINVAL;
358 
359 	if (f->fmt.pix.width > MAX_WIDTH)
360 		f->fmt.pix.width = MAX_WIDTH;
361 	if (f->fmt.pix.height > MAX_HEIGHT)
362 		f->fmt.pix.height = MAX_HEIGHT;
363 
364 	if (f->fmt.pix.width < 1)
365 		f->fmt.pix.width = 1;
366 	if (f->fmt.pix.height < 1)
367 		f->fmt.pix.height = 1;
368 
369 	f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
370 	f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
371 	return 0;
372 }
373 
vidioc_s_fmt(struct file * file,void * prv,struct v4l2_format * f)374 static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
375 {
376 	struct g2d_ctx *ctx = prv;
377 	struct g2d_dev *dev = ctx->dev;
378 	struct vb2_queue *vq;
379 	struct g2d_frame *frm;
380 	struct g2d_fmt *fmt;
381 	int ret = 0;
382 
383 	/* Adjust all values accordingly to the hardware capabilities
384 	 * and chosen format. */
385 	ret = vidioc_try_fmt(file, prv, f);
386 	if (ret)
387 		return ret;
388 	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
389 	if (vb2_is_busy(vq)) {
390 		v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type);
391 		return -EBUSY;
392 	}
393 	frm = get_frame(ctx, f->type);
394 	if (IS_ERR(frm))
395 		return PTR_ERR(frm);
396 	fmt = find_fmt(f);
397 	if (!fmt)
398 		return -EINVAL;
399 	frm->width	= f->fmt.pix.width;
400 	frm->height	= f->fmt.pix.height;
401 	frm->size	= f->fmt.pix.sizeimage;
402 	/* Reset crop settings */
403 	frm->o_width	= 0;
404 	frm->o_height	= 0;
405 	frm->c_width	= frm->width;
406 	frm->c_height	= frm->height;
407 	frm->right	= frm->width;
408 	frm->bottom	= frm->height;
409 	frm->fmt	= fmt;
410 	frm->stride	= f->fmt.pix.bytesperline;
411 	return 0;
412 }
413 
vidioc_cropcap(struct file * file,void * priv,struct v4l2_cropcap * cr)414 static int vidioc_cropcap(struct file *file, void *priv,
415 					struct v4l2_cropcap *cr)
416 {
417 	struct g2d_ctx *ctx = priv;
418 	struct g2d_frame *f;
419 
420 	f = get_frame(ctx, cr->type);
421 	if (IS_ERR(f))
422 		return PTR_ERR(f);
423 
424 	cr->bounds.left		= 0;
425 	cr->bounds.top		= 0;
426 	cr->bounds.width	= f->width;
427 	cr->bounds.height	= f->height;
428 	cr->defrect		= cr->bounds;
429 	return 0;
430 }
431 
vidioc_g_crop(struct file * file,void * prv,struct v4l2_crop * cr)432 static int vidioc_g_crop(struct file *file, void *prv, struct v4l2_crop *cr)
433 {
434 	struct g2d_ctx *ctx = prv;
435 	struct g2d_frame *f;
436 
437 	f = get_frame(ctx, cr->type);
438 	if (IS_ERR(f))
439 		return PTR_ERR(f);
440 
441 	cr->c.left	= f->o_height;
442 	cr->c.top	= f->o_width;
443 	cr->c.width	= f->c_width;
444 	cr->c.height	= f->c_height;
445 	return 0;
446 }
447 
vidioc_try_crop(struct file * file,void * prv,const struct v4l2_crop * cr)448 static int vidioc_try_crop(struct file *file, void *prv, const struct v4l2_crop *cr)
449 {
450 	struct g2d_ctx *ctx = prv;
451 	struct g2d_dev *dev = ctx->dev;
452 	struct g2d_frame *f;
453 
454 	f = get_frame(ctx, cr->type);
455 	if (IS_ERR(f))
456 		return PTR_ERR(f);
457 
458 	if (cr->c.top < 0 || cr->c.left < 0) {
459 		v4l2_err(&dev->v4l2_dev,
460 			"doesn't support negative values for top & left\n");
461 		return -EINVAL;
462 	}
463 
464 	return 0;
465 }
466 
vidioc_s_crop(struct file * file,void * prv,const struct v4l2_crop * cr)467 static int vidioc_s_crop(struct file *file, void *prv, const struct v4l2_crop *cr)
468 {
469 	struct g2d_ctx *ctx = prv;
470 	struct g2d_frame *f;
471 	int ret;
472 
473 	ret = vidioc_try_crop(file, prv, cr);
474 	if (ret)
475 		return ret;
476 	f = get_frame(ctx, cr->type);
477 	if (IS_ERR(f))
478 		return PTR_ERR(f);
479 
480 	f->c_width	= cr->c.width;
481 	f->c_height	= cr->c.height;
482 	f->o_width	= cr->c.left;
483 	f->o_height	= cr->c.top;
484 	f->bottom	= f->o_height + f->c_height;
485 	f->right	= f->o_width + f->c_width;
486 	return 0;
487 }
488 
job_abort(void * prv)489 static void job_abort(void *prv)
490 {
491 	struct g2d_ctx *ctx = prv;
492 	struct g2d_dev *dev = ctx->dev;
493 
494 	if (dev->curr == NULL) /* No job currently running */
495 		return;
496 
497 	wait_event_timeout(dev->irq_queue,
498 			   dev->curr == NULL,
499 			   msecs_to_jiffies(G2D_TIMEOUT));
500 }
501 
device_run(void * prv)502 static void device_run(void *prv)
503 {
504 	struct g2d_ctx *ctx = prv;
505 	struct g2d_dev *dev = ctx->dev;
506 	struct vb2_buffer *src, *dst;
507 	unsigned long flags;
508 	u32 cmd = 0;
509 
510 	dev->curr = ctx;
511 
512 	src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
513 	dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
514 
515 	clk_enable(dev->gate);
516 	g2d_reset(dev);
517 
518 	spin_lock_irqsave(&dev->ctrl_lock, flags);
519 
520 	g2d_set_src_size(dev, &ctx->in);
521 	g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0));
522 
523 	g2d_set_dst_size(dev, &ctx->out);
524 	g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0));
525 
526 	g2d_set_rop4(dev, ctx->rop);
527 	g2d_set_flip(dev, ctx->flip);
528 
529 	if (ctx->in.c_width != ctx->out.c_width ||
530 		ctx->in.c_height != ctx->out.c_height) {
531 		if (dev->variant->hw_rev == TYPE_G2D_3X)
532 			cmd |= CMD_V3_ENABLE_STRETCH;
533 		else
534 			g2d_set_v41_stretch(dev, &ctx->in, &ctx->out);
535 	}
536 
537 	g2d_set_cmd(dev, cmd);
538 	g2d_start(dev);
539 
540 	spin_unlock_irqrestore(&dev->ctrl_lock, flags);
541 }
542 
g2d_isr(int irq,void * prv)543 static irqreturn_t g2d_isr(int irq, void *prv)
544 {
545 	struct g2d_dev *dev = prv;
546 	struct g2d_ctx *ctx = dev->curr;
547 	struct vb2_buffer *src, *dst;
548 
549 	g2d_clear_int(dev);
550 	clk_disable(dev->gate);
551 
552 	BUG_ON(ctx == NULL);
553 
554 	src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
555 	dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
556 
557 	BUG_ON(src == NULL);
558 	BUG_ON(dst == NULL);
559 
560 	dst->v4l2_buf.timecode = src->v4l2_buf.timecode;
561 	dst->v4l2_buf.timestamp = src->v4l2_buf.timestamp;
562 	dst->v4l2_buf.flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
563 	dst->v4l2_buf.flags |=
564 		src->v4l2_buf.flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
565 
566 	v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
567 	v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
568 	v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx);
569 
570 	dev->curr = NULL;
571 	wake_up(&dev->irq_queue);
572 	return IRQ_HANDLED;
573 }
574 
575 static const struct v4l2_file_operations g2d_fops = {
576 	.owner		= THIS_MODULE,
577 	.open		= g2d_open,
578 	.release	= g2d_release,
579 	.poll		= v4l2_m2m_fop_poll,
580 	.unlocked_ioctl	= video_ioctl2,
581 	.mmap		= v4l2_m2m_fop_mmap,
582 };
583 
584 static const struct v4l2_ioctl_ops g2d_ioctl_ops = {
585 	.vidioc_querycap	= vidioc_querycap,
586 
587 	.vidioc_enum_fmt_vid_cap	= vidioc_enum_fmt,
588 	.vidioc_g_fmt_vid_cap		= vidioc_g_fmt,
589 	.vidioc_try_fmt_vid_cap		= vidioc_try_fmt,
590 	.vidioc_s_fmt_vid_cap		= vidioc_s_fmt,
591 
592 	.vidioc_enum_fmt_vid_out	= vidioc_enum_fmt,
593 	.vidioc_g_fmt_vid_out		= vidioc_g_fmt,
594 	.vidioc_try_fmt_vid_out		= vidioc_try_fmt,
595 	.vidioc_s_fmt_vid_out		= vidioc_s_fmt,
596 
597 	.vidioc_reqbufs			= v4l2_m2m_ioctl_reqbufs,
598 	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
599 	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
600 	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
601 
602 	.vidioc_streamon		= v4l2_m2m_ioctl_streamon,
603 	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
604 
605 	.vidioc_g_crop			= vidioc_g_crop,
606 	.vidioc_s_crop			= vidioc_s_crop,
607 	.vidioc_cropcap			= vidioc_cropcap,
608 };
609 
610 static struct video_device g2d_videodev = {
611 	.name		= G2D_NAME,
612 	.fops		= &g2d_fops,
613 	.ioctl_ops	= &g2d_ioctl_ops,
614 	.minor		= -1,
615 	.release	= video_device_release,
616 	.vfl_dir	= VFL_DIR_M2M,
617 };
618 
619 static struct v4l2_m2m_ops g2d_m2m_ops = {
620 	.device_run	= device_run,
621 	.job_abort	= job_abort,
622 };
623 
624 static const struct of_device_id exynos_g2d_match[];
625 
g2d_probe(struct platform_device * pdev)626 static int g2d_probe(struct platform_device *pdev)
627 {
628 	struct g2d_dev *dev;
629 	struct video_device *vfd;
630 	struct resource *res;
631 	const struct of_device_id *of_id;
632 	int ret = 0;
633 
634 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
635 	if (!dev)
636 		return -ENOMEM;
637 
638 	spin_lock_init(&dev->ctrl_lock);
639 	mutex_init(&dev->mutex);
640 	atomic_set(&dev->num_inst, 0);
641 	init_waitqueue_head(&dev->irq_queue);
642 
643 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
644 
645 	dev->regs = devm_ioremap_resource(&pdev->dev, res);
646 	if (IS_ERR(dev->regs))
647 		return PTR_ERR(dev->regs);
648 
649 	dev->clk = clk_get(&pdev->dev, "sclk_fimg2d");
650 	if (IS_ERR(dev->clk)) {
651 		dev_err(&pdev->dev, "failed to get g2d clock\n");
652 		return -ENXIO;
653 	}
654 
655 	ret = clk_prepare(dev->clk);
656 	if (ret) {
657 		dev_err(&pdev->dev, "failed to prepare g2d clock\n");
658 		goto put_clk;
659 	}
660 
661 	dev->gate = clk_get(&pdev->dev, "fimg2d");
662 	if (IS_ERR(dev->gate)) {
663 		dev_err(&pdev->dev, "failed to get g2d clock gate\n");
664 		ret = -ENXIO;
665 		goto unprep_clk;
666 	}
667 
668 	ret = clk_prepare(dev->gate);
669 	if (ret) {
670 		dev_err(&pdev->dev, "failed to prepare g2d clock gate\n");
671 		goto put_clk_gate;
672 	}
673 
674 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
675 	if (!res) {
676 		dev_err(&pdev->dev, "failed to find IRQ\n");
677 		ret = -ENXIO;
678 		goto unprep_clk_gate;
679 	}
680 
681 	dev->irq = res->start;
682 
683 	ret = devm_request_irq(&pdev->dev, dev->irq, g2d_isr,
684 						0, pdev->name, dev);
685 	if (ret) {
686 		dev_err(&pdev->dev, "failed to install IRQ\n");
687 		goto put_clk_gate;
688 	}
689 
690 	dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
691 	if (IS_ERR(dev->alloc_ctx)) {
692 		ret = PTR_ERR(dev->alloc_ctx);
693 		goto unprep_clk_gate;
694 	}
695 
696 	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
697 	if (ret)
698 		goto alloc_ctx_cleanup;
699 	vfd = video_device_alloc();
700 	if (!vfd) {
701 		v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
702 		ret = -ENOMEM;
703 		goto unreg_v4l2_dev;
704 	}
705 	*vfd = g2d_videodev;
706 	vfd->lock = &dev->mutex;
707 	vfd->v4l2_dev = &dev->v4l2_dev;
708 	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
709 	if (ret) {
710 		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
711 		goto rel_vdev;
712 	}
713 	video_set_drvdata(vfd, dev);
714 	snprintf(vfd->name, sizeof(vfd->name), "%s", g2d_videodev.name);
715 	dev->vfd = vfd;
716 	v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n",
717 								vfd->num);
718 	platform_set_drvdata(pdev, dev);
719 	dev->m2m_dev = v4l2_m2m_init(&g2d_m2m_ops);
720 	if (IS_ERR(dev->m2m_dev)) {
721 		v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
722 		ret = PTR_ERR(dev->m2m_dev);
723 		goto unreg_video_dev;
724 	}
725 
726 	def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
727 
728 	if (!pdev->dev.of_node) {
729 		dev->variant = g2d_get_drv_data(pdev);
730 	} else {
731 		of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node);
732 		if (!of_id) {
733 			ret = -ENODEV;
734 			goto unreg_video_dev;
735 		}
736 		dev->variant = (struct g2d_variant *)of_id->data;
737 	}
738 
739 	return 0;
740 
741 unreg_video_dev:
742 	video_unregister_device(dev->vfd);
743 rel_vdev:
744 	video_device_release(vfd);
745 unreg_v4l2_dev:
746 	v4l2_device_unregister(&dev->v4l2_dev);
747 alloc_ctx_cleanup:
748 	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
749 unprep_clk_gate:
750 	clk_unprepare(dev->gate);
751 put_clk_gate:
752 	clk_put(dev->gate);
753 unprep_clk:
754 	clk_unprepare(dev->clk);
755 put_clk:
756 	clk_put(dev->clk);
757 
758 	return ret;
759 }
760 
g2d_remove(struct platform_device * pdev)761 static int g2d_remove(struct platform_device *pdev)
762 {
763 	struct g2d_dev *dev = platform_get_drvdata(pdev);
764 
765 	v4l2_info(&dev->v4l2_dev, "Removing " G2D_NAME);
766 	v4l2_m2m_release(dev->m2m_dev);
767 	video_unregister_device(dev->vfd);
768 	v4l2_device_unregister(&dev->v4l2_dev);
769 	vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
770 	clk_unprepare(dev->gate);
771 	clk_put(dev->gate);
772 	clk_unprepare(dev->clk);
773 	clk_put(dev->clk);
774 	return 0;
775 }
776 
777 static struct g2d_variant g2d_drvdata_v3x = {
778 	.hw_rev = TYPE_G2D_3X, /* Revision 3.0 for S5PV210 and Exynos4210 */
779 };
780 
781 static struct g2d_variant g2d_drvdata_v4x = {
782 	.hw_rev = TYPE_G2D_4X, /* Revision 4.1 for Exynos4X12 and Exynos5 */
783 };
784 
785 static const struct of_device_id exynos_g2d_match[] = {
786 	{
787 		.compatible = "samsung,s5pv210-g2d",
788 		.data = &g2d_drvdata_v3x,
789 	}, {
790 		.compatible = "samsung,exynos4212-g2d",
791 		.data = &g2d_drvdata_v4x,
792 	},
793 	{},
794 };
795 MODULE_DEVICE_TABLE(of, exynos_g2d_match);
796 
797 static struct platform_device_id g2d_driver_ids[] = {
798 	{
799 		.name = "s5p-g2d",
800 		.driver_data = (unsigned long)&g2d_drvdata_v3x,
801 	}, {
802 		.name = "s5p-g2d-v4x",
803 		.driver_data = (unsigned long)&g2d_drvdata_v4x,
804 	},
805 	{},
806 };
807 MODULE_DEVICE_TABLE(platform, g2d_driver_ids);
808 
809 static struct platform_driver g2d_pdrv = {
810 	.probe		= g2d_probe,
811 	.remove		= g2d_remove,
812 	.id_table	= g2d_driver_ids,
813 	.driver		= {
814 		.name = G2D_NAME,
815 		.owner = THIS_MODULE,
816 		.of_match_table = exynos_g2d_match,
817 	},
818 };
819 
820 module_platform_driver(g2d_pdrv);
821 
822 MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
823 MODULE_DESCRIPTION("S5P G2D 2d graphics accelerator driver");
824 MODULE_LICENSE("GPL");
825