cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

gsc-core.c (32257B)


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