brintos

brintos / linux-shallow public Read only

0
0
Text · 35.8 KiB · 4d7ea65 Raw
1418 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2012 Samsung Electronics Co.Ltd4 * Authors:5 *	Eunchul Kim <chulspro.kim@samsung.com>6 *	Jinyoung Jeon <jy0.jeon@samsung.com>7 *	Sangmin Lee <lsmin.lee@samsung.com>8 */9 10#include <linux/clk.h>11#include <linux/component.h>12#include <linux/kernel.h>13#include <linux/mfd/syscon.h>14#include <linux/of.h>15#include <linux/platform_device.h>16#include <linux/pm_runtime.h>17#include <linux/regmap.h>18#include <linux/spinlock.h>19 20#include <drm/drm_fourcc.h>21#include <drm/drm_print.h>22#include <drm/exynos_drm.h>23 24#include "exynos_drm_drv.h"25#include "exynos_drm_ipp.h"26#include "regs-fimc.h"27 28/*29 * FIMC stands for Fully Interactive Mobile Camera and30 * supports image scaler/rotator and input/output DMA operations.31 * input DMA reads image data from the memory.32 * output DMA writes image data to memory.33 * FIMC supports image rotation and image effect functions.34 */35 36#define FIMC_MAX_DEVS	437#define FIMC_MAX_SRC	238#define FIMC_MAX_DST	3239#define FIMC_SHFACTOR	1040#define FIMC_BUF_STOP	141#define FIMC_BUF_START	242#define FIMC_WIDTH_ITU_709	128043#define FIMC_AUTOSUSPEND_DELAY	200044 45static unsigned int fimc_mask = 0xc;46module_param_named(fimc_devs, fimc_mask, uint, 0644);47MODULE_PARM_DESC(fimc_devs, "Alias mask for assigning FIMC devices to Exynos DRM");48 49#define get_fimc_context(dev)	dev_get_drvdata(dev)50 51enum {52	FIMC_CLK_LCLK,53	FIMC_CLK_GATE,54	FIMC_CLK_WB_A,55	FIMC_CLK_WB_B,56	FIMC_CLKS_MAX57};58 59static const char * const fimc_clock_names[] = {60	[FIMC_CLK_LCLK]   = "sclk_fimc",61	[FIMC_CLK_GATE]   = "fimc",62	[FIMC_CLK_WB_A]   = "pxl_async0",63	[FIMC_CLK_WB_B]   = "pxl_async1",64};65 66/*67 * A structure of scaler.68 *69 * @range: narrow, wide.70 * @bypass: unused scaler path.71 * @up_h: horizontal scale up.72 * @up_v: vertical scale up.73 * @hratio: horizontal ratio.74 * @vratio: vertical ratio.75 */76struct fimc_scaler {77	bool range;78	bool bypass;79	bool up_h;80	bool up_v;81	u32 hratio;82	u32 vratio;83};84 85/*86 * A structure of fimc context.87 *88 * @regs: memory mapped io registers.89 * @lock: locking of operations.90 * @clocks: fimc clocks.91 * @sc: scaler infomations.92 * @pol: porarity of writeback.93 * @id: fimc id.94 * @irq: irq number.95 */96struct fimc_context {97	struct exynos_drm_ipp ipp;98	struct drm_device *drm_dev;99	void		*dma_priv;100	struct device	*dev;101	struct exynos_drm_ipp_task	*task;102	struct exynos_drm_ipp_formats	*formats;103	unsigned int			num_formats;104 105	void __iomem	*regs;106	spinlock_t	lock;107	struct clk	*clocks[FIMC_CLKS_MAX];108	struct fimc_scaler	sc;109	int	id;110	int	irq;111};112 113static u32 fimc_read(struct fimc_context *ctx, u32 reg)114{115	return readl(ctx->regs + reg);116}117 118static void fimc_write(struct fimc_context *ctx, u32 val, u32 reg)119{120	writel(val, ctx->regs + reg);121}122 123static void fimc_set_bits(struct fimc_context *ctx, u32 reg, u32 bits)124{125	void __iomem *r = ctx->regs + reg;126 127	writel(readl(r) | bits, r);128}129 130static void fimc_clear_bits(struct fimc_context *ctx, u32 reg, u32 bits)131{132	void __iomem *r = ctx->regs + reg;133 134	writel(readl(r) & ~bits, r);135}136 137static void fimc_sw_reset(struct fimc_context *ctx)138{139	u32 cfg;140 141	/* stop dma operation */142	cfg = fimc_read(ctx, EXYNOS_CISTATUS);143	if (EXYNOS_CISTATUS_GET_ENVID_STATUS(cfg))144		fimc_clear_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID);145 146	fimc_set_bits(ctx, EXYNOS_CISRCFMT, EXYNOS_CISRCFMT_ITU601_8BIT);147 148	/* disable image capture */149	fimc_clear_bits(ctx, EXYNOS_CIIMGCPT,150		EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN);151 152	/* s/w reset */153	fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_SWRST);154 155	/* s/w reset complete */156	fimc_clear_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_SWRST);157 158	/* reset sequence */159	fimc_write(ctx, 0x0, EXYNOS_CIFCNTSEQ);160}161 162static void fimc_set_type_ctrl(struct fimc_context *ctx)163{164	u32 cfg;165 166	cfg = fimc_read(ctx, EXYNOS_CIGCTRL);167	cfg &= ~(EXYNOS_CIGCTRL_TESTPATTERN_MASK |168		EXYNOS_CIGCTRL_SELCAM_ITU_MASK |169		EXYNOS_CIGCTRL_SELCAM_MIPI_MASK |170		EXYNOS_CIGCTRL_SELCAM_FIMC_MASK |171		EXYNOS_CIGCTRL_SELWB_CAMIF_MASK |172		EXYNOS_CIGCTRL_SELWRITEBACK_MASK);173 174	cfg |= (EXYNOS_CIGCTRL_SELCAM_ITU_A |175		EXYNOS_CIGCTRL_SELWRITEBACK_A |176		EXYNOS_CIGCTRL_SELCAM_MIPI_A |177		EXYNOS_CIGCTRL_SELCAM_FIMC_ITU);178 179	fimc_write(ctx, cfg, EXYNOS_CIGCTRL);180}181 182static void fimc_handle_jpeg(struct fimc_context *ctx, bool enable)183{184	u32 cfg;185 186	DRM_DEV_DEBUG_KMS(ctx->dev, "enable[%d]\n", enable);187 188	cfg = fimc_read(ctx, EXYNOS_CIGCTRL);189	if (enable)190		cfg |= EXYNOS_CIGCTRL_CAM_JPEG;191	else192		cfg &= ~EXYNOS_CIGCTRL_CAM_JPEG;193 194	fimc_write(ctx, cfg, EXYNOS_CIGCTRL);195}196 197static void fimc_mask_irq(struct fimc_context *ctx, bool enable)198{199	u32 cfg;200 201	DRM_DEV_DEBUG_KMS(ctx->dev, "enable[%d]\n", enable);202 203	cfg = fimc_read(ctx, EXYNOS_CIGCTRL);204	if (enable) {205		cfg &= ~EXYNOS_CIGCTRL_IRQ_OVFEN;206		cfg |= EXYNOS_CIGCTRL_IRQ_ENABLE | EXYNOS_CIGCTRL_IRQ_LEVEL;207	} else208		cfg &= ~EXYNOS_CIGCTRL_IRQ_ENABLE;209	fimc_write(ctx, cfg, EXYNOS_CIGCTRL);210}211 212static void fimc_clear_irq(struct fimc_context *ctx)213{214	fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_CLR);215}216 217static bool fimc_check_ovf(struct fimc_context *ctx)218{219	u32 status, flag;220 221	status = fimc_read(ctx, EXYNOS_CISTATUS);222	flag = EXYNOS_CISTATUS_OVFIY | EXYNOS_CISTATUS_OVFICB |223		EXYNOS_CISTATUS_OVFICR;224 225	DRM_DEV_DEBUG_KMS(ctx->dev, "flag[0x%x]\n", flag);226 227	if (status & flag) {228		fimc_set_bits(ctx, EXYNOS_CIWDOFST,229			EXYNOS_CIWDOFST_CLROVFIY | EXYNOS_CIWDOFST_CLROVFICB |230			EXYNOS_CIWDOFST_CLROVFICR);231 232		DRM_DEV_ERROR(ctx->dev,233			      "occurred overflow at %d, status 0x%x.\n",234			      ctx->id, status);235		return true;236	}237 238	return false;239}240 241static bool fimc_check_frame_end(struct fimc_context *ctx)242{243	u32 cfg;244 245	cfg = fimc_read(ctx, EXYNOS_CISTATUS);246 247	DRM_DEV_DEBUG_KMS(ctx->dev, "cfg[0x%x]\n", cfg);248 249	if (!(cfg & EXYNOS_CISTATUS_FRAMEEND))250		return false;251 252	cfg &= ~(EXYNOS_CISTATUS_FRAMEEND);253	fimc_write(ctx, cfg, EXYNOS_CISTATUS);254 255	return true;256}257 258static int fimc_get_buf_id(struct fimc_context *ctx)259{260	u32 cfg;261	int frame_cnt, buf_id;262 263	cfg = fimc_read(ctx, EXYNOS_CISTATUS2);264	frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg);265 266	if (frame_cnt == 0)267		frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg);268 269	DRM_DEV_DEBUG_KMS(ctx->dev, "present[%d]before[%d]\n",270			  EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg),271			  EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg));272 273	if (frame_cnt == 0) {274		DRM_DEV_ERROR(ctx->dev, "failed to get frame count.\n");275		return -EIO;276	}277 278	buf_id = frame_cnt - 1;279	DRM_DEV_DEBUG_KMS(ctx->dev, "buf_id[%d]\n", buf_id);280 281	return buf_id;282}283 284static void fimc_handle_lastend(struct fimc_context *ctx, bool enable)285{286	u32 cfg;287 288	DRM_DEV_DEBUG_KMS(ctx->dev, "enable[%d]\n", enable);289 290	cfg = fimc_read(ctx, EXYNOS_CIOCTRL);291	if (enable)292		cfg |= EXYNOS_CIOCTRL_LASTENDEN;293	else294		cfg &= ~EXYNOS_CIOCTRL_LASTENDEN;295 296	fimc_write(ctx, cfg, EXYNOS_CIOCTRL);297}298 299static void fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt)300{301	u32 cfg;302 303	DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt);304 305	/* RGB */306	cfg = fimc_read(ctx, EXYNOS_CISCCTRL);307	cfg &= ~EXYNOS_CISCCTRL_INRGB_FMT_RGB_MASK;308 309	switch (fmt) {310	case DRM_FORMAT_RGB565:311		cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB565;312		fimc_write(ctx, cfg, EXYNOS_CISCCTRL);313		return;314	case DRM_FORMAT_RGB888:315	case DRM_FORMAT_XRGB8888:316		cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB888;317		fimc_write(ctx, cfg, EXYNOS_CISCCTRL);318		return;319	default:320		/* bypass */321		break;322	}323 324	/* YUV */325	cfg = fimc_read(ctx, EXYNOS_MSCTRL);326	cfg &= ~(EXYNOS_MSCTRL_ORDER2P_SHIFT_MASK |327		EXYNOS_MSCTRL_C_INT_IN_2PLANE |328		EXYNOS_MSCTRL_ORDER422_YCBYCR);329 330	switch (fmt) {331	case DRM_FORMAT_YUYV:332		cfg |= EXYNOS_MSCTRL_ORDER422_YCBYCR;333		break;334	case DRM_FORMAT_YVYU:335		cfg |= EXYNOS_MSCTRL_ORDER422_YCRYCB;336		break;337	case DRM_FORMAT_UYVY:338		cfg |= EXYNOS_MSCTRL_ORDER422_CBYCRY;339		break;340	case DRM_FORMAT_VYUY:341	case DRM_FORMAT_YUV444:342		cfg |= EXYNOS_MSCTRL_ORDER422_CRYCBY;343		break;344	case DRM_FORMAT_NV21:345	case DRM_FORMAT_NV61:346		cfg |= (EXYNOS_MSCTRL_ORDER2P_LSB_CRCB |347			EXYNOS_MSCTRL_C_INT_IN_2PLANE);348		break;349	case DRM_FORMAT_YUV422:350	case DRM_FORMAT_YUV420:351	case DRM_FORMAT_YVU420:352		cfg |= EXYNOS_MSCTRL_C_INT_IN_3PLANE;353		break;354	case DRM_FORMAT_NV12:355	case DRM_FORMAT_NV16:356		cfg |= (EXYNOS_MSCTRL_ORDER2P_LSB_CBCR |357			EXYNOS_MSCTRL_C_INT_IN_2PLANE);358		break;359	}360 361	fimc_write(ctx, cfg, EXYNOS_MSCTRL);362}363 364static void fimc_src_set_fmt(struct fimc_context *ctx, u32 fmt, bool tiled)365{366	u32 cfg;367 368	DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt);369 370	cfg = fimc_read(ctx, EXYNOS_MSCTRL);371	cfg &= ~EXYNOS_MSCTRL_INFORMAT_RGB;372 373	switch (fmt) {374	case DRM_FORMAT_RGB565:375	case DRM_FORMAT_RGB888:376	case DRM_FORMAT_XRGB8888:377		cfg |= EXYNOS_MSCTRL_INFORMAT_RGB;378		break;379	case DRM_FORMAT_YUV444:380		cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420;381		break;382	case DRM_FORMAT_YUYV:383	case DRM_FORMAT_YVYU:384	case DRM_FORMAT_UYVY:385	case DRM_FORMAT_VYUY:386		cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR422_1PLANE;387		break;388	case DRM_FORMAT_NV16:389	case DRM_FORMAT_NV61:390	case DRM_FORMAT_YUV422:391		cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR422;392		break;393	case DRM_FORMAT_YUV420:394	case DRM_FORMAT_YVU420:395	case DRM_FORMAT_NV12:396	case DRM_FORMAT_NV21:397		cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420;398		break;399	}400 401	fimc_write(ctx, cfg, EXYNOS_MSCTRL);402 403	cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM);404	cfg &= ~EXYNOS_CIDMAPARAM_R_MODE_MASK;405 406	if (tiled)407		cfg |= EXYNOS_CIDMAPARAM_R_MODE_64X32;408	else409		cfg |= EXYNOS_CIDMAPARAM_R_MODE_LINEAR;410 411	fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM);412 413	fimc_src_set_fmt_order(ctx, fmt);414}415 416static void fimc_src_set_transf(struct fimc_context *ctx, unsigned int rotation)417{418	unsigned int degree = rotation & DRM_MODE_ROTATE_MASK;419	u32 cfg1, cfg2;420 421	DRM_DEV_DEBUG_KMS(ctx->dev, "rotation[%x]\n", rotation);422 423	cfg1 = fimc_read(ctx, EXYNOS_MSCTRL);424	cfg1 &= ~(EXYNOS_MSCTRL_FLIP_X_MIRROR |425		EXYNOS_MSCTRL_FLIP_Y_MIRROR);426 427	cfg2 = fimc_read(ctx, EXYNOS_CITRGFMT);428	cfg2 &= ~EXYNOS_CITRGFMT_INROT90_CLOCKWISE;429 430	switch (degree) {431	case DRM_MODE_ROTATE_0:432		if (rotation & DRM_MODE_REFLECT_X)433			cfg1 |= EXYNOS_MSCTRL_FLIP_X_MIRROR;434		if (rotation & DRM_MODE_REFLECT_Y)435			cfg1 |= EXYNOS_MSCTRL_FLIP_Y_MIRROR;436		break;437	case DRM_MODE_ROTATE_90:438		cfg2 |= EXYNOS_CITRGFMT_INROT90_CLOCKWISE;439		if (rotation & DRM_MODE_REFLECT_X)440			cfg1 |= EXYNOS_MSCTRL_FLIP_X_MIRROR;441		if (rotation & DRM_MODE_REFLECT_Y)442			cfg1 |= EXYNOS_MSCTRL_FLIP_Y_MIRROR;443		break;444	case DRM_MODE_ROTATE_180:445		cfg1 |= (EXYNOS_MSCTRL_FLIP_X_MIRROR |446			EXYNOS_MSCTRL_FLIP_Y_MIRROR);447		if (rotation & DRM_MODE_REFLECT_X)448			cfg1 &= ~EXYNOS_MSCTRL_FLIP_X_MIRROR;449		if (rotation & DRM_MODE_REFLECT_Y)450			cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR;451		break;452	case DRM_MODE_ROTATE_270:453		cfg1 |= (EXYNOS_MSCTRL_FLIP_X_MIRROR |454			EXYNOS_MSCTRL_FLIP_Y_MIRROR);455		cfg2 |= EXYNOS_CITRGFMT_INROT90_CLOCKWISE;456		if (rotation & DRM_MODE_REFLECT_X)457			cfg1 &= ~EXYNOS_MSCTRL_FLIP_X_MIRROR;458		if (rotation & DRM_MODE_REFLECT_Y)459			cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR;460		break;461	}462 463	fimc_write(ctx, cfg1, EXYNOS_MSCTRL);464	fimc_write(ctx, cfg2, EXYNOS_CITRGFMT);465}466 467static void fimc_set_window(struct fimc_context *ctx,468			    struct exynos_drm_ipp_buffer *buf)469{470	unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0];471	u32 cfg, h1, h2, v1, v2;472 473	/* cropped image */474	h1 = buf->rect.x;475	h2 = real_width - buf->rect.w - buf->rect.x;476	v1 = buf->rect.y;477	v2 = buf->buf.height - buf->rect.h - buf->rect.y;478 479	DRM_DEV_DEBUG_KMS(ctx->dev, "x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n",480			  buf->rect.x, buf->rect.y, buf->rect.w, buf->rect.h,481			  real_width, buf->buf.height);482	DRM_DEV_DEBUG_KMS(ctx->dev, "h1[%d]h2[%d]v1[%d]v2[%d]\n", h1, h2, v1,483			  v2);484 485	/*486	 * set window offset 1, 2 size487	 * check figure 43-21 in user manual488	 */489	cfg = fimc_read(ctx, EXYNOS_CIWDOFST);490	cfg &= ~(EXYNOS_CIWDOFST_WINHOROFST_MASK |491		EXYNOS_CIWDOFST_WINVEROFST_MASK);492	cfg |= (EXYNOS_CIWDOFST_WINHOROFST(h1) |493		EXYNOS_CIWDOFST_WINVEROFST(v1));494	cfg |= EXYNOS_CIWDOFST_WINOFSEN;495	fimc_write(ctx, cfg, EXYNOS_CIWDOFST);496 497	cfg = (EXYNOS_CIWDOFST2_WINHOROFST2(h2) |498		EXYNOS_CIWDOFST2_WINVEROFST2(v2));499	fimc_write(ctx, cfg, EXYNOS_CIWDOFST2);500}501 502static void fimc_src_set_size(struct fimc_context *ctx,503			      struct exynos_drm_ipp_buffer *buf)504{505	unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0];506	u32 cfg;507 508	DRM_DEV_DEBUG_KMS(ctx->dev, "hsize[%d]vsize[%d]\n", real_width,509			  buf->buf.height);510 511	/* original size */512	cfg = (EXYNOS_ORGISIZE_HORIZONTAL(real_width) |513		EXYNOS_ORGISIZE_VERTICAL(buf->buf.height));514 515	fimc_write(ctx, cfg, EXYNOS_ORGISIZE);516 517	DRM_DEV_DEBUG_KMS(ctx->dev, "x[%d]y[%d]w[%d]h[%d]\n", buf->rect.x,518			  buf->rect.y, buf->rect.w, buf->rect.h);519 520	/* set input DMA image size */521	cfg = fimc_read(ctx, EXYNOS_CIREAL_ISIZE);522	cfg &= ~(EXYNOS_CIREAL_ISIZE_HEIGHT_MASK |523		EXYNOS_CIREAL_ISIZE_WIDTH_MASK);524	cfg |= (EXYNOS_CIREAL_ISIZE_WIDTH(buf->rect.w) |525		EXYNOS_CIREAL_ISIZE_HEIGHT(buf->rect.h));526	fimc_write(ctx, cfg, EXYNOS_CIREAL_ISIZE);527 528	/*529	 * set input FIFO image size530	 * for now, we support only ITU601 8 bit mode531	 */532	cfg = (EXYNOS_CISRCFMT_ITU601_8BIT |533		EXYNOS_CISRCFMT_SOURCEHSIZE(real_width) |534		EXYNOS_CISRCFMT_SOURCEVSIZE(buf->buf.height));535	fimc_write(ctx, cfg, EXYNOS_CISRCFMT);536 537	/* offset Y(RGB), Cb, Cr */538	cfg = (EXYNOS_CIIYOFF_HORIZONTAL(buf->rect.x) |539		EXYNOS_CIIYOFF_VERTICAL(buf->rect.y));540	fimc_write(ctx, cfg, EXYNOS_CIIYOFF);541	cfg = (EXYNOS_CIICBOFF_HORIZONTAL(buf->rect.x) |542		EXYNOS_CIICBOFF_VERTICAL(buf->rect.y));543	fimc_write(ctx, cfg, EXYNOS_CIICBOFF);544	cfg = (EXYNOS_CIICROFF_HORIZONTAL(buf->rect.x) |545		EXYNOS_CIICROFF_VERTICAL(buf->rect.y));546	fimc_write(ctx, cfg, EXYNOS_CIICROFF);547 548	fimc_set_window(ctx, buf);549}550 551static void fimc_src_set_addr(struct fimc_context *ctx,552			      struct exynos_drm_ipp_buffer *buf)553{554	fimc_write(ctx, buf->dma_addr[0], EXYNOS_CIIYSA(0));555	fimc_write(ctx, buf->dma_addr[1], EXYNOS_CIICBSA(0));556	fimc_write(ctx, buf->dma_addr[2], EXYNOS_CIICRSA(0));557}558 559static void fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt)560{561	u32 cfg;562 563	DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt);564 565	/* RGB */566	cfg = fimc_read(ctx, EXYNOS_CISCCTRL);567	cfg &= ~EXYNOS_CISCCTRL_OUTRGB_FMT_RGB_MASK;568 569	switch (fmt) {570	case DRM_FORMAT_RGB565:571		cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB565;572		fimc_write(ctx, cfg, EXYNOS_CISCCTRL);573		return;574	case DRM_FORMAT_RGB888:575		cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888;576		fimc_write(ctx, cfg, EXYNOS_CISCCTRL);577		return;578	case DRM_FORMAT_XRGB8888:579		cfg |= (EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888 |580			EXYNOS_CISCCTRL_EXTRGB_EXTENSION);581		fimc_write(ctx, cfg, EXYNOS_CISCCTRL);582		break;583	default:584		/* bypass */585		break;586	}587 588	/* YUV */589	cfg = fimc_read(ctx, EXYNOS_CIOCTRL);590	cfg &= ~(EXYNOS_CIOCTRL_ORDER2P_MASK |591		EXYNOS_CIOCTRL_ORDER422_MASK |592		EXYNOS_CIOCTRL_YCBCR_PLANE_MASK);593 594	switch (fmt) {595	case DRM_FORMAT_XRGB8888:596		cfg |= EXYNOS_CIOCTRL_ALPHA_OUT;597		break;598	case DRM_FORMAT_YUYV:599		cfg |= EXYNOS_CIOCTRL_ORDER422_YCBYCR;600		break;601	case DRM_FORMAT_YVYU:602		cfg |= EXYNOS_CIOCTRL_ORDER422_YCRYCB;603		break;604	case DRM_FORMAT_UYVY:605		cfg |= EXYNOS_CIOCTRL_ORDER422_CBYCRY;606		break;607	case DRM_FORMAT_VYUY:608		cfg |= EXYNOS_CIOCTRL_ORDER422_CRYCBY;609		break;610	case DRM_FORMAT_NV21:611	case DRM_FORMAT_NV61:612		cfg |= EXYNOS_CIOCTRL_ORDER2P_LSB_CRCB;613		cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE;614		break;615	case DRM_FORMAT_YUV422:616	case DRM_FORMAT_YUV420:617	case DRM_FORMAT_YVU420:618		cfg |= EXYNOS_CIOCTRL_YCBCR_3PLANE;619		break;620	case DRM_FORMAT_NV12:621	case DRM_FORMAT_NV16:622		cfg |= EXYNOS_CIOCTRL_ORDER2P_LSB_CBCR;623		cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE;624		break;625	}626 627	fimc_write(ctx, cfg, EXYNOS_CIOCTRL);628}629 630static void fimc_dst_set_fmt(struct fimc_context *ctx, u32 fmt, bool tiled)631{632	u32 cfg;633 634	DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt);635 636	cfg = fimc_read(ctx, EXYNOS_CIEXTEN);637 638	if (fmt == DRM_FORMAT_AYUV) {639		cfg |= EXYNOS_CIEXTEN_YUV444_OUT;640		fimc_write(ctx, cfg, EXYNOS_CIEXTEN);641	} else {642		cfg &= ~EXYNOS_CIEXTEN_YUV444_OUT;643		fimc_write(ctx, cfg, EXYNOS_CIEXTEN);644 645		cfg = fimc_read(ctx, EXYNOS_CITRGFMT);646		cfg &= ~EXYNOS_CITRGFMT_OUTFORMAT_MASK;647 648		switch (fmt) {649		case DRM_FORMAT_RGB565:650		case DRM_FORMAT_RGB888:651		case DRM_FORMAT_XRGB8888:652			cfg |= EXYNOS_CITRGFMT_OUTFORMAT_RGB;653			break;654		case DRM_FORMAT_YUYV:655		case DRM_FORMAT_YVYU:656		case DRM_FORMAT_UYVY:657		case DRM_FORMAT_VYUY:658			cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE;659			break;660		case DRM_FORMAT_NV16:661		case DRM_FORMAT_NV61:662		case DRM_FORMAT_YUV422:663			cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422;664			break;665		case DRM_FORMAT_YUV420:666		case DRM_FORMAT_YVU420:667		case DRM_FORMAT_NV12:668		case DRM_FORMAT_NV21:669			cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420;670			break;671		}672 673		fimc_write(ctx, cfg, EXYNOS_CITRGFMT);674	}675 676	cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM);677	cfg &= ~EXYNOS_CIDMAPARAM_W_MODE_MASK;678 679	if (tiled)680		cfg |= EXYNOS_CIDMAPARAM_W_MODE_64X32;681	else682		cfg |= EXYNOS_CIDMAPARAM_W_MODE_LINEAR;683 684	fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM);685 686	fimc_dst_set_fmt_order(ctx, fmt);687}688 689static void fimc_dst_set_transf(struct fimc_context *ctx, unsigned int rotation)690{691	unsigned int degree = rotation & DRM_MODE_ROTATE_MASK;692	u32 cfg;693 694	DRM_DEV_DEBUG_KMS(ctx->dev, "rotation[0x%x]\n", rotation);695 696	cfg = fimc_read(ctx, EXYNOS_CITRGFMT);697	cfg &= ~EXYNOS_CITRGFMT_FLIP_MASK;698	cfg &= ~EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE;699 700	switch (degree) {701	case DRM_MODE_ROTATE_0:702		if (rotation & DRM_MODE_REFLECT_X)703			cfg |= EXYNOS_CITRGFMT_FLIP_X_MIRROR;704		if (rotation & DRM_MODE_REFLECT_Y)705			cfg |= EXYNOS_CITRGFMT_FLIP_Y_MIRROR;706		break;707	case DRM_MODE_ROTATE_90:708		cfg |= EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE;709		if (rotation & DRM_MODE_REFLECT_X)710			cfg |= EXYNOS_CITRGFMT_FLIP_X_MIRROR;711		if (rotation & DRM_MODE_REFLECT_Y)712			cfg |= EXYNOS_CITRGFMT_FLIP_Y_MIRROR;713		break;714	case DRM_MODE_ROTATE_180:715		cfg |= (EXYNOS_CITRGFMT_FLIP_X_MIRROR |716			EXYNOS_CITRGFMT_FLIP_Y_MIRROR);717		if (rotation & DRM_MODE_REFLECT_X)718			cfg &= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR;719		if (rotation & DRM_MODE_REFLECT_Y)720			cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR;721		break;722	case DRM_MODE_ROTATE_270:723		cfg |= (EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE |724			EXYNOS_CITRGFMT_FLIP_X_MIRROR |725			EXYNOS_CITRGFMT_FLIP_Y_MIRROR);726		if (rotation & DRM_MODE_REFLECT_X)727			cfg &= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR;728		if (rotation & DRM_MODE_REFLECT_Y)729			cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR;730		break;731	}732 733	fimc_write(ctx, cfg, EXYNOS_CITRGFMT);734}735 736static int fimc_set_prescaler(struct fimc_context *ctx, struct fimc_scaler *sc,737			      struct drm_exynos_ipp_task_rect *src,738			      struct drm_exynos_ipp_task_rect *dst)739{740	u32 cfg, cfg_ext, shfactor;741	u32 pre_dst_width, pre_dst_height;742	u32 hfactor, vfactor;743	int ret = 0;744	u32 src_w, src_h, dst_w, dst_h;745 746	cfg_ext = fimc_read(ctx, EXYNOS_CITRGFMT);747	if (cfg_ext & EXYNOS_CITRGFMT_INROT90_CLOCKWISE) {748		src_w = src->h;749		src_h = src->w;750	} else {751		src_w = src->w;752		src_h = src->h;753	}754 755	if (cfg_ext & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE) {756		dst_w = dst->h;757		dst_h = dst->w;758	} else {759		dst_w = dst->w;760		dst_h = dst->h;761	}762 763	/* fimc_ippdrv_check_property assures that dividers are not null */764	hfactor = fls(src_w / dst_w / 2);765	if (hfactor > FIMC_SHFACTOR / 2) {766		dev_err(ctx->dev, "failed to get ratio horizontal.\n");767		return -EINVAL;768	}769 770	vfactor = fls(src_h / dst_h / 2);771	if (vfactor > FIMC_SHFACTOR / 2) {772		dev_err(ctx->dev, "failed to get ratio vertical.\n");773		return -EINVAL;774	}775 776	pre_dst_width = src_w >> hfactor;777	pre_dst_height = src_h >> vfactor;778	DRM_DEV_DEBUG_KMS(ctx->dev, "pre_dst_width[%d]pre_dst_height[%d]\n",779			  pre_dst_width, pre_dst_height);780	DRM_DEV_DEBUG_KMS(ctx->dev, "hfactor[%d]vfactor[%d]\n", hfactor,781			  vfactor);782 783	sc->hratio = (src_w << 14) / (dst_w << hfactor);784	sc->vratio = (src_h << 14) / (dst_h << vfactor);785	sc->up_h = (dst_w >= src_w);786	sc->up_v = (dst_h >= src_h);787	DRM_DEV_DEBUG_KMS(ctx->dev, "hratio[%d]vratio[%d]up_h[%d]up_v[%d]\n",788			  sc->hratio, sc->vratio, sc->up_h, sc->up_v);789 790	shfactor = FIMC_SHFACTOR - (hfactor + vfactor);791	DRM_DEV_DEBUG_KMS(ctx->dev, "shfactor[%d]\n", shfactor);792 793	cfg = (EXYNOS_CISCPRERATIO_SHFACTOR(shfactor) |794		EXYNOS_CISCPRERATIO_PREHORRATIO(1 << hfactor) |795		EXYNOS_CISCPRERATIO_PREVERRATIO(1 << vfactor));796	fimc_write(ctx, cfg, EXYNOS_CISCPRERATIO);797 798	cfg = (EXYNOS_CISCPREDST_PREDSTWIDTH(pre_dst_width) |799		EXYNOS_CISCPREDST_PREDSTHEIGHT(pre_dst_height));800	fimc_write(ctx, cfg, EXYNOS_CISCPREDST);801 802	return ret;803}804 805static void fimc_set_scaler(struct fimc_context *ctx, struct fimc_scaler *sc)806{807	u32 cfg, cfg_ext;808 809	DRM_DEV_DEBUG_KMS(ctx->dev, "range[%d]bypass[%d]up_h[%d]up_v[%d]\n",810			  sc->range, sc->bypass, sc->up_h, sc->up_v);811	DRM_DEV_DEBUG_KMS(ctx->dev, "hratio[%d]vratio[%d]\n",812			  sc->hratio, sc->vratio);813 814	cfg = fimc_read(ctx, EXYNOS_CISCCTRL);815	cfg &= ~(EXYNOS_CISCCTRL_SCALERBYPASS |816		EXYNOS_CISCCTRL_SCALEUP_H | EXYNOS_CISCCTRL_SCALEUP_V |817		EXYNOS_CISCCTRL_MAIN_V_RATIO_MASK |818		EXYNOS_CISCCTRL_MAIN_H_RATIO_MASK |819		EXYNOS_CISCCTRL_CSCR2Y_WIDE |820		EXYNOS_CISCCTRL_CSCY2R_WIDE);821 822	if (sc->range)823		cfg |= (EXYNOS_CISCCTRL_CSCR2Y_WIDE |824			EXYNOS_CISCCTRL_CSCY2R_WIDE);825	if (sc->bypass)826		cfg |= EXYNOS_CISCCTRL_SCALERBYPASS;827	if (sc->up_h)828		cfg |= EXYNOS_CISCCTRL_SCALEUP_H;829	if (sc->up_v)830		cfg |= EXYNOS_CISCCTRL_SCALEUP_V;831 832	cfg |= (EXYNOS_CISCCTRL_MAINHORRATIO((sc->hratio >> 6)) |833		EXYNOS_CISCCTRL_MAINVERRATIO((sc->vratio >> 6)));834	fimc_write(ctx, cfg, EXYNOS_CISCCTRL);835 836	cfg_ext = fimc_read(ctx, EXYNOS_CIEXTEN);837	cfg_ext &= ~EXYNOS_CIEXTEN_MAINHORRATIO_EXT_MASK;838	cfg_ext &= ~EXYNOS_CIEXTEN_MAINVERRATIO_EXT_MASK;839	cfg_ext |= (EXYNOS_CIEXTEN_MAINHORRATIO_EXT(sc->hratio) |840		EXYNOS_CIEXTEN_MAINVERRATIO_EXT(sc->vratio));841	fimc_write(ctx, cfg_ext, EXYNOS_CIEXTEN);842}843 844static void fimc_dst_set_size(struct fimc_context *ctx,845			     struct exynos_drm_ipp_buffer *buf)846{847	unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0];848	u32 cfg, cfg_ext;849 850	DRM_DEV_DEBUG_KMS(ctx->dev, "hsize[%d]vsize[%d]\n", real_width,851			  buf->buf.height);852 853	/* original size */854	cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(real_width) |855		EXYNOS_ORGOSIZE_VERTICAL(buf->buf.height));856 857	fimc_write(ctx, cfg, EXYNOS_ORGOSIZE);858 859	DRM_DEV_DEBUG_KMS(ctx->dev, "x[%d]y[%d]w[%d]h[%d]\n", buf->rect.x,860			  buf->rect.y,861			  buf->rect.w, buf->rect.h);862 863	/* CSC ITU */864	cfg = fimc_read(ctx, EXYNOS_CIGCTRL);865	cfg &= ~EXYNOS_CIGCTRL_CSC_MASK;866 867	if (buf->buf.width >= FIMC_WIDTH_ITU_709)868		cfg |= EXYNOS_CIGCTRL_CSC_ITU709;869	else870		cfg |= EXYNOS_CIGCTRL_CSC_ITU601;871 872	fimc_write(ctx, cfg, EXYNOS_CIGCTRL);873 874	cfg_ext = fimc_read(ctx, EXYNOS_CITRGFMT);875 876	/* target image size */877	cfg = fimc_read(ctx, EXYNOS_CITRGFMT);878	cfg &= ~(EXYNOS_CITRGFMT_TARGETH_MASK |879		EXYNOS_CITRGFMT_TARGETV_MASK);880	if (cfg_ext & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE)881		cfg |= (EXYNOS_CITRGFMT_TARGETHSIZE(buf->rect.h) |882			EXYNOS_CITRGFMT_TARGETVSIZE(buf->rect.w));883	else884		cfg |= (EXYNOS_CITRGFMT_TARGETHSIZE(buf->rect.w) |885			EXYNOS_CITRGFMT_TARGETVSIZE(buf->rect.h));886	fimc_write(ctx, cfg, EXYNOS_CITRGFMT);887 888	/* target area */889	cfg = EXYNOS_CITAREA_TARGET_AREA(buf->rect.w * buf->rect.h);890	fimc_write(ctx, cfg, EXYNOS_CITAREA);891 892	/* offset Y(RGB), Cb, Cr */893	cfg = (EXYNOS_CIOYOFF_HORIZONTAL(buf->rect.x) |894		EXYNOS_CIOYOFF_VERTICAL(buf->rect.y));895	fimc_write(ctx, cfg, EXYNOS_CIOYOFF);896	cfg = (EXYNOS_CIOCBOFF_HORIZONTAL(buf->rect.x) |897		EXYNOS_CIOCBOFF_VERTICAL(buf->rect.y));898	fimc_write(ctx, cfg, EXYNOS_CIOCBOFF);899	cfg = (EXYNOS_CIOCROFF_HORIZONTAL(buf->rect.x) |900		EXYNOS_CIOCROFF_VERTICAL(buf->rect.y));901	fimc_write(ctx, cfg, EXYNOS_CIOCROFF);902}903 904static void fimc_dst_set_buf_seq(struct fimc_context *ctx, u32 buf_id,905		bool enqueue)906{907	unsigned long flags;908	u32 buf_num;909	u32 cfg;910 911	DRM_DEV_DEBUG_KMS(ctx->dev, "buf_id[%d]enqueu[%d]\n", buf_id, enqueue);912 913	spin_lock_irqsave(&ctx->lock, flags);914 915	cfg = fimc_read(ctx, EXYNOS_CIFCNTSEQ);916 917	if (enqueue)918		cfg |= (1 << buf_id);919	else920		cfg &= ~(1 << buf_id);921 922	fimc_write(ctx, cfg, EXYNOS_CIFCNTSEQ);923 924	buf_num = hweight32(cfg);925 926	if (enqueue && buf_num >= FIMC_BUF_START)927		fimc_mask_irq(ctx, true);928	else if (!enqueue && buf_num <= FIMC_BUF_STOP)929		fimc_mask_irq(ctx, false);930 931	spin_unlock_irqrestore(&ctx->lock, flags);932}933 934static void fimc_dst_set_addr(struct fimc_context *ctx,935			     struct exynos_drm_ipp_buffer *buf)936{937	fimc_write(ctx, buf->dma_addr[0], EXYNOS_CIOYSA(0));938	fimc_write(ctx, buf->dma_addr[1], EXYNOS_CIOCBSA(0));939	fimc_write(ctx, buf->dma_addr[2], EXYNOS_CIOCRSA(0));940 941	fimc_dst_set_buf_seq(ctx, 0, true);942}943 944static void fimc_stop(struct fimc_context *ctx);945 946static irqreturn_t fimc_irq_handler(int irq, void *dev_id)947{948	struct fimc_context *ctx = dev_id;949	int buf_id;950 951	DRM_DEV_DEBUG_KMS(ctx->dev, "fimc id[%d]\n", ctx->id);952 953	fimc_clear_irq(ctx);954	if (fimc_check_ovf(ctx))955		return IRQ_NONE;956 957	if (!fimc_check_frame_end(ctx))958		return IRQ_NONE;959 960	buf_id = fimc_get_buf_id(ctx);961	if (buf_id < 0)962		return IRQ_HANDLED;963 964	DRM_DEV_DEBUG_KMS(ctx->dev, "buf_id[%d]\n", buf_id);965 966	if (ctx->task) {967		struct exynos_drm_ipp_task *task = ctx->task;968 969		ctx->task = NULL;970		pm_runtime_mark_last_busy(ctx->dev);971		pm_runtime_put_autosuspend(ctx->dev);972		exynos_drm_ipp_task_done(task, 0);973	}974 975	fimc_dst_set_buf_seq(ctx, buf_id, false);976	fimc_stop(ctx);977 978	return IRQ_HANDLED;979}980 981static void fimc_clear_addr(struct fimc_context *ctx)982{983	int i;984 985	for (i = 0; i < FIMC_MAX_SRC; i++) {986		fimc_write(ctx, 0, EXYNOS_CIIYSA(i));987		fimc_write(ctx, 0, EXYNOS_CIICBSA(i));988		fimc_write(ctx, 0, EXYNOS_CIICRSA(i));989	}990 991	for (i = 0; i < FIMC_MAX_DST; i++) {992		fimc_write(ctx, 0, EXYNOS_CIOYSA(i));993		fimc_write(ctx, 0, EXYNOS_CIOCBSA(i));994		fimc_write(ctx, 0, EXYNOS_CIOCRSA(i));995	}996}997 998static void fimc_reset(struct fimc_context *ctx)999{1000	/* reset h/w block */1001	fimc_sw_reset(ctx);1002 1003	/* reset scaler capability */1004	memset(&ctx->sc, 0x0, sizeof(ctx->sc));1005 1006	fimc_clear_addr(ctx);1007}1008 1009static void fimc_start(struct fimc_context *ctx)1010{1011	u32 cfg0, cfg1;1012 1013	fimc_mask_irq(ctx, true);1014 1015	/* If set true, we can save jpeg about screen */1016	fimc_handle_jpeg(ctx, false);1017	fimc_set_scaler(ctx, &ctx->sc);1018 1019	fimc_set_type_ctrl(ctx);1020	fimc_handle_lastend(ctx, false);1021 1022	/* setup dma */1023	cfg0 = fimc_read(ctx, EXYNOS_MSCTRL);1024	cfg0 &= ~EXYNOS_MSCTRL_INPUT_MASK;1025	cfg0 |= EXYNOS_MSCTRL_INPUT_MEMORY;1026	fimc_write(ctx, cfg0, EXYNOS_MSCTRL);1027 1028	/* Reset status */1029	fimc_write(ctx, 0x0, EXYNOS_CISTATUS);1030 1031	cfg0 = fimc_read(ctx, EXYNOS_CIIMGCPT);1032	cfg0 &= ~EXYNOS_CIIMGCPT_IMGCPTEN_SC;1033	cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN_SC;1034 1035	/* Scaler */1036	cfg1 = fimc_read(ctx, EXYNOS_CISCCTRL);1037	cfg1 &= ~EXYNOS_CISCCTRL_SCAN_MASK;1038	cfg1 |= (EXYNOS_CISCCTRL_PROGRESSIVE |1039		EXYNOS_CISCCTRL_SCALERSTART);1040 1041	fimc_write(ctx, cfg1, EXYNOS_CISCCTRL);1042 1043	/* Enable image capture*/1044	cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN;1045	fimc_write(ctx, cfg0, EXYNOS_CIIMGCPT);1046 1047	/* Disable frame end irq */1048	fimc_clear_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_END_DISABLE);1049 1050	fimc_clear_bits(ctx, EXYNOS_CIOCTRL, EXYNOS_CIOCTRL_WEAVE_MASK);1051 1052	fimc_set_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID);1053}1054 1055static void fimc_stop(struct fimc_context *ctx)1056{1057	u32 cfg;1058 1059	/* Source clear */1060	cfg = fimc_read(ctx, EXYNOS_MSCTRL);1061	cfg &= ~EXYNOS_MSCTRL_INPUT_MASK;1062	cfg &= ~EXYNOS_MSCTRL_ENVID;1063	fimc_write(ctx, cfg, EXYNOS_MSCTRL);1064 1065	fimc_mask_irq(ctx, false);1066 1067	/* reset sequence */1068	fimc_write(ctx, 0x0, EXYNOS_CIFCNTSEQ);1069 1070	/* Scaler disable */1071	fimc_clear_bits(ctx, EXYNOS_CISCCTRL, EXYNOS_CISCCTRL_SCALERSTART);1072 1073	/* Disable image capture */1074	fimc_clear_bits(ctx, EXYNOS_CIIMGCPT,1075		EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN);1076 1077	/* Enable frame end irq */1078	fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_END_DISABLE);1079}1080 1081static int fimc_commit(struct exynos_drm_ipp *ipp,1082			  struct exynos_drm_ipp_task *task)1083{1084	struct fimc_context *ctx =1085			container_of(ipp, struct fimc_context, ipp);1086	int ret;1087 1088	ret = pm_runtime_resume_and_get(ctx->dev);1089	if (ret < 0) {1090		dev_err(ctx->dev, "failed to enable FIMC device.\n");1091		return ret;1092	}1093 1094	ctx->task = task;1095 1096	fimc_src_set_fmt(ctx, task->src.buf.fourcc, task->src.buf.modifier);1097	fimc_src_set_size(ctx, &task->src);1098	fimc_src_set_transf(ctx, DRM_MODE_ROTATE_0);1099	fimc_src_set_addr(ctx, &task->src);1100	fimc_dst_set_fmt(ctx, task->dst.buf.fourcc, task->dst.buf.modifier);1101	fimc_dst_set_transf(ctx, task->transform.rotation);1102	fimc_dst_set_size(ctx, &task->dst);1103	fimc_dst_set_addr(ctx, &task->dst);1104	fimc_set_prescaler(ctx, &ctx->sc, &task->src.rect, &task->dst.rect);1105	fimc_start(ctx);1106 1107	return 0;1108}1109 1110static void fimc_abort(struct exynos_drm_ipp *ipp,1111			  struct exynos_drm_ipp_task *task)1112{1113	struct fimc_context *ctx =1114			container_of(ipp, struct fimc_context, ipp);1115 1116	fimc_reset(ctx);1117 1118	if (ctx->task) {1119		struct exynos_drm_ipp_task *task = ctx->task;1120 1121		ctx->task = NULL;1122		pm_runtime_mark_last_busy(ctx->dev);1123		pm_runtime_put_autosuspend(ctx->dev);1124		exynos_drm_ipp_task_done(task, -EIO);1125	}1126}1127 1128static const struct exynos_drm_ipp_funcs ipp_funcs = {1129	.commit = fimc_commit,1130	.abort = fimc_abort,1131};1132 1133static int fimc_bind(struct device *dev, struct device *master, void *data)1134{1135	struct fimc_context *ctx = dev_get_drvdata(dev);1136	struct drm_device *drm_dev = data;1137	struct exynos_drm_ipp *ipp = &ctx->ipp;1138 1139	ctx->drm_dev = drm_dev;1140	ipp->drm_dev = drm_dev;1141	exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);1142 1143	exynos_drm_ipp_register(dev, ipp, &ipp_funcs,1144			DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |1145			DRM_EXYNOS_IPP_CAP_SCALE | DRM_EXYNOS_IPP_CAP_CONVERT,1146			ctx->formats, ctx->num_formats, "fimc");1147 1148	dev_info(dev, "The exynos fimc has been probed successfully\n");1149 1150	return 0;1151}1152 1153static void fimc_unbind(struct device *dev, struct device *master,1154			void *data)1155{1156	struct fimc_context *ctx = dev_get_drvdata(dev);1157	struct drm_device *drm_dev = data;1158	struct exynos_drm_ipp *ipp = &ctx->ipp;1159 1160	exynos_drm_ipp_unregister(dev, ipp);1161	exynos_drm_unregister_dma(drm_dev, dev, &ctx->dma_priv);1162}1163 1164static const struct component_ops fimc_component_ops = {1165	.bind	= fimc_bind,1166	.unbind = fimc_unbind,1167};1168 1169static void fimc_put_clocks(struct fimc_context *ctx)1170{1171	int i;1172 1173	for (i = 0; i < FIMC_CLKS_MAX; i++) {1174		if (IS_ERR(ctx->clocks[i]))1175			continue;1176		clk_put(ctx->clocks[i]);1177		ctx->clocks[i] = ERR_PTR(-EINVAL);1178	}1179}1180 1181static int fimc_setup_clocks(struct fimc_context *ctx)1182{1183	struct device *fimc_dev = ctx->dev;1184	struct device *dev;1185	int ret, i;1186 1187	for (i = 0; i < FIMC_CLKS_MAX; i++)1188		ctx->clocks[i] = ERR_PTR(-EINVAL);1189 1190	for (i = 0; i < FIMC_CLKS_MAX; i++) {1191		if (i == FIMC_CLK_WB_A || i == FIMC_CLK_WB_B)1192			dev = fimc_dev->parent;1193		else1194			dev = fimc_dev;1195 1196		ctx->clocks[i] = clk_get(dev, fimc_clock_names[i]);1197		if (IS_ERR(ctx->clocks[i])) {1198			ret = PTR_ERR(ctx->clocks[i]);1199			dev_err(fimc_dev, "failed to get clock: %s\n",1200						fimc_clock_names[i]);1201			goto e_clk_free;1202		}1203	}1204 1205	ret = clk_prepare_enable(ctx->clocks[FIMC_CLK_LCLK]);1206	if (!ret)1207		return ret;1208e_clk_free:1209	fimc_put_clocks(ctx);1210	return ret;1211}1212 1213int exynos_drm_check_fimc_device(struct device *dev)1214{1215	int id = of_alias_get_id(dev->of_node, "fimc");1216 1217	if (id >= 0 && (BIT(id) & fimc_mask))1218		return 0;1219	return -ENODEV;1220}1221 1222static const unsigned int fimc_formats[] = {1223	DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565,1224	DRM_FORMAT_NV12, DRM_FORMAT_NV16, DRM_FORMAT_NV21, DRM_FORMAT_NV61,1225	DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU,1226	DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422,1227	DRM_FORMAT_YUV444,1228};1229 1230static const unsigned int fimc_tiled_formats[] = {1231	DRM_FORMAT_NV12, DRM_FORMAT_NV21,1232};1233 1234static const struct drm_exynos_ipp_limit fimc_4210_limits_v1[] = {1235	{ IPP_SIZE_LIMIT(BUFFER, .h = { 16, 8192, 8 }, .v = { 16, 8192, 2 }) },1236	{ IPP_SIZE_LIMIT(AREA, .h = { 16, 4224, 2 }, .v = { 16, 0, 2 }) },1237	{ IPP_SIZE_LIMIT(ROTATED, .h = { 128, 1920 }, .v = { 128, 0 }) },1238	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 },1239			  .v = { (1 << 16) / 64, (1 << 16) * 64 }) },1240};1241 1242static const struct drm_exynos_ipp_limit fimc_4210_limits_v2[] = {1243	{ IPP_SIZE_LIMIT(BUFFER, .h = { 16, 8192, 8 }, .v = { 16, 8192, 2 }) },1244	{ IPP_SIZE_LIMIT(AREA, .h = { 16, 1920, 2 }, .v = { 16, 0, 2 }) },1245	{ IPP_SIZE_LIMIT(ROTATED, .h = { 128, 1366 }, .v = { 128, 0 }) },1246	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 },1247			  .v = { (1 << 16) / 64, (1 << 16) * 64 }) },1248};1249 1250static const struct drm_exynos_ipp_limit fimc_4210_limits_tiled_v1[] = {1251	{ IPP_SIZE_LIMIT(BUFFER, .h = { 128, 1920, 128 }, .v = { 32, 1920, 32 }) },1252	{ IPP_SIZE_LIMIT(AREA, .h = { 128, 1920, 2 }, .v = { 128, 0, 2 }) },1253	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 },1254			  .v = { (1 << 16) / 64, (1 << 16) * 64 }) },1255};1256 1257static const struct drm_exynos_ipp_limit fimc_4210_limits_tiled_v2[] = {1258	{ IPP_SIZE_LIMIT(BUFFER, .h = { 128, 1920, 128 }, .v = { 32, 1920, 32 }) },1259	{ IPP_SIZE_LIMIT(AREA, .h = { 128, 1366, 2 }, .v = { 128, 0, 2 }) },1260	{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 },1261			  .v = { (1 << 16) / 64, (1 << 16) * 64 }) },1262};1263 1264static int fimc_probe(struct platform_device *pdev)1265{1266	const struct drm_exynos_ipp_limit *limits;1267	struct exynos_drm_ipp_formats *formats;1268	struct device *dev = &pdev->dev;1269	struct fimc_context *ctx;1270	int ret;1271	int i, j, num_limits, num_formats;1272 1273	if (exynos_drm_check_fimc_device(dev) != 0)1274		return -ENODEV;1275 1276	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);1277	if (!ctx)1278		return -ENOMEM;1279 1280	ctx->dev = dev;1281	ctx->id = of_alias_get_id(dev->of_node, "fimc");1282 1283	/* construct formats/limits array */1284	num_formats = ARRAY_SIZE(fimc_formats) + ARRAY_SIZE(fimc_tiled_formats);1285	formats = devm_kcalloc(dev, num_formats, sizeof(*formats),1286			       GFP_KERNEL);1287	if (!formats)1288		return -ENOMEM;1289 1290	/* linear formats */1291	if (ctx->id < 3) {1292		limits = fimc_4210_limits_v1;1293		num_limits = ARRAY_SIZE(fimc_4210_limits_v1);1294	} else {1295		limits = fimc_4210_limits_v2;1296		num_limits = ARRAY_SIZE(fimc_4210_limits_v2);1297	}1298	for (i = 0; i < ARRAY_SIZE(fimc_formats); i++) {1299		formats[i].fourcc = fimc_formats[i];1300		formats[i].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |1301				  DRM_EXYNOS_IPP_FORMAT_DESTINATION;1302		formats[i].limits = limits;1303		formats[i].num_limits = num_limits;1304	}1305 1306	/* tiled formats */1307	if (ctx->id < 3) {1308		limits = fimc_4210_limits_tiled_v1;1309		num_limits = ARRAY_SIZE(fimc_4210_limits_tiled_v1);1310	} else {1311		limits = fimc_4210_limits_tiled_v2;1312		num_limits = ARRAY_SIZE(fimc_4210_limits_tiled_v2);1313	}1314	for (j = i, i = 0; i < ARRAY_SIZE(fimc_tiled_formats); j++, i++) {1315		formats[j].fourcc = fimc_tiled_formats[i];1316		formats[j].modifier = DRM_FORMAT_MOD_SAMSUNG_64_32_TILE;1317		formats[j].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |1318				  DRM_EXYNOS_IPP_FORMAT_DESTINATION;1319		formats[j].limits = limits;1320		formats[j].num_limits = num_limits;1321	}1322 1323	ctx->formats = formats;1324	ctx->num_formats = num_formats;1325 1326	/* resource memory */1327	ctx->regs = devm_platform_ioremap_resource(pdev, 0);1328	if (IS_ERR(ctx->regs))1329		return PTR_ERR(ctx->regs);1330 1331	/* resource irq */1332	ret = platform_get_irq(pdev, 0);1333	if (ret < 0)1334		return ret;1335 1336	ret = devm_request_irq(dev, ret, fimc_irq_handler,1337			       0, dev_name(dev), ctx);1338	if (ret < 0) {1339		dev_err(dev, "failed to request irq.\n");1340		return ret;1341	}1342 1343	ret = fimc_setup_clocks(ctx);1344	if (ret < 0)1345		return ret;1346 1347	spin_lock_init(&ctx->lock);1348	platform_set_drvdata(pdev, ctx);1349 1350	pm_runtime_use_autosuspend(dev);1351	pm_runtime_set_autosuspend_delay(dev, FIMC_AUTOSUSPEND_DELAY);1352	pm_runtime_enable(dev);1353 1354	ret = component_add(dev, &fimc_component_ops);1355	if (ret)1356		goto err_pm_dis;1357 1358	dev_info(dev, "drm fimc registered successfully.\n");1359 1360	return 0;1361 1362err_pm_dis:1363	pm_runtime_dont_use_autosuspend(dev);1364	pm_runtime_disable(dev);1365	fimc_put_clocks(ctx);1366 1367	return ret;1368}1369 1370static void fimc_remove(struct platform_device *pdev)1371{1372	struct device *dev = &pdev->dev;1373	struct fimc_context *ctx = get_fimc_context(dev);1374 1375	component_del(dev, &fimc_component_ops);1376	pm_runtime_dont_use_autosuspend(dev);1377	pm_runtime_disable(dev);1378 1379	fimc_put_clocks(ctx);1380}1381 1382static int fimc_runtime_suspend(struct device *dev)1383{1384	struct fimc_context *ctx = get_fimc_context(dev);1385 1386	DRM_DEV_DEBUG_KMS(dev, "id[%d]\n", ctx->id);1387	clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]);1388	return 0;1389}1390 1391static int fimc_runtime_resume(struct device *dev)1392{1393	struct fimc_context *ctx = get_fimc_context(dev);1394 1395	DRM_DEV_DEBUG_KMS(dev, "id[%d]\n", ctx->id);1396	return clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]);1397}1398 1399static DEFINE_RUNTIME_DEV_PM_OPS(fimc_pm_ops, fimc_runtime_suspend,1400				 fimc_runtime_resume, NULL);1401 1402static const struct of_device_id fimc_of_match[] = {1403	{ .compatible = "samsung,exynos4210-fimc" },1404	{ .compatible = "samsung,exynos4212-fimc" },1405	{ },1406};1407MODULE_DEVICE_TABLE(of, fimc_of_match);1408 1409struct platform_driver fimc_driver = {1410	.probe		= fimc_probe,1411	.remove_new	= fimc_remove,1412	.driver		= {1413		.of_match_table = fimc_of_match,1414		.name	= "exynos-drm-fimc",1415		.pm	= pm_ptr(&fimc_pm_ops),1416	},1417};1418