brintos

brintos / linux-shallow public Read only

0
0
Text · 28.3 KiB · adfc2d7 Raw
1177 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Samsung S5P/EXYNOS4 SoC series FIMC (CAMIF) driver4 *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->color282		&& s_frame->width == d_frame->width283		&& s_frame->height == d_frame->height)284		sc->copy_mode = 1;285	else286		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 handling502 */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	else595		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 plane693 * @fmt: fimc pixel format description (input)694 * @width: requested pixel width695 * @height: requested pixel height696 * @pix: multi-plane format to adjust697 */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, except724		 * V4L2_PIX_FMT_YUV420M format. This calculation may need725		 * to be changed when other multi-planar formats are added726		 * 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 format750 * @pixelformat: fourcc to match, ignored if null751 * @mbus_code: media bus code to match, ignored if null752 * @mask: the color flags to match753 * @index: offset in the fimc_formats array, ignored if negative754 */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_PM822static 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_PM1020static 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	else1045		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#endif1053 1054#ifdef CONFIG_PM_SLEEP1055static 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_new	= 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}1177