fimc-core.c 32.3 KB
Newer Older
1
/*
2
 * Samsung S5P/EXYNOS4 SoC series FIMC (CAMIF) driver
3
 *
4 5
 * Copyright (C) 2010-2012 Samsung Electronics Co., Ltd.
 * Sylwester Nawrocki <s.nawrocki@samsung.com>
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either version 2 of the License,
 * or (at your option) any later version.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/bug.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/platform_device.h>
21
#include <linux/pm_runtime.h>
22
#include <linux/list.h>
23
#include <linux/mfd/syscon.h>
24
#include <linux/io.h>
25 26
#include <linux/of.h>
#include <linux/of_device.h>
27 28 29
#include <linux/slab.h>
#include <linux/clk.h>
#include <media/v4l2-ioctl.h>
30 31
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
32 33

#include "fimc-core.h"
34
#include "fimc-reg.h"
35
#include "media-dev.h"
36

37
static char *fimc_clocks[MAX_FIMC_CLOCKS] = {
38
	"sclk_fimc", "fimc"
39
};
40 41 42

static struct fimc_fmt fimc_formats[] = {
	{
43
		.name		= "RGB565",
44
		.fourcc		= V4L2_PIX_FMT_RGB565,
45
		.depth		= { 16 },
46
		.color		= FIMC_FMT_RGB565,
47 48 49
		.memplanes	= 1,
		.colplanes	= 1,
		.flags		= FMT_FLAGS_M2M,
50
	}, {
51 52 53
		.name		= "BGR666",
		.fourcc		= V4L2_PIX_FMT_BGR666,
		.depth		= { 32 },
54
		.color		= FIMC_FMT_RGB666,
55 56 57
		.memplanes	= 1,
		.colplanes	= 1,
		.flags		= FMT_FLAGS_M2M,
58
	}, {
59
		.name		= "ARGB8888, 32 bpp",
60 61
		.fourcc		= V4L2_PIX_FMT_RGB32,
		.depth		= { 32 },
62
		.color		= FIMC_FMT_RGB888,
63 64
		.memplanes	= 1,
		.colplanes	= 1,
65 66 67 68 69
		.flags		= FMT_FLAGS_M2M | FMT_HAS_ALPHA,
	}, {
		.name		= "ARGB1555",
		.fourcc		= V4L2_PIX_FMT_RGB555,
		.depth		= { 16 },
70
		.color		= FIMC_FMT_RGB555,
71 72 73 74 75 76 77
		.memplanes	= 1,
		.colplanes	= 1,
		.flags		= FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
	}, {
		.name		= "ARGB4444",
		.fourcc		= V4L2_PIX_FMT_RGB444,
		.depth		= { 16 },
78
		.color		= FIMC_FMT_RGB444,
79 80 81
		.memplanes	= 1,
		.colplanes	= 1,
		.flags		= FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
82 83 84 85
	}, {
		.name		= "YUV 4:4:4",
		.mbus_code	= V4L2_MBUS_FMT_YUV10_1X30,
		.flags		= FMT_FLAGS_WRITEBACK,
86
	}, {
87 88 89
		.name		= "YUV 4:2:2 packed, YCbYCr",
		.fourcc		= V4L2_PIX_FMT_YUYV,
		.depth		= { 16 },
90
		.color		= FIMC_FMT_YCBYCR422,
91 92 93 94
		.memplanes	= 1,
		.colplanes	= 1,
		.mbus_code	= V4L2_MBUS_FMT_YUYV8_2X8,
		.flags		= FMT_FLAGS_M2M | FMT_FLAGS_CAM,
95
	}, {
96 97 98
		.name		= "YUV 4:2:2 packed, CbYCrY",
		.fourcc		= V4L2_PIX_FMT_UYVY,
		.depth		= { 16 },
99
		.color		= FIMC_FMT_CBYCRY422,
100 101 102 103
		.memplanes	= 1,
		.colplanes	= 1,
		.mbus_code	= V4L2_MBUS_FMT_UYVY8_2X8,
		.flags		= FMT_FLAGS_M2M | FMT_FLAGS_CAM,
104
	}, {
105 106 107
		.name		= "YUV 4:2:2 packed, CrYCbY",
		.fourcc		= V4L2_PIX_FMT_VYUY,
		.depth		= { 16 },
108
		.color		= FIMC_FMT_CRYCBY422,
109 110 111 112
		.memplanes	= 1,
		.colplanes	= 1,
		.mbus_code	= V4L2_MBUS_FMT_VYUY8_2X8,
		.flags		= FMT_FLAGS_M2M | FMT_FLAGS_CAM,
113
	}, {
114 115 116
		.name		= "YUV 4:2:2 packed, YCrYCb",
		.fourcc		= V4L2_PIX_FMT_YVYU,
		.depth		= { 16 },
117
		.color		= FIMC_FMT_YCRYCB422,
118 119 120 121
		.memplanes	= 1,
		.colplanes	= 1,
		.mbus_code	= V4L2_MBUS_FMT_YVYU8_2X8,
		.flags		= FMT_FLAGS_M2M | FMT_FLAGS_CAM,
122
	}, {
123 124 125
		.name		= "YUV 4:2:2 planar, Y/Cb/Cr",
		.fourcc		= V4L2_PIX_FMT_YUV422P,
		.depth		= { 12 },
126
		.color		= FIMC_FMT_YCBYCR422,
127 128 129
		.memplanes	= 1,
		.colplanes	= 3,
		.flags		= FMT_FLAGS_M2M,
130
	}, {
131 132 133
		.name		= "YUV 4:2:2 planar, Y/CbCr",
		.fourcc		= V4L2_PIX_FMT_NV16,
		.depth		= { 16 },
134
		.color		= FIMC_FMT_YCBYCR422,
135 136 137
		.memplanes	= 1,
		.colplanes	= 2,
		.flags		= FMT_FLAGS_M2M,
138
	}, {
139 140 141
		.name		= "YUV 4:2:2 planar, Y/CrCb",
		.fourcc		= V4L2_PIX_FMT_NV61,
		.depth		= { 16 },
142
		.color		= FIMC_FMT_YCRYCB422,
143 144 145
		.memplanes	= 1,
		.colplanes	= 2,
		.flags		= FMT_FLAGS_M2M,
146
	}, {
147 148 149
		.name		= "YUV 4:2:0 planar, YCbCr",
		.fourcc		= V4L2_PIX_FMT_YUV420,
		.depth		= { 12 },
150
		.color		= FIMC_FMT_YCBCR420,
151 152 153
		.memplanes	= 1,
		.colplanes	= 3,
		.flags		= FMT_FLAGS_M2M,
154
	}, {
155 156 157
		.name		= "YUV 4:2:0 planar, Y/CbCr",
		.fourcc		= V4L2_PIX_FMT_NV12,
		.depth		= { 12 },
158
		.color		= FIMC_FMT_YCBCR420,
159 160 161 162
		.memplanes	= 1,
		.colplanes	= 2,
		.flags		= FMT_FLAGS_M2M,
	}, {
163
		.name		= "YUV 4:2:0 non-contig. 2p, Y/CbCr",
164
		.fourcc		= V4L2_PIX_FMT_NV12M,
165
		.color		= FIMC_FMT_YCBCR420,
166 167 168 169 170
		.depth		= { 8, 4 },
		.memplanes	= 2,
		.colplanes	= 2,
		.flags		= FMT_FLAGS_M2M,
	}, {
171
		.name		= "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
172
		.fourcc		= V4L2_PIX_FMT_YUV420M,
173
		.color		= FIMC_FMT_YCBCR420,
174 175 176 177 178
		.depth		= { 8, 2, 2 },
		.memplanes	= 3,
		.colplanes	= 3,
		.flags		= FMT_FLAGS_M2M,
	}, {
179
		.name		= "YUV 4:2:0 non-contig. 2p, tiled",
180
		.fourcc		= V4L2_PIX_FMT_NV12MT,
181
		.color		= FIMC_FMT_YCBCR420,
182 183 184 185
		.depth		= { 8, 4 },
		.memplanes	= 2,
		.colplanes	= 2,
		.flags		= FMT_FLAGS_M2M,
186 187 188
	}, {
		.name		= "JPEG encoded data",
		.fourcc		= V4L2_PIX_FMT_JPEG,
189
		.color		= FIMC_FMT_JPEG,
190 191 192 193
		.depth		= { 8 },
		.memplanes	= 1,
		.colplanes	= 1,
		.mbus_code	= V4L2_MBUS_FMT_JPEG_1X8,
194 195 196 197 198 199 200 201 202 203 204
		.flags		= FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED,
	}, {
		.name		= "S5C73MX interleaved UYVY/JPEG",
		.fourcc		= V4L2_PIX_FMT_S5C_UYVY_JPG,
		.color		= FIMC_FMT_YUYV_JPEG,
		.depth		= { 8 },
		.memplanes	= 2,
		.colplanes	= 1,
		.mdataplanes	= 0x2, /* plane 1 holds frame meta data */
		.mbus_code	= V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8,
		.flags		= FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED,
205
	},
206
};
207

208
struct fimc_fmt *fimc_get_format(unsigned int index)
209
{
210 211 212 213
	if (index >= ARRAY_SIZE(fimc_formats))
		return NULL;

	return &fimc_formats[index];
214 215
}

216 217
int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
			    int dw, int dh, int rotation)
218
{
219 220
	if (rotation == 90 || rotation == 270)
		swap(dw, dh);
221

222 223
	if (!ctx->scaler.enabled)
		return (sw == dw && sh == dh) ? 0 : -EINVAL;
224

225
	if ((sw >= SCALER_MAX_HRATIO * dw) || (sh >= SCALER_MAX_VRATIO * dh))
226 227
		return -EINVAL;

228 229 230 231 232
	return 0;
}

static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
{
233 234 235
	u32 sh = 6;

	if (src >= 64 * tar)
236
		return -EINVAL;
237 238 239 240 241 242 243

	while (sh--) {
		u32 tmp = 1 << sh;
		if (src >= tar * tmp) {
			*shift = sh, *ratio = tmp;
			return 0;
		}
244
	}
245
	*shift = 0, *ratio = 1;
246 247 248
	return 0;
}

249
int fimc_set_scaler_info(struct fimc_ctx *ctx)
250
{
251
	const struct fimc_variant *variant = ctx->fimc_dev->variant;
252
	struct device *dev = &ctx->fimc_dev->pdev->dev;
253 254 255 256 257 258
	struct fimc_scaler *sc = &ctx->scaler;
	struct fimc_frame *s_frame = &ctx->s_frame;
	struct fimc_frame *d_frame = &ctx->d_frame;
	int tx, ty, sx, sy;
	int ret;

259 260 261 262 263 264 265
	if (ctx->rotation == 90 || ctx->rotation == 270) {
		ty = d_frame->width;
		tx = d_frame->height;
	} else {
		tx = d_frame->width;
		ty = d_frame->height;
	}
266
	if (tx <= 0 || ty <= 0) {
267
		dev_err(dev, "Invalid target size: %dx%d\n", tx, ty);
268 269 270 271 272 273
		return -EINVAL;
	}

	sx = s_frame->width;
	sy = s_frame->height;
	if (sx <= 0 || sy <= 0) {
274
		dev_err(dev, "Invalid source size: %dx%d\n", sx, sy);
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
		return -EINVAL;
	}
	sc->real_width = sx;
	sc->real_height = sy;

	ret = fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor);
	if (ret)
		return ret;

	ret = fimc_get_scaler_factor(sy, ty,  &sc->pre_vratio, &sc->vfactor);
	if (ret)
		return ret;

	sc->pre_dst_width = sx / sc->pre_hratio;
	sc->pre_dst_height = sy / sc->pre_vratio;

291 292 293 294 295 296 297 298
	if (variant->has_mainscaler_ext) {
		sc->main_hratio = (sx << 14) / (tx << sc->hfactor);
		sc->main_vratio = (sy << 14) / (ty << sc->vfactor);
	} else {
		sc->main_hratio = (sx << 8) / (tx << sc->hfactor);
		sc->main_vratio = (sy << 8) / (ty << sc->vfactor);

	}
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313

	sc->scaleup_h = (tx >= sx) ? 1 : 0;
	sc->scaleup_v = (ty >= sy) ? 1 : 0;

	/* check to see if input and output size/format differ */
	if (s_frame->fmt->color == d_frame->fmt->color
		&& s_frame->width == d_frame->width
		&& s_frame->height == d_frame->height)
		sc->copy_mode = 1;
	else
		sc->copy_mode = 0;

	return 0;
}

314
static irqreturn_t fimc_irq_handler(int irq, void *priv)
315
{
316
	struct fimc_dev *fimc = priv;
317
	struct fimc_ctx *ctx;
318 319 320

	fimc_hw_clear_irq(fimc);

321 322
	spin_lock(&fimc->slock);

323
	if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) {
324 325 326 327 328
		if (test_and_clear_bit(ST_M2M_SUSPENDING, &fimc->state)) {
			set_bit(ST_M2M_SUSPENDED, &fimc->state);
			wake_up(&fimc->irq_queue);
			goto out;
		}
329 330
		ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev);
		if (ctx != NULL) {
331
			spin_unlock(&fimc->slock);
332
			fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
333

334 335 336 337
			if (ctx->state & FIMC_CTX_SHUT) {
				ctx->state &= ~FIMC_CTX_SHUT;
				wake_up(&fimc->irq_queue);
			}
338
			return IRQ_HANDLED;
339
		}
340
	} else if (test_bit(ST_CAPT_PEND, &fimc->state)) {
341 342 343
		int last_buf = test_bit(ST_CAPT_JPEG, &fimc->state) &&
				fimc->vid_cap.reqbufs_count == 1;
		fimc_capture_irq_handler(fimc, !last_buf);
344
	}
345
out:
346 347 348 349
	spin_unlock(&fimc->slock);
	return IRQ_HANDLED;
}

350
/* The color format (colplanes, memplanes) must be already configured. */
351
int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
352
		      struct fimc_frame *frame, struct fimc_addr *paddr)
353 354
{
	int ret = 0;
355
	u32 pix_size;
356

357
	if (vb == NULL || frame == NULL)
358 359 360 361
		return -EINVAL;

	pix_size = frame->width * frame->height;

362 363 364
	dbg("memplanes= %d, colplanes= %d, pix_size= %d",
		frame->fmt->memplanes, frame->fmt->colplanes, pix_size);

365
	paddr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
366

367 368
	if (frame->fmt->memplanes == 1) {
		switch (frame->fmt->colplanes) {
369 370 371 372 373 374 375 376 377 378 379 380
		case 1:
			paddr->cb = 0;
			paddr->cr = 0;
			break;
		case 2:
			/* decompose Y into Y/Cb */
			paddr->cb = (u32)(paddr->y + pix_size);
			paddr->cr = 0;
			break;
		case 3:
			paddr->cb = (u32)(paddr->y + pix_size);
			/* decompose Y into Y/Cb/Cr */
381
			if (FIMC_FMT_YCBCR420 == frame->fmt->color)
382 383 384 385 386 387 388 389 390
				paddr->cr = (u32)(paddr->cb
						+ (pix_size >> 2));
			else /* 422 */
				paddr->cr = (u32)(paddr->cb
						+ (pix_size >> 1));
			break;
		default:
			return -EINVAL;
		}
391
	} else if (!frame->fmt->mdataplanes) {
392
		if (frame->fmt->memplanes >= 2)
393
			paddr->cb = vb2_dma_contig_plane_dma_addr(vb, 1);
394 395

		if (frame->fmt->memplanes == 3)
396
			paddr->cr = vb2_dma_contig_plane_dma_addr(vb, 2);
397 398
	}

399 400
	dbg("PHYS_ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
	    paddr->y, paddr->cb, paddr->cr, ret);
401 402 403 404 405

	return ret;
}

/* Set order for 1 and 2 plane YCBCR 4:2:2 formats. */
406
void fimc_set_yuv_order(struct fimc_ctx *ctx)
407 408
{
	/* The one only mode supported in SoC. */
409 410
	ctx->in_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
	ctx->out_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
411 412 413

	/* Set order for 1 plane input formats. */
	switch (ctx->s_frame.fmt->color) {
414
	case FIMC_FMT_YCRYCB422:
415
		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CBYCRY;
416
		break;
417
	case FIMC_FMT_CBYCRY422:
418
		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCRYCB;
419
		break;
420
	case FIMC_FMT_CRYCBY422:
421
		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCBYCR;
422
		break;
423
	case FIMC_FMT_YCBYCR422:
424
	default:
425
		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CRYCBY;
426 427 428 429 430
		break;
	}
	dbg("ctx->in_order_1p= %d", ctx->in_order_1p);

	switch (ctx->d_frame.fmt->color) {
431
	case FIMC_FMT_YCRYCB422:
432
		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CBYCRY;
433
		break;
434
	case FIMC_FMT_CBYCRY422:
435
		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCRYCB;
436
		break;
437
	case FIMC_FMT_CRYCBY422:
438
		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCBYCR;
439
		break;
440
	case FIMC_FMT_YCBYCR422:
441
	default:
442
		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CRYCBY;
443 444 445 446 447
		break;
	}
	dbg("ctx->out_order_1p= %d", ctx->out_order_1p);
}

448
void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
449
{
450
	bool pix_hoff = ctx->fimc_dev->drv_data->dma_pix_hoff;
451 452 453 454
	u32 i, depth = 0;

	for (i = 0; i < f->fmt->colplanes; i++)
		depth += f->fmt->depth[i];
455 456

	f->dma_offset.y_h = f->offs_h;
457
	if (!pix_hoff)
458
		f->dma_offset.y_h *= (depth >> 3);
459 460 461 462 463 464 465 466 467

	f->dma_offset.y_v = f->offs_v;

	f->dma_offset.cb_h = f->offs_h;
	f->dma_offset.cb_v = f->offs_v;

	f->dma_offset.cr_h = f->offs_h;
	f->dma_offset.cr_v = f->offs_v;

468
	if (!pix_hoff) {
469
		if (f->fmt->colplanes == 3) {
470 471 472
			f->dma_offset.cb_h >>= 1;
			f->dma_offset.cr_h >>= 1;
		}
473
		if (f->fmt->color == FIMC_FMT_YCBCR420) {
474 475 476 477 478 479 480 481 482
			f->dma_offset.cb_v >>= 1;
			f->dma_offset.cr_v >>= 1;
		}
	}

	dbg("in_offset: color= %d, y_h= %d, y_v= %d",
	    f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v);
}

483
static int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx)
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
{
	struct fimc_effect *effect = &ctx->effect;

	switch (colorfx) {
	case V4L2_COLORFX_NONE:
		effect->type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
		break;
	case V4L2_COLORFX_BW:
		effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
		effect->pat_cb = 128;
		effect->pat_cr = 128;
		break;
	case V4L2_COLORFX_SEPIA:
		effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
		effect->pat_cb = 115;
		effect->pat_cr = 145;
		break;
	case V4L2_COLORFX_NEGATIVE:
		effect->type = FIMC_REG_CIIMGEFF_FIN_NEGATIVE;
		break;
	case V4L2_COLORFX_EMBOSS:
		effect->type = FIMC_REG_CIIMGEFF_FIN_EMBOSSING;
		break;
	case V4L2_COLORFX_ART_FREEZE:
		effect->type = FIMC_REG_CIIMGEFF_FIN_ARTFREEZE;
		break;
	case V4L2_COLORFX_SILHOUETTE:
		effect->type = FIMC_REG_CIIMGEFF_FIN_SILHOUETTE;
		break;
	case V4L2_COLORFX_SET_CBCR:
		effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
		effect->pat_cb = ctx->ctrls.colorfx_cbcr->val >> 8;
		effect->pat_cr = ctx->ctrls.colorfx_cbcr->val & 0xff;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

525 526 527 528
/*
 * V4L2 controls handling
 */
#define ctrl_to_ctx(__ctrl) \
529
	container_of((__ctrl)->handler, struct fimc_ctx, ctrls.handler)
530

531
static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
532 533
{
	struct fimc_dev *fimc = ctx->fimc_dev;
534
	const struct fimc_variant *variant = fimc->variant;
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
	int ret = 0;

	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
		return 0;

	switch (ctrl->id) {
	case V4L2_CID_HFLIP:
		ctx->hflip = ctrl->val;
		break;

	case V4L2_CID_VFLIP:
		ctx->vflip = ctrl->val;
		break;

	case V4L2_CID_ROTATE:
550
		if (fimc_capture_pending(fimc)) {
551
			ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
552 553
					ctx->s_frame.height, ctx->d_frame.width,
					ctx->d_frame.height, ctrl->val);
554 555
			if (ret)
				return -EINVAL;
556 557 558 559
		}
		if ((ctrl->val == 90 || ctrl->val == 270) &&
		    !variant->has_out_rot)
			return -EINVAL;
560

561 562 563
		ctx->rotation = ctrl->val;
		break;

564 565 566
	case V4L2_CID_ALPHA_COMPONENT:
		ctx->d_frame.alpha = ctrl->val;
		break;
567 568 569 570 571 572

	case V4L2_CID_COLORFX:
		ret = fimc_set_color_effect(ctx, ctrl->val);
		if (ret)
			return ret;
		break;
573
	}
574

575 576 577 578 579
	ctx->state |= FIMC_PARAMS;
	set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
	return 0;
}

580 581 582 583 584 585
static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct fimc_ctx *ctx = ctrl_to_ctx(ctrl);
	unsigned long flags;
	int ret;

586
	spin_lock_irqsave(&ctx->fimc_dev->slock, flags);
587
	ret = __fimc_s_ctrl(ctx, ctrl);
588
	spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags);
589 590 591 592

	return ret;
}

593 594 595 596 597 598
static const struct v4l2_ctrl_ops fimc_ctrl_ops = {
	.s_ctrl = fimc_s_ctrl,
};

int fimc_ctrls_create(struct fimc_ctx *ctx)
{
599
	unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt);
600 601
	struct fimc_ctrls *ctrls = &ctx->ctrls;
	struct v4l2_ctrl_handler *handler = &ctrls->handler;
602

603
	if (ctx->ctrls.ready)
604 605
		return 0;

606 607 608
	v4l2_ctrl_handler_init(handler, 6);

	ctrls->rotate = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
609
					V4L2_CID_ROTATE, 0, 270, 90, 0);
610
	ctrls->hflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
611
					V4L2_CID_HFLIP, 0, 1, 1, 0);
612
	ctrls->vflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
613
					V4L2_CID_VFLIP, 0, 1, 1, 0);
614

615
	if (ctx->fimc_dev->drv_data->alpha_color)
616 617 618
		ctrls->alpha = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
					V4L2_CID_ALPHA_COMPONENT,
					0, max_alpha, 1, 0);
619
	else
620 621 622 623 624 625 626 627
		ctrls->alpha = NULL;

	ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, &fimc_ctrl_ops,
				V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR,
				~0x983f, V4L2_COLORFX_NONE);

	ctrls->colorfx_cbcr = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
				V4L2_CID_COLORFX_CBCR, 0, 0xffff, 1, 0);
628

629
	ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
630

631
	if (!handler->error) {
632
		v4l2_ctrl_cluster(2, &ctrls->colorfx);
633 634 635 636
		ctrls->ready = true;
	}

	return handler->error;
637 638 639 640
}

void fimc_ctrls_delete(struct fimc_ctx *ctx)
{
641 642 643 644 645 646
	struct fimc_ctrls *ctrls = &ctx->ctrls;

	if (ctrls->ready) {
		v4l2_ctrl_handler_free(&ctrls->handler);
		ctrls->ready = false;
		ctrls->alpha = NULL;
647 648 649 650 651
	}
}

void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
{
652
	unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA;
653
	struct fimc_ctrls *ctrls = &ctx->ctrls;
654

655
	if (!ctrls->ready)
656 657
		return;

658
	mutex_lock(ctrls->handler.lock);
659 660 661 662 663 664
	v4l2_ctrl_activate(ctrls->rotate, active);
	v4l2_ctrl_activate(ctrls->hflip, active);
	v4l2_ctrl_activate(ctrls->vflip, active);
	v4l2_ctrl_activate(ctrls->colorfx, active);
	if (ctrls->alpha)
		v4l2_ctrl_activate(ctrls->alpha, active && has_alpha);
665 666

	if (active) {
667 668 669 670
		fimc_set_color_effect(ctx, ctrls->colorfx->cur.val);
		ctx->rotation = ctrls->rotate->val;
		ctx->hflip    = ctrls->hflip->val;
		ctx->vflip    = ctrls->vflip->val;
671
	} else {
672
		ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
673 674 675 676
		ctx->rotation = 0;
		ctx->hflip    = 0;
		ctx->vflip    = 0;
	}
677
	mutex_unlock(ctrls->handler.lock);
678 679
}

680 681 682 683
/* Update maximum value of the alpha color control */
void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
{
	struct fimc_dev *fimc = ctx->fimc_dev;
684
	struct v4l2_ctrl *ctrl = ctx->ctrls.alpha;
685

686
	if (ctrl == NULL || !fimc->drv_data->alpha_color)
687 688 689 690 691 692 693 694 695 696 697
		return;

	v4l2_ctrl_lock(ctrl);
	ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt);

	if (ctrl->cur.val > ctrl->maximum)
		ctrl->cur.val = ctrl->maximum;

	v4l2_ctrl_unlock(ctrl);
}

698
void __fimc_get_format(struct fimc_frame *frame, struct v4l2_format *f)
699
{
700
	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
701
	int i;
702

703 704 705 706 707 708
	pixm->width = frame->o_width;
	pixm->height = frame->o_height;
	pixm->field = V4L2_FIELD_NONE;
	pixm->pixelformat = frame->fmt->fourcc;
	pixm->colorspace = V4L2_COLORSPACE_JPEG;
	pixm->num_planes = frame->fmt->memplanes;
709 710

	for (i = 0; i < pixm->num_planes; ++i) {
711 712
		pixm->plane_fmt[i].bytesperline = frame->bytesperline[i];
		pixm->plane_fmt[i].sizeimage = frame->payload[i];
713
	}
714 715
}

716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
/**
 * fimc_adjust_mplane_format - adjust bytesperline/sizeimage for each plane
 * @fmt: fimc pixel format description (input)
 * @width: requested pixel width
 * @height: requested pixel height
 * @pix: multi-plane format to adjust
 */
void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
			       struct v4l2_pix_format_mplane *pix)
{
	u32 bytesperline = 0;
	int i;

	pix->colorspace	= V4L2_COLORSPACE_JPEG;
	pix->field = V4L2_FIELD_NONE;
	pix->num_planes = fmt->memplanes;
732
	pix->pixelformat = fmt->fourcc;
733 734 735 736
	pix->height = height;
	pix->width = width;

	for (i = 0; i < pix->num_planes; ++i) {
737 738
		struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i];
		u32 bpl = plane_fmt->bytesperline;
739 740 741 742 743 744 745

		if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width))
			bpl = pix->width; /* Planar */

		if (fmt->colplanes == 1 && /* Packed */
		    (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width))
			bpl = (pix->width * fmt->depth[0]) / 8;
746 747 748 749 750 751 752
		/*
		 * Currently bytesperline for each plane is same, except
		 * V4L2_PIX_FMT_YUV420M format. This calculation may need
		 * to be changed when other multi-planar formats are added
		 * to the fimc_formats[] array.
		 */
		if (i == 0)
753
			bytesperline = bpl;
754 755
		else if (i == 1 && fmt->memplanes == 3)
			bytesperline /= 2;
756

757 758 759
		plane_fmt->bytesperline = bytesperline;
		plane_fmt->sizeimage = max((pix->width * pix->height *
				   fmt->depth[i]) / 8, plane_fmt->sizeimage);
760 761 762
	}
}

763 764 765 766 767 768 769
/**
 * fimc_find_format - lookup fimc color format by fourcc or media bus format
 * @pixelformat: fourcc to match, ignored if null
 * @mbus_code: media bus code to match, ignored if null
 * @mask: the color flags to match
 * @index: offset in the fimc_formats array, ignored if negative
 */
770
struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code,
771
				  unsigned int mask, int index)
772
{
773
	struct fimc_fmt *fmt, *def_fmt = NULL;
774
	unsigned int i;
775
	int id = 0;
776

777
	if (index >= (int)ARRAY_SIZE(fimc_formats))
778
		return NULL;
779 780 781

	for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
		fmt = &fimc_formats[i];
782 783 784 785 786 787 788 789 790
		if (!(fmt->flags & mask))
			continue;
		if (pixelformat && fmt->fourcc == *pixelformat)
			return fmt;
		if (mbus_code && fmt->mbus_code == *mbus_code)
			return fmt;
		if (index == id)
			def_fmt = fmt;
		id++;
791
	}
792
	return def_fmt;
793 794
}

795
static void fimc_clk_put(struct fimc_dev *fimc)
796 797
{
	int i;
798
	for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
799
		if (IS_ERR(fimc->clock[i]))
800 801 802
			continue;
		clk_unprepare(fimc->clock[i]);
		clk_put(fimc->clock[i]);
803
		fimc->clock[i] = ERR_PTR(-EINVAL);
804 805 806 807 808
	}
}

static int fimc_clk_get(struct fimc_dev *fimc)
{
809 810
	int i, ret;

811 812 813
	for (i = 0; i < MAX_FIMC_CLOCKS; i++)
		fimc->clock[i] = ERR_PTR(-EINVAL);

814
	for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
815
		fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]);
816 817
		if (IS_ERR(fimc->clock[i])) {
			ret = PTR_ERR(fimc->clock[i]);
818
			goto err;
819
		}
820 821 822
		ret = clk_prepare(fimc->clock[i]);
		if (ret < 0) {
			clk_put(fimc->clock[i]);
823
			fimc->clock[i] = ERR_PTR(-EINVAL);
824 825
			goto err;
		}
826
	}
827
	return 0;
828 829 830 831 832
err:
	fimc_clk_put(fimc);
	dev_err(&fimc->pdev->dev, "failed to get clock: %s\n",
		fimc_clocks[i]);
	return -ENXIO;
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
}

static int fimc_m2m_suspend(struct fimc_dev *fimc)
{
	unsigned long flags;
	int timeout;

	spin_lock_irqsave(&fimc->slock, flags);
	if (!fimc_m2m_pending(fimc)) {
		spin_unlock_irqrestore(&fimc->slock, flags);
		return 0;
	}
	clear_bit(ST_M2M_SUSPENDED, &fimc->state);
	set_bit(ST_M2M_SUSPENDING, &fimc->state);
	spin_unlock_irqrestore(&fimc->slock, flags);

	timeout = wait_event_timeout(fimc->irq_queue,
			     test_bit(ST_M2M_SUSPENDED, &fimc->state),
			     FIMC_SHUTDOWN_TIMEOUT);

	clear_bit(ST_M2M_SUSPENDING, &fimc->state);
	return timeout == 0 ? -EAGAIN : 0;
}

static int fimc_m2m_resume(struct fimc_dev *fimc)
{
859
	struct fimc_ctx *ctx;
860 861 862 863
	unsigned long flags;

	spin_lock_irqsave(&fimc->slock, flags);
	/* Clear for full H/W setup in first run after resume */
864
	ctx = fimc->m2m.ctx;
865 866 867 868
	fimc->m2m.ctx = NULL;
	spin_unlock_irqrestore(&fimc->slock, flags);

	if (test_and_clear_bit(ST_M2M_SUSPENDED, &fimc->state))
869 870
		fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);

871 872 873
	return 0;
}

874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
static const struct of_device_id fimc_of_match[];

static int fimc_parse_dt(struct fimc_dev *fimc, u32 *clk_freq)
{
	struct device *dev = &fimc->pdev->dev;
	struct device_node *node = dev->of_node;
	const struct of_device_id *of_id;
	struct fimc_variant *v;
	struct fimc_pix_limit *lim;
	u32 args[FIMC_PIX_LIMITS_MAX];
	int ret;

	if (of_property_read_bool(node, "samsung,lcd-wb"))
		return -ENODEV;

	v = devm_kzalloc(dev, sizeof(*v) + sizeof(*lim), GFP_KERNEL);
	if (!v)
		return -ENOMEM;

	of_id = of_match_node(fimc_of_match, node);
	if (!of_id)
		return -EINVAL;
	fimc->drv_data = of_id->data;
	ret = of_property_read_u32_array(node, "samsung,pix-limits",
					 args, FIMC_PIX_LIMITS_MAX);
	if (ret < 0)
		return ret;

	lim = (struct fimc_pix_limit *)&v[1];

	lim->scaler_en_w = args[0];
	lim->scaler_dis_w = args[1];
	lim->out_rot_en_w = args[2];
	lim->out_rot_dis_w = args[3];
	v->pix_limit = lim;

	ret = of_property_read_u32_array(node, "samsung,min-pix-sizes",
								args, 2);
	v->min_inp_pixsize = ret ? FIMC_DEF_MIN_SIZE : args[0];
	v->min_out_pixsize = ret ? FIMC_DEF_MIN_SIZE : args[1];
	ret = of_property_read_u32_array(node, "samsung,min-pix-alignment",
								args, 2);
	v->min_vsize_align = ret ? FIMC_DEF_HEIGHT_ALIGN : args[0];
	v->hor_offs_align = ret ? FIMC_DEF_HOR_OFFS_ALIGN : args[1];

	ret = of_property_read_u32(node, "samsung,rotators", &args[1]);
	v->has_inp_rot = ret ? 1 : args[1] & 0x01;
	v->has_out_rot = ret ? 1 : args[1] & 0x10;
	v->has_mainscaler_ext = of_property_read_bool(node,
					"samsung,mainscaler-ext");

	v->has_isp_wb = of_property_read_bool(node, "samsung,isp-wb");
	v->has_cam_if = of_property_read_bool(node, "samsung,cam-if");
	of_property_read_u32(node, "clock-frequency", clk_freq);
	fimc->id = of_alias_get_id(node, "fimc");

	fimc->variant = v;
	return 0;
}

934 935
static int fimc_probe(struct platform_device *pdev)
{
936 937
	struct device *dev = &pdev->dev;
	u32 lclk_freq = 0;
938 939 940 941
	struct fimc_dev *fimc;
	struct resource *res;
	int ret = 0;

942
	fimc = devm_kzalloc(dev, sizeof(*fimc), GFP_KERNEL);
943 944 945 946
	if (!fimc)
		return -ENOMEM;

	fimc->pdev = pdev;
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963

	if (dev->of_node) {
		ret = fimc_parse_dt(fimc, &lclk_freq);
		if (ret < 0)
			return ret;
	} else {
		fimc->drv_data = fimc_get_drvdata(pdev);
		fimc->id = pdev->id;
	}
	if (!fimc->drv_data || fimc->id >= fimc->drv_data->num_entities ||
	    fimc->id < 0) {
		dev_err(dev, "Invalid driver data or device id (%d/%d)\n",
			fimc->id, fimc->drv_data->num_entities);
		return -EINVAL;
	}
	if (!dev->of_node)
		fimc->variant = fimc->drv_data->variant[fimc->id];
964

965
	init_waitqueue_head(&fimc->irq_queue);
966 967 968
	spin_lock_init(&fimc->slock);
	mutex_init(&fimc->lock);

969
	fimc->sysreg = fimc_get_sysreg_regmap(dev->of_node);
970 971 972
	if (IS_ERR(fimc->sysreg))
		return PTR_ERR(fimc->sysreg);

973
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
974
	fimc->regs = devm_ioremap_resource(dev, res);
975 976
	if (IS_ERR(fimc->regs))
		return PTR_ERR(fimc->regs);
977 978

	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
979
	if (res == NULL) {
980
		dev_err(dev, "Failed to get IRQ resource\n");
981
		return -ENXIO;
982 983
	}

984 985
	ret = fimc_clk_get(fimc);
	if (ret)
986
		return ret;
987

988 989 990 991
	if (lclk_freq == 0)
		lclk_freq = fimc->drv_data->lclk_frequency;

	ret = clk_set_rate(fimc->clock[CLK_BUS], lclk_freq);
992 993 994 995 996 997
	if (ret < 0)
		return ret;

	ret = clk_enable(fimc->clock[CLK_BUS]);
	if (ret < 0)
		return ret;
998

999 1000
	ret = devm_request_irq(dev, res->start, fimc_irq_handler,
			       0, dev_name(dev), fimc);
1001
	if (ret) {
1002
		dev_err(dev, "failed to install irq (%d)\n", ret);
1003 1004 1005
		goto err_clk;
	}

1006 1007 1008 1009 1010
	ret = fimc_initialize_capture_subdev(fimc);
	if (ret)
		goto err_clk;

	platform_set_drvdata(pdev, fimc);
1011 1012
	pm_runtime_enable(dev);
	ret = pm_runtime_get_sync(dev);
1013
	if (ret < 0)
1014
		goto err_sd;
1015
	/* Initialize contiguous memory allocator */
1016
	fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev);
1017 1018
	if (IS_ERR(fimc->alloc_ctx)) {
		ret = PTR_ERR(fimc->alloc_ctx);
1019
		goto err_pm;
1020 1021
	}

1022
	dev_dbg(dev, "FIMC.%d registered successfully\n", fimc->id);
1023

1024
	pm_runtime_put(dev);
1025
	return 0;
1026
err_pm:
1027
	pm_runtime_put(dev);
1028 1029
err_sd:
	fimc_unregister_capture_subdev(fimc);
1030
err_clk:
1031
	clk_disable(fimc->clock[CLK_BUS]);
1032
	fimc_clk_put(fimc);
1033 1034 1035
	return ret;
}

1036
static int fimc_runtime_resume(struct device *dev)
1037
{
1038
	struct fimc_dev *fimc =	dev_get_drvdata(dev);
1039

1040 1041 1042 1043
	dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);

	/* Enable clocks and perform basic initalization */
	clk_enable(fimc->clock[CLK_GATE]);
1044
	fimc_hw_reset(fimc);
1045 1046 1047 1048

	/* Resume the capture or mem-to-mem device */
	if (fimc_capture_busy(fimc))
		return fimc_capture_resume(fimc);
1049 1050

	return fimc_m2m_resume(fimc);
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
}

static int fimc_runtime_suspend(struct device *dev)
{
	struct fimc_dev *fimc =	dev_get_drvdata(dev);
	int ret = 0;

	if (fimc_capture_busy(fimc))
		ret = fimc_capture_suspend(fimc);
	else
		ret = fimc_m2m_suspend(fimc);
	if (!ret)
		clk_disable(fimc->clock[CLK_GATE]);

	dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
	return ret;
}

#ifdef CONFIG_PM_SLEEP
static int fimc_resume(struct device *dev)
{
	struct fimc_dev *fimc =	dev_get_drvdata(dev);
	unsigned long flags;

	dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);

	/* Do not resume if the device was idle before system suspend */
	spin_lock_irqsave(&fimc->slock, flags);
	if (!test_and_clear_bit(ST_LPM, &fimc->state) ||
	    (!fimc_m2m_active(fimc) && !fimc_capture_busy(fimc))) {
		spin_unlock_irqrestore(&fimc->slock, flags);
		return 0;
	}
	fimc_hw_reset(fimc);
	spin_unlock_irqrestore(&fimc->slock, flags);

	if (fimc_capture_busy(fimc))
		return fimc_capture_resume(fimc);

	return fimc_m2m_resume(fimc);
}

static int fimc_suspend(struct device *dev)
{
	struct fimc_dev *fimc =	dev_get_drvdata(dev);

	dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);

	if (test_and_set_bit(ST_LPM, &fimc->state))
		return 0;
	if (fimc_capture_busy(fimc))
		return fimc_capture_suspend(fimc);

	return fimc_m2m_suspend(fimc);
}
#endif /* CONFIG_PM_SLEEP */

1108
static int fimc_remove(struct platform_device *pdev)
1109 1110 1111 1112 1113
{
	struct fimc_dev *fimc = platform_get_drvdata(pdev);

	pm_runtime_disable(&pdev->dev);
	pm_runtime_set_suspended(&pdev->dev);
1114

1115
	fimc_unregister_capture_subdev(fimc);
1116 1117
	vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);

1118 1119
	clk_disable(fimc->clock[CLK_BUS]);
	fimc_clk_put(fimc);
1120

1121
	dev_info(&pdev->dev, "driver unloaded\n");
1122 1123 1124
	return 0;
}

1125
/* Image pixel limits, similar across several FIMC HW revisions. */
1126
static const struct fimc_pix_limit s5p_pix_limit[4] = {
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144
	[0] = {
		.scaler_en_w	= 3264,
		.scaler_dis_w	= 8192,
		.out_rot_en_w	= 1920,
		.out_rot_dis_w	= 4224,
	},
	[1] = {
		.scaler_en_w	= 4224,
		.scaler_dis_w	= 8192,
		.out_rot_en_w	= 1920,
		.out_rot_dis_w	= 4224,
	},
	[2] = {
		.scaler_en_w	= 1920,
		.scaler_dis_w	= 8192,
		.out_rot_en_w	= 1280,
		.out_rot_dis_w	= 1920,
	},
1145 1146 1147 1148 1149 1150 1151 1152
	[3] = {
		.scaler_en_w	= 1920,
		.scaler_dis_w	= 8192,
		.in_rot_en_h	= 1366,
		.in_rot_dis_w	= 8192,
		.out_rot_en_w	= 1366,
		.out_rot_dis_w	= 1920,
	},
1153 1154
};

1155
static const struct fimc_variant fimc0_variant_s5p = {
1156 1157
	.has_inp_rot	 = 1,
	.has_out_rot	 = 1,
1158
	.has_cam_if	 = 1,
1159 1160
	.min_inp_pixsize = 16,
	.min_out_pixsize = 16,
1161
	.hor_offs_align	 = 8,
1162
	.min_vsize_align = 16,
1163
	.pix_limit	 = &s5p_pix_limit[0],
1164 1165
};

1166
static const struct fimc_variant fimc2_variant_s5p = {
1167
	.has_cam_if	 = 1,
1168 1169
	.min_inp_pixsize = 16,
	.min_out_pixsize = 16,
1170
	.hor_offs_align	 = 8,
1171
	.min_vsize_align = 16,
1172
	.pix_limit	 = &s5p_pix_limit[1],
1173 1174
};

1175
static const struct fimc_variant fimc0_variant_s5pv210 = {
1176 1177
	.has_inp_rot	 = 1,
	.has_out_rot	 = 1,
1178
	.has_cam_if	 = 1,
1179
	.min_inp_pixsize = 16,
1180
	.min_out_pixsize = 16,
1181
	.hor_offs_align	 = 8,
1182
	.min_vsize_align = 16,
1183 1184
	.pix_limit	 = &s5p_pix_limit[1],
};
1185

1186
static const struct fimc_variant fimc1_variant_s5pv210 = {
1187 1188
	.has_inp_rot	 = 1,
	.has_out_rot	 = 1,
1189
	.has_cam_if	 = 1,
1190
	.has_mainscaler_ext = 1,
1191 1192 1193
	.min_inp_pixsize = 16,
	.min_out_pixsize = 16,
	.hor_offs_align	 = 1,
1194
	.min_vsize_align = 1,
1195
	.pix_limit	 = &s5p_pix_limit[2],
1196 1197
};

1198
static const struct fimc_variant fimc2_variant_s5pv210 = {
1199
	.has_cam_if	 = 1,
1200
	.min_inp_pixsize = 16,
1201
	.min_out_pixsize = 16,
1202
	.hor_offs_align	 = 8,
1203
	.min_vsize_align = 16,
1204 1205
	.pix_limit	 = &s5p_pix_limit[2],
};
1206

1207
static const struct fimc_variant fimc0_variant_exynos4210 = {
1208 1209
	.has_inp_rot	 = 1,
	.has_out_rot	 = 1,
1210
	.has_cam_if	 = 1,
1211
	.has_mainscaler_ext = 1,
1212 1213
	.min_inp_pixsize = 16,
	.min_out_pixsize = 16,
1214
	.hor_offs_align	 = 2,
1215
	.min_vsize_align = 1,
1216 1217 1218
	.pix_limit	 = &s5p_pix_limit[1],
};

1219
static const struct fimc_variant fimc3_variant_exynos4210 = {
1220
	.has_mainscaler_ext = 1,
1221 1222
	.min_inp_pixsize = 16,
	.min_out_pixsize = 16,
1223
	.hor_offs_align	 = 2,
1224
	.min_vsize_align = 1,
1225
	.pix_limit	 = &s5p_pix_limit[3],
1226 1227
};

1228
/* S5PC100 */
1229
static const struct fimc_drvdata fimc_drvdata_s5p = {
1230
	.variant = {
1231 1232
		[0] = &fimc0_variant_s5p,
		[1] = &fimc0_variant_s5p,
1233 1234
		[2] = &fimc2_variant_s5p,
	},
1235
	.num_entities	= 3,
1236
	.lclk_frequency = 133000000UL,
1237
	.out_buf_count	= 4,
1238 1239
};

1240
/* S5PV210, S5PC110 */
1241
static const struct fimc_drvdata fimc_drvdata_s5pv210 = {
1242
	.variant = {
1243 1244
		[0] = &fimc0_variant_s5pv210,
		[1] = &fimc1_variant_s5pv210,
1245 1246
		[2] = &fimc2_variant_s5pv210,
	},
1247 1248 1249 1250
	.num_entities	= 3,
	.lclk_frequency	= 166000000UL,
	.out_buf_count	= 4,
	.dma_pix_hoff	= 1,
1251 1252
};

1253
/* EXYNOS4210, S5PV310, S5PC210 */
1254 1255 1256 1257 1258 1259 1260
static const struct fimc_drvdata fimc_drvdata_exynos4210 = {
	.variant = {
		[0] = &fimc0_variant_exynos4210,
		[1] = &fimc0_variant_exynos4210,
		[2] = &fimc0_variant_exynos4210,
		[3] = &fimc3_variant_exynos4210,
	},
1261
	.num_entities	= 4,
1262
	.lclk_frequency = 166000000UL,
1263 1264 1265 1266
	.dma_pix_hoff	= 1,
	.cistatus2	= 1,
	.alpha_color	= 1,
	.out_buf_count	= 32,
1267 1268 1269 1270
};

/* EXYNOS4212, EXYNOS4412 */
static const struct fimc_drvdata fimc_drvdata_exynos4x12 = {
1271 1272 1273 1274 1275 1276
	.num_entities	= 4,
	.lclk_frequency	= 166000000UL,
	.dma_pix_hoff	= 1,
	.cistatus2	= 1,
	.alpha_color	= 1,
	.out_buf_count	= 32,
1277 1278
};

1279
static const struct platform_device_id fimc_driver_ids[] = {
1280 1281 1282 1283 1284 1285
	{
		.name		= "s5p-fimc",
		.driver_data	= (unsigned long)&fimc_drvdata_s5p,
	}, {
		.name		= "s5pv210-fimc",
		.driver_data	= (unsigned long)&fimc_drvdata_s5pv210,
1286
	}, {
1287
		.name		= "exynos4-fimc",
1288 1289 1290 1291
		.driver_data	= (unsigned long)&fimc_drvdata_exynos4210,
	}, {
		.name		= "exynos4x12-fimc",
		.driver_data	= (unsigned long)&fimc_drvdata_exynos4x12,
1292
	},
1293
	{ },
1294 1295
};

1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
static const struct of_device_id fimc_of_match[] = {
	{
		.compatible = "samsung,s5pv210-fimc",
		.data = &fimc_drvdata_s5pv210,
	}, {
		.compatible = "samsung,exynos4210-fimc",
		.data = &fimc_drvdata_exynos4210,
	}, {
		.compatible = "samsung,exynos4212-fimc",
		.data = &fimc_drvdata_exynos4x12,
	},
	{ /* sentinel */ },
};

1310 1311 1312 1313 1314
static const struct dev_pm_ops fimc_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume)
	SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL)
};

1315 1316
static struct platform_driver fimc_driver = {
	.probe		= fimc_probe,
1317
	.remove		= fimc_remove,
1318 1319
	.id_table	= fimc_driver_ids,
	.driver = {
1320 1321 1322 1323
		.of_match_table = fimc_of_match,
		.name		= FIMC_MODULE_NAME,
		.owner		= THIS_MODULE,
		.pm     	= &fimc_pm_ops,
1324 1325 1326
	}
};

1327
int __init fimc_register_driver(void)
1328
{
1329
	return platform_driver_register(&fimc_driver);
1330 1331
}

1332
void __exit fimc_unregister_driver(void)
1333 1334 1335
{
	platform_driver_unregister(&fimc_driver);
}