| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (C) 2012 Samsung Electronics Co.Ltd | 
					
						
							|  |  |  |  * Authors: | 
					
						
							|  |  |  |  *	Eunchul Kim <chulspro.kim@samsung.com> | 
					
						
							|  |  |  |  *	Jinyoung Jeon <jy0.jeon@samsung.com> | 
					
						
							|  |  |  |  *	Sangmin Lee <lsmin.lee@samsung.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute  it and/or modify it | 
					
						
							|  |  |  |  * under  the terms of  the GNU General  Public License as published by the | 
					
						
							|  |  |  |  * Free Software Foundation;  either version 2 of the  License, or (at your | 
					
						
							|  |  |  |  * option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							|  |  |  | #include <linux/platform_device.h>
 | 
					
						
							| 
									
										
										
										
											2013-05-22 21:14:15 +09:00
										 |  |  | #include <linux/mfd/syscon.h>
 | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:38 +02:00
										 |  |  | #include <linux/regmap.h>
 | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | #include <linux/clk.h>
 | 
					
						
							|  |  |  | #include <linux/pm_runtime.h>
 | 
					
						
							| 
									
										
										
										
											2013-08-14 16:38:01 +05:30
										 |  |  | #include <linux/of.h>
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:09 +02:00
										 |  |  | #include <linux/spinlock.h>
 | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <drm/drmP.h>
 | 
					
						
							|  |  |  | #include <drm/exynos_drm.h>
 | 
					
						
							|  |  |  | #include "regs-fimc.h"
 | 
					
						
							| 
									
										
										
										
											2013-08-13 00:46:40 +01:00
										 |  |  | #include "exynos_drm_drv.h"
 | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | #include "exynos_drm_ipp.h"
 | 
					
						
							|  |  |  | #include "exynos_drm_fimc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2012-12-22 17:49:26 +09:00
										 |  |  |  * FIMC stands for Fully Interactive Mobile Camera and | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  |  * supports image scaler/rotator and input/output DMA operations. | 
					
						
							|  |  |  |  * input DMA reads image data from the memory. | 
					
						
							|  |  |  |  * output DMA writes image data to memory. | 
					
						
							|  |  |  |  * FIMC supports image rotation and image effect functions. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * M2M operation : supports crop/scale/rotation/csc so on. | 
					
						
							|  |  |  |  * Memory ----> FIMC H/W ----> Memory. | 
					
						
							|  |  |  |  * Writeback operation : supports cloned screen with FIMD. | 
					
						
							|  |  |  |  * FIMD ----> FIMC H/W ----> Memory. | 
					
						
							|  |  |  |  * Output operation : supports direct display using local path. | 
					
						
							|  |  |  |  * Memory ----> FIMC H/W ----> FIMD. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * TODO | 
					
						
							|  |  |  |  * 1. check suspend/resume api if needed. | 
					
						
							|  |  |  |  * 2. need to check use case platform_device_id. | 
					
						
							|  |  |  |  * 3. check src/dst size with, height. | 
					
						
							|  |  |  |  * 4. added check_prepare api for right register. | 
					
						
							|  |  |  |  * 5. need to add supported list in prop_list. | 
					
						
							|  |  |  |  * 6. check prescaler/scaler optimization. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define FIMC_MAX_DEVS	4
 | 
					
						
							|  |  |  | #define FIMC_MAX_SRC	2
 | 
					
						
							|  |  |  | #define FIMC_MAX_DST	32
 | 
					
						
							|  |  |  | #define FIMC_SHFACTOR	10
 | 
					
						
							|  |  |  | #define FIMC_BUF_STOP	1
 | 
					
						
							|  |  |  | #define FIMC_BUF_START	2
 | 
					
						
							|  |  |  | #define FIMC_WIDTH_ITU_709	1280
 | 
					
						
							|  |  |  | #define FIMC_REFRESH_MAX	60
 | 
					
						
							|  |  |  | #define FIMC_REFRESH_MIN	12
 | 
					
						
							|  |  |  | #define FIMC_CROP_MAX	8192
 | 
					
						
							|  |  |  | #define FIMC_CROP_MIN	32
 | 
					
						
							|  |  |  | #define FIMC_SCALE_MAX	4224
 | 
					
						
							|  |  |  | #define FIMC_SCALE_MIN	32
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define get_fimc_context(dev)	platform_get_drvdata(to_platform_device(dev))
 | 
					
						
							|  |  |  | #define get_ctx_from_ippdrv(ippdrv)	container_of(ippdrv,\
 | 
					
						
							|  |  |  | 					struct fimc_context, ippdrv); | 
					
						
							|  |  |  | enum fimc_wb { | 
					
						
							|  |  |  | 	FIMC_WB_NONE, | 
					
						
							|  |  |  | 	FIMC_WB_A, | 
					
						
							|  |  |  | 	FIMC_WB_B, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:37 +02:00
										 |  |  | enum { | 
					
						
							|  |  |  | 	FIMC_CLK_LCLK, | 
					
						
							|  |  |  | 	FIMC_CLK_GATE, | 
					
						
							|  |  |  | 	FIMC_CLK_WB_A, | 
					
						
							|  |  |  | 	FIMC_CLK_WB_B, | 
					
						
							|  |  |  | 	FIMC_CLK_MUX, | 
					
						
							|  |  |  | 	FIMC_CLK_PARENT, | 
					
						
							|  |  |  | 	FIMC_CLKS_MAX | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char * const fimc_clock_names[] = { | 
					
						
							|  |  |  | 	[FIMC_CLK_LCLK]   = "sclk_fimc", | 
					
						
							|  |  |  | 	[FIMC_CLK_GATE]   = "fimc", | 
					
						
							|  |  |  | 	[FIMC_CLK_WB_A]   = "pxl_async0", | 
					
						
							|  |  |  | 	[FIMC_CLK_WB_B]   = "pxl_async1", | 
					
						
							|  |  |  | 	[FIMC_CLK_MUX]    = "mux", | 
					
						
							|  |  |  | 	[FIMC_CLK_PARENT] = "parent", | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define FIMC_DEFAULT_LCLK_FREQUENCY 133000000UL
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * A structure of scaler. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @range: narrow, wide. | 
					
						
							|  |  |  |  * @bypass: unused scaler path. | 
					
						
							|  |  |  |  * @up_h: horizontal scale up. | 
					
						
							|  |  |  |  * @up_v: vertical scale up. | 
					
						
							|  |  |  |  * @hratio: horizontal ratio. | 
					
						
							|  |  |  |  * @vratio: vertical ratio. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct fimc_scaler { | 
					
						
							|  |  |  | 	bool	range; | 
					
						
							|  |  |  | 	bool bypass; | 
					
						
							|  |  |  | 	bool up_h; | 
					
						
							|  |  |  | 	bool up_v; | 
					
						
							|  |  |  | 	u32 hratio; | 
					
						
							|  |  |  | 	u32 vratio; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * A structure of scaler capability. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * find user manual table 43-1. | 
					
						
							|  |  |  |  * @in_hori: scaler input horizontal size. | 
					
						
							|  |  |  |  * @bypass: scaler bypass mode. | 
					
						
							|  |  |  |  * @dst_h_wo_rot: target horizontal size without output rotation. | 
					
						
							|  |  |  |  * @dst_h_rot: target horizontal size with output rotation. | 
					
						
							|  |  |  |  * @rl_w_wo_rot: real width without input rotation. | 
					
						
							|  |  |  |  * @rl_h_rot: real height without output rotation. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct fimc_capability { | 
					
						
							|  |  |  | 	/* scaler */ | 
					
						
							|  |  |  | 	u32	in_hori; | 
					
						
							|  |  |  | 	u32	bypass; | 
					
						
							|  |  |  | 	/* output rotator */ | 
					
						
							|  |  |  | 	u32	dst_h_wo_rot; | 
					
						
							|  |  |  | 	u32	dst_h_rot; | 
					
						
							|  |  |  | 	/* input rotator */ | 
					
						
							|  |  |  | 	u32	rl_w_wo_rot; | 
					
						
							|  |  |  | 	u32	rl_h_rot; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * A structure of fimc context. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @ippdrv: prepare initialization using ippdrv. | 
					
						
							|  |  |  |  * @regs_res: register resources. | 
					
						
							|  |  |  |  * @regs: memory mapped io registers. | 
					
						
							|  |  |  |  * @lock: locking of operations. | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:37 +02:00
										 |  |  |  * @clocks: fimc clocks. | 
					
						
							|  |  |  |  * @clk_frequency: LCLK clock frequency. | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:38 +02:00
										 |  |  |  * @sysreg: handle to SYSREG block regmap. | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  |  * @sc: scaler infomations. | 
					
						
							|  |  |  |  * @pol: porarity of writeback. | 
					
						
							|  |  |  |  * @id: fimc id. | 
					
						
							|  |  |  |  * @irq: irq number. | 
					
						
							|  |  |  |  * @suspended: qos operations. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct fimc_context { | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv	ippdrv; | 
					
						
							|  |  |  | 	struct resource	*regs_res; | 
					
						
							|  |  |  | 	void __iomem	*regs; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:09 +02:00
										 |  |  | 	spinlock_t	lock; | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:37 +02:00
										 |  |  | 	struct clk	*clocks[FIMC_CLKS_MAX]; | 
					
						
							|  |  |  | 	u32		clk_frequency; | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:38 +02:00
										 |  |  | 	struct regmap	*sysreg; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	struct fimc_scaler	sc; | 
					
						
							|  |  |  | 	struct exynos_drm_ipp_pol	pol; | 
					
						
							|  |  |  | 	int	id; | 
					
						
							|  |  |  | 	int	irq; | 
					
						
							|  |  |  | 	bool	suspended; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | static u32 fimc_read(struct fimc_context *ctx, u32 reg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return readl(ctx->regs + reg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void fimc_write(struct fimc_context *ctx, u32 val, u32 reg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	writel(val, ctx->regs + reg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void fimc_set_bits(struct fimc_context *ctx, u32 reg, u32 bits) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	void __iomem *r = ctx->regs + reg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writel(readl(r) | bits, r); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void fimc_clear_bits(struct fimc_context *ctx, u32 reg, u32 bits) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	void __iomem *r = ctx->regs + reg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writel(readl(r) & ~bits, r); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-22 17:49:27 +09:00
										 |  |  | static void fimc_sw_reset(struct fimc_context *ctx) | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | { | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-22 17:49:28 +09:00
										 |  |  | 	/* stop dma operation */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CISTATUS); | 
					
						
							|  |  |  | 	if (EXYNOS_CISTATUS_GET_ENVID_STATUS(cfg)) | 
					
						
							|  |  |  | 		fimc_clear_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_set_bits(ctx, EXYNOS_CISRCFMT, EXYNOS_CISRCFMT_ITU601_8BIT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-22 17:49:28 +09:00
										 |  |  | 	/* disable image capture */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_clear_bits(ctx, EXYNOS_CIIMGCPT, | 
					
						
							|  |  |  | 		EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN); | 
					
						
							| 
									
										
										
										
											2012-12-22 17:49:28 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	/* s/w reset */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_SWRST); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* s/w reset complete */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_clear_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_SWRST); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* reset sequence */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, 0x0, EXYNOS_CIFCNTSEQ); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:38 +02:00
										 |  |  | static int fimc_set_camblk_fimd0_wb(struct fimc_context *ctx) | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:38 +02:00
										 |  |  | 	return regmap_update_bits(ctx->sysreg, SYSREG_CAMERA_BLK, | 
					
						
							|  |  |  | 				  SYSREG_FIMD0WB_DEST_MASK, | 
					
						
							|  |  |  | 				  ctx->id << SYSREG_FIMD0WB_DEST_SHIFT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void fimc_set_type_ctrl(struct fimc_context *ctx, enum fimc_wb wb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("wb[%d]\n", wb); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CIGCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~(EXYNOS_CIGCTRL_TESTPATTERN_MASK | | 
					
						
							|  |  |  | 		EXYNOS_CIGCTRL_SELCAM_ITU_MASK | | 
					
						
							|  |  |  | 		EXYNOS_CIGCTRL_SELCAM_MIPI_MASK | | 
					
						
							|  |  |  | 		EXYNOS_CIGCTRL_SELCAM_FIMC_MASK | | 
					
						
							|  |  |  | 		EXYNOS_CIGCTRL_SELWB_CAMIF_MASK | | 
					
						
							|  |  |  | 		EXYNOS_CIGCTRL_SELWRITEBACK_MASK); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (wb) { | 
					
						
							|  |  |  | 	case FIMC_WB_A: | 
					
						
							|  |  |  | 		cfg |= (EXYNOS_CIGCTRL_SELWRITEBACK_A | | 
					
						
							|  |  |  | 			EXYNOS_CIGCTRL_SELWB_CAMIF_WRITEBACK); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case FIMC_WB_B: | 
					
						
							|  |  |  | 		cfg |= (EXYNOS_CIGCTRL_SELWRITEBACK_B | | 
					
						
							|  |  |  | 			EXYNOS_CIGCTRL_SELWB_CAMIF_WRITEBACK); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case FIMC_WB_NONE: | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		cfg |= (EXYNOS_CIGCTRL_SELCAM_ITU_A | | 
					
						
							|  |  |  | 			EXYNOS_CIGCTRL_SELWRITEBACK_A | | 
					
						
							|  |  |  | 			EXYNOS_CIGCTRL_SELCAM_MIPI_A | | 
					
						
							|  |  |  | 			EXYNOS_CIGCTRL_SELCAM_FIMC_ITU); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIGCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void fimc_set_polarity(struct fimc_context *ctx, | 
					
						
							|  |  |  | 		struct exynos_drm_ipp_pol *pol) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("inv_pclk[%d]inv_vsync[%d]\n", | 
					
						
							|  |  |  | 		pol->inv_pclk, pol->inv_vsync); | 
					
						
							|  |  |  | 	DRM_DEBUG_KMS("inv_href[%d]inv_hsync[%d]\n", | 
					
						
							|  |  |  | 		pol->inv_href, pol->inv_hsync); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CIGCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~(EXYNOS_CIGCTRL_INVPOLPCLK | EXYNOS_CIGCTRL_INVPOLVSYNC | | 
					
						
							|  |  |  | 		 EXYNOS_CIGCTRL_INVPOLHREF | EXYNOS_CIGCTRL_INVPOLHSYNC); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pol->inv_pclk) | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIGCTRL_INVPOLPCLK; | 
					
						
							|  |  |  | 	if (pol->inv_vsync) | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIGCTRL_INVPOLVSYNC; | 
					
						
							|  |  |  | 	if (pol->inv_href) | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIGCTRL_INVPOLHREF; | 
					
						
							|  |  |  | 	if (pol->inv_hsync) | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIGCTRL_INVPOLHSYNC; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIGCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void fimc_handle_jpeg(struct fimc_context *ctx, bool enable) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("enable[%d]\n", enable); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CIGCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	if (enable) | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIGCTRL_CAM_JPEG; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		cfg &= ~EXYNOS_CIGCTRL_CAM_JPEG; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIGCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:07 +02:00
										 |  |  | static void fimc_mask_irq(struct fimc_context *ctx, bool enable) | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | { | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:07 +02:00
										 |  |  | 	DRM_DEBUG_KMS("enable[%d]\n", enable); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CIGCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	if (enable) { | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:07 +02:00
										 |  |  | 		cfg &= ~EXYNOS_CIGCTRL_IRQ_OVFEN; | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIGCTRL_IRQ_ENABLE | EXYNOS_CIGCTRL_IRQ_LEVEL; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	} else | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:07 +02:00
										 |  |  | 		cfg &= ~EXYNOS_CIGCTRL_IRQ_ENABLE; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIGCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void fimc_clear_irq(struct fimc_context *ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_CLR); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool fimc_check_ovf(struct fimc_context *ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	u32 status, flag; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	status = fimc_read(ctx, EXYNOS_CISTATUS); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	flag = EXYNOS_CISTATUS_OVFIY | EXYNOS_CISTATUS_OVFICB | | 
					
						
							|  |  |  | 		EXYNOS_CISTATUS_OVFICR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("flag[0x%x]\n", flag); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (status & flag) { | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_set_bits(ctx, EXYNOS_CIWDOFST, | 
					
						
							|  |  |  | 			EXYNOS_CIWDOFST_CLROVFIY | EXYNOS_CIWDOFST_CLROVFICB | | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 			EXYNOS_CIWDOFST_CLROVFICR); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-09 00:22:53 +09:00
										 |  |  | 		dev_err(ippdrv->dev, "occurred overflow at %d, status 0x%x.\n", | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 			ctx->id, status); | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool fimc_check_frame_end(struct fimc_context *ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CISTATUS); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("cfg[0x%x]\n", cfg); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!(cfg & EXYNOS_CISTATUS_FRAMEEND)) | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cfg &= ~(EXYNOS_CISTATUS_FRAMEEND); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CISTATUS); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_get_buf_id(struct fimc_context *ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 	int frame_cnt, buf_id; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CISTATUS2); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (frame_cnt == 0) | 
					
						
							|  |  |  | 		frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("present[%d]before[%d]\n", | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg), | 
					
						
							|  |  |  | 		EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (frame_cnt == 0) { | 
					
						
							|  |  |  | 		DRM_ERROR("failed to get frame count.\n"); | 
					
						
							|  |  |  | 		return -EIO; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	buf_id = frame_cnt - 1; | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("buf_id[%d]\n", buf_id); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return buf_id; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void fimc_handle_lastend(struct fimc_context *ctx, bool enable) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("enable[%d]\n", enable); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CIOCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	if (enable) | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIOCTRL_LASTENDEN; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		cfg &= ~EXYNOS_CIOCTRL_LASTENDEN; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIOCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("fmt[0x%x]\n", fmt); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* RGB */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CISCCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~EXYNOS_CISCCTRL_INRGB_FMT_RGB_MASK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (fmt) { | 
					
						
							|  |  |  | 	case DRM_FORMAT_RGB565: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB565; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, cfg, EXYNOS_CISCCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	case DRM_FORMAT_RGB888: | 
					
						
							|  |  |  | 	case DRM_FORMAT_XRGB8888: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB888; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, cfg, EXYNOS_CISCCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		/* bypass */ | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* YUV */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_MSCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~(EXYNOS_MSCTRL_ORDER2P_SHIFT_MASK | | 
					
						
							|  |  |  | 		EXYNOS_MSCTRL_C_INT_IN_2PLANE | | 
					
						
							|  |  |  | 		EXYNOS_MSCTRL_ORDER422_YCBYCR); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (fmt) { | 
					
						
							|  |  |  | 	case DRM_FORMAT_YUYV: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_MSCTRL_ORDER422_YCBYCR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_YVYU: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_MSCTRL_ORDER422_YCRYCB; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_UYVY: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_MSCTRL_ORDER422_CBYCRY; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_VYUY: | 
					
						
							|  |  |  | 	case DRM_FORMAT_YUV444: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_MSCTRL_ORDER422_CRYCBY; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV21: | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV61: | 
					
						
							|  |  |  | 		cfg |= (EXYNOS_MSCTRL_ORDER2P_LSB_CRCB | | 
					
						
							|  |  |  | 			EXYNOS_MSCTRL_C_INT_IN_2PLANE); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_YUV422: | 
					
						
							|  |  |  | 	case DRM_FORMAT_YUV420: | 
					
						
							|  |  |  | 	case DRM_FORMAT_YVU420: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_MSCTRL_C_INT_IN_3PLANE; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV12: | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV12MT: | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV16: | 
					
						
							|  |  |  | 		cfg |= (EXYNOS_MSCTRL_ORDER2P_LSB_CBCR | | 
					
						
							|  |  |  | 			EXYNOS_MSCTRL_C_INT_IN_2PLANE); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		dev_err(ippdrv->dev, "inavlid source yuv order 0x%x.\n", fmt); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_MSCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_src_set_fmt(struct device *dev, u32 fmt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("fmt[0x%x]\n", fmt); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_MSCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~EXYNOS_MSCTRL_INFORMAT_RGB; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (fmt) { | 
					
						
							|  |  |  | 	case DRM_FORMAT_RGB565: | 
					
						
							|  |  |  | 	case DRM_FORMAT_RGB888: | 
					
						
							|  |  |  | 	case DRM_FORMAT_XRGB8888: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_MSCTRL_INFORMAT_RGB; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_YUV444: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_YUYV: | 
					
						
							|  |  |  | 	case DRM_FORMAT_YVYU: | 
					
						
							|  |  |  | 	case DRM_FORMAT_UYVY: | 
					
						
							|  |  |  | 	case DRM_FORMAT_VYUY: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR422_1PLANE; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV16: | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV61: | 
					
						
							|  |  |  | 	case DRM_FORMAT_YUV422: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR422; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_YUV420: | 
					
						
							|  |  |  | 	case DRM_FORMAT_YVU420: | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV12: | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV21: | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV12MT: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		dev_err(ippdrv->dev, "inavlid source format 0x%x.\n", fmt); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_MSCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~EXYNOS_CIDMAPARAM_R_MODE_MASK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (fmt == DRM_FORMAT_NV12MT) | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIDMAPARAM_R_MODE_64X32; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIDMAPARAM_R_MODE_LINEAR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return fimc_src_set_fmt_order(ctx, fmt); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_src_set_transf(struct device *dev, | 
					
						
							|  |  |  | 		enum drm_exynos_degree degree, | 
					
						
							|  |  |  | 		enum drm_exynos_flip flip, bool *swap) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							|  |  |  | 	u32 cfg1, cfg2; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg1 = fimc_read(ctx, EXYNOS_MSCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg1 &= ~(EXYNOS_MSCTRL_FLIP_X_MIRROR | | 
					
						
							|  |  |  | 		EXYNOS_MSCTRL_FLIP_Y_MIRROR); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg2 = fimc_read(ctx, EXYNOS_CITRGFMT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg2 &= ~EXYNOS_CITRGFMT_INROT90_CLOCKWISE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (degree) { | 
					
						
							|  |  |  | 	case EXYNOS_DRM_DEGREE_0: | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_VERTICAL) | 
					
						
							|  |  |  | 			cfg1 |= EXYNOS_MSCTRL_FLIP_X_MIRROR; | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) | 
					
						
							|  |  |  | 			cfg1 |= EXYNOS_MSCTRL_FLIP_Y_MIRROR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case EXYNOS_DRM_DEGREE_90: | 
					
						
							|  |  |  | 		cfg2 |= EXYNOS_CITRGFMT_INROT90_CLOCKWISE; | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_VERTICAL) | 
					
						
							|  |  |  | 			cfg1 |= EXYNOS_MSCTRL_FLIP_X_MIRROR; | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) | 
					
						
							|  |  |  | 			cfg1 |= EXYNOS_MSCTRL_FLIP_Y_MIRROR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case EXYNOS_DRM_DEGREE_180: | 
					
						
							|  |  |  | 		cfg1 |= (EXYNOS_MSCTRL_FLIP_X_MIRROR | | 
					
						
							|  |  |  | 			EXYNOS_MSCTRL_FLIP_Y_MIRROR); | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_VERTICAL) | 
					
						
							|  |  |  | 			cfg1 &= ~EXYNOS_MSCTRL_FLIP_X_MIRROR; | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) | 
					
						
							|  |  |  | 			cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case EXYNOS_DRM_DEGREE_270: | 
					
						
							|  |  |  | 		cfg1 |= (EXYNOS_MSCTRL_FLIP_X_MIRROR | | 
					
						
							|  |  |  | 			EXYNOS_MSCTRL_FLIP_Y_MIRROR); | 
					
						
							|  |  |  | 		cfg2 |= EXYNOS_CITRGFMT_INROT90_CLOCKWISE; | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_VERTICAL) | 
					
						
							|  |  |  | 			cfg1 &= ~EXYNOS_MSCTRL_FLIP_X_MIRROR; | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) | 
					
						
							|  |  |  | 			cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg1, EXYNOS_MSCTRL); | 
					
						
							|  |  |  | 	fimc_write(ctx, cfg2, EXYNOS_CITRGFMT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	*swap = (cfg2 & EXYNOS_CITRGFMT_INROT90_CLOCKWISE) ? 1 : 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_set_window(struct fimc_context *ctx, | 
					
						
							|  |  |  | 		struct drm_exynos_pos *pos, struct drm_exynos_sz *sz) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 cfg, h1, h2, v1, v2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* cropped image */ | 
					
						
							|  |  |  | 	h1 = pos->x; | 
					
						
							|  |  |  | 	h2 = sz->hsize - pos->w - pos->x; | 
					
						
							|  |  |  | 	v1 = pos->y; | 
					
						
							|  |  |  | 	v2 = sz->vsize - pos->h - pos->y; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n", | 
					
						
							|  |  |  | 		pos->x, pos->y, pos->w, pos->h, sz->hsize, sz->vsize); | 
					
						
							|  |  |  | 	DRM_DEBUG_KMS("h1[%d]h2[%d]v1[%d]v2[%d]\n", h1, h2, v1, v2); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * set window offset 1, 2 size | 
					
						
							|  |  |  | 	 * check figure 43-21 in user manual | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CIWDOFST); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~(EXYNOS_CIWDOFST_WINHOROFST_MASK | | 
					
						
							|  |  |  | 		EXYNOS_CIWDOFST_WINVEROFST_MASK); | 
					
						
							|  |  |  | 	cfg |= (EXYNOS_CIWDOFST_WINHOROFST(h1) | | 
					
						
							|  |  |  | 		EXYNOS_CIWDOFST_WINVEROFST(v1)); | 
					
						
							|  |  |  | 	cfg |= EXYNOS_CIWDOFST_WINOFSEN; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIWDOFST); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cfg = (EXYNOS_CIWDOFST2_WINHOROFST2(h2) | | 
					
						
							|  |  |  | 		EXYNOS_CIWDOFST2_WINVEROFST2(v2)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIWDOFST2); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_src_set_size(struct device *dev, int swap, | 
					
						
							|  |  |  | 		struct drm_exynos_pos *pos, struct drm_exynos_sz *sz) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 	struct drm_exynos_pos img_pos = *pos; | 
					
						
							|  |  |  | 	struct drm_exynos_sz img_sz = *sz; | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("swap[%d]hsize[%d]vsize[%d]\n", | 
					
						
							|  |  |  | 		swap, sz->hsize, sz->vsize); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* original size */ | 
					
						
							|  |  |  | 	cfg = (EXYNOS_ORGISIZE_HORIZONTAL(img_sz.hsize) | | 
					
						
							|  |  |  | 		EXYNOS_ORGISIZE_VERTICAL(img_sz.vsize)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_ORGISIZE); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos->x, pos->y, pos->w, pos->h); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (swap) { | 
					
						
							|  |  |  | 		img_pos.w = pos->h; | 
					
						
							|  |  |  | 		img_pos.h = pos->w; | 
					
						
							|  |  |  | 		img_sz.hsize = sz->vsize; | 
					
						
							|  |  |  | 		img_sz.vsize = sz->hsize; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* set input DMA image size */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CIREAL_ISIZE); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~(EXYNOS_CIREAL_ISIZE_HEIGHT_MASK | | 
					
						
							|  |  |  | 		EXYNOS_CIREAL_ISIZE_WIDTH_MASK); | 
					
						
							|  |  |  | 	cfg |= (EXYNOS_CIREAL_ISIZE_WIDTH(img_pos.w) | | 
					
						
							|  |  |  | 		EXYNOS_CIREAL_ISIZE_HEIGHT(img_pos.h)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIREAL_ISIZE); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * set input FIFO image size | 
					
						
							|  |  |  | 	 * for now, we support only ITU601 8 bit mode | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	cfg = (EXYNOS_CISRCFMT_ITU601_8BIT | | 
					
						
							|  |  |  | 		EXYNOS_CISRCFMT_SOURCEHSIZE(img_sz.hsize) | | 
					
						
							|  |  |  | 		EXYNOS_CISRCFMT_SOURCEVSIZE(img_sz.vsize)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CISRCFMT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* offset Y(RGB), Cb, Cr */ | 
					
						
							|  |  |  | 	cfg = (EXYNOS_CIIYOFF_HORIZONTAL(img_pos.x) | | 
					
						
							|  |  |  | 		EXYNOS_CIIYOFF_VERTICAL(img_pos.y)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIIYOFF); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg = (EXYNOS_CIICBOFF_HORIZONTAL(img_pos.x) | | 
					
						
							|  |  |  | 		EXYNOS_CIICBOFF_VERTICAL(img_pos.y)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIICBOFF); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg = (EXYNOS_CIICROFF_HORIZONTAL(img_pos.x) | | 
					
						
							|  |  |  | 		EXYNOS_CIICROFF_VERTICAL(img_pos.y)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIICROFF); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return fimc_set_window(ctx, &img_pos, &img_sz); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_src_set_addr(struct device *dev, | 
					
						
							|  |  |  | 		struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id, | 
					
						
							|  |  |  | 		enum drm_exynos_ipp_buf_type buf_type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							| 
									
										
										
										
											2012-12-22 17:49:22 +09:00
										 |  |  | 	struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	struct drm_exynos_ipp_property *property; | 
					
						
							|  |  |  | 	struct drm_exynos_ipp_config *config; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!c_node) { | 
					
						
							|  |  |  | 		DRM_ERROR("failed to get c_node.\n"); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	property = &c_node->property; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n", | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		property->prop_id, buf_id, buf_type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (buf_id > FIMC_MAX_SRC) { | 
					
						
							|  |  |  | 		dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id); | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* address register set */ | 
					
						
							|  |  |  | 	switch (buf_type) { | 
					
						
							|  |  |  | 	case IPP_BUF_ENQUEUE: | 
					
						
							|  |  |  | 		config = &property->config[EXYNOS_DRM_OPS_SRC]; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_Y], | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:39 +02:00
										 |  |  | 			EXYNOS_CIIYSA0); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (config->fmt == DRM_FORMAT_YVU420) { | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 			fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR], | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:39 +02:00
										 |  |  | 				EXYNOS_CIICBSA0); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 			fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB], | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:39 +02:00
										 |  |  | 				EXYNOS_CIICRSA0); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 			fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB], | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:39 +02:00
										 |  |  | 				EXYNOS_CIICBSA0); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 			fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR], | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:39 +02:00
										 |  |  | 				EXYNOS_CIICRSA0); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case IPP_BUF_DEQUEUE: | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:39 +02:00
										 |  |  | 		fimc_write(ctx, 0x0, EXYNOS_CIIYSA0); | 
					
						
							|  |  |  | 		fimc_write(ctx, 0x0, EXYNOS_CIICBSA0); | 
					
						
							|  |  |  | 		fimc_write(ctx, 0x0, EXYNOS_CIICRSA0); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		/* bypass */ | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct exynos_drm_ipp_ops fimc_src_ops = { | 
					
						
							|  |  |  | 	.set_fmt = fimc_src_set_fmt, | 
					
						
							|  |  |  | 	.set_transf = fimc_src_set_transf, | 
					
						
							|  |  |  | 	.set_size = fimc_src_set_size, | 
					
						
							|  |  |  | 	.set_addr = fimc_src_set_addr, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("fmt[0x%x]\n", fmt); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* RGB */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CISCCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~EXYNOS_CISCCTRL_OUTRGB_FMT_RGB_MASK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (fmt) { | 
					
						
							|  |  |  | 	case DRM_FORMAT_RGB565: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB565; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, cfg, EXYNOS_CISCCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	case DRM_FORMAT_RGB888: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, cfg, EXYNOS_CISCCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	case DRM_FORMAT_XRGB8888: | 
					
						
							|  |  |  | 		cfg |= (EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888 | | 
					
						
							|  |  |  | 			EXYNOS_CISCCTRL_EXTRGB_EXTENSION); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, cfg, EXYNOS_CISCCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		/* bypass */ | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* YUV */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CIOCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~(EXYNOS_CIOCTRL_ORDER2P_MASK | | 
					
						
							|  |  |  | 		EXYNOS_CIOCTRL_ORDER422_MASK | | 
					
						
							|  |  |  | 		EXYNOS_CIOCTRL_YCBCR_PLANE_MASK); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (fmt) { | 
					
						
							|  |  |  | 	case DRM_FORMAT_XRGB8888: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIOCTRL_ALPHA_OUT; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_YUYV: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIOCTRL_ORDER422_YCBYCR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_YVYU: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIOCTRL_ORDER422_YCRYCB; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_UYVY: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIOCTRL_ORDER422_CBYCRY; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_VYUY: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIOCTRL_ORDER422_CRYCBY; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV21: | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV61: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIOCTRL_ORDER2P_LSB_CRCB; | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_YUV422: | 
					
						
							|  |  |  | 	case DRM_FORMAT_YUV420: | 
					
						
							|  |  |  | 	case DRM_FORMAT_YVU420: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIOCTRL_YCBCR_3PLANE; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV12: | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV12MT: | 
					
						
							|  |  |  | 	case DRM_FORMAT_NV16: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIOCTRL_ORDER2P_LSB_CBCR; | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIOCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_dst_set_fmt(struct device *dev, u32 fmt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("fmt[0x%x]\n", fmt); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CIEXTEN); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (fmt == DRM_FORMAT_AYUV) { | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIEXTEN_YUV444_OUT; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, cfg, EXYNOS_CIEXTEN); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		cfg &= ~EXYNOS_CIEXTEN_YUV444_OUT; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, cfg, EXYNOS_CIEXTEN); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		cfg = fimc_read(ctx, EXYNOS_CITRGFMT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		cfg &= ~EXYNOS_CITRGFMT_OUTFORMAT_MASK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch (fmt) { | 
					
						
							|  |  |  | 		case DRM_FORMAT_RGB565: | 
					
						
							|  |  |  | 		case DRM_FORMAT_RGB888: | 
					
						
							|  |  |  | 		case DRM_FORMAT_XRGB8888: | 
					
						
							|  |  |  | 			cfg |= EXYNOS_CITRGFMT_OUTFORMAT_RGB; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case DRM_FORMAT_YUYV: | 
					
						
							|  |  |  | 		case DRM_FORMAT_YVYU: | 
					
						
							|  |  |  | 		case DRM_FORMAT_UYVY: | 
					
						
							|  |  |  | 		case DRM_FORMAT_VYUY: | 
					
						
							|  |  |  | 			cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case DRM_FORMAT_NV16: | 
					
						
							|  |  |  | 		case DRM_FORMAT_NV61: | 
					
						
							|  |  |  | 		case DRM_FORMAT_YUV422: | 
					
						
							|  |  |  | 			cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case DRM_FORMAT_YUV420: | 
					
						
							|  |  |  | 		case DRM_FORMAT_YVU420: | 
					
						
							|  |  |  | 		case DRM_FORMAT_NV12: | 
					
						
							|  |  |  | 		case DRM_FORMAT_NV12MT: | 
					
						
							|  |  |  | 		case DRM_FORMAT_NV21: | 
					
						
							|  |  |  | 			cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			dev_err(ippdrv->dev, "inavlid target format 0x%x.\n", | 
					
						
							|  |  |  | 				fmt); | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, cfg, EXYNOS_CITRGFMT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~EXYNOS_CIDMAPARAM_W_MODE_MASK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (fmt == DRM_FORMAT_NV12MT) | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIDMAPARAM_W_MODE_64X32; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIDMAPARAM_W_MODE_LINEAR; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return fimc_dst_set_fmt_order(ctx, fmt); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_dst_set_transf(struct device *dev, | 
					
						
							|  |  |  | 		enum drm_exynos_degree degree, | 
					
						
							|  |  |  | 		enum drm_exynos_flip flip, bool *swap) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CITRGFMT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~EXYNOS_CITRGFMT_FLIP_MASK; | 
					
						
							|  |  |  | 	cfg &= ~EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (degree) { | 
					
						
							|  |  |  | 	case EXYNOS_DRM_DEGREE_0: | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_VERTICAL) | 
					
						
							|  |  |  | 			cfg |= EXYNOS_CITRGFMT_FLIP_X_MIRROR; | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) | 
					
						
							|  |  |  | 			cfg |= EXYNOS_CITRGFMT_FLIP_Y_MIRROR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case EXYNOS_DRM_DEGREE_90: | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE; | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_VERTICAL) | 
					
						
							|  |  |  | 			cfg |= EXYNOS_CITRGFMT_FLIP_X_MIRROR; | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) | 
					
						
							|  |  |  | 			cfg |= EXYNOS_CITRGFMT_FLIP_Y_MIRROR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case EXYNOS_DRM_DEGREE_180: | 
					
						
							|  |  |  | 		cfg |= (EXYNOS_CITRGFMT_FLIP_X_MIRROR | | 
					
						
							|  |  |  | 			EXYNOS_CITRGFMT_FLIP_Y_MIRROR); | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_VERTICAL) | 
					
						
							|  |  |  | 			cfg &= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR; | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) | 
					
						
							|  |  |  | 			cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case EXYNOS_DRM_DEGREE_270: | 
					
						
							|  |  |  | 		cfg |= (EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE | | 
					
						
							|  |  |  | 			EXYNOS_CITRGFMT_FLIP_X_MIRROR | | 
					
						
							|  |  |  | 			EXYNOS_CITRGFMT_FLIP_Y_MIRROR); | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_VERTICAL) | 
					
						
							|  |  |  | 			cfg &= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR; | 
					
						
							|  |  |  | 		if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) | 
					
						
							|  |  |  | 			cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CITRGFMT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	*swap = (cfg & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE) ? 1 : 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_set_prescaler(struct fimc_context *ctx, struct fimc_scaler *sc, | 
					
						
							|  |  |  | 		struct drm_exynos_pos *src, struct drm_exynos_pos *dst) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							|  |  |  | 	u32 cfg, cfg_ext, shfactor; | 
					
						
							|  |  |  | 	u32 pre_dst_width, pre_dst_height; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:06 +02:00
										 |  |  | 	u32 hfactor, vfactor; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 	u32 src_w, src_h, dst_w, dst_h; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg_ext = fimc_read(ctx, EXYNOS_CITRGFMT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	if (cfg_ext & EXYNOS_CITRGFMT_INROT90_CLOCKWISE) { | 
					
						
							|  |  |  | 		src_w = src->h; | 
					
						
							|  |  |  | 		src_h = src->w; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		src_w = src->w; | 
					
						
							|  |  |  | 		src_h = src->h; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cfg_ext & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE) { | 
					
						
							|  |  |  | 		dst_w = dst->h; | 
					
						
							|  |  |  | 		dst_h = dst->w; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		dst_w = dst->w; | 
					
						
							|  |  |  | 		dst_h = dst->h; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:06 +02:00
										 |  |  | 	/* fimc_ippdrv_check_property assures that dividers are not null */ | 
					
						
							|  |  |  | 	hfactor = fls(src_w / dst_w / 2); | 
					
						
							|  |  |  | 	if (hfactor > FIMC_SHFACTOR / 2) { | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		dev_err(ippdrv->dev, "failed to get ratio horizontal.\n"); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:06 +02:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:06 +02:00
										 |  |  | 	vfactor = fls(src_h / dst_h / 2); | 
					
						
							|  |  |  | 	if (vfactor > FIMC_SHFACTOR / 2) { | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		dev_err(ippdrv->dev, "failed to get ratio vertical.\n"); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:06 +02:00
										 |  |  | 		return -EINVAL; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:06 +02:00
										 |  |  | 	pre_dst_width = src_w >> hfactor; | 
					
						
							|  |  |  | 	pre_dst_height = src_h >> vfactor; | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("pre_dst_width[%d]pre_dst_height[%d]\n", | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		pre_dst_width, pre_dst_height); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:06 +02:00
										 |  |  | 	DRM_DEBUG_KMS("hfactor[%d]vfactor[%d]\n", hfactor, vfactor); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	sc->hratio = (src_w << 14) / (dst_w << hfactor); | 
					
						
							|  |  |  | 	sc->vratio = (src_h << 14) / (dst_h << vfactor); | 
					
						
							|  |  |  | 	sc->up_h = (dst_w >= src_w) ? true : false; | 
					
						
							|  |  |  | 	sc->up_v = (dst_h >= src_h) ? true : false; | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("hratio[%d]vratio[%d]up_h[%d]up_v[%d]\n", | 
					
						
							|  |  |  | 		sc->hratio, sc->vratio, sc->up_h, sc->up_v); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	shfactor = FIMC_SHFACTOR - (hfactor + vfactor); | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("shfactor[%d]\n", shfactor); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cfg = (EXYNOS_CISCPRERATIO_SHFACTOR(shfactor) | | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:06 +02:00
										 |  |  | 		EXYNOS_CISCPRERATIO_PREHORRATIO(1 << hfactor) | | 
					
						
							|  |  |  | 		EXYNOS_CISCPRERATIO_PREVERRATIO(1 << vfactor)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CISCPRERATIO); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cfg = (EXYNOS_CISCPREDST_PREDSTWIDTH(pre_dst_width) | | 
					
						
							|  |  |  | 		EXYNOS_CISCPREDST_PREDSTHEIGHT(pre_dst_height)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CISCPREDST); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void fimc_set_scaler(struct fimc_context *ctx, struct fimc_scaler *sc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 cfg, cfg_ext; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("range[%d]bypass[%d]up_h[%d]up_v[%d]\n", | 
					
						
							|  |  |  | 		sc->range, sc->bypass, sc->up_h, sc->up_v); | 
					
						
							|  |  |  | 	DRM_DEBUG_KMS("hratio[%d]vratio[%d]\n", | 
					
						
							|  |  |  | 		sc->hratio, sc->vratio); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CISCCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~(EXYNOS_CISCCTRL_SCALERBYPASS | | 
					
						
							|  |  |  | 		EXYNOS_CISCCTRL_SCALEUP_H | EXYNOS_CISCCTRL_SCALEUP_V | | 
					
						
							|  |  |  | 		EXYNOS_CISCCTRL_MAIN_V_RATIO_MASK | | 
					
						
							|  |  |  | 		EXYNOS_CISCCTRL_MAIN_H_RATIO_MASK | | 
					
						
							|  |  |  | 		EXYNOS_CISCCTRL_CSCR2Y_WIDE | | 
					
						
							|  |  |  | 		EXYNOS_CISCCTRL_CSCY2R_WIDE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (sc->range) | 
					
						
							|  |  |  | 		cfg |= (EXYNOS_CISCCTRL_CSCR2Y_WIDE | | 
					
						
							|  |  |  | 			EXYNOS_CISCCTRL_CSCY2R_WIDE); | 
					
						
							|  |  |  | 	if (sc->bypass) | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CISCCTRL_SCALERBYPASS; | 
					
						
							|  |  |  | 	if (sc->up_h) | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CISCCTRL_SCALEUP_H; | 
					
						
							|  |  |  | 	if (sc->up_v) | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CISCCTRL_SCALEUP_V; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cfg |= (EXYNOS_CISCCTRL_MAINHORRATIO((sc->hratio >> 6)) | | 
					
						
							|  |  |  | 		EXYNOS_CISCCTRL_MAINVERRATIO((sc->vratio >> 6))); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CISCCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg_ext = fimc_read(ctx, EXYNOS_CIEXTEN); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg_ext &= ~EXYNOS_CIEXTEN_MAINHORRATIO_EXT_MASK; | 
					
						
							|  |  |  | 	cfg_ext &= ~EXYNOS_CIEXTEN_MAINVERRATIO_EXT_MASK; | 
					
						
							|  |  |  | 	cfg_ext |= (EXYNOS_CIEXTEN_MAINHORRATIO_EXT(sc->hratio) | | 
					
						
							|  |  |  | 		EXYNOS_CIEXTEN_MAINVERRATIO_EXT(sc->vratio)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg_ext, EXYNOS_CIEXTEN); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_dst_set_size(struct device *dev, int swap, | 
					
						
							|  |  |  | 		struct drm_exynos_pos *pos, struct drm_exynos_sz *sz) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 	struct drm_exynos_pos img_pos = *pos; | 
					
						
							|  |  |  | 	struct drm_exynos_sz img_sz = *sz; | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("swap[%d]hsize[%d]vsize[%d]\n", | 
					
						
							|  |  |  | 		swap, sz->hsize, sz->vsize); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* original size */ | 
					
						
							|  |  |  | 	cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(img_sz.hsize) | | 
					
						
							|  |  |  | 		EXYNOS_ORGOSIZE_VERTICAL(img_sz.vsize)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_ORGOSIZE); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos->x, pos->y, pos->w, pos->h); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* CSC ITU */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CIGCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~EXYNOS_CIGCTRL_CSC_MASK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (sz->hsize >= FIMC_WIDTH_ITU_709) | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIGCTRL_CSC_ITU709; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		cfg |= EXYNOS_CIGCTRL_CSC_ITU601; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIGCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (swap) { | 
					
						
							|  |  |  | 		img_pos.w = pos->h; | 
					
						
							|  |  |  | 		img_pos.h = pos->w; | 
					
						
							|  |  |  | 		img_sz.hsize = sz->vsize; | 
					
						
							|  |  |  | 		img_sz.vsize = sz->hsize; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* target image size */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CITRGFMT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg &= ~(EXYNOS_CITRGFMT_TARGETH_MASK | | 
					
						
							|  |  |  | 		EXYNOS_CITRGFMT_TARGETV_MASK); | 
					
						
							|  |  |  | 	cfg |= (EXYNOS_CITRGFMT_TARGETHSIZE(img_pos.w) | | 
					
						
							|  |  |  | 		EXYNOS_CITRGFMT_TARGETVSIZE(img_pos.h)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CITRGFMT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* target area */ | 
					
						
							|  |  |  | 	cfg = EXYNOS_CITAREA_TARGET_AREA(img_pos.w * img_pos.h); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CITAREA); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* offset Y(RGB), Cb, Cr */ | 
					
						
							|  |  |  | 	cfg = (EXYNOS_CIOYOFF_HORIZONTAL(img_pos.x) | | 
					
						
							|  |  |  | 		EXYNOS_CIOYOFF_VERTICAL(img_pos.y)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIOYOFF); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg = (EXYNOS_CIOCBOFF_HORIZONTAL(img_pos.x) | | 
					
						
							|  |  |  | 		EXYNOS_CIOCBOFF_VERTICAL(img_pos.y)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIOCBOFF); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg = (EXYNOS_CIOCROFF_HORIZONTAL(img_pos.x) | | 
					
						
							|  |  |  | 		EXYNOS_CIOCROFF_VERTICAL(img_pos.y)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIOCROFF); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:38 +02:00
										 |  |  | static void fimc_dst_set_buf_seq(struct fimc_context *ctx, u32 buf_id, | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		enum drm_exynos_ipp_buf_type buf_type) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:09 +02:00
										 |  |  | 	unsigned long flags; | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:38 +02:00
										 |  |  | 	u32 buf_num; | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:09 +02:00
										 |  |  | 	spin_lock_irqsave(&ctx->lock, flags); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg = fimc_read(ctx, EXYNOS_CIFCNTSEQ); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:38 +02:00
										 |  |  | 	if (buf_type == IPP_BUF_ENQUEUE) | 
					
						
							|  |  |  | 		cfg |= (1 << buf_id); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		cfg &= ~(1 << buf_id); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg, EXYNOS_CIFCNTSEQ); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:38 +02:00
										 |  |  | 	buf_num = hweight32(cfg); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:38 +02:00
										 |  |  | 	if (buf_type == IPP_BUF_ENQUEUE && buf_num >= FIMC_BUF_START) | 
					
						
							|  |  |  | 		fimc_mask_irq(ctx, true); | 
					
						
							|  |  |  | 	else if (buf_type == IPP_BUF_DEQUEUE && buf_num <= FIMC_BUF_STOP) | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:07 +02:00
										 |  |  | 		fimc_mask_irq(ctx, false); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:09 +02:00
										 |  |  | 	spin_unlock_irqrestore(&ctx->lock, flags); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_dst_set_addr(struct device *dev, | 
					
						
							|  |  |  | 		struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id, | 
					
						
							|  |  |  | 		enum drm_exynos_ipp_buf_type buf_type) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							| 
									
										
										
										
											2012-12-22 17:49:22 +09:00
										 |  |  | 	struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	struct drm_exynos_ipp_property *property; | 
					
						
							|  |  |  | 	struct drm_exynos_ipp_config *config; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!c_node) { | 
					
						
							|  |  |  | 		DRM_ERROR("failed to get c_node.\n"); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	property = &c_node->property; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n", | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		property->prop_id, buf_id, buf_type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (buf_id > FIMC_MAX_DST) { | 
					
						
							|  |  |  | 		dev_info(ippdrv->dev, "inavlid buf_id %d.\n", buf_id); | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* address register set */ | 
					
						
							|  |  |  | 	switch (buf_type) { | 
					
						
							|  |  |  | 	case IPP_BUF_ENQUEUE: | 
					
						
							|  |  |  | 		config = &property->config[EXYNOS_DRM_OPS_DST]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_Y], | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 			EXYNOS_CIOYSA(buf_id)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (config->fmt == DRM_FORMAT_YVU420) { | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 			fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR], | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 				EXYNOS_CIOCBSA(buf_id)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 			fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB], | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 				EXYNOS_CIOCRSA(buf_id)); | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 			fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CB], | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 				EXYNOS_CIOCBSA(buf_id)); | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 			fimc_write(ctx, buf_info->base[EXYNOS_DRM_PLANAR_CR], | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 				EXYNOS_CIOCRSA(buf_id)); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case IPP_BUF_DEQUEUE: | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, 0x0, EXYNOS_CIOYSA(buf_id)); | 
					
						
							|  |  |  | 		fimc_write(ctx, 0x0, EXYNOS_CIOCBSA(buf_id)); | 
					
						
							|  |  |  | 		fimc_write(ctx, 0x0, EXYNOS_CIOCRSA(buf_id)); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		/* bypass */ | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:38 +02:00
										 |  |  | 	fimc_dst_set_buf_seq(ctx, buf_id, buf_type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct exynos_drm_ipp_ops fimc_dst_ops = { | 
					
						
							|  |  |  | 	.set_fmt = fimc_dst_set_fmt, | 
					
						
							|  |  |  | 	.set_transf = fimc_dst_set_transf, | 
					
						
							|  |  |  | 	.set_size = fimc_dst_set_size, | 
					
						
							|  |  |  | 	.set_addr = fimc_dst_set_addr, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_clk_ctrl(struct fimc_context *ctx, bool enable) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("enable[%d]\n", enable); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (enable) { | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:37 +02:00
										 |  |  | 		clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]); | 
					
						
							|  |  |  | 		clk_prepare_enable(ctx->clocks[FIMC_CLK_WB_A]); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		ctx->suspended = false; | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:37 +02:00
										 |  |  | 		clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]); | 
					
						
							|  |  |  | 		clk_disable_unprepare(ctx->clocks[FIMC_CLK_WB_A]); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		ctx->suspended = true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static irqreturn_t fimc_irq_handler(int irq, void *dev_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = dev_id; | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							| 
									
										
										
										
											2012-12-22 17:49:22 +09:00
										 |  |  | 	struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	struct drm_exynos_ipp_event_work *event_work = | 
					
						
							|  |  |  | 		c_node->event_work; | 
					
						
							|  |  |  | 	int buf_id; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("fimc id[%d]\n", ctx->id); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	fimc_clear_irq(ctx); | 
					
						
							|  |  |  | 	if (fimc_check_ovf(ctx)) | 
					
						
							|  |  |  | 		return IRQ_NONE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!fimc_check_frame_end(ctx)) | 
					
						
							|  |  |  | 		return IRQ_NONE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	buf_id = fimc_get_buf_id(ctx); | 
					
						
							|  |  |  | 	if (buf_id < 0) | 
					
						
							|  |  |  | 		return IRQ_HANDLED; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("buf_id[%d]\n", buf_id); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:38 +02:00
										 |  |  | 	fimc_dst_set_buf_seq(ctx, buf_id, IPP_BUF_DEQUEUE); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	event_work->ippdrv = ippdrv; | 
					
						
							|  |  |  | 	event_work->buf_id[EXYNOS_DRM_OPS_DST] = buf_id; | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:33 +02:00
										 |  |  | 	queue_work(ippdrv->event_workq, &event_work->work); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return IRQ_HANDLED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_init_prop_list(struct exynos_drm_ippdrv *ippdrv) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:05 +02:00
										 |  |  | 	struct drm_exynos_ipp_prop_list *prop_list = &ippdrv->prop_list; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	prop_list->version = 1; | 
					
						
							|  |  |  | 	prop_list->writeback = 1; | 
					
						
							|  |  |  | 	prop_list->refresh_min = FIMC_REFRESH_MIN; | 
					
						
							|  |  |  | 	prop_list->refresh_max = FIMC_REFRESH_MAX; | 
					
						
							|  |  |  | 	prop_list->flip = (1 << EXYNOS_DRM_FLIP_NONE) | | 
					
						
							|  |  |  | 				(1 << EXYNOS_DRM_FLIP_VERTICAL) | | 
					
						
							|  |  |  | 				(1 << EXYNOS_DRM_FLIP_HORIZONTAL); | 
					
						
							|  |  |  | 	prop_list->degree = (1 << EXYNOS_DRM_DEGREE_0) | | 
					
						
							|  |  |  | 				(1 << EXYNOS_DRM_DEGREE_90) | | 
					
						
							|  |  |  | 				(1 << EXYNOS_DRM_DEGREE_180) | | 
					
						
							|  |  |  | 				(1 << EXYNOS_DRM_DEGREE_270); | 
					
						
							|  |  |  | 	prop_list->csc = 1; | 
					
						
							|  |  |  | 	prop_list->crop = 1; | 
					
						
							|  |  |  | 	prop_list->crop_max.hsize = FIMC_CROP_MAX; | 
					
						
							|  |  |  | 	prop_list->crop_max.vsize = FIMC_CROP_MAX; | 
					
						
							|  |  |  | 	prop_list->crop_min.hsize = FIMC_CROP_MIN; | 
					
						
							|  |  |  | 	prop_list->crop_min.vsize = FIMC_CROP_MIN; | 
					
						
							|  |  |  | 	prop_list->scale = 1; | 
					
						
							|  |  |  | 	prop_list->scale_max.hsize = FIMC_SCALE_MAX; | 
					
						
							|  |  |  | 	prop_list->scale_max.vsize = FIMC_SCALE_MAX; | 
					
						
							|  |  |  | 	prop_list->scale_min.hsize = FIMC_SCALE_MIN; | 
					
						
							|  |  |  | 	prop_list->scale_min.vsize = FIMC_SCALE_MIN; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline bool fimc_check_drm_flip(enum drm_exynos_flip flip) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (flip) { | 
					
						
							|  |  |  | 	case EXYNOS_DRM_FLIP_NONE: | 
					
						
							|  |  |  | 	case EXYNOS_DRM_FLIP_VERTICAL: | 
					
						
							|  |  |  | 	case EXYNOS_DRM_FLIP_HORIZONTAL: | 
					
						
							| 
									
										
										
										
											2012-12-22 17:49:24 +09:00
										 |  |  | 	case EXYNOS_DRM_FLIP_BOTH: | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		return true; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 		DRM_DEBUG_KMS("invalid flip\n"); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_ippdrv_check_property(struct device *dev, | 
					
						
							|  |  |  | 		struct drm_exynos_ipp_property *property) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:05 +02:00
										 |  |  | 	struct drm_exynos_ipp_prop_list *pp = &ippdrv->prop_list; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	struct drm_exynos_ipp_config *config; | 
					
						
							|  |  |  | 	struct drm_exynos_pos *pos; | 
					
						
							|  |  |  | 	struct drm_exynos_sz *sz; | 
					
						
							|  |  |  | 	bool swap; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for_each_ipp_ops(i) { | 
					
						
							|  |  |  | 		if ((i == EXYNOS_DRM_OPS_SRC) && | 
					
						
							|  |  |  | 			(property->cmd == IPP_CMD_WB)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		config = &property->config[i]; | 
					
						
							|  |  |  | 		pos = &config->pos; | 
					
						
							|  |  |  | 		sz = &config->sz; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* check for flip */ | 
					
						
							|  |  |  | 		if (!fimc_check_drm_flip(config->flip)) { | 
					
						
							|  |  |  | 			DRM_ERROR("invalid flip.\n"); | 
					
						
							|  |  |  | 			goto err_property; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* check for degree */ | 
					
						
							|  |  |  | 		switch (config->degree) { | 
					
						
							|  |  |  | 		case EXYNOS_DRM_DEGREE_90: | 
					
						
							|  |  |  | 		case EXYNOS_DRM_DEGREE_270: | 
					
						
							|  |  |  | 			swap = true; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case EXYNOS_DRM_DEGREE_0: | 
					
						
							|  |  |  | 		case EXYNOS_DRM_DEGREE_180: | 
					
						
							|  |  |  | 			swap = false; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			DRM_ERROR("invalid degree.\n"); | 
					
						
							|  |  |  | 			goto err_property; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* check for buffer bound */ | 
					
						
							|  |  |  | 		if ((pos->x + pos->w > sz->hsize) || | 
					
						
							|  |  |  | 			(pos->y + pos->h > sz->vsize)) { | 
					
						
							|  |  |  | 			DRM_ERROR("out of buf bound.\n"); | 
					
						
							|  |  |  | 			goto err_property; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* check for crop */ | 
					
						
							|  |  |  | 		if ((i == EXYNOS_DRM_OPS_SRC) && (pp->crop)) { | 
					
						
							|  |  |  | 			if (swap) { | 
					
						
							|  |  |  | 				if ((pos->h < pp->crop_min.hsize) || | 
					
						
							|  |  |  | 					(sz->vsize > pp->crop_max.hsize) || | 
					
						
							|  |  |  | 					(pos->w < pp->crop_min.vsize) || | 
					
						
							|  |  |  | 					(sz->hsize > pp->crop_max.vsize)) { | 
					
						
							|  |  |  | 					DRM_ERROR("out of crop size.\n"); | 
					
						
							|  |  |  | 					goto err_property; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				if ((pos->w < pp->crop_min.hsize) || | 
					
						
							|  |  |  | 					(sz->hsize > pp->crop_max.hsize) || | 
					
						
							|  |  |  | 					(pos->h < pp->crop_min.vsize) || | 
					
						
							|  |  |  | 					(sz->vsize > pp->crop_max.vsize)) { | 
					
						
							|  |  |  | 					DRM_ERROR("out of crop size.\n"); | 
					
						
							|  |  |  | 					goto err_property; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* check for scale */ | 
					
						
							|  |  |  | 		if ((i == EXYNOS_DRM_OPS_DST) && (pp->scale)) { | 
					
						
							|  |  |  | 			if (swap) { | 
					
						
							|  |  |  | 				if ((pos->h < pp->scale_min.hsize) || | 
					
						
							|  |  |  | 					(sz->vsize > pp->scale_max.hsize) || | 
					
						
							|  |  |  | 					(pos->w < pp->scale_min.vsize) || | 
					
						
							|  |  |  | 					(sz->hsize > pp->scale_max.vsize)) { | 
					
						
							|  |  |  | 					DRM_ERROR("out of scale size.\n"); | 
					
						
							|  |  |  | 					goto err_property; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				if ((pos->w < pp->scale_min.hsize) || | 
					
						
							|  |  |  | 					(sz->hsize > pp->scale_max.hsize) || | 
					
						
							|  |  |  | 					(pos->h < pp->scale_min.vsize) || | 
					
						
							|  |  |  | 					(sz->vsize > pp->scale_max.vsize)) { | 
					
						
							|  |  |  | 					DRM_ERROR("out of scale size.\n"); | 
					
						
							|  |  |  | 					goto err_property; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | err_property: | 
					
						
							|  |  |  | 	for_each_ipp_ops(i) { | 
					
						
							|  |  |  | 		if ((i == EXYNOS_DRM_OPS_SRC) && | 
					
						
							|  |  |  | 			(property->cmd == IPP_CMD_WB)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		config = &property->config[i]; | 
					
						
							|  |  |  | 		pos = &config->pos; | 
					
						
							|  |  |  | 		sz = &config->sz; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		DRM_ERROR("[%s]f[%d]r[%d]pos[%d %d %d %d]sz[%d %d]\n", | 
					
						
							|  |  |  | 			i ? "dst" : "src", config->flip, config->degree, | 
					
						
							|  |  |  | 			pos->x, pos->y, pos->w, pos->h, | 
					
						
							|  |  |  | 			sz->hsize, sz->vsize); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return -EINVAL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void fimc_clear_addr(struct fimc_context *ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < FIMC_MAX_SRC; i++) { | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, 0, EXYNOS_CIIYSA(i)); | 
					
						
							|  |  |  | 		fimc_write(ctx, 0, EXYNOS_CIICBSA(i)); | 
					
						
							|  |  |  | 		fimc_write(ctx, 0, EXYNOS_CIICRSA(i)); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < FIMC_MAX_DST; i++) { | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, 0, EXYNOS_CIOYSA(i)); | 
					
						
							|  |  |  | 		fimc_write(ctx, 0, EXYNOS_CIOCBSA(i)); | 
					
						
							|  |  |  | 		fimc_write(ctx, 0, EXYNOS_CIOCRSA(i)); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_ippdrv_reset(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* reset h/w block */ | 
					
						
							| 
									
										
										
										
											2012-12-22 17:49:27 +09:00
										 |  |  | 	fimc_sw_reset(ctx); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* reset scaler capability */ | 
					
						
							|  |  |  | 	memset(&ctx->sc, 0x0, sizeof(ctx->sc)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fimc_clear_addr(ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							| 
									
										
										
										
											2012-12-22 17:49:22 +09:00
										 |  |  | 	struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	struct drm_exynos_ipp_property *property; | 
					
						
							|  |  |  | 	struct drm_exynos_ipp_config *config; | 
					
						
							|  |  |  | 	struct drm_exynos_pos	img_pos[EXYNOS_DRM_OPS_MAX]; | 
					
						
							|  |  |  | 	struct drm_exynos_ipp_set_wb set_wb; | 
					
						
							|  |  |  | 	int ret, i; | 
					
						
							|  |  |  | 	u32 cfg0, cfg1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("cmd[%d]\n", cmd); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!c_node) { | 
					
						
							|  |  |  | 		DRM_ERROR("failed to get c_node.\n"); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	property = &c_node->property; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:07 +02:00
										 |  |  | 	fimc_mask_irq(ctx, true); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for_each_ipp_ops(i) { | 
					
						
							|  |  |  | 		config = &property->config[i]; | 
					
						
							|  |  |  | 		img_pos[i] = config->pos; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = fimc_set_prescaler(ctx, &ctx->sc, | 
					
						
							|  |  |  | 		&img_pos[EXYNOS_DRM_OPS_SRC], | 
					
						
							|  |  |  | 		&img_pos[EXYNOS_DRM_OPS_DST]); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		dev_err(dev, "failed to set precalser.\n"); | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* If set ture, we can save jpeg about screen */ | 
					
						
							|  |  |  | 	fimc_handle_jpeg(ctx, false); | 
					
						
							|  |  |  | 	fimc_set_scaler(ctx, &ctx->sc); | 
					
						
							|  |  |  | 	fimc_set_polarity(ctx, &ctx->pol); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case IPP_CMD_M2M: | 
					
						
							|  |  |  | 		fimc_set_type_ctrl(ctx, FIMC_WB_NONE); | 
					
						
							|  |  |  | 		fimc_handle_lastend(ctx, false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* setup dma */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		cfg0 = fimc_read(ctx, EXYNOS_MSCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		cfg0 &= ~EXYNOS_MSCTRL_INPUT_MASK; | 
					
						
							|  |  |  | 		cfg0 |= EXYNOS_MSCTRL_INPUT_MEMORY; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, cfg0, EXYNOS_MSCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case IPP_CMD_WB: | 
					
						
							|  |  |  | 		fimc_set_type_ctrl(ctx, FIMC_WB_A); | 
					
						
							|  |  |  | 		fimc_handle_lastend(ctx, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* setup FIMD */ | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:38 +02:00
										 |  |  | 		ret = fimc_set_camblk_fimd0_wb(ctx); | 
					
						
							|  |  |  | 		if (ret < 0) { | 
					
						
							|  |  |  | 			dev_err(dev, "camblk setup failed.\n"); | 
					
						
							|  |  |  | 			return ret; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		set_wb.enable = 1; | 
					
						
							|  |  |  | 		set_wb.refresh = property->refresh_rate; | 
					
						
							|  |  |  | 		exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case IPP_CMD_OUTPUT: | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		ret = -EINVAL; | 
					
						
							|  |  |  | 		dev_err(dev, "invalid operations.\n"); | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Reset status */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, 0x0, EXYNOS_CISTATUS); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg0 = fimc_read(ctx, EXYNOS_CIIMGCPT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg0 &= ~EXYNOS_CIIMGCPT_IMGCPTEN_SC; | 
					
						
							|  |  |  | 	cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN_SC; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Scaler */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	cfg1 = fimc_read(ctx, EXYNOS_CISCCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	cfg1 &= ~EXYNOS_CISCCTRL_SCAN_MASK; | 
					
						
							|  |  |  | 	cfg1 |= (EXYNOS_CISCCTRL_PROGRESSIVE | | 
					
						
							|  |  |  | 		EXYNOS_CISCCTRL_SCALERSTART); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg1, EXYNOS_CISCCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Enable image capture*/ | 
					
						
							|  |  |  | 	cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, cfg0, EXYNOS_CIIMGCPT); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Disable frame end irq */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_clear_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_END_DISABLE); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_clear_bits(ctx, EXYNOS_CIOCTRL, EXYNOS_CIOCTRL_WEAVE_MASK); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-28 11:07:37 +02:00
										 |  |  | 	if (cmd == IPP_CMD_M2M) | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_set_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 	struct drm_exynos_ipp_set_wb set_wb = {0, 0}; | 
					
						
							|  |  |  | 	u32 cfg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("cmd[%d]\n", cmd); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case IPP_CMD_M2M: | 
					
						
							|  |  |  | 		/* Source clear */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		cfg = fimc_read(ctx, EXYNOS_MSCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		cfg &= ~EXYNOS_MSCTRL_INPUT_MASK; | 
					
						
							|  |  |  | 		cfg &= ~EXYNOS_MSCTRL_ENVID; | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 		fimc_write(ctx, cfg, EXYNOS_MSCTRL); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case IPP_CMD_WB: | 
					
						
							|  |  |  | 		exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case IPP_CMD_OUTPUT: | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		dev_err(dev, "invalid operations.\n"); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:07 +02:00
										 |  |  | 	fimc_mask_irq(ctx, false); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* reset sequence */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_write(ctx, 0x0, EXYNOS_CIFCNTSEQ); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Scaler disable */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_clear_bits(ctx, EXYNOS_CISCCTRL, EXYNOS_CISCCTRL_SCALERSTART); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Disable image capture */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_clear_bits(ctx, EXYNOS_CIIMGCPT, | 
					
						
							|  |  |  | 		EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Enable frame end irq */ | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:08 +02:00
										 |  |  | 	fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_END_DISABLE); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:37 +02:00
										 |  |  | static void fimc_put_clocks(struct fimc_context *ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < FIMC_CLKS_MAX; i++) { | 
					
						
							|  |  |  | 		if (IS_ERR(ctx->clocks[i])) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		clk_put(ctx->clocks[i]); | 
					
						
							|  |  |  | 		ctx->clocks[i] = ERR_PTR(-EINVAL); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_setup_clocks(struct fimc_context *ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct device *fimc_dev = ctx->ippdrv.dev; | 
					
						
							|  |  |  | 	struct device *dev; | 
					
						
							|  |  |  | 	int ret, i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < FIMC_CLKS_MAX; i++) | 
					
						
							|  |  |  | 		ctx->clocks[i] = ERR_PTR(-EINVAL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < FIMC_CLKS_MAX; i++) { | 
					
						
							|  |  |  | 		if (i == FIMC_CLK_WB_A || i == FIMC_CLK_WB_B) | 
					
						
							|  |  |  | 			dev = fimc_dev->parent; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			dev = fimc_dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ctx->clocks[i] = clk_get(dev, fimc_clock_names[i]); | 
					
						
							|  |  |  | 		if (IS_ERR(ctx->clocks[i])) { | 
					
						
							|  |  |  | 			if (i >= FIMC_CLK_MUX) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			ret = PTR_ERR(ctx->clocks[i]); | 
					
						
							|  |  |  | 			dev_err(fimc_dev, "failed to get clock: %s\n", | 
					
						
							|  |  |  | 						fimc_clock_names[i]); | 
					
						
							|  |  |  | 			goto e_clk_free; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Optional FIMC LCLK parent clock setting */ | 
					
						
							|  |  |  | 	if (!IS_ERR(ctx->clocks[FIMC_CLK_PARENT])) { | 
					
						
							|  |  |  | 		ret = clk_set_parent(ctx->clocks[FIMC_CLK_MUX], | 
					
						
							|  |  |  | 				     ctx->clocks[FIMC_CLK_PARENT]); | 
					
						
							|  |  |  | 		if (ret < 0) { | 
					
						
							|  |  |  | 			dev_err(fimc_dev, "failed to set parent.\n"); | 
					
						
							|  |  |  | 			goto e_clk_free; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = clk_set_rate(ctx->clocks[FIMC_CLK_LCLK], ctx->clk_frequency); | 
					
						
							|  |  |  | 	if (ret < 0) | 
					
						
							|  |  |  | 		goto e_clk_free; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = clk_prepare_enable(ctx->clocks[FIMC_CLK_LCLK]); | 
					
						
							|  |  |  | 	if (!ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | e_clk_free: | 
					
						
							|  |  |  | 	fimc_put_clocks(ctx); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:38 +02:00
										 |  |  | static int fimc_parse_dt(struct fimc_context *ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct device_node *node = ctx->ippdrv.dev->of_node; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Handle only devices that support the LCD Writeback data path */ | 
					
						
							|  |  |  | 	if (!of_property_read_bool(node, "samsung,lcd-wb")) | 
					
						
							|  |  |  | 		return -ENODEV; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (of_property_read_u32(node, "clock-frequency", | 
					
						
							|  |  |  | 					&ctx->clk_frequency)) | 
					
						
							|  |  |  | 		ctx->clk_frequency = FIMC_DEFAULT_LCLK_FREQUENCY; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ctx->id = of_alias_get_id(node, "fimc"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ctx->id < 0) { | 
					
						
							|  |  |  | 		dev_err(ctx->ippdrv.dev, "failed to get node alias id.\n"); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-21 15:09:25 -08:00
										 |  |  | static int fimc_probe(struct platform_device *pdev) | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &pdev->dev; | 
					
						
							|  |  |  | 	struct fimc_context *ctx; | 
					
						
							|  |  |  | 	struct resource *res; | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:38 +02:00
										 |  |  | 	if (!dev->of_node) { | 
					
						
							|  |  |  | 		dev_err(dev, "device tree node not found.\n"); | 
					
						
							|  |  |  | 		return -ENODEV; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | 
					
						
							|  |  |  | 	if (!ctx) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:38 +02:00
										 |  |  | 	ctx->ippdrv.dev = dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = fimc_parse_dt(ctx); | 
					
						
							|  |  |  | 	if (ret < 0) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, | 
					
						
							|  |  |  | 						"samsung,sysreg"); | 
					
						
							|  |  |  | 	if (IS_ERR(ctx->sysreg)) { | 
					
						
							|  |  |  | 		dev_err(dev, "syscon regmap lookup failed.\n"); | 
					
						
							|  |  |  | 		return PTR_ERR(ctx->sysreg); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	/* resource memory */ | 
					
						
							|  |  |  | 	ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 
					
						
							| 
									
										
										
										
											2013-01-21 11:09:02 +01:00
										 |  |  | 	ctx->regs = devm_ioremap_resource(dev, ctx->regs_res); | 
					
						
							|  |  |  | 	if (IS_ERR(ctx->regs)) | 
					
						
							|  |  |  | 		return PTR_ERR(ctx->regs); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* resource irq */ | 
					
						
							|  |  |  | 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 
					
						
							|  |  |  | 	if (!res) { | 
					
						
							|  |  |  | 		dev_err(dev, "failed to request irq resource.\n"); | 
					
						
							| 
									
										
										
										
											2012-12-28 15:56:18 +05:30
										 |  |  | 		return -ENOENT; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ctx->irq = res->start; | 
					
						
							| 
									
										
										
										
											2013-05-22 21:14:17 +09:00
										 |  |  | 	ret = devm_request_threaded_irq(dev, ctx->irq, NULL, fimc_irq_handler, | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		IRQF_ONESHOT, "drm_fimc", ctx); | 
					
						
							|  |  |  | 	if (ret < 0) { | 
					
						
							|  |  |  | 		dev_err(dev, "failed to request irq.\n"); | 
					
						
							| 
									
										
										
										
											2012-12-28 15:56:18 +05:30
										 |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:37 +02:00
										 |  |  | 	ret = fimc_setup_clocks(ctx); | 
					
						
							|  |  |  | 	if (ret < 0) | 
					
						
							| 
									
										
										
										
											2013-05-22 21:14:17 +09:00
										 |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ippdrv = &ctx->ippdrv; | 
					
						
							|  |  |  | 	ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &fimc_src_ops; | 
					
						
							|  |  |  | 	ippdrv->ops[EXYNOS_DRM_OPS_DST] = &fimc_dst_ops; | 
					
						
							|  |  |  | 	ippdrv->check_property = fimc_ippdrv_check_property; | 
					
						
							|  |  |  | 	ippdrv->reset = fimc_ippdrv_reset; | 
					
						
							|  |  |  | 	ippdrv->start = fimc_ippdrv_start; | 
					
						
							|  |  |  | 	ippdrv->stop = fimc_ippdrv_stop; | 
					
						
							|  |  |  | 	ret = fimc_init_prop_list(ippdrv); | 
					
						
							|  |  |  | 	if (ret < 0) { | 
					
						
							|  |  |  | 		dev_err(dev, "failed to init property list.\n"); | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:37 +02:00
										 |  |  | 		goto err_put_clk; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("id[%d]ippdrv[0x%x]\n", ctx->id, (int)ippdrv); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-19 12:54:09 +02:00
										 |  |  | 	spin_lock_init(&ctx->lock); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	platform_set_drvdata(pdev, ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pm_runtime_set_active(dev); | 
					
						
							|  |  |  | 	pm_runtime_enable(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = exynos_drm_ippdrv_register(ippdrv); | 
					
						
							|  |  |  | 	if (ret < 0) { | 
					
						
							|  |  |  | 		dev_err(dev, "failed to register drm fimc device.\n"); | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:37 +02:00
										 |  |  | 		goto err_pm_dis; | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-22 21:14:14 +09:00
										 |  |  | 	dev_info(dev, "drm fimc registered successfully.\n"); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:37 +02:00
										 |  |  | err_pm_dis: | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	pm_runtime_disable(dev); | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:37 +02:00
										 |  |  | err_put_clk: | 
					
						
							|  |  |  | 	fimc_put_clocks(ctx); | 
					
						
							| 
									
										
										
										
											2012-12-24 14:03:43 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-21 15:09:25 -08:00
										 |  |  | static int fimc_remove(struct platform_device *pdev) | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &pdev->dev; | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	exynos_drm_ippdrv_unregister(ippdrv); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:37 +02:00
										 |  |  | 	fimc_put_clocks(ctx); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	pm_runtime_set_suspended(dev); | 
					
						
							|  |  |  | 	pm_runtime_disable(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_PM_SLEEP
 | 
					
						
							|  |  |  | static int fimc_suspend(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("id[%d]\n", ctx->id); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (pm_runtime_suspended(dev)) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return fimc_clk_ctrl(ctx, false); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_resume(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("id[%d]\n", ctx->id); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!pm_runtime_suspended(dev)) | 
					
						
							|  |  |  | 		return fimc_clk_ctrl(ctx, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-04 01:04:55 +01:00
										 |  |  | #ifdef CONFIG_PM
 | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | static int fimc_runtime_suspend(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("id[%d]\n", ctx->id); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return  fimc_clk_ctrl(ctx, false); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int fimc_runtime_resume(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct fimc_context *ctx = get_fimc_context(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 10:44:40 +09:00
										 |  |  | 	DRM_DEBUG_KMS("id[%d]\n", ctx->id); | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return  fimc_clk_ctrl(ctx, true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct dev_pm_ops fimc_pm_ops = { | 
					
						
							|  |  |  | 	SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume) | 
					
						
							|  |  |  | 	SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL) | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:38 +02:00
										 |  |  | static const struct of_device_id fimc_of_match[] = { | 
					
						
							|  |  |  | 	{ .compatible = "samsung,exynos4210-fimc" }, | 
					
						
							|  |  |  | 	{ .compatible = "samsung,exynos4212-fimc" }, | 
					
						
							|  |  |  | 	{ }, | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2014-07-18 22:36:41 +02:00
										 |  |  | MODULE_DEVICE_TABLE(of, fimc_of_match); | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | struct platform_driver fimc_driver = { | 
					
						
							|  |  |  | 	.probe		= fimc_probe, | 
					
						
							| 
									
										
										
										
											2012-12-21 15:09:25 -08:00
										 |  |  | 	.remove		= fimc_remove, | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 	.driver		= { | 
					
						
							| 
									
										
										
										
											2013-04-23 13:34:38 +02:00
										 |  |  | 		.of_match_table = fimc_of_match, | 
					
						
							| 
									
										
										
										
											2012-12-14 17:58:55 +09:00
										 |  |  | 		.name	= "exynos-drm-fimc", | 
					
						
							|  |  |  | 		.owner	= THIS_MODULE, | 
					
						
							|  |  |  | 		.pm	= &fimc_pm_ops, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 |