File Index
Files and directories
Sign in
FILE

fimc-core.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/samsung/exynos4-is/fimc-core.c C
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Samsung S5P/EXYNOS4 SoC series FIMC (CAMIF) driver
   4 *
   5 * Copyright (C) 2010-2012 Samsung Electronics Co., Ltd.
   6 * Sylwester Nawrocki <s.nawrocki@samsung.com>
   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/device.h>
  16#include <linux/platform_device.h>
  17#include <linux/pm_runtime.h>
  18#include <linux/list.h>
  19#include <linux/mfd/syscon.h>
  20#include <linux/io.h>
  21#include <linux/of.h>
  22#include <linux/slab.h>
  23#include <linux/clk.h>
  24#include <media/v4l2-ioctl.h>
  25#include <media/videobuf2-v4l2.h>
  26#include <media/videobuf2-dma-contig.h>
  27
  28#include "fimc-core.h"
  29#include "fimc-reg.h"
  30#include "media-dev.h"
  31
  32static const char *fimc_clocks[MAX_FIMC_CLOCKS] = {
  33	"sclk_fimc", "fimc"
  34};
  35
  36static const struct fimc_fmt fimc_formats[] = {
  37	{
  38		.fourcc		= V4L2_PIX_FMT_RGB565,
  39		.depth		= { 16 },
  40		.color		= FIMC_FMT_RGB565,
  41		.memplanes	= 1,
  42		.colplanes	= 1,
  43		.flags		= FMT_FLAGS_M2M,
  44	}, {
  45		.fourcc		= V4L2_PIX_FMT_BGR666,
  46		.depth		= { 32 },
  47		.color		= FIMC_FMT_RGB666,
  48		.memplanes	= 1,
  49		.colplanes	= 1,
  50		.flags		= FMT_FLAGS_M2M,
  51	}, {
  52		.fourcc		= V4L2_PIX_FMT_BGR32,
  53		.depth		= { 32 },
  54		.color		= FIMC_FMT_RGB888,
  55		.memplanes	= 1,
  56		.colplanes	= 1,
  57		.flags		= FMT_FLAGS_M2M | FMT_HAS_ALPHA,
  58	}, {
  59		.fourcc		= V4L2_PIX_FMT_RGB555,
  60		.depth		= { 16 },
  61		.color		= FIMC_FMT_RGB555,
  62		.memplanes	= 1,
  63		.colplanes	= 1,
  64		.flags		= FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
  65	}, {
  66		.fourcc		= V4L2_PIX_FMT_RGB444,
  67		.depth		= { 16 },
  68		.color		= FIMC_FMT_RGB444,
  69		.memplanes	= 1,
  70		.colplanes	= 1,
  71		.flags		= FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
  72	}, {
  73		.mbus_code	= MEDIA_BUS_FMT_YUV10_1X30,
  74		.flags		= FMT_FLAGS_WRITEBACK,
  75	}, {
  76		.fourcc		= V4L2_PIX_FMT_YUYV,
  77		.depth		= { 16 },
  78		.color		= FIMC_FMT_YCBYCR422,
  79		.memplanes	= 1,
  80		.colplanes	= 1,
  81		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
  82		.flags		= FMT_FLAGS_M2M | FMT_FLAGS_CAM,
  83	}, {
  84		.fourcc		= V4L2_PIX_FMT_UYVY,
  85		.depth		= { 16 },
  86		.color		= FIMC_FMT_CBYCRY422,
  87		.memplanes	= 1,
  88		.colplanes	= 1,
  89		.mbus_code	= MEDIA_BUS_FMT_UYVY8_2X8,
  90		.flags		= FMT_FLAGS_M2M | FMT_FLAGS_CAM,
  91	}, {
  92		.fourcc		= V4L2_PIX_FMT_VYUY,
  93		.depth		= { 16 },
  94		.color		= FIMC_FMT_CRYCBY422,
  95		.memplanes	= 1,
  96		.colplanes	= 1,
  97		.mbus_code	= MEDIA_BUS_FMT_VYUY8_2X8,
  98		.flags		= FMT_FLAGS_M2M | FMT_FLAGS_CAM,
  99	}, {
 100		.fourcc		= V4L2_PIX_FMT_YVYU,
 101		.depth		= { 16 },
 102		.color		= FIMC_FMT_YCRYCB422,
 103		.memplanes	= 1,
 104		.colplanes	= 1,
 105		.mbus_code	= MEDIA_BUS_FMT_YVYU8_2X8,
 106		.flags		= FMT_FLAGS_M2M | FMT_FLAGS_CAM,
 107	}, {
 108		.fourcc		= V4L2_PIX_FMT_YUV422P,
 109		.depth		= { 16 },
 110		.color		= FIMC_FMT_YCBYCR422,
 111		.memplanes	= 1,
 112		.colplanes	= 3,
 113		.flags		= FMT_FLAGS_M2M,
 114	}, {
 115		.fourcc		= V4L2_PIX_FMT_NV16,
 116		.depth		= { 16 },
 117		.color		= FIMC_FMT_YCBYCR422,
 118		.memplanes	= 1,
 119		.colplanes	= 2,
 120		.flags		= FMT_FLAGS_M2M,
 121	}, {
 122		.fourcc		= V4L2_PIX_FMT_NV61,
 123		.depth		= { 16 },
 124		.color		= FIMC_FMT_YCRYCB422,
 125		.memplanes	= 1,
 126		.colplanes	= 2,
 127		.flags		= FMT_FLAGS_M2M,
 128	}, {
 129		.fourcc		= V4L2_PIX_FMT_YUV420,
 130		.depth		= { 12 },
 131		.color		= FIMC_FMT_YCBCR420,
 132		.memplanes	= 1,
 133		.colplanes	= 3,
 134		.flags		= FMT_FLAGS_M2M,
 135	}, {
 136		.fourcc		= V4L2_PIX_FMT_NV12,
 137		.depth		= { 12 },
 138		.color		= FIMC_FMT_YCBCR420,
 139		.memplanes	= 1,
 140		.colplanes	= 2,
 141		.flags		= FMT_FLAGS_M2M,
 142	}, {
 143		.fourcc		= V4L2_PIX_FMT_NV12M,
 144		.color		= FIMC_FMT_YCBCR420,
 145		.depth		= { 8, 4 },
 146		.memplanes	= 2,
 147		.colplanes	= 2,
 148		.flags		= FMT_FLAGS_M2M,
 149	}, {
 150		.fourcc		= V4L2_PIX_FMT_YUV420M,
 151		.color		= FIMC_FMT_YCBCR420,
 152		.depth		= { 8, 2, 2 },
 153		.memplanes	= 3,
 154		.colplanes	= 3,
 155		.flags		= FMT_FLAGS_M2M,
 156	}, {
 157		.fourcc		= V4L2_PIX_FMT_NV12MT,
 158		.color		= FIMC_FMT_YCBCR420,
 159		.depth		= { 8, 4 },
 160		.memplanes	= 2,
 161		.colplanes	= 2,
 162		.flags		= FMT_FLAGS_M2M,
 163	}, {
 164		.fourcc		= V4L2_PIX_FMT_JPEG,
 165		.color		= FIMC_FMT_JPEG,
 166		.depth		= { 8 },
 167		.memplanes	= 1,
 168		.colplanes	= 1,
 169		.mbus_code	= MEDIA_BUS_FMT_JPEG_1X8,
 170		.flags		= FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED,
 171	}, {
 172		.fourcc		= V4L2_PIX_FMT_S5C_UYVY_JPG,
 173		.color		= FIMC_FMT_YUYV_JPEG,
 174		.depth		= { 8 },
 175		.memplanes	= 2,
 176		.colplanes	= 1,
 177		.mdataplanes	= 0x2, /* plane 1 holds frame meta data */
 178		.mbus_code	= MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8,
 179		.flags		= FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED,
 180	},
 181};
 182
 183const struct fimc_fmt *fimc_get_format(unsigned int index)
 184{
 185	if (index >= ARRAY_SIZE(fimc_formats))
 186		return NULL;
 187
 188	return &fimc_formats[index];
 189}
 190
 191int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
 192			    int dw, int dh, int rotation)
 193{
 194	if (rotation == 90 || rotation == 270)
 195		swap(dw, dh);
 196
 197	if (!ctx->scaler.enabled)
 198		return (sw == dw && sh == dh) ? 0 : -EINVAL;
 199
 200	if ((sw >= SCALER_MAX_HRATIO * dw) || (sh >= SCALER_MAX_VRATIO * dh))
 201		return -EINVAL;
 202
 203	return 0;
 204}
 205
 206static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
 207{
 208	u32 sh = 6;
 209
 210	if (src >= 64 * tar)
 211		return -EINVAL;
 212
 213	while (sh--) {
 214		u32 tmp = 1 << sh;
 215		if (src >= tar * tmp) {
 216			*shift = sh;
 217			*ratio = tmp;
 218			return 0;
 219		}
 220	}
 221	*shift = 0;
 222	*ratio = 1;
 223	return 0;
 224}
 225
 226int fimc_set_scaler_info(struct fimc_ctx *ctx)
 227{
 228	const struct fimc_variant *variant = ctx->fimc_dev->variant;
 229	struct device *dev = &ctx->fimc_dev->pdev->dev;
 230	struct fimc_scaler *sc = &ctx->scaler;
 231	const struct fimc_frame *s_frame = &ctx->s_frame;
 232	const struct fimc_frame *d_frame = &ctx->d_frame;
 233	int tx, ty, sx, sy;
 234	int ret;
 235
 236	if (ctx->rotation == 90 || ctx->rotation == 270) {
 237		ty = d_frame->width;
 238		tx = d_frame->height;
 239	} else {
 240		tx = d_frame->width;
 241		ty = d_frame->height;
 242	}
 243	if (tx <= 0 || ty <= 0) {
 244		dev_err(dev, "Invalid target size: %dx%d\n", tx, ty);
 245		return -EINVAL;
 246	}
 247
 248	sx = s_frame->width;
 249	sy = s_frame->height;
 250	if (sx <= 0 || sy <= 0) {
 251		dev_err(dev, "Invalid source size: %dx%d\n", sx, sy);
 252		return -EINVAL;
 253	}
 254	sc->real_width = sx;
 255	sc->real_height = sy;
 256
 257	ret = fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor);
 258	if (ret)
 259		return ret;
 260
 261	ret = fimc_get_scaler_factor(sy, ty,  &sc->pre_vratio, &sc->vfactor);
 262	if (ret)
 263		return ret;
 264
 265	sc->pre_dst_width = sx / sc->pre_hratio;
 266	sc->pre_dst_height = sy / sc->pre_vratio;
 267
 268	if (variant->has_mainscaler_ext) {
 269		sc->main_hratio = (sx << 14) / (tx << sc->hfactor);
 270		sc->main_vratio = (sy << 14) / (ty << sc->vfactor);
 271	} else {
 272		sc->main_hratio = (sx << 8) / (tx << sc->hfactor);
 273		sc->main_vratio = (sy << 8) / (ty << sc->vfactor);
 274
 275	}
 276
 277	sc->scaleup_h = (tx >= sx) ? 1 : 0;
 278	sc->scaleup_v = (ty >= sy) ? 1 : 0;
 279
 280	/* check to see if input and output size/format differ */
 281	if (s_frame->fmt->color == d_frame->fmt->color
 282		&& s_frame->width == d_frame->width
 283		&& s_frame->height == d_frame->height)
 284		sc->copy_mode = 1;
 285	else
 286		sc->copy_mode = 0;
 287
 288	return 0;
 289}
 290
 291static irqreturn_t fimc_irq_handler(int irq, void *priv)
 292{
 293	struct fimc_dev *fimc = priv;
 294	struct fimc_ctx *ctx;
 295
 296	fimc_hw_clear_irq(fimc);
 297
 298	spin_lock(&fimc->slock);
 299
 300	if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) {
 301		if (test_and_clear_bit(ST_M2M_SUSPENDING, &fimc->state)) {
 302			set_bit(ST_M2M_SUSPENDED, &fimc->state);
 303			wake_up(&fimc->irq_queue);
 304			goto out;
 305		}
 306		ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev);
 307		if (ctx != NULL) {
 308			spin_unlock(&fimc->slock);
 309			fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
 310
 311			if (ctx->state & FIMC_CTX_SHUT) {
 312				ctx->state &= ~FIMC_CTX_SHUT;
 313				wake_up(&fimc->irq_queue);
 314			}
 315			return IRQ_HANDLED;
 316		}
 317	} else if (test_bit(ST_CAPT_PEND, &fimc->state)) {
 318		int last_buf = test_bit(ST_CAPT_JPEG, &fimc->state) &&
 319				fimc->vid_cap.reqbufs_count == 1;
 320		fimc_capture_irq_handler(fimc, !last_buf);
 321	}
 322out:
 323	spin_unlock(&fimc->slock);
 324	return IRQ_HANDLED;
 325}
 326
 327/* The color format (colplanes, memplanes) must be already configured. */
 328int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
 329		      const struct fimc_frame *frame, struct fimc_addr *addr)
 330{
 331	int ret = 0;
 332	u32 pix_size;
 333
 334	if (vb == NULL || frame == NULL)
 335		return -EINVAL;
 336
 337	pix_size = frame->width * frame->height;
 338
 339	dbg("memplanes= %d, colplanes= %d, pix_size= %d",
 340		frame->fmt->memplanes, frame->fmt->colplanes, pix_size);
 341
 342	addr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
 343
 344	if (frame->fmt->memplanes == 1) {
 345		switch (frame->fmt->colplanes) {
 346		case 1:
 347			addr->cb = 0;
 348			addr->cr = 0;
 349			break;
 350		case 2:
 351			/* decompose Y into Y/Cb */
 352			addr->cb = (u32)(addr->y + pix_size);
 353			addr->cr = 0;
 354			break;
 355		case 3:
 356			addr->cb = (u32)(addr->y + pix_size);
 357			/* decompose Y into Y/Cb/Cr */
 358			if (FIMC_FMT_YCBCR420 == frame->fmt->color)
 359				addr->cr = (u32)(addr->cb + (pix_size >> 2));
 360			else /* 422 */
 361				addr->cr = (u32)(addr->cb + (pix_size >> 1));
 362			break;
 363		default:
 364			return -EINVAL;
 365		}
 366	} else if (!frame->fmt->mdataplanes) {
 367		if (frame->fmt->memplanes >= 2)
 368			addr->cb = vb2_dma_contig_plane_dma_addr(vb, 1);
 369
 370		if (frame->fmt->memplanes == 3)
 371			addr->cr = vb2_dma_contig_plane_dma_addr(vb, 2);
 372	}
 373
 374	dbg("DMA ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
 375	    addr->y, addr->cb, addr->cr, ret);
 376
 377	return ret;
 378}
 379
 380/* Set order for 1 and 2 plane YCBCR 4:2:2 formats. */
 381void fimc_set_yuv_order(struct fimc_ctx *ctx)
 382{
 383	/* The one only mode supported in SoC. */
 384	ctx->in_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
 385	ctx->out_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
 386
 387	/* Set order for 1 plane input formats. */
 388	switch (ctx->s_frame.fmt->color) {
 389	case FIMC_FMT_YCRYCB422:
 390		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCRYCB;
 391		break;
 392	case FIMC_FMT_CBYCRY422:
 393		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CBYCRY;
 394		break;
 395	case FIMC_FMT_CRYCBY422:
 396		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CRYCBY;
 397		break;
 398	case FIMC_FMT_YCBYCR422:
 399	default:
 400		ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCBYCR;
 401		break;
 402	}
 403	dbg("ctx->in_order_1p= %d", ctx->in_order_1p);
 404
 405	switch (ctx->d_frame.fmt->color) {
 406	case FIMC_FMT_YCRYCB422:
 407		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCRYCB;
 408		break;
 409	case FIMC_FMT_CBYCRY422:
 410		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CBYCRY;
 411		break;
 412	case FIMC_FMT_CRYCBY422:
 413		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CRYCBY;
 414		break;
 415	case FIMC_FMT_YCBYCR422:
 416	default:
 417		ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCBYCR;
 418		break;
 419	}
 420	dbg("ctx->out_order_1p= %d", ctx->out_order_1p);
 421}
 422
 423void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
 424{
 425	bool pix_hoff = ctx->fimc_dev->drv_data->dma_pix_hoff;
 426	u32 i, depth = 0;
 427
 428	for (i = 0; i < f->fmt->memplanes; i++)
 429		depth += f->fmt->depth[i];
 430
 431	f->dma_offset.y_h = f->offs_h;
 432	if (!pix_hoff)
 433		f->dma_offset.y_h *= (depth >> 3);
 434
 435	f->dma_offset.y_v = f->offs_v;
 436
 437	f->dma_offset.cb_h = f->offs_h;
 438	f->dma_offset.cb_v = f->offs_v;
 439
 440	f->dma_offset.cr_h = f->offs_h;
 441	f->dma_offset.cr_v = f->offs_v;
 442
 443	if (!pix_hoff) {
 444		if (f->fmt->colplanes == 3) {
 445			f->dma_offset.cb_h >>= 1;
 446			f->dma_offset.cr_h >>= 1;
 447		}
 448		if (f->fmt->color == FIMC_FMT_YCBCR420) {
 449			f->dma_offset.cb_v >>= 1;
 450			f->dma_offset.cr_v >>= 1;
 451		}
 452	}
 453
 454	dbg("in_offset: color= %d, y_h= %d, y_v= %d",
 455	    f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v);
 456}
 457
 458static int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx)
 459{
 460	struct fimc_effect *effect = &ctx->effect;
 461
 462	switch (colorfx) {
 463	case V4L2_COLORFX_NONE:
 464		effect->type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
 465		break;
 466	case V4L2_COLORFX_BW:
 467		effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
 468		effect->pat_cb = 128;
 469		effect->pat_cr = 128;
 470		break;
 471	case V4L2_COLORFX_SEPIA:
 472		effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
 473		effect->pat_cb = 115;
 474		effect->pat_cr = 145;
 475		break;
 476	case V4L2_COLORFX_NEGATIVE:
 477		effect->type = FIMC_REG_CIIMGEFF_FIN_NEGATIVE;
 478		break;
 479	case V4L2_COLORFX_EMBOSS:
 480		effect->type = FIMC_REG_CIIMGEFF_FIN_EMBOSSING;
 481		break;
 482	case V4L2_COLORFX_ART_FREEZE:
 483		effect->type = FIMC_REG_CIIMGEFF_FIN_ARTFREEZE;
 484		break;
 485	case V4L2_COLORFX_SILHOUETTE:
 486		effect->type = FIMC_REG_CIIMGEFF_FIN_SILHOUETTE;
 487		break;
 488	case V4L2_COLORFX_SET_CBCR:
 489		effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
 490		effect->pat_cb = ctx->ctrls.colorfx_cbcr->val >> 8;
 491		effect->pat_cr = ctx->ctrls.colorfx_cbcr->val & 0xff;
 492		break;
 493	default:
 494		return -EINVAL;
 495	}
 496
 497	return 0;
 498}
 499
 500/*
 501 * V4L2 controls handling
 502 */
 503#define ctrl_to_ctx(__ctrl) \
 504	container_of((__ctrl)->handler, struct fimc_ctx, ctrls.handler)
 505
 506static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
 507{
 508	struct fimc_dev *fimc = ctx->fimc_dev;
 509	const struct fimc_variant *variant = fimc->variant;
 510	int ret = 0;
 511
 512	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
 513		return 0;
 514
 515	switch (ctrl->id) {
 516	case V4L2_CID_HFLIP:
 517		ctx->hflip = ctrl->val;
 518		break;
 519
 520	case V4L2_CID_VFLIP:
 521		ctx->vflip = ctrl->val;
 522		break;
 523
 524	case V4L2_CID_ROTATE:
 525		if (fimc_capture_pending(fimc)) {
 526			ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
 527					ctx->s_frame.height, ctx->d_frame.width,
 528					ctx->d_frame.height, ctrl->val);
 529			if (ret)
 530				return -EINVAL;
 531		}
 532		if ((ctrl->val == 90 || ctrl->val == 270) &&
 533		    !variant->has_out_rot)
 534			return -EINVAL;
 535
 536		ctx->rotation = ctrl->val;
 537		break;
 538
 539	case V4L2_CID_ALPHA_COMPONENT:
 540		ctx->d_frame.alpha = ctrl->val;
 541		break;
 542
 543	case V4L2_CID_COLORFX:
 544		ret = fimc_set_color_effect(ctx, ctrl->val);
 545		if (ret)
 546			return ret;
 547		break;
 548	}
 549
 550	ctx->state |= FIMC_PARAMS;
 551	set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
 552	return 0;
 553}
 554
 555static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
 556{
 557	struct fimc_ctx *ctx = ctrl_to_ctx(ctrl);
 558	unsigned long flags;
 559	int ret;
 560
 561	spin_lock_irqsave(&ctx->fimc_dev->slock, flags);
 562	ret = __fimc_s_ctrl(ctx, ctrl);
 563	spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags);
 564
 565	return ret;
 566}
 567
 568static const struct v4l2_ctrl_ops fimc_ctrl_ops = {
 569	.s_ctrl = fimc_s_ctrl,
 570};
 571
 572int fimc_ctrls_create(struct fimc_ctx *ctx)
 573{
 574	unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt);
 575	struct fimc_ctrls *ctrls = &ctx->ctrls;
 576	struct v4l2_ctrl_handler *handler = &ctrls->handler;
 577
 578	if (ctx->ctrls.ready)
 579		return 0;
 580
 581	v4l2_ctrl_handler_init(handler, 6);
 582
 583	ctrls->rotate = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
 584					V4L2_CID_ROTATE, 0, 270, 90, 0);
 585	ctrls->hflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
 586					V4L2_CID_HFLIP, 0, 1, 1, 0);
 587	ctrls->vflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
 588					V4L2_CID_VFLIP, 0, 1, 1, 0);
 589
 590	if (ctx->fimc_dev->drv_data->alpha_color)
 591		ctrls->alpha = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
 592					V4L2_CID_ALPHA_COMPONENT,
 593					0, max_alpha, 1, 0);
 594	else
 595		ctrls->alpha = NULL;
 596
 597	ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, &fimc_ctrl_ops,
 598				V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR,
 599				~0x983f, V4L2_COLORFX_NONE);
 600
 601	ctrls->colorfx_cbcr = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
 602				V4L2_CID_COLORFX_CBCR, 0, 0xffff, 1, 0);
 603
 604	ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
 605
 606	if (!handler->error) {
 607		v4l2_ctrl_cluster(2, &ctrls->colorfx);
 608		ctrls->ready = true;
 609	}
 610
 611	return handler->error;
 612}
 613
 614void fimc_ctrls_delete(struct fimc_ctx *ctx)
 615{
 616	struct fimc_ctrls *ctrls = &ctx->ctrls;
 617
 618	if (ctrls->ready) {
 619		v4l2_ctrl_handler_free(&ctrls->handler);
 620		ctrls->ready = false;
 621		ctrls->alpha = NULL;
 622	}
 623}
 624
 625void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
 626{
 627	unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA;
 628	struct fimc_ctrls *ctrls = &ctx->ctrls;
 629
 630	if (!ctrls->ready)
 631		return;
 632
 633	mutex_lock(ctrls->handler.lock);
 634	v4l2_ctrl_activate(ctrls->rotate, active);
 635	v4l2_ctrl_activate(ctrls->hflip, active);
 636	v4l2_ctrl_activate(ctrls->vflip, active);
 637	v4l2_ctrl_activate(ctrls->colorfx, active);
 638	if (ctrls->alpha)
 639		v4l2_ctrl_activate(ctrls->alpha, active && has_alpha);
 640
 641	if (active) {
 642		fimc_set_color_effect(ctx, ctrls->colorfx->cur.val);
 643		ctx->rotation = ctrls->rotate->val;
 644		ctx->hflip    = ctrls->hflip->val;
 645		ctx->vflip    = ctrls->vflip->val;
 646	} else {
 647		ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
 648		ctx->rotation = 0;
 649		ctx->hflip    = 0;
 650		ctx->vflip    = 0;
 651	}
 652	mutex_unlock(ctrls->handler.lock);
 653}
 654
 655/* Update maximum value of the alpha color control */
 656void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
 657{
 658	struct fimc_dev *fimc = ctx->fimc_dev;
 659	struct v4l2_ctrl *ctrl = ctx->ctrls.alpha;
 660
 661	if (ctrl == NULL || !fimc->drv_data->alpha_color)
 662		return;
 663
 664	v4l2_ctrl_lock(ctrl);
 665	ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt);
 666
 667	if (ctrl->cur.val > ctrl->maximum)
 668		ctrl->cur.val = ctrl->maximum;
 669
 670	v4l2_ctrl_unlock(ctrl);
 671}
 672
 673void __fimc_get_format(const struct fimc_frame *frame, struct v4l2_format *f)
 674{
 675	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
 676	int i;
 677
 678	pixm->width = frame->o_width;
 679	pixm->height = frame->o_height;
 680	pixm->field = V4L2_FIELD_NONE;
 681	pixm->pixelformat = frame->fmt->fourcc;
 682	pixm->colorspace = V4L2_COLORSPACE_JPEG;
 683	pixm->num_planes = frame->fmt->memplanes;
 684
 685	for (i = 0; i < pixm->num_planes; ++i) {
 686		pixm->plane_fmt[i].bytesperline = frame->bytesperline[i];
 687		pixm->plane_fmt[i].sizeimage = frame->payload[i];
 688	}
 689}
 690
 691/**
 692 * fimc_adjust_mplane_format - adjust bytesperline/sizeimage for each plane
 693 * @fmt: fimc pixel format description (input)
 694 * @width: requested pixel width
 695 * @height: requested pixel height
 696 * @pix: multi-plane format to adjust
 697 */
 698void fimc_adjust_mplane_format(const struct fimc_fmt *fmt, u32 width, u32 height,
 699			       struct v4l2_pix_format_mplane *pix)
 700{
 701	u32 bytesperline = 0;
 702	int i;
 703
 704	pix->colorspace	= V4L2_COLORSPACE_JPEG;
 705	pix->field = V4L2_FIELD_NONE;
 706	pix->num_planes = fmt->memplanes;
 707	pix->pixelformat = fmt->fourcc;
 708	pix->height = height;
 709	pix->width = width;
 710
 711	for (i = 0; i < pix->num_planes; ++i) {
 712		struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i];
 713		u32 bpl = plane_fmt->bytesperline;
 714		u32 sizeimage;
 715
 716		if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width))
 717			bpl = pix->width; /* Planar */
 718
 719		if (fmt->colplanes == 1 && /* Packed */
 720		    (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width))
 721			bpl = (pix->width * fmt->depth[0]) / 8;
 722		/*
 723		 * Currently bytesperline for each plane is same, except
 724		 * V4L2_PIX_FMT_YUV420M format. This calculation may need
 725		 * to be changed when other multi-planar formats are added
 726		 * to the fimc_formats[] array.
 727		 */
 728		if (i == 0)
 729			bytesperline = bpl;
 730		else if (i == 1 && fmt->memplanes == 3)
 731			bytesperline /= 2;
 732
 733		plane_fmt->bytesperline = bytesperline;
 734		sizeimage = pix->width * pix->height * fmt->depth[i] / 8;
 735
 736		/* Ensure full last row for tiled formats */
 737		if (tiled_fmt(fmt)) {
 738			/* 64 * 32 * plane_fmt->bytesperline / 64 */
 739			u32 row_size = plane_fmt->bytesperline * 32;
 740
 741			sizeimage = roundup(sizeimage, row_size);
 742		}
 743
 744		plane_fmt->sizeimage = max(sizeimage, plane_fmt->sizeimage);
 745	}
 746}
 747
 748/**
 749 * fimc_find_format - lookup fimc color format by fourcc or media bus format
 750 * @pixelformat: fourcc to match, ignored if null
 751 * @mbus_code: media bus code to match, ignored if null
 752 * @mask: the color flags to match
 753 * @index: offset in the fimc_formats array, ignored if negative
 754 */
 755const struct fimc_fmt *fimc_find_format(const u32 *pixelformat,
 756					const u32 *mbus_code,
 757					unsigned int mask, int index)
 758{
 759	const struct fimc_fmt *fmt, *def_fmt = NULL;
 760	unsigned int i;
 761	int id = 0;
 762
 763	if (index >= (int)ARRAY_SIZE(fimc_formats))
 764		return NULL;
 765
 766	for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
 767		fmt = &fimc_formats[i];
 768		if (!(fmt->flags & mask))
 769			continue;
 770		if (pixelformat && fmt->fourcc == *pixelformat)
 771			return fmt;
 772		if (mbus_code && fmt->mbus_code == *mbus_code)
 773			return fmt;
 774		if (index == id)
 775			def_fmt = fmt;
 776		id++;
 777	}
 778	return def_fmt;
 779}
 780
 781static void fimc_clk_put(struct fimc_dev *fimc)
 782{
 783	int i;
 784	for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
 785		if (IS_ERR(fimc->clock[i]))
 786			continue;
 787		clk_unprepare(fimc->clock[i]);
 788		clk_put(fimc->clock[i]);
 789		fimc->clock[i] = ERR_PTR(-EINVAL);
 790	}
 791}
 792
 793static int fimc_clk_get(struct fimc_dev *fimc)
 794{
 795	int i, ret;
 796
 797	for (i = 0; i < MAX_FIMC_CLOCKS; i++)
 798		fimc->clock[i] = ERR_PTR(-EINVAL);
 799
 800	for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
 801		fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]);
 802		if (IS_ERR(fimc->clock[i])) {
 803			ret = PTR_ERR(fimc->clock[i]);
 804			goto err;
 805		}
 806		ret = clk_prepare(fimc->clock[i]);
 807		if (ret < 0) {
 808			clk_put(fimc->clock[i]);
 809			fimc->clock[i] = ERR_PTR(-EINVAL);
 810			goto err;
 811		}
 812	}
 813	return 0;
 814err:
 815	fimc_clk_put(fimc);
 816	dev_err(&fimc->pdev->dev, "failed to get clock: %s\n",
 817		fimc_clocks[i]);
 818	return ret;
 819}
 820
 821#ifdef CONFIG_PM
 822static int fimc_m2m_suspend(struct fimc_dev *fimc)
 823{
 824	unsigned long flags;
 825	long time_left;
 826
 827	spin_lock_irqsave(&fimc->slock, flags);
 828	if (!fimc_m2m_pending(fimc)) {
 829		spin_unlock_irqrestore(&fimc->slock, flags);
 830		return 0;
 831	}
 832	clear_bit(ST_M2M_SUSPENDED, &fimc->state);
 833	set_bit(ST_M2M_SUSPENDING, &fimc->state);
 834	spin_unlock_irqrestore(&fimc->slock, flags);
 835
 836	time_left = wait_event_timeout(fimc->irq_queue,
 837				       test_bit(ST_M2M_SUSPENDED, &fimc->state),
 838				       FIMC_SHUTDOWN_TIMEOUT);
 839
 840	clear_bit(ST_M2M_SUSPENDING, &fimc->state);
 841	return time_left == 0 ? -EAGAIN : 0;
 842}
 843
 844static int fimc_m2m_resume(struct fimc_dev *fimc)
 845{
 846	struct fimc_ctx *ctx;
 847	unsigned long flags;
 848
 849	spin_lock_irqsave(&fimc->slock, flags);
 850	/* Clear for full H/W setup in first run after resume */
 851	ctx = fimc->m2m.ctx;
 852	fimc->m2m.ctx = NULL;
 853	spin_unlock_irqrestore(&fimc->slock, flags);
 854
 855	if (test_and_clear_bit(ST_M2M_SUSPENDED, &fimc->state))
 856		fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
 857
 858	return 0;
 859}
 860#endif /* CONFIG_PM */
 861
 862static const struct of_device_id fimc_of_match[];
 863
 864static int fimc_parse_dt(struct fimc_dev *fimc, u32 *clk_freq)
 865{
 866	struct device *dev = &fimc->pdev->dev;
 867	struct device_node *node = dev->of_node;
 868	const struct of_device_id *of_id;
 869	struct fimc_variant *v;
 870	struct fimc_pix_limit *lim;
 871	u32 args[FIMC_PIX_LIMITS_MAX];
 872	int ret;
 873
 874	if (of_property_read_bool(node, "samsung,lcd-wb"))
 875		return -ENODEV;
 876
 877	v = devm_kzalloc(dev, sizeof(*v) + sizeof(*lim), GFP_KERNEL);
 878	if (!v)
 879		return -ENOMEM;
 880
 881	of_id = of_match_node(fimc_of_match, node);
 882	if (!of_id)
 883		return -EINVAL;
 884	fimc->drv_data = of_id->data;
 885	ret = of_property_read_u32_array(node, "samsung,pix-limits",
 886					 args, FIMC_PIX_LIMITS_MAX);
 887	if (ret < 0)
 888		return ret;
 889
 890	lim = (struct fimc_pix_limit *)&v[1];
 891
 892	lim->scaler_en_w = args[0];
 893	lim->scaler_dis_w = args[1];
 894	lim->out_rot_en_w = args[2];
 895	lim->out_rot_dis_w = args[3];
 896	v->pix_limit = lim;
 897
 898	ret = of_property_read_u32_array(node, "samsung,min-pix-sizes",
 899								args, 2);
 900	v->min_inp_pixsize = ret ? FIMC_DEF_MIN_SIZE : args[0];
 901	v->min_out_pixsize = ret ? FIMC_DEF_MIN_SIZE : args[1];
 902	ret = of_property_read_u32_array(node, "samsung,min-pix-alignment",
 903								args, 2);
 904	v->min_vsize_align = ret ? FIMC_DEF_HEIGHT_ALIGN : args[0];
 905	v->hor_offs_align = ret ? FIMC_DEF_HOR_OFFS_ALIGN : args[1];
 906
 907	ret = of_property_read_u32(node, "samsung,rotators", &args[1]);
 908	v->has_inp_rot = ret ? 1 : args[1] & 0x01;
 909	v->has_out_rot = ret ? 1 : args[1] & 0x10;
 910	v->has_mainscaler_ext = of_property_read_bool(node,
 911					"samsung,mainscaler-ext");
 912
 913	v->has_isp_wb = of_property_read_bool(node, "samsung,isp-wb");
 914	v->has_cam_if = of_property_read_bool(node, "samsung,cam-if");
 915	of_property_read_u32(node, "clock-frequency", clk_freq);
 916	fimc->id = of_alias_get_id(node, "fimc");
 917
 918	fimc->variant = v;
 919	return 0;
 920}
 921
 922static int fimc_probe(struct platform_device *pdev)
 923{
 924	struct device *dev = &pdev->dev;
 925	u32 lclk_freq = 0;
 926	struct fimc_dev *fimc;
 927	int ret = 0;
 928	int irq;
 929
 930	fimc = devm_kzalloc(dev, sizeof(*fimc), GFP_KERNEL);
 931	if (!fimc)
 932		return -ENOMEM;
 933
 934	fimc->pdev = pdev;
 935
 936	if (dev->of_node) {
 937		ret = fimc_parse_dt(fimc, &lclk_freq);
 938		if (ret < 0)
 939			return ret;
 940	} else {
 941		fimc->drv_data = fimc_get_drvdata(pdev);
 942		fimc->id = pdev->id;
 943	}
 944	if (!fimc->drv_data || fimc->id >= fimc->drv_data->num_entities ||
 945	    fimc->id < 0) {
 946		dev_err(dev, "Invalid driver data or device id (%d)\n",
 947			fimc->id);
 948		return -EINVAL;
 949	}
 950	if (!dev->of_node)
 951		fimc->variant = fimc->drv_data->variant[fimc->id];
 952
 953	init_waitqueue_head(&fimc->irq_queue);
 954	spin_lock_init(&fimc->slock);
 955	mutex_init(&fimc->lock);
 956
 957	if (fimc->variant->has_isp_wb) {
 958		fimc->sysreg = fimc_get_sysreg_regmap(dev->of_node);
 959		if (IS_ERR(fimc->sysreg))
 960			return PTR_ERR(fimc->sysreg);
 961	}
 962
 963	fimc->regs = devm_platform_ioremap_resource(pdev, 0);
 964	if (IS_ERR(fimc->regs))
 965		return PTR_ERR(fimc->regs);
 966
 967	irq = platform_get_irq(pdev, 0);
 968	if (irq < 0)
 969		return irq;
 970
 971	ret = fimc_clk_get(fimc);
 972	if (ret)
 973		return ret;
 974
 975	if (lclk_freq == 0)
 976		lclk_freq = fimc->drv_data->lclk_frequency;
 977
 978	ret = clk_set_rate(fimc->clock[CLK_BUS], lclk_freq);
 979	if (ret < 0)
 980		return ret;
 981
 982	ret = clk_enable(fimc->clock[CLK_BUS]);
 983	if (ret < 0)
 984		return ret;
 985
 986	ret = devm_request_irq(dev, irq, fimc_irq_handler,
 987			       0, dev_name(dev), fimc);
 988	if (ret < 0) {
 989		dev_err(dev, "failed to install irq (%d)\n", ret);
 990		goto err_sclk;
 991	}
 992
 993	ret = fimc_initialize_capture_subdev(fimc);
 994	if (ret < 0)
 995		goto err_sclk;
 996
 997	platform_set_drvdata(pdev, fimc);
 998	pm_runtime_enable(dev);
 999
1000	if (!pm_runtime_enabled(dev)) {
1001		ret = clk_enable(fimc->clock[CLK_GATE]);
1002		if (ret < 0)
1003			goto err_sd;
1004	}
1005
1006	vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
1007
1008	dev_dbg(dev, "FIMC.%d registered successfully\n", fimc->id);
1009	return 0;
1010
1011err_sd:
1012	fimc_unregister_capture_subdev(fimc);
1013err_sclk:
1014	clk_disable(fimc->clock[CLK_BUS]);
1015	fimc_clk_put(fimc);
1016	return ret;
1017}
1018
1019#ifdef CONFIG_PM
1020static int fimc_runtime_resume(struct device *dev)
1021{
1022	struct fimc_dev *fimc =	dev_get_drvdata(dev);
1023
1024	dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
1025
1026	/* Enable clocks and perform basic initialization */
1027	clk_enable(fimc->clock[CLK_GATE]);
1028	fimc_hw_reset(fimc);
1029
1030	/* Resume the capture or mem-to-mem device */
1031	if (fimc_capture_busy(fimc))
1032		return fimc_capture_resume(fimc);
1033
1034	return fimc_m2m_resume(fimc);
1035}
1036
1037static int fimc_runtime_suspend(struct device *dev)
1038{
1039	struct fimc_dev *fimc =	dev_get_drvdata(dev);
1040	int ret = 0;
1041
1042	if (fimc_capture_busy(fimc))
1043		ret = fimc_capture_suspend(fimc);
1044	else
1045		ret = fimc_m2m_suspend(fimc);
1046	if (!ret)
1047		clk_disable(fimc->clock[CLK_GATE]);
1048
1049	dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
1050	return ret;
1051}
1052#endif
1053
1054#ifdef CONFIG_PM_SLEEP
1055static int fimc_resume(struct device *dev)
1056{
1057	struct fimc_dev *fimc =	dev_get_drvdata(dev);
1058	unsigned long flags;
1059
1060	dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
1061
1062	/* Do not resume if the device was idle before system suspend */
1063	spin_lock_irqsave(&fimc->slock, flags);
1064	if (!test_and_clear_bit(ST_LPM, &fimc->state) ||
1065	    (!fimc_m2m_active(fimc) && !fimc_capture_busy(fimc))) {
1066		spin_unlock_irqrestore(&fimc->slock, flags);
1067		return 0;
1068	}
1069	fimc_hw_reset(fimc);
1070	spin_unlock_irqrestore(&fimc->slock, flags);
1071
1072	if (fimc_capture_busy(fimc))
1073		return fimc_capture_resume(fimc);
1074
1075	return fimc_m2m_resume(fimc);
1076}
1077
1078static int fimc_suspend(struct device *dev)
1079{
1080	struct fimc_dev *fimc =	dev_get_drvdata(dev);
1081
1082	dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
1083
1084	if (test_and_set_bit(ST_LPM, &fimc->state))
1085		return 0;
1086	if (fimc_capture_busy(fimc))
1087		return fimc_capture_suspend(fimc);
1088
1089	return fimc_m2m_suspend(fimc);
1090}
1091#endif /* CONFIG_PM_SLEEP */
1092
1093static void fimc_remove(struct platform_device *pdev)
1094{
1095	struct fimc_dev *fimc = platform_get_drvdata(pdev);
1096
1097	pm_runtime_disable(&pdev->dev);
1098	if (!pm_runtime_status_suspended(&pdev->dev))
1099		clk_disable(fimc->clock[CLK_GATE]);
1100	pm_runtime_set_suspended(&pdev->dev);
1101
1102	fimc_unregister_capture_subdev(fimc);
1103	vb2_dma_contig_clear_max_seg_size(&pdev->dev);
1104
1105	clk_disable(fimc->clock[CLK_BUS]);
1106	fimc_clk_put(fimc);
1107
1108	dev_info(&pdev->dev, "driver unloaded\n");
1109}
1110
1111/* S5PV210, S5PC110 */
1112static const struct fimc_drvdata fimc_drvdata_s5pv210 = {
1113	.num_entities	= 3,
1114	.lclk_frequency	= 166000000UL,
1115	.out_buf_count	= 4,
1116	.dma_pix_hoff	= 1,
1117};
1118
1119/* EXYNOS4210, S5PV310, S5PC210 */
1120static const struct fimc_drvdata fimc_drvdata_exynos4210 = {
1121	.num_entities	= 4,
1122	.lclk_frequency = 166000000UL,
1123	.dma_pix_hoff	= 1,
1124	.cistatus2	= 1,
1125	.alpha_color	= 1,
1126	.out_buf_count	= 32,
1127};
1128
1129/* EXYNOS4212, EXYNOS4412 */
1130static const struct fimc_drvdata fimc_drvdata_exynos4x12 = {
1131	.num_entities	= 4,
1132	.lclk_frequency	= 166000000UL,
1133	.dma_pix_hoff	= 1,
1134	.cistatus2	= 1,
1135	.alpha_color	= 1,
1136	.out_buf_count	= 32,
1137};
1138
1139static const struct of_device_id fimc_of_match[] = {
1140	{
1141		.compatible = "samsung,s5pv210-fimc",
1142		.data = &fimc_drvdata_s5pv210,
1143	}, {
1144		.compatible = "samsung,exynos4210-fimc",
1145		.data = &fimc_drvdata_exynos4210,
1146	}, {
1147		.compatible = "samsung,exynos4212-fimc",
1148		.data = &fimc_drvdata_exynos4x12,
1149	},
1150	{ /* sentinel */ },
1151};
1152
1153static const struct dev_pm_ops fimc_pm_ops = {
1154	SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume)
1155	SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL)
1156};
1157
1158static struct platform_driver fimc_driver = {
1159	.probe		= fimc_probe,
1160	.remove		= fimc_remove,
1161	.driver = {
1162		.of_match_table = fimc_of_match,
1163		.name		= FIMC_DRIVER_NAME,
1164		.pm		= &fimc_pm_ops,
1165	}
1166};
1167
1168int __init fimc_register_driver(void)
1169{
1170	return platform_driver_register(&fimc_driver);
1171}
1172
1173void fimc_unregister_driver(void)
1174{
1175	platform_driver_unregister(&fimc_driver);
1176}
~/ Read-only file preview.