1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/types.h>
16#include <linux/errno.h>
17#include <linux/bug.h>
18#include <linux/interrupt.h>
19#include <linux/workqueue.h>
20#include <linux/device.h>
21#include <linux/platform_device.h>
22#include <linux/list.h>
23#include <linux/io.h>
24#include <linux/slab.h>
25#include <linux/clk.h>
26#include <linux/of.h>
27#include <linux/of_device.h>
28#include <media/v4l2-ioctl.h>
29
30#include "gsc-core.h"
31
32static const struct gsc_fmt gsc_formats[] = {
33 {
34 .name = "RGB565",
35 .pixelformat = V4L2_PIX_FMT_RGB565X,
36 .depth = { 16 },
37 .color = GSC_RGB,
38 .num_planes = 1,
39 .num_comp = 1,
40 }, {
41 .name = "BGRX-8-8-8-8, 32 bpp",
42 .pixelformat = V4L2_PIX_FMT_BGR32,
43 .depth = { 32 },
44 .color = GSC_RGB,
45 .num_planes = 1,
46 .num_comp = 1,
47 }, {
48 .name = "YUV 4:2:2 packed, YCbYCr",
49 .pixelformat = V4L2_PIX_FMT_YUYV,
50 .depth = { 16 },
51 .color = GSC_YUV422,
52 .yorder = GSC_LSB_Y,
53 .corder = GSC_CBCR,
54 .num_planes = 1,
55 .num_comp = 1,
56 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
57 }, {
58 .name = "YUV 4:2:2 packed, CbYCrY",
59 .pixelformat = V4L2_PIX_FMT_UYVY,
60 .depth = { 16 },
61 .color = GSC_YUV422,
62 .yorder = GSC_LSB_C,
63 .corder = GSC_CBCR,
64 .num_planes = 1,
65 .num_comp = 1,
66 .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
67 }, {
68 .name = "YUV 4:2:2 packed, CrYCbY",
69 .pixelformat = V4L2_PIX_FMT_VYUY,
70 .depth = { 16 },
71 .color = GSC_YUV422,
72 .yorder = GSC_LSB_C,
73 .corder = GSC_CRCB,
74 .num_planes = 1,
75 .num_comp = 1,
76 .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
77 }, {
78 .name = "YUV 4:2:2 packed, YCrYCb",
79 .pixelformat = V4L2_PIX_FMT_YVYU,
80 .depth = { 16 },
81 .color = GSC_YUV422,
82 .yorder = GSC_LSB_Y,
83 .corder = GSC_CRCB,
84 .num_planes = 1,
85 .num_comp = 1,
86 .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8,
87 }, {
88 .name = "YUV 4:4:4 planar, YCbYCr",
89 .pixelformat = V4L2_PIX_FMT_YUV32,
90 .depth = { 32 },
91 .color = GSC_YUV444,
92 .yorder = GSC_LSB_Y,
93 .corder = GSC_CBCR,
94 .num_planes = 1,
95 .num_comp = 1,
96 }, {
97 .name = "YUV 4:2:2 planar, Y/Cb/Cr",
98 .pixelformat = V4L2_PIX_FMT_YUV422P,
99 .depth = { 16 },
100 .color = GSC_YUV422,
101 .yorder = GSC_LSB_Y,
102 .corder = GSC_CBCR,
103 .num_planes = 1,
104 .num_comp = 3,
105 }, {
106 .name = "YUV 4:2:2 planar, Y/CbCr",
107 .pixelformat = V4L2_PIX_FMT_NV16,
108 .depth = { 16 },
109 .color = GSC_YUV422,
110 .yorder = GSC_LSB_Y,
111 .corder = GSC_CBCR,
112 .num_planes = 1,
113 .num_comp = 2,
114 }, {
115 .name = "YUV 4:2:2 non-contig, Y/CbCr",
116 .pixelformat = V4L2_PIX_FMT_NV16M,
117 .depth = { 8, 8 },
118 .color = GSC_YUV422,
119 .yorder = GSC_LSB_Y,
120 .corder = GSC_CBCR,
121 .num_planes = 2,
122 .num_comp = 2,
123 }, {
124 .name = "YUV 4:2:2 planar, Y/CrCb",
125 .pixelformat = V4L2_PIX_FMT_NV61,
126 .depth = { 16 },
127 .color = GSC_YUV422,
128 .yorder = GSC_LSB_Y,
129 .corder = GSC_CRCB,
130 .num_planes = 1,
131 .num_comp = 2,
132 }, {
133 .name = "YUV 4:2:2 non-contig, Y/CrCb",
134 .pixelformat = V4L2_PIX_FMT_NV61M,
135 .depth = { 8, 8 },
136 .color = GSC_YUV422,
137 .yorder = GSC_LSB_Y,
138 .corder = GSC_CRCB,
139 .num_planes = 2,
140 .num_comp = 2,
141 }, {
142 .name = "YUV 4:2:0 planar, YCbCr",
143 .pixelformat = V4L2_PIX_FMT_YUV420,
144 .depth = { 12 },
145 .color = GSC_YUV420,
146 .yorder = GSC_LSB_Y,
147 .corder = GSC_CBCR,
148 .num_planes = 1,
149 .num_comp = 3,
150 }, {
151 .name = "YUV 4:2:0 planar, YCrCb",
152 .pixelformat = V4L2_PIX_FMT_YVU420,
153 .depth = { 12 },
154 .color = GSC_YUV420,
155 .yorder = GSC_LSB_Y,
156 .corder = GSC_CRCB,
157 .num_planes = 1,
158 .num_comp = 3,
159
160 }, {
161 .name = "YUV 4:2:0 planar, Y/CbCr",
162 .pixelformat = V4L2_PIX_FMT_NV12,
163 .depth = { 12 },
164 .color = GSC_YUV420,
165 .yorder = GSC_LSB_Y,
166 .corder = GSC_CBCR,
167 .num_planes = 1,
168 .num_comp = 2,
169 }, {
170 .name = "YUV 4:2:0 planar, Y/CrCb",
171 .pixelformat = V4L2_PIX_FMT_NV21,
172 .depth = { 12 },
173 .color = GSC_YUV420,
174 .yorder = GSC_LSB_Y,
175 .corder = GSC_CRCB,
176 .num_planes = 1,
177 .num_comp = 2,
178 }, {
179 .name = "YUV 4:2:0 non-contig. 2p, Y/CrCb",
180 .pixelformat = V4L2_PIX_FMT_NV21M,
181 .depth = { 8, 4 },
182 .color = GSC_YUV420,
183 .yorder = GSC_LSB_Y,
184 .corder = GSC_CRCB,
185 .num_planes = 2,
186 .num_comp = 2,
187 }, {
188 .name = "YUV 4:2:0 non-contig. 2p, Y/CbCr",
189 .pixelformat = V4L2_PIX_FMT_NV12M,
190 .depth = { 8, 4 },
191 .color = GSC_YUV420,
192 .yorder = GSC_LSB_Y,
193 .corder = GSC_CBCR,
194 .num_planes = 2,
195 .num_comp = 2,
196 }, {
197 .name = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
198 .pixelformat = V4L2_PIX_FMT_YUV420M,
199 .depth = { 8, 2, 2 },
200 .color = GSC_YUV420,
201 .yorder = GSC_LSB_Y,
202 .corder = GSC_CBCR,
203 .num_planes = 3,
204 .num_comp = 3,
205 }, {
206 .name = "YUV 4:2:0 non-contig. 3p, Y/Cr/Cb",
207 .pixelformat = V4L2_PIX_FMT_YVU420M,
208 .depth = { 8, 2, 2 },
209 .color = GSC_YUV420,
210 .yorder = GSC_LSB_Y,
211 .corder = GSC_CRCB,
212 .num_planes = 3,
213 .num_comp = 3,
214 }, {
215 .name = "YUV 4:2:0 n.c. 2p, Y/CbCr tiled",
216 .pixelformat = V4L2_PIX_FMT_NV12MT_16X16,
217 .depth = { 8, 4 },
218 .color = GSC_YUV420,
219 .yorder = GSC_LSB_Y,
220 .corder = GSC_CBCR,
221 .num_planes = 2,
222 .num_comp = 2,
223 }
224};
225
226const struct gsc_fmt *get_format(int index)
227{
228 if (index >= ARRAY_SIZE(gsc_formats))
229 return NULL;
230
231 return (struct gsc_fmt *)&gsc_formats[index];
232}
233
234const struct gsc_fmt *find_fmt(u32 *pixelformat, u32 *mbus_code, u32 index)
235{
236 const struct gsc_fmt *fmt, *def_fmt = NULL;
237 unsigned int i;
238
239 if (index >= ARRAY_SIZE(gsc_formats))
240 return NULL;
241
242 for (i = 0; i < ARRAY_SIZE(gsc_formats); ++i) {
243 fmt = get_format(i);
244 if (pixelformat && fmt->pixelformat == *pixelformat)
245 return fmt;
246 if (mbus_code && fmt->mbus_code == *mbus_code)
247 return fmt;
248 if (index == i)
249 def_fmt = fmt;
250 }
251 return def_fmt;
252
253}
254
255void gsc_set_frame_size(struct gsc_frame *frame, int width, int height)
256{
257 frame->f_width = width;
258 frame->f_height = height;
259 frame->crop.width = width;
260 frame->crop.height = height;
261 frame->crop.left = 0;
262 frame->crop.top = 0;
263}
264
265int gsc_cal_prescaler_ratio(struct gsc_variant *var, u32 src, u32 dst,
266 u32 *ratio)
267{
268 if ((dst > src) || (dst >= src / var->poly_sc_down_max)) {
269 *ratio = 1;
270 return 0;
271 }
272
273 if ((src / var->poly_sc_down_max / var->pre_sc_down_max) > dst) {
274 pr_err("Exceeded maximum downscaling ratio (1/16))");
275 return -EINVAL;
276 }
277
278 *ratio = (dst > (src / 8)) ? 2 : 4;
279
280 return 0;
281}
282
283void gsc_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *sh)
284{
285 if (hratio == 4 && vratio == 4)
286 *sh = 4;
287 else if ((hratio == 4 && vratio == 2) ||
288 (hratio == 2 && vratio == 4))
289 *sh = 3;
290 else if ((hratio == 4 && vratio == 1) ||
291 (hratio == 1 && vratio == 4) ||
292 (hratio == 2 && vratio == 2))
293 *sh = 2;
294 else if (hratio == 1 && vratio == 1)
295 *sh = 0;
296 else
297 *sh = 1;
298}
299
300void gsc_check_src_scale_info(struct gsc_variant *var,
301 struct gsc_frame *s_frame, u32 *wratio,
302 u32 tx, u32 ty, u32 *hratio)
303{
304 int remainder = 0, walign, halign;
305
306 if (is_yuv420(s_frame->fmt->color)) {
307 walign = GSC_SC_ALIGN_4;
308 halign = GSC_SC_ALIGN_4;
309 } else if (is_yuv422(s_frame->fmt->color)) {
310 walign = GSC_SC_ALIGN_4;
311 halign = GSC_SC_ALIGN_2;
312 } else {
313 walign = GSC_SC_ALIGN_2;
314 halign = GSC_SC_ALIGN_2;
315 }
316
317 remainder = s_frame->crop.width % (*wratio * walign);
318 if (remainder) {
319 s_frame->crop.width -= remainder;
320 gsc_cal_prescaler_ratio(var, s_frame->crop.width, tx, wratio);
321 pr_info("cropped src width size is recalculated from %d to %d",
322 s_frame->crop.width + remainder, s_frame->crop.width);
323 }
324
325 remainder = s_frame->crop.height % (*hratio * halign);
326 if (remainder) {
327 s_frame->crop.height -= remainder;
328 gsc_cal_prescaler_ratio(var, s_frame->crop.height, ty, hratio);
329 pr_info("cropped src height size is recalculated from %d to %d",
330 s_frame->crop.height + remainder, s_frame->crop.height);
331 }
332}
333
334int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f)
335{
336 const struct gsc_fmt *fmt;
337
338 fmt = find_fmt(NULL, NULL, f->index);
339 if (!fmt)
340 return -EINVAL;
341
342 strlcpy(f->description, fmt->name, sizeof(f->description));
343 f->pixelformat = fmt->pixelformat;
344
345 return 0;
346}
347
348static int get_plane_info(struct gsc_frame *frm, u32 addr, u32 *index, u32 *ret_addr)
349{
350 if (frm->addr.y == addr) {
351 *index = 0;
352 *ret_addr = frm->addr.y;
353 } else if (frm->addr.cb == addr) {
354 *index = 1;
355 *ret_addr = frm->addr.cb;
356 } else if (frm->addr.cr == addr) {
357 *index = 2;
358 *ret_addr = frm->addr.cr;
359 } else {
360 pr_err("Plane address is wrong");
361 return -EINVAL;
362 }
363 return 0;
364}
365
366void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm)
367{
368 u32 f_chk_addr, f_chk_len, s_chk_addr, s_chk_len;
369 f_chk_addr = f_chk_len = s_chk_addr = s_chk_len = 0;
370
371 f_chk_addr = frm->addr.y;
372 f_chk_len = frm->payload[0];
373 if (frm->fmt->num_planes == 2) {
374 s_chk_addr = frm->addr.cb;
375 s_chk_len = frm->payload[1];
376 } else if (frm->fmt->num_planes == 3) {
377 u32 low_addr, low_plane, mid_addr, mid_plane;
378 u32 high_addr, high_plane;
379 u32 t_min, t_max;
380
381 t_min = min3(frm->addr.y, frm->addr.cb, frm->addr.cr);
382 if (get_plane_info(frm, t_min, &low_plane, &low_addr))
383 return;
384 t_max = max3(frm->addr.y, frm->addr.cb, frm->addr.cr);
385 if (get_plane_info(frm, t_max, &high_plane, &high_addr))
386 return;
387
388 mid_plane = 3 - (low_plane + high_plane);
389 if (mid_plane == 0)
390 mid_addr = frm->addr.y;
391 else if (mid_plane == 1)
392 mid_addr = frm->addr.cb;
393 else if (mid_plane == 2)
394 mid_addr = frm->addr.cr;
395 else
396 return;
397
398 f_chk_addr = low_addr;
399 if (mid_addr + frm->payload[mid_plane] - low_addr >
400 high_addr + frm->payload[high_plane] - mid_addr) {
401 f_chk_len = frm->payload[low_plane];
402 s_chk_addr = mid_addr;
403 s_chk_len = high_addr +
404 frm->payload[high_plane] - mid_addr;
405 } else {
406 f_chk_len = mid_addr +
407 frm->payload[mid_plane] - low_addr;
408 s_chk_addr = high_addr;
409 s_chk_len = frm->payload[high_plane];
410 }
411 }
412 pr_debug("f_addr = 0x%08x, f_len = %d, s_addr = 0x%08x, s_len = %d\n",
413 f_chk_addr, f_chk_len, s_chk_addr, s_chk_len);
414}
415
416int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
417{
418 struct gsc_dev *gsc = ctx->gsc_dev;
419 struct gsc_variant *variant = gsc->variant;
420 struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
421 const struct gsc_fmt *fmt;
422 u32 max_w, max_h, mod_x, mod_y;
423 u32 min_w, min_h, tmp_w, tmp_h;
424 int i;
425
426 pr_debug("user put w: %d, h: %d", pix_mp->width, pix_mp->height);
427
428 fmt = find_fmt(&pix_mp->pixelformat, NULL, 0);
429 if (!fmt) {
430 pr_err("pixelformat format (0x%X) invalid\n",
431 pix_mp->pixelformat);
432 return -EINVAL;
433 }
434
435 if (pix_mp->field == V4L2_FIELD_ANY)
436 pix_mp->field = V4L2_FIELD_NONE;
437 else if (pix_mp->field != V4L2_FIELD_NONE) {
438 pr_debug("Not supported field order(%d)\n", pix_mp->field);
439 return -EINVAL;
440 }
441
442 max_w = variant->pix_max->target_rot_dis_w;
443 max_h = variant->pix_max->target_rot_dis_h;
444
445 mod_x = ffs(variant->pix_align->org_w) - 1;
446 if (is_yuv420(fmt->color))
447 mod_y = ffs(variant->pix_align->org_h) - 1;
448 else
449 mod_y = ffs(variant->pix_align->org_h) - 2;
450
451 if (V4L2_TYPE_IS_OUTPUT(f->type)) {
452 min_w = variant->pix_min->org_w;
453 min_h = variant->pix_min->org_h;
454 } else {
455 min_w = variant->pix_min->target_rot_dis_w;
456 min_h = variant->pix_min->target_rot_dis_h;
457 pix_mp->colorspace = ctx->out_colorspace;
458 }
459
460 pr_debug("mod_x: %d, mod_y: %d, max_w: %d, max_h = %d",
461 mod_x, mod_y, max_w, max_h);
462
463
464
465 tmp_w = pix_mp->width;
466 tmp_h = pix_mp->height;
467
468 v4l_bound_align_image(&pix_mp->width, min_w, max_w, mod_x,
469 &pix_mp->height, min_h, max_h, mod_y, 0);
470 if (tmp_w != pix_mp->width || tmp_h != pix_mp->height)
471 pr_debug("Image size has been modified from %dx%d to %dx%d\n",
472 tmp_w, tmp_h, pix_mp->width, pix_mp->height);
473
474 pix_mp->num_planes = fmt->num_planes;
475
476 if (V4L2_TYPE_IS_OUTPUT(f->type))
477 ctx->out_colorspace = pix_mp->colorspace;
478
479 for (i = 0; i < pix_mp->num_planes; ++i) {
480 struct v4l2_plane_pix_format *plane_fmt = &pix_mp->plane_fmt[i];
481 u32 bpl = plane_fmt->bytesperline;
482
483 if (fmt->num_comp == 1 &&
484 (bpl == 0 || (bpl * 8 / fmt->depth[i]) < pix_mp->width))
485 bpl = pix_mp->width * fmt->depth[i] / 8;
486
487 if (fmt->num_comp > 1 &&
488 (bpl == 0 || bpl < pix_mp->width))
489 bpl = pix_mp->width;
490
491 if (i != 0 && fmt->num_comp == 3)
492 bpl /= 2;
493
494 plane_fmt->bytesperline = bpl;
495 plane_fmt->sizeimage = max(pix_mp->width * pix_mp->height *
496 fmt->depth[i] / 8,
497 plane_fmt->sizeimage);
498 pr_debug("[%d]: bpl: %d, sizeimage: %d",
499 i, bpl, pix_mp->plane_fmt[i].sizeimage);
500 }
501
502 return 0;
503}
504
505int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
506{
507 struct gsc_frame *frame;
508 struct v4l2_pix_format_mplane *pix_mp;
509 int i;
510
511 frame = ctx_get_frame(ctx, f->type);
512 if (IS_ERR(frame))
513 return PTR_ERR(frame);
514
515 pix_mp = &f->fmt.pix_mp;
516
517 pix_mp->width = frame->f_width;
518 pix_mp->height = frame->f_height;
519 pix_mp->field = V4L2_FIELD_NONE;
520 pix_mp->pixelformat = frame->fmt->pixelformat;
521 pix_mp->num_planes = frame->fmt->num_planes;
522 pix_mp->colorspace = ctx->out_colorspace;
523
524 for (i = 0; i < pix_mp->num_planes; ++i) {
525 pix_mp->plane_fmt[i].bytesperline = (frame->f_width *
526 frame->fmt->depth[i]) / 8;
527 pix_mp->plane_fmt[i].sizeimage =
528 pix_mp->plane_fmt[i].bytesperline * frame->f_height;
529 }
530
531 return 0;
532}
533
534void gsc_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h)
535{
536 if (tmp_w != *w || tmp_h != *h) {
537 pr_info("Cropped size has been modified from %dx%d to %dx%d",
538 *w, *h, tmp_w, tmp_h);
539 *w = tmp_w;
540 *h = tmp_h;
541 }
542}
543
544int gsc_g_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
545{
546 struct gsc_frame *frame;
547
548 frame = ctx_get_frame(ctx, cr->type);
549 if (IS_ERR(frame))
550 return PTR_ERR(frame);
551
552 cr->c = frame->crop;
553
554 return 0;
555}
556
557int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
558{
559 struct gsc_frame *f;
560 struct gsc_dev *gsc = ctx->gsc_dev;
561 struct gsc_variant *variant = gsc->variant;
562 u32 mod_x = 0, mod_y = 0, tmp_w, tmp_h;
563 u32 min_w, min_h, max_w, max_h;
564
565 if (cr->c.top < 0 || cr->c.left < 0) {
566 pr_err("doesn't support negative values for top & left\n");
567 return -EINVAL;
568 }
569 pr_debug("user put w: %d, h: %d", cr->c.width, cr->c.height);
570
571 if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
572 f = &ctx->d_frame;
573 else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
574 f = &ctx->s_frame;
575 else
576 return -EINVAL;
577
578 max_w = f->f_width;
579 max_h = f->f_height;
580 tmp_w = cr->c.width;
581 tmp_h = cr->c.height;
582
583 if (V4L2_TYPE_IS_OUTPUT(cr->type)) {
584 if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 1) ||
585 is_rgb(f->fmt->color))
586 min_w = 32;
587 else
588 min_w = 64;
589 if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 3) ||
590 is_yuv420(f->fmt->color))
591 min_h = 32;
592 else
593 min_h = 16;
594 } else {
595 if (is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color))
596 mod_x = ffs(variant->pix_align->target_w) - 1;
597 if (is_yuv420(f->fmt->color))
598 mod_y = ffs(variant->pix_align->target_h) - 1;
599 if (ctx->gsc_ctrls.rotate->val == 90 ||
600 ctx->gsc_ctrls.rotate->val == 270) {
601 max_w = f->f_height;
602 max_h = f->f_width;
603 min_w = variant->pix_min->target_rot_en_w;
604 min_h = variant->pix_min->target_rot_en_h;
605 tmp_w = cr->c.height;
606 tmp_h = cr->c.width;
607 } else {
608 min_w = variant->pix_min->target_rot_dis_w;
609 min_h = variant->pix_min->target_rot_dis_h;
610 }
611 }
612 pr_debug("mod_x: %d, mod_y: %d, min_w: %d, min_h = %d",
613 mod_x, mod_y, min_w, min_h);
614 pr_debug("tmp_w : %d, tmp_h : %d", tmp_w, tmp_h);
615
616 v4l_bound_align_image(&tmp_w, min_w, max_w, mod_x,
617 &tmp_h, min_h, max_h, mod_y, 0);
618
619 if (!V4L2_TYPE_IS_OUTPUT(cr->type) &&
620 (ctx->gsc_ctrls.rotate->val == 90 ||
621 ctx->gsc_ctrls.rotate->val == 270))
622 gsc_check_crop_change(tmp_h, tmp_w,
623 &cr->c.width, &cr->c.height);
624 else
625 gsc_check_crop_change(tmp_w, tmp_h,
626 &cr->c.width, &cr->c.height);
627
628
629
630
631 if (cr->c.left + tmp_w > max_w)
632 cr->c.left = max_w - tmp_w;
633 if (cr->c.top + tmp_h > max_h)
634 cr->c.top = max_h - tmp_h;
635
636 if ((is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color)) &&
637 cr->c.left & 1)
638 cr->c.left -= 1;
639
640 pr_debug("Aligned l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
641 cr->c.left, cr->c.top, cr->c.width, cr->c.height, max_w, max_h);
642
643 return 0;
644}
645
646int gsc_check_scaler_ratio(struct gsc_variant *var, int sw, int sh, int dw,
647 int dh, int rot, int out_path)
648{
649 int tmp_w, tmp_h, sc_down_max;
650
651 if (out_path == GSC_DMA)
652 sc_down_max = var->sc_down_max;
653 else
654 sc_down_max = var->local_sc_down;
655
656 if (rot == 90 || rot == 270) {
657 tmp_w = dh;
658 tmp_h = dw;
659 } else {
660 tmp_w = dw;
661 tmp_h = dh;
662 }
663
664 if ((sw / tmp_w) > sc_down_max ||
665 (sh / tmp_h) > sc_down_max ||
666 (tmp_w / sw) > var->sc_up_max ||
667 (tmp_h / sh) > var->sc_up_max)
668 return -EINVAL;
669
670 return 0;
671}
672
673int gsc_set_scaler_info(struct gsc_ctx *ctx)
674{
675 struct gsc_scaler *sc = &ctx->scaler;
676 struct gsc_frame *s_frame = &ctx->s_frame;
677 struct gsc_frame *d_frame = &ctx->d_frame;
678 struct gsc_variant *variant = ctx->gsc_dev->variant;
679 struct device *dev = &ctx->gsc_dev->pdev->dev;
680 int tx, ty;
681 int ret;
682
683 ret = gsc_check_scaler_ratio(variant, s_frame->crop.width,
684 s_frame->crop.height, d_frame->crop.width, d_frame->crop.height,
685 ctx->gsc_ctrls.rotate->val, ctx->out_path);
686 if (ret) {
687 pr_err("out of scaler range");
688 return ret;
689 }
690
691 if (ctx->gsc_ctrls.rotate->val == 90 ||
692 ctx->gsc_ctrls.rotate->val == 270) {
693 ty = d_frame->crop.width;
694 tx = d_frame->crop.height;
695 } else {
696 tx = d_frame->crop.width;
697 ty = d_frame->crop.height;
698 }
699
700 if (tx <= 0 || ty <= 0) {
701 dev_err(dev, "Invalid target size: %dx%d", tx, ty);
702 return -EINVAL;
703 }
704
705 ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.width,
706 tx, &sc->pre_hratio);
707 if (ret) {
708 pr_err("Horizontal scale ratio is out of range");
709 return ret;
710 }
711
712 ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.height,
713 ty, &sc->pre_vratio);
714 if (ret) {
715 pr_err("Vertical scale ratio is out of range");
716 return ret;
717 }
718
719 gsc_check_src_scale_info(variant, s_frame, &sc->pre_hratio,
720 tx, ty, &sc->pre_vratio);
721
722 gsc_get_prescaler_shfactor(sc->pre_hratio, sc->pre_vratio,
723 &sc->pre_shfactor);
724
725 sc->main_hratio = (s_frame->crop.width << 16) / tx;
726 sc->main_vratio = (s_frame->crop.height << 16) / ty;
727
728 pr_debug("scaler input/output size : sx = %d, sy = %d, tx = %d, ty = %d",
729 s_frame->crop.width, s_frame->crop.height, tx, ty);
730 pr_debug("scaler ratio info : pre_shfactor : %d, pre_h : %d",
731 sc->pre_shfactor, sc->pre_hratio);
732 pr_debug("pre_v :%d, main_h : %d, main_v : %d",
733 sc->pre_vratio, sc->main_hratio, sc->main_vratio);
734
735 return 0;
736}
737
738static int __gsc_s_ctrl(struct gsc_ctx *ctx, struct v4l2_ctrl *ctrl)
739{
740 struct gsc_dev *gsc = ctx->gsc_dev;
741 struct gsc_variant *variant = gsc->variant;
742 unsigned int flags = GSC_DST_FMT | GSC_SRC_FMT;
743 int ret = 0;
744
745 if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
746 return 0;
747
748 switch (ctrl->id) {
749 case V4L2_CID_HFLIP:
750 ctx->hflip = ctrl->val;
751 break;
752
753 case V4L2_CID_VFLIP:
754 ctx->vflip = ctrl->val;
755 break;
756
757 case V4L2_CID_ROTATE:
758 if ((ctx->state & flags) == flags) {
759 ret = gsc_check_scaler_ratio(variant,
760 ctx->s_frame.crop.width,
761 ctx->s_frame.crop.height,
762 ctx->d_frame.crop.width,
763 ctx->d_frame.crop.height,
764 ctx->gsc_ctrls.rotate->val,
765 ctx->out_path);
766
767 if (ret)
768 return -EINVAL;
769 }
770
771 ctx->rotation = ctrl->val;
772 break;
773
774 case V4L2_CID_ALPHA_COMPONENT:
775 ctx->d_frame.alpha = ctrl->val;
776 break;
777 }
778
779 ctx->state |= GSC_PARAMS;
780 return 0;
781}
782
783static int gsc_s_ctrl(struct v4l2_ctrl *ctrl)
784{
785 struct gsc_ctx *ctx = ctrl_to_ctx(ctrl);
786 unsigned long flags;
787 int ret;
788
789 spin_lock_irqsave(&ctx->gsc_dev->slock, flags);
790 ret = __gsc_s_ctrl(ctx, ctrl);
791 spin_unlock_irqrestore(&ctx->gsc_dev->slock, flags);
792
793 return ret;
794}
795
796static const struct v4l2_ctrl_ops gsc_ctrl_ops = {
797 .s_ctrl = gsc_s_ctrl,
798};
799
800int gsc_ctrls_create(struct gsc_ctx *ctx)
801{
802 if (ctx->ctrls_rdy) {
803 pr_err("Control handler of this context was created already");
804 return 0;
805 }
806
807 v4l2_ctrl_handler_init(&ctx->ctrl_handler, GSC_MAX_CTRL_NUM);
808
809 ctx->gsc_ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
810 &gsc_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
811 ctx->gsc_ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
812 &gsc_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
813 ctx->gsc_ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
814 &gsc_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
815 ctx->gsc_ctrls.global_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
816 &gsc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
817
818 ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
819
820 if (ctx->ctrl_handler.error) {
821 int err = ctx->ctrl_handler.error;
822 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
823 pr_err("Failed to create G-Scaler control handlers");
824 return err;
825 }
826
827 return 0;
828}
829
830void gsc_ctrls_delete(struct gsc_ctx *ctx)
831{
832 if (ctx->ctrls_rdy) {
833 v4l2_ctrl_handler_free(&ctx->ctrl_handler);
834 ctx->ctrls_rdy = false;
835 }
836}
837
838
839int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
840 struct gsc_frame *frame, struct gsc_addr *addr)
841{
842 int ret = 0;
843 u32 pix_size;
844
845 if ((vb == NULL) || (frame == NULL))
846 return -EINVAL;
847
848 pix_size = frame->f_width * frame->f_height;
849
850 pr_debug("num_planes= %d, num_comp= %d, pix_size= %d",
851 frame->fmt->num_planes, frame->fmt->num_comp, pix_size);
852
853 addr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
854
855 if (frame->fmt->num_planes == 1) {
856 switch (frame->fmt->num_comp) {
857 case 1:
858 addr->cb = 0;
859 addr->cr = 0;
860 break;
861 case 2:
862
863 addr->cb = (dma_addr_t)(addr->y + pix_size);
864 addr->cr = 0;
865 break;
866 case 3:
867
868 addr->cb = (dma_addr_t)(addr->y + pix_size);
869 if (GSC_YUV420 == frame->fmt->color)
870 addr->cr = (dma_addr_t)(addr->cb
871 + (pix_size >> 2));
872 else
873 addr->cr = (dma_addr_t)(addr->cb
874 + (pix_size >> 1));
875 break;
876 default:
877 pr_err("Invalid the number of color planes");
878 return -EINVAL;
879 }
880 } else {
881 if (frame->fmt->num_planes >= 2)
882 addr->cb = vb2_dma_contig_plane_dma_addr(vb, 1);
883
884 if (frame->fmt->num_planes == 3)
885 addr->cr = vb2_dma_contig_plane_dma_addr(vb, 2);
886 }
887
888 if ((frame->fmt->pixelformat == V4L2_PIX_FMT_VYUY) ||
889 (frame->fmt->pixelformat == V4L2_PIX_FMT_YVYU) ||
890 (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) ||
891 (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M))
892 swap(addr->cb, addr->cr);
893
894 pr_debug("ADDR: y= %pad cb= %pad cr= %pad ret= %d",
895 &addr->y, &addr->cb, &addr->cr, ret);
896
897 return ret;
898}
899
900static irqreturn_t gsc_irq_handler(int irq, void *priv)
901{
902 struct gsc_dev *gsc = priv;
903 struct gsc_ctx *ctx;
904 int gsc_irq;
905
906 gsc_irq = gsc_hw_get_irq_status(gsc);
907 gsc_hw_clear_irq(gsc, gsc_irq);
908
909 if (gsc_irq == GSC_IRQ_OVERRUN) {
910 pr_err("Local path input over-run interrupt has occurred!\n");
911 return IRQ_HANDLED;
912 }
913
914 spin_lock(&gsc->slock);
915
916 if (test_and_clear_bit(ST_M2M_PEND, &gsc->state)) {
917
918 gsc_hw_enable_control(gsc, false);
919
920 if (test_and_clear_bit(ST_M2M_SUSPENDING, &gsc->state)) {
921 set_bit(ST_M2M_SUSPENDED, &gsc->state);
922 wake_up(&gsc->irq_queue);
923 goto isr_unlock;
924 }
925 ctx = v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev);
926
927 if (!ctx || !ctx->m2m_ctx)
928 goto isr_unlock;
929
930 spin_unlock(&gsc->slock);
931 gsc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
932
933
934 if (ctx->state & GSC_CTX_STOP_REQ) {
935 ctx->state &= ~GSC_CTX_STOP_REQ;
936 wake_up(&gsc->irq_queue);
937 }
938 return IRQ_HANDLED;
939 }
940
941isr_unlock:
942 spin_unlock(&gsc->slock);
943 return IRQ_HANDLED;
944}
945
946static struct gsc_pix_max gsc_v_100_max = {
947 .org_scaler_bypass_w = 8192,
948 .org_scaler_bypass_h = 8192,
949 .org_scaler_input_w = 4800,
950 .org_scaler_input_h = 3344,
951 .real_rot_dis_w = 4800,
952 .real_rot_dis_h = 3344,
953 .real_rot_en_w = 2047,
954 .real_rot_en_h = 2047,
955 .target_rot_dis_w = 4800,
956 .target_rot_dis_h = 3344,
957 .target_rot_en_w = 2016,
958 .target_rot_en_h = 2016,
959};
960
961static struct gsc_pix_max gsc_v_5250_max = {
962 .org_scaler_bypass_w = 8192,
963 .org_scaler_bypass_h = 8192,
964 .org_scaler_input_w = 4800,
965 .org_scaler_input_h = 3344,
966 .real_rot_dis_w = 4800,
967 .real_rot_dis_h = 3344,
968 .real_rot_en_w = 2016,
969 .real_rot_en_h = 2016,
970 .target_rot_dis_w = 4800,
971 .target_rot_dis_h = 3344,
972 .target_rot_en_w = 2016,
973 .target_rot_en_h = 2016,
974};
975
976static struct gsc_pix_max gsc_v_5420_max = {
977 .org_scaler_bypass_w = 8192,
978 .org_scaler_bypass_h = 8192,
979 .org_scaler_input_w = 4800,
980 .org_scaler_input_h = 3344,
981 .real_rot_dis_w = 4800,
982 .real_rot_dis_h = 3344,
983 .real_rot_en_w = 2048,
984 .real_rot_en_h = 2048,
985 .target_rot_dis_w = 4800,
986 .target_rot_dis_h = 3344,
987 .target_rot_en_w = 2016,
988 .target_rot_en_h = 2016,
989};
990
991static struct gsc_pix_max gsc_v_5433_max = {
992 .org_scaler_bypass_w = 8192,
993 .org_scaler_bypass_h = 8192,
994 .org_scaler_input_w = 4800,
995 .org_scaler_input_h = 3344,
996 .real_rot_dis_w = 4800,
997 .real_rot_dis_h = 3344,
998 .real_rot_en_w = 2047,
999 .real_rot_en_h = 2047,
1000 .target_rot_dis_w = 4800,
1001 .target_rot_dis_h = 3344,
1002 .target_rot_en_w = 2016,
1003 .target_rot_en_h = 2016,
1004};
1005
1006static struct gsc_pix_min gsc_v_100_min = {
1007 .org_w = 64,
1008 .org_h = 32,
1009 .real_w = 64,
1010 .real_h = 32,
1011 .target_rot_dis_w = 64,
1012 .target_rot_dis_h = 32,
1013 .target_rot_en_w = 32,
1014 .target_rot_en_h = 16,
1015};
1016
1017static struct gsc_pix_align gsc_v_100_align = {
1018 .org_h = 16,
1019 .org_w = 16,
1020 .offset_h = 2,
1021 .real_w = 16,
1022 .real_h = 16,
1023 .target_w = 2,
1024 .target_h = 2,
1025};
1026
1027static struct gsc_variant gsc_v_100_variant = {
1028 .pix_max = &gsc_v_100_max,
1029 .pix_min = &gsc_v_100_min,
1030 .pix_align = &gsc_v_100_align,
1031 .in_buf_cnt = 32,
1032 .out_buf_cnt = 32,
1033 .sc_up_max = 8,
1034 .sc_down_max = 16,
1035 .poly_sc_down_max = 4,
1036 .pre_sc_down_max = 4,
1037 .local_sc_down = 2,
1038};
1039
1040static struct gsc_variant gsc_v_5250_variant = {
1041 .pix_max = &gsc_v_5250_max,
1042 .pix_min = &gsc_v_100_min,
1043 .pix_align = &gsc_v_100_align,
1044 .in_buf_cnt = 32,
1045 .out_buf_cnt = 32,
1046 .sc_up_max = 8,
1047 .sc_down_max = 16,
1048 .poly_sc_down_max = 4,
1049 .pre_sc_down_max = 4,
1050 .local_sc_down = 2,
1051};
1052
1053static struct gsc_variant gsc_v_5420_variant = {
1054 .pix_max = &gsc_v_5420_max,
1055 .pix_min = &gsc_v_100_min,
1056 .pix_align = &gsc_v_100_align,
1057 .in_buf_cnt = 32,
1058 .out_buf_cnt = 32,
1059 .sc_up_max = 8,
1060 .sc_down_max = 16,
1061 .poly_sc_down_max = 4,
1062 .pre_sc_down_max = 4,
1063 .local_sc_down = 2,
1064};
1065
1066static struct gsc_variant gsc_v_5433_variant = {
1067 .pix_max = &gsc_v_5433_max,
1068 .pix_min = &gsc_v_100_min,
1069 .pix_align = &gsc_v_100_align,
1070 .in_buf_cnt = 32,
1071 .out_buf_cnt = 32,
1072 .sc_up_max = 8,
1073 .sc_down_max = 16,
1074 .poly_sc_down_max = 4,
1075 .pre_sc_down_max = 4,
1076 .local_sc_down = 2,
1077};
1078
1079static struct gsc_driverdata gsc_v_100_drvdata = {
1080 .variant = {
1081 [0] = &gsc_v_100_variant,
1082 [1] = &gsc_v_100_variant,
1083 [2] = &gsc_v_100_variant,
1084 [3] = &gsc_v_100_variant,
1085 },
1086 .num_entities = 4,
1087 .clk_names = { "gscl" },
1088 .num_clocks = 1,
1089};
1090
1091static struct gsc_driverdata gsc_v_5250_drvdata = {
1092 .variant = {
1093 [0] = &gsc_v_5250_variant,
1094 [1] = &gsc_v_5250_variant,
1095 [2] = &gsc_v_5250_variant,
1096 [3] = &gsc_v_5250_variant,
1097 },
1098 .num_entities = 4,
1099 .clk_names = { "gscl" },
1100 .num_clocks = 1,
1101};
1102
1103static struct gsc_driverdata gsc_v_5420_drvdata = {
1104 .variant = {
1105 [0] = &gsc_v_5420_variant,
1106 [1] = &gsc_v_5420_variant,
1107 },
1108 .num_entities = 2,
1109 .clk_names = { "gscl" },
1110 .num_clocks = 1,
1111};
1112
1113static struct gsc_driverdata gsc_5433_drvdata = {
1114 .variant = {
1115 [0] = &gsc_v_5433_variant,
1116 [1] = &gsc_v_5433_variant,
1117 [2] = &gsc_v_5433_variant,
1118 },
1119 .num_entities = 3,
1120 .clk_names = { "pclk", "aclk", "aclk_xiu", "aclk_gsclbend" },
1121 .num_clocks = 4,
1122};
1123
1124static const struct of_device_id exynos_gsc_match[] = {
1125 {
1126 .compatible = "samsung,exynos5250-gsc",
1127 .data = &gsc_v_5250_drvdata,
1128 },
1129 {
1130 .compatible = "samsung,exynos5420-gsc",
1131 .data = &gsc_v_5420_drvdata,
1132 },
1133 {
1134 .compatible = "samsung,exynos5433-gsc",
1135 .data = &gsc_5433_drvdata,
1136 },
1137 {
1138 .compatible = "samsung,exynos5-gsc",
1139 .data = &gsc_v_100_drvdata,
1140 },
1141 {},
1142};
1143MODULE_DEVICE_TABLE(of, exynos_gsc_match);
1144
1145static int gsc_probe(struct platform_device *pdev)
1146{
1147 struct gsc_dev *gsc;
1148 struct resource *res;
1149 struct device *dev = &pdev->dev;
1150 const struct gsc_driverdata *drv_data = of_device_get_match_data(dev);
1151 int ret;
1152 int i;
1153
1154 gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL);
1155 if (!gsc)
1156 return -ENOMEM;
1157
1158 ret = of_alias_get_id(pdev->dev.of_node, "gsc");
1159 if (ret < 0)
1160 return ret;
1161
1162 if (drv_data == &gsc_v_100_drvdata)
1163 dev_info(dev, "compatible 'exynos5-gsc' is deprecated\n");
1164
1165 gsc->id = ret;
1166 if (gsc->id >= drv_data->num_entities) {
1167 dev_err(dev, "Invalid platform device id: %d\n", gsc->id);
1168 return -EINVAL;
1169 }
1170
1171 gsc->num_clocks = drv_data->num_clocks;
1172 gsc->variant = drv_data->variant[gsc->id];
1173 gsc->pdev = pdev;
1174
1175 init_waitqueue_head(&gsc->irq_queue);
1176 spin_lock_init(&gsc->slock);
1177 mutex_init(&gsc->lock);
1178
1179 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1180 gsc->regs = devm_ioremap_resource(dev, res);
1181 if (IS_ERR(gsc->regs))
1182 return PTR_ERR(gsc->regs);
1183
1184 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1185 if (!res) {
1186 dev_err(dev, "failed to get IRQ resource\n");
1187 return -ENXIO;
1188 }
1189
1190 for (i = 0; i < gsc->num_clocks; i++) {
1191 gsc->clock[i] = devm_clk_get(dev, drv_data->clk_names[i]);
1192 if (IS_ERR(gsc->clock[i])) {
1193 dev_err(dev, "failed to get clock: %s\n",
1194 drv_data->clk_names[i]);
1195 return PTR_ERR(gsc->clock[i]);
1196 }
1197 }
1198
1199 for (i = 0; i < gsc->num_clocks; i++) {
1200 ret = clk_prepare_enable(gsc->clock[i]);
1201 if (ret) {
1202 dev_err(dev, "clock prepare failed for clock: %s\n",
1203 drv_data->clk_names[i]);
1204 while (--i >= 0)
1205 clk_disable_unprepare(gsc->clock[i]);
1206 return ret;
1207 }
1208 }
1209
1210 ret = devm_request_irq(dev, res->start, gsc_irq_handler,
1211 0, pdev->name, gsc);
1212 if (ret) {
1213 dev_err(dev, "failed to install irq (%d)\n", ret);
1214 goto err_clk;
1215 }
1216
1217 ret = v4l2_device_register(dev, &gsc->v4l2_dev);
1218 if (ret)
1219 goto err_clk;
1220
1221 ret = gsc_register_m2m_device(gsc);
1222 if (ret)
1223 goto err_v4l2;
1224
1225 platform_set_drvdata(pdev, gsc);
1226
1227 gsc_hw_set_sw_reset(gsc);
1228 gsc_wait_reset(gsc);
1229
1230 vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
1231
1232 dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id);
1233
1234 pm_runtime_set_active(dev);
1235 pm_runtime_enable(dev);
1236
1237 return 0;
1238
1239err_v4l2:
1240 v4l2_device_unregister(&gsc->v4l2_dev);
1241err_clk:
1242 for (i = gsc->num_clocks - 1; i >= 0; i--)
1243 clk_disable_unprepare(gsc->clock[i]);
1244 return ret;
1245}
1246
1247static int gsc_remove(struct platform_device *pdev)
1248{
1249 struct gsc_dev *gsc = platform_get_drvdata(pdev);
1250 int i;
1251
1252 pm_runtime_get_sync(&pdev->dev);
1253
1254 gsc_unregister_m2m_device(gsc);
1255 v4l2_device_unregister(&gsc->v4l2_dev);
1256
1257 vb2_dma_contig_clear_max_seg_size(&pdev->dev);
1258 for (i = 0; i < gsc->num_clocks; i++)
1259 clk_disable_unprepare(gsc->clock[i]);
1260
1261 pm_runtime_put_noidle(&pdev->dev);
1262 pm_runtime_disable(&pdev->dev);
1263
1264 dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
1265 return 0;
1266}
1267
1268#ifdef CONFIG_PM
1269static int gsc_m2m_suspend(struct gsc_dev *gsc)
1270{
1271 unsigned long flags;
1272 int timeout;
1273
1274 spin_lock_irqsave(&gsc->slock, flags);
1275 if (!gsc_m2m_pending(gsc)) {
1276 spin_unlock_irqrestore(&gsc->slock, flags);
1277 return 0;
1278 }
1279 clear_bit(ST_M2M_SUSPENDED, &gsc->state);
1280 set_bit(ST_M2M_SUSPENDING, &gsc->state);
1281 spin_unlock_irqrestore(&gsc->slock, flags);
1282
1283 timeout = wait_event_timeout(gsc->irq_queue,
1284 test_bit(ST_M2M_SUSPENDED, &gsc->state),
1285 GSC_SHUTDOWN_TIMEOUT);
1286
1287 clear_bit(ST_M2M_SUSPENDING, &gsc->state);
1288 return timeout == 0 ? -EAGAIN : 0;
1289}
1290
1291static void gsc_m2m_resume(struct gsc_dev *gsc)
1292{
1293 struct gsc_ctx *ctx;
1294 unsigned long flags;
1295
1296 spin_lock_irqsave(&gsc->slock, flags);
1297
1298 ctx = gsc->m2m.ctx;
1299 gsc->m2m.ctx = NULL;
1300 spin_unlock_irqrestore(&gsc->slock, flags);
1301
1302 if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state))
1303 gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
1304}
1305
1306static int gsc_runtime_resume(struct device *dev)
1307{
1308 struct gsc_dev *gsc = dev_get_drvdata(dev);
1309 int ret = 0;
1310 int i;
1311
1312 pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state);
1313
1314 for (i = 0; i < gsc->num_clocks; i++) {
1315 ret = clk_prepare_enable(gsc->clock[i]);
1316 if (ret) {
1317 while (--i >= 0)
1318 clk_disable_unprepare(gsc->clock[i]);
1319 return ret;
1320 }
1321 }
1322
1323 gsc_hw_set_sw_reset(gsc);
1324 gsc_wait_reset(gsc);
1325 gsc_m2m_resume(gsc);
1326
1327 return 0;
1328}
1329
1330static int gsc_runtime_suspend(struct device *dev)
1331{
1332 struct gsc_dev *gsc = dev_get_drvdata(dev);
1333 int ret = 0;
1334 int i;
1335
1336 ret = gsc_m2m_suspend(gsc);
1337 if (ret)
1338 return ret;
1339
1340 for (i = gsc->num_clocks - 1; i >= 0; i--)
1341 clk_disable_unprepare(gsc->clock[i]);
1342
1343 pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state);
1344 return ret;
1345}
1346#endif
1347
1348static const struct dev_pm_ops gsc_pm_ops = {
1349 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
1350 pm_runtime_force_resume)
1351 SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)
1352};
1353
1354static struct platform_driver gsc_driver = {
1355 .probe = gsc_probe,
1356 .remove = gsc_remove,
1357 .driver = {
1358 .name = GSC_MODULE_NAME,
1359 .pm = &gsc_pm_ops,
1360 .of_match_table = exynos_gsc_match,
1361 }
1362};
1363
1364module_platform_driver(gsc_driver);
1365
1366MODULE_AUTHOR("Hyunwong Kim <khw0178.kim@samsung.com>");
1367MODULE_DESCRIPTION("Samsung EXYNOS5 Soc series G-Scaler driver");
1368MODULE_LICENSE("GPL");
1369