12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 216102edbSEunchul Kim /* 316102edbSEunchul Kim * Copyright (C) 2012 Samsung Electronics Co.Ltd 416102edbSEunchul Kim * Authors: 516102edbSEunchul Kim * Eunchul Kim <chulspro.kim@samsung.com> 616102edbSEunchul Kim * Jinyoung Jeon <jy0.jeon@samsung.com> 716102edbSEunchul Kim * Sangmin Lee <lsmin.lee@samsung.com> 816102edbSEunchul Kim */ 92bda34d7SSam Ravnborg 1016102edbSEunchul Kim #include <linux/clk.h> 112bda34d7SSam Ravnborg #include <linux/component.h> 122bda34d7SSam Ravnborg #include <linux/kernel.h> 132bda34d7SSam Ravnborg #include <linux/mfd/syscon.h> 143f1c781dSSachin Kamat #include <linux/of.h> 152bda34d7SSam Ravnborg #include <linux/platform_device.h> 162bda34d7SSam Ravnborg #include <linux/pm_runtime.h> 172bda34d7SSam Ravnborg #include <linux/regmap.h> 1872d465aaSAndrzej Hajda #include <linux/spinlock.h> 1916102edbSEunchul Kim 20226024b1SSam Ravnborg #include <drm/drm_fourcc.h> 21226024b1SSam Ravnborg #include <drm/drm_print.h> 2216102edbSEunchul Kim #include <drm/exynos_drm.h> 232bda34d7SSam Ravnborg 24e30655d0SMark Brown #include "exynos_drm_drv.h" 2516102edbSEunchul Kim #include "exynos_drm_ipp.h" 262bda34d7SSam Ravnborg #include "regs-fimc.h" 2716102edbSEunchul Kim 2816102edbSEunchul Kim /* 296fe891f6SEunchul Kim * FIMC stands for Fully Interactive Mobile Camera and 3016102edbSEunchul Kim * supports image scaler/rotator and input/output DMA operations. 3116102edbSEunchul Kim * input DMA reads image data from the memory. 3216102edbSEunchul Kim * output DMA writes image data to memory. 3316102edbSEunchul Kim * FIMC supports image rotation and image effect functions. 3416102edbSEunchul Kim */ 3516102edbSEunchul Kim 3616102edbSEunchul Kim #define FIMC_MAX_DEVS 4 3716102edbSEunchul Kim #define FIMC_MAX_SRC 2 3816102edbSEunchul Kim #define FIMC_MAX_DST 32 3916102edbSEunchul Kim #define FIMC_SHFACTOR 10 4016102edbSEunchul Kim #define FIMC_BUF_STOP 1 4116102edbSEunchul Kim #define FIMC_BUF_START 2 4216102edbSEunchul Kim #define FIMC_WIDTH_ITU_709 1280 437a2d5c77SMarek Szyprowski #define FIMC_AUTOSUSPEND_DELAY 2000 447a2d5c77SMarek Szyprowski 457a2d5c77SMarek Szyprowski static unsigned int fimc_mask = 0xc; 467a2d5c77SMarek Szyprowski module_param_named(fimc_devs, fimc_mask, uint, 0644); 477a2d5c77SMarek Szyprowski MODULE_PARM_DESC(fimc_devs, "Alias mask for assigning FIMC devices to Exynos DRM"); 4816102edbSEunchul Kim 499eae7c3bSFuqian Huang #define get_fimc_context(dev) dev_get_drvdata(dev) 5016102edbSEunchul Kim 51e5f86839SSylwester Nawrocki enum { 52e5f86839SSylwester Nawrocki FIMC_CLK_LCLK, 53e5f86839SSylwester Nawrocki FIMC_CLK_GATE, 54e5f86839SSylwester Nawrocki FIMC_CLK_WB_A, 55e5f86839SSylwester Nawrocki FIMC_CLK_WB_B, 56e5f86839SSylwester Nawrocki FIMC_CLKS_MAX 57e5f86839SSylwester Nawrocki }; 58e5f86839SSylwester Nawrocki 59e5f86839SSylwester Nawrocki static const char * const fimc_clock_names[] = { 60e5f86839SSylwester Nawrocki [FIMC_CLK_LCLK] = "sclk_fimc", 61e5f86839SSylwester Nawrocki [FIMC_CLK_GATE] = "fimc", 62e5f86839SSylwester Nawrocki [FIMC_CLK_WB_A] = "pxl_async0", 63e5f86839SSylwester Nawrocki [FIMC_CLK_WB_B] = "pxl_async1", 64e5f86839SSylwester Nawrocki }; 65e5f86839SSylwester Nawrocki 6616102edbSEunchul Kim /* 6716102edbSEunchul Kim * A structure of scaler. 6816102edbSEunchul Kim * 6916102edbSEunchul Kim * @range: narrow, wide. 7016102edbSEunchul Kim * @bypass: unused scaler path. 7116102edbSEunchul Kim * @up_h: horizontal scale up. 7216102edbSEunchul Kim * @up_v: vertical scale up. 7316102edbSEunchul Kim * @hratio: horizontal ratio. 7416102edbSEunchul Kim * @vratio: vertical ratio. 7516102edbSEunchul Kim */ 7616102edbSEunchul Kim struct fimc_scaler { 7716102edbSEunchul Kim bool range; 7816102edbSEunchul Kim bool bypass; 7916102edbSEunchul Kim bool up_h; 8016102edbSEunchul Kim bool up_v; 8116102edbSEunchul Kim u32 hratio; 8216102edbSEunchul Kim u32 vratio; 8316102edbSEunchul Kim }; 8416102edbSEunchul Kim 8516102edbSEunchul Kim /* 8616102edbSEunchul Kim * A structure of fimc context. 8716102edbSEunchul Kim * 8816102edbSEunchul Kim * @regs_res: register resources. 8916102edbSEunchul Kim * @regs: memory mapped io registers. 9016102edbSEunchul Kim * @lock: locking of operations. 91e5f86839SSylwester Nawrocki * @clocks: fimc clocks. 9216102edbSEunchul Kim * @sc: scaler infomations. 9316102edbSEunchul Kim * @pol: porarity of writeback. 9416102edbSEunchul Kim * @id: fimc id. 9516102edbSEunchul Kim * @irq: irq number. 9616102edbSEunchul Kim */ 9716102edbSEunchul Kim struct fimc_context { 987a2d5c77SMarek Szyprowski struct exynos_drm_ipp ipp; 997a2d5c77SMarek Szyprowski struct drm_device *drm_dev; 1007a2d5c77SMarek Szyprowski struct device *dev; 1017a2d5c77SMarek Szyprowski struct exynos_drm_ipp_task *task; 1027a2d5c77SMarek Szyprowski struct exynos_drm_ipp_formats *formats; 1037a2d5c77SMarek Szyprowski unsigned int num_formats; 1047a2d5c77SMarek Szyprowski 10516102edbSEunchul Kim struct resource *regs_res; 10616102edbSEunchul Kim void __iomem *regs; 10772d465aaSAndrzej Hajda spinlock_t lock; 108e5f86839SSylwester Nawrocki struct clk *clocks[FIMC_CLKS_MAX]; 10916102edbSEunchul Kim struct fimc_scaler sc; 11016102edbSEunchul Kim int id; 11116102edbSEunchul Kim int irq; 11216102edbSEunchul Kim }; 11316102edbSEunchul Kim 114acd8afa8SAndrzej Hajda static u32 fimc_read(struct fimc_context *ctx, u32 reg) 115acd8afa8SAndrzej Hajda { 116acd8afa8SAndrzej Hajda return readl(ctx->regs + reg); 117acd8afa8SAndrzej Hajda } 118acd8afa8SAndrzej Hajda 119acd8afa8SAndrzej Hajda static void fimc_write(struct fimc_context *ctx, u32 val, u32 reg) 120acd8afa8SAndrzej Hajda { 121acd8afa8SAndrzej Hajda writel(val, ctx->regs + reg); 122acd8afa8SAndrzej Hajda } 123acd8afa8SAndrzej Hajda 124acd8afa8SAndrzej Hajda static void fimc_set_bits(struct fimc_context *ctx, u32 reg, u32 bits) 125acd8afa8SAndrzej Hajda { 126acd8afa8SAndrzej Hajda void __iomem *r = ctx->regs + reg; 127acd8afa8SAndrzej Hajda 128acd8afa8SAndrzej Hajda writel(readl(r) | bits, r); 129acd8afa8SAndrzej Hajda } 130acd8afa8SAndrzej Hajda 131acd8afa8SAndrzej Hajda static void fimc_clear_bits(struct fimc_context *ctx, u32 reg, u32 bits) 132acd8afa8SAndrzej Hajda { 133acd8afa8SAndrzej Hajda void __iomem *r = ctx->regs + reg; 134acd8afa8SAndrzej Hajda 135acd8afa8SAndrzej Hajda writel(readl(r) & ~bits, r); 136acd8afa8SAndrzej Hajda } 137acd8afa8SAndrzej Hajda 138b5c0b552SJoongMock Shin static void fimc_sw_reset(struct fimc_context *ctx) 13916102edbSEunchul Kim { 14016102edbSEunchul Kim u32 cfg; 14116102edbSEunchul Kim 142e39d5ce1SJinyoung Jeon /* stop dma operation */ 143acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CISTATUS); 144acd8afa8SAndrzej Hajda if (EXYNOS_CISTATUS_GET_ENVID_STATUS(cfg)) 145acd8afa8SAndrzej Hajda fimc_clear_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID); 14616102edbSEunchul Kim 147acd8afa8SAndrzej Hajda fimc_set_bits(ctx, EXYNOS_CISRCFMT, EXYNOS_CISRCFMT_ITU601_8BIT); 14816102edbSEunchul Kim 149e39d5ce1SJinyoung Jeon /* disable image capture */ 150acd8afa8SAndrzej Hajda fimc_clear_bits(ctx, EXYNOS_CIIMGCPT, 151acd8afa8SAndrzej Hajda EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN); 152e39d5ce1SJinyoung Jeon 15316102edbSEunchul Kim /* s/w reset */ 154acd8afa8SAndrzej Hajda fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_SWRST); 15516102edbSEunchul Kim 15616102edbSEunchul Kim /* s/w reset complete */ 157acd8afa8SAndrzej Hajda fimc_clear_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_SWRST); 15816102edbSEunchul Kim 15916102edbSEunchul Kim /* reset sequence */ 160acd8afa8SAndrzej Hajda fimc_write(ctx, 0x0, EXYNOS_CIFCNTSEQ); 16116102edbSEunchul Kim } 16216102edbSEunchul Kim 1637a2d5c77SMarek Szyprowski static void fimc_set_type_ctrl(struct fimc_context *ctx) 16416102edbSEunchul Kim { 16516102edbSEunchul Kim u32 cfg; 16616102edbSEunchul Kim 167acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CIGCTRL); 16816102edbSEunchul Kim cfg &= ~(EXYNOS_CIGCTRL_TESTPATTERN_MASK | 16916102edbSEunchul Kim EXYNOS_CIGCTRL_SELCAM_ITU_MASK | 17016102edbSEunchul Kim EXYNOS_CIGCTRL_SELCAM_MIPI_MASK | 17116102edbSEunchul Kim EXYNOS_CIGCTRL_SELCAM_FIMC_MASK | 17216102edbSEunchul Kim EXYNOS_CIGCTRL_SELWB_CAMIF_MASK | 17316102edbSEunchul Kim EXYNOS_CIGCTRL_SELWRITEBACK_MASK); 17416102edbSEunchul Kim 17516102edbSEunchul Kim cfg |= (EXYNOS_CIGCTRL_SELCAM_ITU_A | 17616102edbSEunchul Kim EXYNOS_CIGCTRL_SELWRITEBACK_A | 17716102edbSEunchul Kim EXYNOS_CIGCTRL_SELCAM_MIPI_A | 17816102edbSEunchul Kim EXYNOS_CIGCTRL_SELCAM_FIMC_ITU); 17916102edbSEunchul Kim 180acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIGCTRL); 18116102edbSEunchul Kim } 18216102edbSEunchul Kim 18316102edbSEunchul Kim static void fimc_handle_jpeg(struct fimc_context *ctx, bool enable) 18416102edbSEunchul Kim { 18516102edbSEunchul Kim u32 cfg; 18616102edbSEunchul Kim 1876be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "enable[%d]\n", enable); 18816102edbSEunchul Kim 189acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CIGCTRL); 19016102edbSEunchul Kim if (enable) 19116102edbSEunchul Kim cfg |= EXYNOS_CIGCTRL_CAM_JPEG; 19216102edbSEunchul Kim else 19316102edbSEunchul Kim cfg &= ~EXYNOS_CIGCTRL_CAM_JPEG; 19416102edbSEunchul Kim 195acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIGCTRL); 19616102edbSEunchul Kim } 19716102edbSEunchul Kim 1988b4609cdSAndrzej Hajda static void fimc_mask_irq(struct fimc_context *ctx, bool enable) 19916102edbSEunchul Kim { 20016102edbSEunchul Kim u32 cfg; 20116102edbSEunchul Kim 2026be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "enable[%d]\n", enable); 20316102edbSEunchul Kim 204acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CIGCTRL); 20516102edbSEunchul Kim if (enable) { 2068b4609cdSAndrzej Hajda cfg &= ~EXYNOS_CIGCTRL_IRQ_OVFEN; 2078b4609cdSAndrzej Hajda cfg |= EXYNOS_CIGCTRL_IRQ_ENABLE | EXYNOS_CIGCTRL_IRQ_LEVEL; 20816102edbSEunchul Kim } else 2098b4609cdSAndrzej Hajda cfg &= ~EXYNOS_CIGCTRL_IRQ_ENABLE; 210acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIGCTRL); 21116102edbSEunchul Kim } 21216102edbSEunchul Kim 21316102edbSEunchul Kim static void fimc_clear_irq(struct fimc_context *ctx) 21416102edbSEunchul Kim { 215acd8afa8SAndrzej Hajda fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_CLR); 21616102edbSEunchul Kim } 21716102edbSEunchul Kim 21816102edbSEunchul Kim static bool fimc_check_ovf(struct fimc_context *ctx) 21916102edbSEunchul Kim { 220acd8afa8SAndrzej Hajda u32 status, flag; 22116102edbSEunchul Kim 222acd8afa8SAndrzej Hajda status = fimc_read(ctx, EXYNOS_CISTATUS); 22316102edbSEunchul Kim flag = EXYNOS_CISTATUS_OVFIY | EXYNOS_CISTATUS_OVFICB | 22416102edbSEunchul Kim EXYNOS_CISTATUS_OVFICR; 22516102edbSEunchul Kim 2266be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "flag[0x%x]\n", flag); 22716102edbSEunchul Kim 22816102edbSEunchul Kim if (status & flag) { 229acd8afa8SAndrzej Hajda fimc_set_bits(ctx, EXYNOS_CIWDOFST, 230acd8afa8SAndrzej Hajda EXYNOS_CIWDOFST_CLROVFIY | EXYNOS_CIWDOFST_CLROVFICB | 23116102edbSEunchul Kim EXYNOS_CIWDOFST_CLROVFICR); 23216102edbSEunchul Kim 2336f83d208SInki Dae DRM_DEV_ERROR(ctx->dev, 2346f83d208SInki Dae "occurred overflow at %d, status 0x%x.\n", 23516102edbSEunchul Kim ctx->id, status); 23616102edbSEunchul Kim return true; 23716102edbSEunchul Kim } 23816102edbSEunchul Kim 23916102edbSEunchul Kim return false; 24016102edbSEunchul Kim } 24116102edbSEunchul Kim 24216102edbSEunchul Kim static bool fimc_check_frame_end(struct fimc_context *ctx) 24316102edbSEunchul Kim { 24416102edbSEunchul Kim u32 cfg; 24516102edbSEunchul Kim 246acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CISTATUS); 24716102edbSEunchul Kim 2486be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "cfg[0x%x]\n", cfg); 24916102edbSEunchul Kim 25016102edbSEunchul Kim if (!(cfg & EXYNOS_CISTATUS_FRAMEEND)) 25116102edbSEunchul Kim return false; 25216102edbSEunchul Kim 25316102edbSEunchul Kim cfg &= ~(EXYNOS_CISTATUS_FRAMEEND); 254acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CISTATUS); 25516102edbSEunchul Kim 25616102edbSEunchul Kim return true; 25716102edbSEunchul Kim } 25816102edbSEunchul Kim 25916102edbSEunchul Kim static int fimc_get_buf_id(struct fimc_context *ctx) 26016102edbSEunchul Kim { 26116102edbSEunchul Kim u32 cfg; 26216102edbSEunchul Kim int frame_cnt, buf_id; 26316102edbSEunchul Kim 264acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CISTATUS2); 26516102edbSEunchul Kim frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg); 26616102edbSEunchul Kim 26716102edbSEunchul Kim if (frame_cnt == 0) 26816102edbSEunchul Kim frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg); 26916102edbSEunchul Kim 2706be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "present[%d]before[%d]\n", 27116102edbSEunchul Kim EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg), 27216102edbSEunchul Kim EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg)); 27316102edbSEunchul Kim 27416102edbSEunchul Kim if (frame_cnt == 0) { 2756f83d208SInki Dae DRM_DEV_ERROR(ctx->dev, "failed to get frame count.\n"); 27616102edbSEunchul Kim return -EIO; 27716102edbSEunchul Kim } 27816102edbSEunchul Kim 27916102edbSEunchul Kim buf_id = frame_cnt - 1; 2806be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "buf_id[%d]\n", buf_id); 28116102edbSEunchul Kim 28216102edbSEunchul Kim return buf_id; 28316102edbSEunchul Kim } 28416102edbSEunchul Kim 28516102edbSEunchul Kim static void fimc_handle_lastend(struct fimc_context *ctx, bool enable) 28616102edbSEunchul Kim { 28716102edbSEunchul Kim u32 cfg; 28816102edbSEunchul Kim 2896be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "enable[%d]\n", enable); 29016102edbSEunchul Kim 291acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CIOCTRL); 29216102edbSEunchul Kim if (enable) 29316102edbSEunchul Kim cfg |= EXYNOS_CIOCTRL_LASTENDEN; 29416102edbSEunchul Kim else 29516102edbSEunchul Kim cfg &= ~EXYNOS_CIOCTRL_LASTENDEN; 29616102edbSEunchul Kim 297acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIOCTRL); 29816102edbSEunchul Kim } 29916102edbSEunchul Kim 3007a2d5c77SMarek Szyprowski static void fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt) 30116102edbSEunchul Kim { 30216102edbSEunchul Kim u32 cfg; 30316102edbSEunchul Kim 3046be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt); 30516102edbSEunchul Kim 30616102edbSEunchul Kim /* RGB */ 307acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CISCCTRL); 30816102edbSEunchul Kim cfg &= ~EXYNOS_CISCCTRL_INRGB_FMT_RGB_MASK; 30916102edbSEunchul Kim 31016102edbSEunchul Kim switch (fmt) { 31116102edbSEunchul Kim case DRM_FORMAT_RGB565: 31216102edbSEunchul Kim cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB565; 313acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CISCCTRL); 3147a2d5c77SMarek Szyprowski return; 31516102edbSEunchul Kim case DRM_FORMAT_RGB888: 31616102edbSEunchul Kim case DRM_FORMAT_XRGB8888: 31716102edbSEunchul Kim cfg |= EXYNOS_CISCCTRL_INRGB_FMT_RGB888; 318acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CISCCTRL); 3197a2d5c77SMarek Szyprowski return; 32016102edbSEunchul Kim default: 32116102edbSEunchul Kim /* bypass */ 32216102edbSEunchul Kim break; 32316102edbSEunchul Kim } 32416102edbSEunchul Kim 32516102edbSEunchul Kim /* YUV */ 326acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_MSCTRL); 32716102edbSEunchul Kim cfg &= ~(EXYNOS_MSCTRL_ORDER2P_SHIFT_MASK | 32816102edbSEunchul Kim EXYNOS_MSCTRL_C_INT_IN_2PLANE | 32916102edbSEunchul Kim EXYNOS_MSCTRL_ORDER422_YCBYCR); 33016102edbSEunchul Kim 33116102edbSEunchul Kim switch (fmt) { 33216102edbSEunchul Kim case DRM_FORMAT_YUYV: 33316102edbSEunchul Kim cfg |= EXYNOS_MSCTRL_ORDER422_YCBYCR; 33416102edbSEunchul Kim break; 33516102edbSEunchul Kim case DRM_FORMAT_YVYU: 33616102edbSEunchul Kim cfg |= EXYNOS_MSCTRL_ORDER422_YCRYCB; 33716102edbSEunchul Kim break; 33816102edbSEunchul Kim case DRM_FORMAT_UYVY: 33916102edbSEunchul Kim cfg |= EXYNOS_MSCTRL_ORDER422_CBYCRY; 34016102edbSEunchul Kim break; 34116102edbSEunchul Kim case DRM_FORMAT_VYUY: 34216102edbSEunchul Kim case DRM_FORMAT_YUV444: 34316102edbSEunchul Kim cfg |= EXYNOS_MSCTRL_ORDER422_CRYCBY; 34416102edbSEunchul Kim break; 34516102edbSEunchul Kim case DRM_FORMAT_NV21: 34616102edbSEunchul Kim case DRM_FORMAT_NV61: 34716102edbSEunchul Kim cfg |= (EXYNOS_MSCTRL_ORDER2P_LSB_CRCB | 34816102edbSEunchul Kim EXYNOS_MSCTRL_C_INT_IN_2PLANE); 34916102edbSEunchul Kim break; 35016102edbSEunchul Kim case DRM_FORMAT_YUV422: 35116102edbSEunchul Kim case DRM_FORMAT_YUV420: 35216102edbSEunchul Kim case DRM_FORMAT_YVU420: 35316102edbSEunchul Kim cfg |= EXYNOS_MSCTRL_C_INT_IN_3PLANE; 35416102edbSEunchul Kim break; 35516102edbSEunchul Kim case DRM_FORMAT_NV12: 35616102edbSEunchul Kim case DRM_FORMAT_NV16: 35716102edbSEunchul Kim cfg |= (EXYNOS_MSCTRL_ORDER2P_LSB_CBCR | 35816102edbSEunchul Kim EXYNOS_MSCTRL_C_INT_IN_2PLANE); 35916102edbSEunchul Kim break; 36016102edbSEunchul Kim } 36116102edbSEunchul Kim 362acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_MSCTRL); 36316102edbSEunchul Kim } 36416102edbSEunchul Kim 3657a2d5c77SMarek Szyprowski static void fimc_src_set_fmt(struct fimc_context *ctx, u32 fmt, bool tiled) 36616102edbSEunchul Kim { 36716102edbSEunchul Kim u32 cfg; 36816102edbSEunchul Kim 3696be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt); 37016102edbSEunchul Kim 371acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_MSCTRL); 37216102edbSEunchul Kim cfg &= ~EXYNOS_MSCTRL_INFORMAT_RGB; 37316102edbSEunchul Kim 37416102edbSEunchul Kim switch (fmt) { 37516102edbSEunchul Kim case DRM_FORMAT_RGB565: 37616102edbSEunchul Kim case DRM_FORMAT_RGB888: 37716102edbSEunchul Kim case DRM_FORMAT_XRGB8888: 37816102edbSEunchul Kim cfg |= EXYNOS_MSCTRL_INFORMAT_RGB; 37916102edbSEunchul Kim break; 38016102edbSEunchul Kim case DRM_FORMAT_YUV444: 38116102edbSEunchul Kim cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420; 38216102edbSEunchul Kim break; 38316102edbSEunchul Kim case DRM_FORMAT_YUYV: 38416102edbSEunchul Kim case DRM_FORMAT_YVYU: 38516102edbSEunchul Kim case DRM_FORMAT_UYVY: 38616102edbSEunchul Kim case DRM_FORMAT_VYUY: 38716102edbSEunchul Kim cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR422_1PLANE; 38816102edbSEunchul Kim break; 38916102edbSEunchul Kim case DRM_FORMAT_NV16: 39016102edbSEunchul Kim case DRM_FORMAT_NV61: 39116102edbSEunchul Kim case DRM_FORMAT_YUV422: 39216102edbSEunchul Kim cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR422; 39316102edbSEunchul Kim break; 39416102edbSEunchul Kim case DRM_FORMAT_YUV420: 39516102edbSEunchul Kim case DRM_FORMAT_YVU420: 39616102edbSEunchul Kim case DRM_FORMAT_NV12: 39716102edbSEunchul Kim case DRM_FORMAT_NV21: 39816102edbSEunchul Kim cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420; 39916102edbSEunchul Kim break; 40016102edbSEunchul Kim } 40116102edbSEunchul Kim 402acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_MSCTRL); 40316102edbSEunchul Kim 404acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM); 40516102edbSEunchul Kim cfg &= ~EXYNOS_CIDMAPARAM_R_MODE_MASK; 40616102edbSEunchul Kim 4077a2d5c77SMarek Szyprowski if (tiled) 4087a2d5c77SMarek Szyprowski cfg |= EXYNOS_CIDMAPARAM_R_MODE_64X32; 4097a2d5c77SMarek Szyprowski else 41016102edbSEunchul Kim cfg |= EXYNOS_CIDMAPARAM_R_MODE_LINEAR; 41116102edbSEunchul Kim 412acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM); 41316102edbSEunchul Kim 4147a2d5c77SMarek Szyprowski fimc_src_set_fmt_order(ctx, fmt); 41516102edbSEunchul Kim } 41616102edbSEunchul Kim 4177a2d5c77SMarek Szyprowski static void fimc_src_set_transf(struct fimc_context *ctx, unsigned int rotation) 41816102edbSEunchul Kim { 4197a2d5c77SMarek Szyprowski unsigned int degree = rotation & DRM_MODE_ROTATE_MASK; 42016102edbSEunchul Kim u32 cfg1, cfg2; 42116102edbSEunchul Kim 4226be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "rotation[%x]\n", rotation); 42316102edbSEunchul Kim 424acd8afa8SAndrzej Hajda cfg1 = fimc_read(ctx, EXYNOS_MSCTRL); 42516102edbSEunchul Kim cfg1 &= ~(EXYNOS_MSCTRL_FLIP_X_MIRROR | 42616102edbSEunchul Kim EXYNOS_MSCTRL_FLIP_Y_MIRROR); 42716102edbSEunchul Kim 428acd8afa8SAndrzej Hajda cfg2 = fimc_read(ctx, EXYNOS_CITRGFMT); 42916102edbSEunchul Kim cfg2 &= ~EXYNOS_CITRGFMT_INROT90_CLOCKWISE; 43016102edbSEunchul Kim 43116102edbSEunchul Kim switch (degree) { 4327a2d5c77SMarek Szyprowski case DRM_MODE_ROTATE_0: 4337a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_X) 43416102edbSEunchul Kim cfg1 |= EXYNOS_MSCTRL_FLIP_X_MIRROR; 4357a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_Y) 43616102edbSEunchul Kim cfg1 |= EXYNOS_MSCTRL_FLIP_Y_MIRROR; 43716102edbSEunchul Kim break; 4387a2d5c77SMarek Szyprowski case DRM_MODE_ROTATE_90: 43916102edbSEunchul Kim cfg2 |= EXYNOS_CITRGFMT_INROT90_CLOCKWISE; 4407a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_X) 44116102edbSEunchul Kim cfg1 |= EXYNOS_MSCTRL_FLIP_X_MIRROR; 4427a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_Y) 44316102edbSEunchul Kim cfg1 |= EXYNOS_MSCTRL_FLIP_Y_MIRROR; 44416102edbSEunchul Kim break; 4457a2d5c77SMarek Szyprowski case DRM_MODE_ROTATE_180: 44616102edbSEunchul Kim cfg1 |= (EXYNOS_MSCTRL_FLIP_X_MIRROR | 44716102edbSEunchul Kim EXYNOS_MSCTRL_FLIP_Y_MIRROR); 4487a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_X) 44916102edbSEunchul Kim cfg1 &= ~EXYNOS_MSCTRL_FLIP_X_MIRROR; 4507a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_Y) 45116102edbSEunchul Kim cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR; 45216102edbSEunchul Kim break; 4537a2d5c77SMarek Szyprowski case DRM_MODE_ROTATE_270: 45416102edbSEunchul Kim cfg1 |= (EXYNOS_MSCTRL_FLIP_X_MIRROR | 45516102edbSEunchul Kim EXYNOS_MSCTRL_FLIP_Y_MIRROR); 45616102edbSEunchul Kim cfg2 |= EXYNOS_CITRGFMT_INROT90_CLOCKWISE; 4577a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_X) 45816102edbSEunchul Kim cfg1 &= ~EXYNOS_MSCTRL_FLIP_X_MIRROR; 4597a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_Y) 46016102edbSEunchul Kim cfg1 &= ~EXYNOS_MSCTRL_FLIP_Y_MIRROR; 46116102edbSEunchul Kim break; 46216102edbSEunchul Kim } 46316102edbSEunchul Kim 464acd8afa8SAndrzej Hajda fimc_write(ctx, cfg1, EXYNOS_MSCTRL); 465acd8afa8SAndrzej Hajda fimc_write(ctx, cfg2, EXYNOS_CITRGFMT); 46616102edbSEunchul Kim } 46716102edbSEunchul Kim 4687a2d5c77SMarek Szyprowski static void fimc_set_window(struct fimc_context *ctx, 4697a2d5c77SMarek Szyprowski struct exynos_drm_ipp_buffer *buf) 47016102edbSEunchul Kim { 4715d5657aaSMarek Szyprowski unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0]; 47216102edbSEunchul Kim u32 cfg, h1, h2, v1, v2; 47316102edbSEunchul Kim 47416102edbSEunchul Kim /* cropped image */ 4757a2d5c77SMarek Szyprowski h1 = buf->rect.x; 4765d5657aaSMarek Szyprowski h2 = real_width - buf->rect.w - buf->rect.x; 4777a2d5c77SMarek Szyprowski v1 = buf->rect.y; 4787a2d5c77SMarek Szyprowski v2 = buf->buf.height - buf->rect.h - buf->rect.y; 47916102edbSEunchul Kim 4806be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n", 4817a2d5c77SMarek Szyprowski buf->rect.x, buf->rect.y, buf->rect.w, buf->rect.h, 4825d5657aaSMarek Szyprowski real_width, buf->buf.height); 4836be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "h1[%d]h2[%d]v1[%d]v2[%d]\n", h1, h2, v1, 4846be90056SInki Dae v2); 48516102edbSEunchul Kim 48616102edbSEunchul Kim /* 48716102edbSEunchul Kim * set window offset 1, 2 size 48816102edbSEunchul Kim * check figure 43-21 in user manual 48916102edbSEunchul Kim */ 490acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CIWDOFST); 49116102edbSEunchul Kim cfg &= ~(EXYNOS_CIWDOFST_WINHOROFST_MASK | 49216102edbSEunchul Kim EXYNOS_CIWDOFST_WINVEROFST_MASK); 49316102edbSEunchul Kim cfg |= (EXYNOS_CIWDOFST_WINHOROFST(h1) | 49416102edbSEunchul Kim EXYNOS_CIWDOFST_WINVEROFST(v1)); 49516102edbSEunchul Kim cfg |= EXYNOS_CIWDOFST_WINOFSEN; 496acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIWDOFST); 49716102edbSEunchul Kim 49816102edbSEunchul Kim cfg = (EXYNOS_CIWDOFST2_WINHOROFST2(h2) | 49916102edbSEunchul Kim EXYNOS_CIWDOFST2_WINVEROFST2(v2)); 500acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIWDOFST2); 50116102edbSEunchul Kim } 50216102edbSEunchul Kim 5037a2d5c77SMarek Szyprowski static void fimc_src_set_size(struct fimc_context *ctx, 5047a2d5c77SMarek Szyprowski struct exynos_drm_ipp_buffer *buf) 50516102edbSEunchul Kim { 5065d5657aaSMarek Szyprowski unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0]; 50716102edbSEunchul Kim u32 cfg; 50816102edbSEunchul Kim 5096be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "hsize[%d]vsize[%d]\n", real_width, 5106be90056SInki Dae buf->buf.height); 51116102edbSEunchul Kim 51216102edbSEunchul Kim /* original size */ 5135d5657aaSMarek Szyprowski cfg = (EXYNOS_ORGISIZE_HORIZONTAL(real_width) | 5147a2d5c77SMarek Szyprowski EXYNOS_ORGISIZE_VERTICAL(buf->buf.height)); 51516102edbSEunchul Kim 516acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_ORGISIZE); 51716102edbSEunchul Kim 5186be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "x[%d]y[%d]w[%d]h[%d]\n", buf->rect.x, 5196be90056SInki Dae buf->rect.y, buf->rect.w, buf->rect.h); 52016102edbSEunchul Kim 52116102edbSEunchul Kim /* set input DMA image size */ 522acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CIREAL_ISIZE); 52316102edbSEunchul Kim cfg &= ~(EXYNOS_CIREAL_ISIZE_HEIGHT_MASK | 52416102edbSEunchul Kim EXYNOS_CIREAL_ISIZE_WIDTH_MASK); 5257a2d5c77SMarek Szyprowski cfg |= (EXYNOS_CIREAL_ISIZE_WIDTH(buf->rect.w) | 5267a2d5c77SMarek Szyprowski EXYNOS_CIREAL_ISIZE_HEIGHT(buf->rect.h)); 527acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIREAL_ISIZE); 52816102edbSEunchul Kim 52916102edbSEunchul Kim /* 53016102edbSEunchul Kim * set input FIFO image size 53116102edbSEunchul Kim * for now, we support only ITU601 8 bit mode 53216102edbSEunchul Kim */ 53316102edbSEunchul Kim cfg = (EXYNOS_CISRCFMT_ITU601_8BIT | 5345d5657aaSMarek Szyprowski EXYNOS_CISRCFMT_SOURCEHSIZE(real_width) | 5357a2d5c77SMarek Szyprowski EXYNOS_CISRCFMT_SOURCEVSIZE(buf->buf.height)); 536acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CISRCFMT); 53716102edbSEunchul Kim 53816102edbSEunchul Kim /* offset Y(RGB), Cb, Cr */ 5397a2d5c77SMarek Szyprowski cfg = (EXYNOS_CIIYOFF_HORIZONTAL(buf->rect.x) | 5407a2d5c77SMarek Szyprowski EXYNOS_CIIYOFF_VERTICAL(buf->rect.y)); 541acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIIYOFF); 5427a2d5c77SMarek Szyprowski cfg = (EXYNOS_CIICBOFF_HORIZONTAL(buf->rect.x) | 5437a2d5c77SMarek Szyprowski EXYNOS_CIICBOFF_VERTICAL(buf->rect.y)); 544acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIICBOFF); 5457a2d5c77SMarek Szyprowski cfg = (EXYNOS_CIICROFF_HORIZONTAL(buf->rect.x) | 5467a2d5c77SMarek Szyprowski EXYNOS_CIICROFF_VERTICAL(buf->rect.y)); 547acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIICROFF); 54816102edbSEunchul Kim 5497a2d5c77SMarek Szyprowski fimc_set_window(ctx, buf); 55016102edbSEunchul Kim } 55116102edbSEunchul Kim 5527a2d5c77SMarek Szyprowski static void fimc_src_set_addr(struct fimc_context *ctx, 5537a2d5c77SMarek Szyprowski struct exynos_drm_ipp_buffer *buf) 55416102edbSEunchul Kim { 5557a2d5c77SMarek Szyprowski fimc_write(ctx, buf->dma_addr[0], EXYNOS_CIIYSA(0)); 5567a2d5c77SMarek Szyprowski fimc_write(ctx, buf->dma_addr[1], EXYNOS_CIICBSA(0)); 5577a2d5c77SMarek Szyprowski fimc_write(ctx, buf->dma_addr[2], EXYNOS_CIICRSA(0)); 55816102edbSEunchul Kim } 55916102edbSEunchul Kim 5607a2d5c77SMarek Szyprowski static void fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt) 56116102edbSEunchul Kim { 56216102edbSEunchul Kim u32 cfg; 56316102edbSEunchul Kim 5646be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt); 56516102edbSEunchul Kim 56616102edbSEunchul Kim /* RGB */ 567acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CISCCTRL); 56816102edbSEunchul Kim cfg &= ~EXYNOS_CISCCTRL_OUTRGB_FMT_RGB_MASK; 56916102edbSEunchul Kim 57016102edbSEunchul Kim switch (fmt) { 57116102edbSEunchul Kim case DRM_FORMAT_RGB565: 57216102edbSEunchul Kim cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB565; 573acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CISCCTRL); 5747a2d5c77SMarek Szyprowski return; 57516102edbSEunchul Kim case DRM_FORMAT_RGB888: 57616102edbSEunchul Kim cfg |= EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888; 577acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CISCCTRL); 5787a2d5c77SMarek Szyprowski return; 57916102edbSEunchul Kim case DRM_FORMAT_XRGB8888: 58016102edbSEunchul Kim cfg |= (EXYNOS_CISCCTRL_OUTRGB_FMT_RGB888 | 58116102edbSEunchul Kim EXYNOS_CISCCTRL_EXTRGB_EXTENSION); 582acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CISCCTRL); 58316102edbSEunchul Kim break; 58416102edbSEunchul Kim default: 58516102edbSEunchul Kim /* bypass */ 58616102edbSEunchul Kim break; 58716102edbSEunchul Kim } 58816102edbSEunchul Kim 58916102edbSEunchul Kim /* YUV */ 590acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CIOCTRL); 59116102edbSEunchul Kim cfg &= ~(EXYNOS_CIOCTRL_ORDER2P_MASK | 59216102edbSEunchul Kim EXYNOS_CIOCTRL_ORDER422_MASK | 59316102edbSEunchul Kim EXYNOS_CIOCTRL_YCBCR_PLANE_MASK); 59416102edbSEunchul Kim 59516102edbSEunchul Kim switch (fmt) { 59616102edbSEunchul Kim case DRM_FORMAT_XRGB8888: 59716102edbSEunchul Kim cfg |= EXYNOS_CIOCTRL_ALPHA_OUT; 59816102edbSEunchul Kim break; 59916102edbSEunchul Kim case DRM_FORMAT_YUYV: 60016102edbSEunchul Kim cfg |= EXYNOS_CIOCTRL_ORDER422_YCBYCR; 60116102edbSEunchul Kim break; 60216102edbSEunchul Kim case DRM_FORMAT_YVYU: 60316102edbSEunchul Kim cfg |= EXYNOS_CIOCTRL_ORDER422_YCRYCB; 60416102edbSEunchul Kim break; 60516102edbSEunchul Kim case DRM_FORMAT_UYVY: 60616102edbSEunchul Kim cfg |= EXYNOS_CIOCTRL_ORDER422_CBYCRY; 60716102edbSEunchul Kim break; 60816102edbSEunchul Kim case DRM_FORMAT_VYUY: 60916102edbSEunchul Kim cfg |= EXYNOS_CIOCTRL_ORDER422_CRYCBY; 61016102edbSEunchul Kim break; 61116102edbSEunchul Kim case DRM_FORMAT_NV21: 61216102edbSEunchul Kim case DRM_FORMAT_NV61: 61316102edbSEunchul Kim cfg |= EXYNOS_CIOCTRL_ORDER2P_LSB_CRCB; 61416102edbSEunchul Kim cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE; 61516102edbSEunchul Kim break; 61616102edbSEunchul Kim case DRM_FORMAT_YUV422: 61716102edbSEunchul Kim case DRM_FORMAT_YUV420: 61816102edbSEunchul Kim case DRM_FORMAT_YVU420: 61916102edbSEunchul Kim cfg |= EXYNOS_CIOCTRL_YCBCR_3PLANE; 62016102edbSEunchul Kim break; 62116102edbSEunchul Kim case DRM_FORMAT_NV12: 62216102edbSEunchul Kim case DRM_FORMAT_NV16: 62316102edbSEunchul Kim cfg |= EXYNOS_CIOCTRL_ORDER2P_LSB_CBCR; 62416102edbSEunchul Kim cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE; 62516102edbSEunchul Kim break; 62616102edbSEunchul Kim } 62716102edbSEunchul Kim 628acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIOCTRL); 62916102edbSEunchul Kim } 63016102edbSEunchul Kim 6317a2d5c77SMarek Szyprowski static void fimc_dst_set_fmt(struct fimc_context *ctx, u32 fmt, bool tiled) 63216102edbSEunchul Kim { 63316102edbSEunchul Kim u32 cfg; 63416102edbSEunchul Kim 6356be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt); 63616102edbSEunchul Kim 637acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CIEXTEN); 63816102edbSEunchul Kim 63916102edbSEunchul Kim if (fmt == DRM_FORMAT_AYUV) { 64016102edbSEunchul Kim cfg |= EXYNOS_CIEXTEN_YUV444_OUT; 641acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIEXTEN); 64216102edbSEunchul Kim } else { 64316102edbSEunchul Kim cfg &= ~EXYNOS_CIEXTEN_YUV444_OUT; 644acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIEXTEN); 64516102edbSEunchul Kim 646acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CITRGFMT); 64716102edbSEunchul Kim cfg &= ~EXYNOS_CITRGFMT_OUTFORMAT_MASK; 64816102edbSEunchul Kim 64916102edbSEunchul Kim switch (fmt) { 65016102edbSEunchul Kim case DRM_FORMAT_RGB565: 65116102edbSEunchul Kim case DRM_FORMAT_RGB888: 65216102edbSEunchul Kim case DRM_FORMAT_XRGB8888: 65316102edbSEunchul Kim cfg |= EXYNOS_CITRGFMT_OUTFORMAT_RGB; 65416102edbSEunchul Kim break; 65516102edbSEunchul Kim case DRM_FORMAT_YUYV: 65616102edbSEunchul Kim case DRM_FORMAT_YVYU: 65716102edbSEunchul Kim case DRM_FORMAT_UYVY: 65816102edbSEunchul Kim case DRM_FORMAT_VYUY: 65916102edbSEunchul Kim cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE; 66016102edbSEunchul Kim break; 66116102edbSEunchul Kim case DRM_FORMAT_NV16: 66216102edbSEunchul Kim case DRM_FORMAT_NV61: 66316102edbSEunchul Kim case DRM_FORMAT_YUV422: 66416102edbSEunchul Kim cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR422; 66516102edbSEunchul Kim break; 66616102edbSEunchul Kim case DRM_FORMAT_YUV420: 66716102edbSEunchul Kim case DRM_FORMAT_YVU420: 66816102edbSEunchul Kim case DRM_FORMAT_NV12: 66916102edbSEunchul Kim case DRM_FORMAT_NV21: 67016102edbSEunchul Kim cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420; 67116102edbSEunchul Kim break; 67216102edbSEunchul Kim } 67316102edbSEunchul Kim 674acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CITRGFMT); 67516102edbSEunchul Kim } 67616102edbSEunchul Kim 677acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM); 67816102edbSEunchul Kim cfg &= ~EXYNOS_CIDMAPARAM_W_MODE_MASK; 67916102edbSEunchul Kim 6807a2d5c77SMarek Szyprowski if (tiled) 6817a2d5c77SMarek Szyprowski cfg |= EXYNOS_CIDMAPARAM_W_MODE_64X32; 6827a2d5c77SMarek Szyprowski else 68316102edbSEunchul Kim cfg |= EXYNOS_CIDMAPARAM_W_MODE_LINEAR; 68416102edbSEunchul Kim 685acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM); 68616102edbSEunchul Kim 6877a2d5c77SMarek Szyprowski fimc_dst_set_fmt_order(ctx, fmt); 68816102edbSEunchul Kim } 68916102edbSEunchul Kim 6907a2d5c77SMarek Szyprowski static void fimc_dst_set_transf(struct fimc_context *ctx, unsigned int rotation) 69116102edbSEunchul Kim { 6927a2d5c77SMarek Szyprowski unsigned int degree = rotation & DRM_MODE_ROTATE_MASK; 69316102edbSEunchul Kim u32 cfg; 69416102edbSEunchul Kim 6956be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "rotation[0x%x]\n", rotation); 69616102edbSEunchul Kim 697acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CITRGFMT); 69816102edbSEunchul Kim cfg &= ~EXYNOS_CITRGFMT_FLIP_MASK; 69916102edbSEunchul Kim cfg &= ~EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE; 70016102edbSEunchul Kim 70116102edbSEunchul Kim switch (degree) { 7027a2d5c77SMarek Szyprowski case DRM_MODE_ROTATE_0: 7037a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_X) 70416102edbSEunchul Kim cfg |= EXYNOS_CITRGFMT_FLIP_X_MIRROR; 7057a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_Y) 70616102edbSEunchul Kim cfg |= EXYNOS_CITRGFMT_FLIP_Y_MIRROR; 70716102edbSEunchul Kim break; 7087a2d5c77SMarek Szyprowski case DRM_MODE_ROTATE_90: 70916102edbSEunchul Kim cfg |= EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE; 7107a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_X) 71116102edbSEunchul Kim cfg |= EXYNOS_CITRGFMT_FLIP_X_MIRROR; 7127a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_Y) 71316102edbSEunchul Kim cfg |= EXYNOS_CITRGFMT_FLIP_Y_MIRROR; 71416102edbSEunchul Kim break; 7157a2d5c77SMarek Szyprowski case DRM_MODE_ROTATE_180: 71616102edbSEunchul Kim cfg |= (EXYNOS_CITRGFMT_FLIP_X_MIRROR | 71716102edbSEunchul Kim EXYNOS_CITRGFMT_FLIP_Y_MIRROR); 7187a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_X) 71916102edbSEunchul Kim cfg &= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR; 7207a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_Y) 72116102edbSEunchul Kim cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR; 72216102edbSEunchul Kim break; 7237a2d5c77SMarek Szyprowski case DRM_MODE_ROTATE_270: 72416102edbSEunchul Kim cfg |= (EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE | 72516102edbSEunchul Kim EXYNOS_CITRGFMT_FLIP_X_MIRROR | 72616102edbSEunchul Kim EXYNOS_CITRGFMT_FLIP_Y_MIRROR); 7277a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_X) 72816102edbSEunchul Kim cfg &= ~EXYNOS_CITRGFMT_FLIP_X_MIRROR; 7297a2d5c77SMarek Szyprowski if (rotation & DRM_MODE_REFLECT_Y) 73016102edbSEunchul Kim cfg &= ~EXYNOS_CITRGFMT_FLIP_Y_MIRROR; 73116102edbSEunchul Kim break; 73216102edbSEunchul Kim } 73316102edbSEunchul Kim 734acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CITRGFMT); 73516102edbSEunchul Kim } 73616102edbSEunchul Kim 73716102edbSEunchul Kim static int fimc_set_prescaler(struct fimc_context *ctx, struct fimc_scaler *sc, 7387a2d5c77SMarek Szyprowski struct drm_exynos_ipp_task_rect *src, 7397a2d5c77SMarek Szyprowski struct drm_exynos_ipp_task_rect *dst) 74016102edbSEunchul Kim { 74116102edbSEunchul Kim u32 cfg, cfg_ext, shfactor; 74216102edbSEunchul Kim u32 pre_dst_width, pre_dst_height; 743be6cdfd1SAndrzej Hajda u32 hfactor, vfactor; 74416102edbSEunchul Kim int ret = 0; 74516102edbSEunchul Kim u32 src_w, src_h, dst_w, dst_h; 74616102edbSEunchul Kim 747acd8afa8SAndrzej Hajda cfg_ext = fimc_read(ctx, EXYNOS_CITRGFMT); 74816102edbSEunchul Kim if (cfg_ext & EXYNOS_CITRGFMT_INROT90_CLOCKWISE) { 74916102edbSEunchul Kim src_w = src->h; 75016102edbSEunchul Kim src_h = src->w; 75116102edbSEunchul Kim } else { 75216102edbSEunchul Kim src_w = src->w; 75316102edbSEunchul Kim src_h = src->h; 75416102edbSEunchul Kim } 75516102edbSEunchul Kim 75616102edbSEunchul Kim if (cfg_ext & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE) { 75716102edbSEunchul Kim dst_w = dst->h; 75816102edbSEunchul Kim dst_h = dst->w; 75916102edbSEunchul Kim } else { 76016102edbSEunchul Kim dst_w = dst->w; 76116102edbSEunchul Kim dst_h = dst->h; 76216102edbSEunchul Kim } 76316102edbSEunchul Kim 764be6cdfd1SAndrzej Hajda /* fimc_ippdrv_check_property assures that dividers are not null */ 765be6cdfd1SAndrzej Hajda hfactor = fls(src_w / dst_w / 2); 766be6cdfd1SAndrzej Hajda if (hfactor > FIMC_SHFACTOR / 2) { 7677a2d5c77SMarek Szyprowski dev_err(ctx->dev, "failed to get ratio horizontal.\n"); 768be6cdfd1SAndrzej Hajda return -EINVAL; 76916102edbSEunchul Kim } 77016102edbSEunchul Kim 771be6cdfd1SAndrzej Hajda vfactor = fls(src_h / dst_h / 2); 772be6cdfd1SAndrzej Hajda if (vfactor > FIMC_SHFACTOR / 2) { 7737a2d5c77SMarek Szyprowski dev_err(ctx->dev, "failed to get ratio vertical.\n"); 774be6cdfd1SAndrzej Hajda return -EINVAL; 77516102edbSEunchul Kim } 77616102edbSEunchul Kim 777be6cdfd1SAndrzej Hajda pre_dst_width = src_w >> hfactor; 778be6cdfd1SAndrzej Hajda pre_dst_height = src_h >> vfactor; 7796be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "pre_dst_width[%d]pre_dst_height[%d]\n", 78016102edbSEunchul Kim pre_dst_width, pre_dst_height); 7816be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "hfactor[%d]vfactor[%d]\n", hfactor, 7826be90056SInki Dae vfactor); 78316102edbSEunchul Kim 78416102edbSEunchul Kim sc->hratio = (src_w << 14) / (dst_w << hfactor); 78516102edbSEunchul Kim sc->vratio = (src_h << 14) / (dst_h << vfactor); 78616102edbSEunchul Kim sc->up_h = (dst_w >= src_w) ? true : false; 78716102edbSEunchul Kim sc->up_v = (dst_h >= src_h) ? true : false; 7886be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "hratio[%d]vratio[%d]up_h[%d]up_v[%d]\n", 789cbc4c33dSYoungJun Cho sc->hratio, sc->vratio, sc->up_h, sc->up_v); 79016102edbSEunchul Kim 79116102edbSEunchul Kim shfactor = FIMC_SHFACTOR - (hfactor + vfactor); 7926be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "shfactor[%d]\n", shfactor); 79316102edbSEunchul Kim 79416102edbSEunchul Kim cfg = (EXYNOS_CISCPRERATIO_SHFACTOR(shfactor) | 795be6cdfd1SAndrzej Hajda EXYNOS_CISCPRERATIO_PREHORRATIO(1 << hfactor) | 796be6cdfd1SAndrzej Hajda EXYNOS_CISCPRERATIO_PREVERRATIO(1 << vfactor)); 797acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CISCPRERATIO); 79816102edbSEunchul Kim 79916102edbSEunchul Kim cfg = (EXYNOS_CISCPREDST_PREDSTWIDTH(pre_dst_width) | 80016102edbSEunchul Kim EXYNOS_CISCPREDST_PREDSTHEIGHT(pre_dst_height)); 801acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CISCPREDST); 80216102edbSEunchul Kim 80316102edbSEunchul Kim return ret; 80416102edbSEunchul Kim } 80516102edbSEunchul Kim 80616102edbSEunchul Kim static void fimc_set_scaler(struct fimc_context *ctx, struct fimc_scaler *sc) 80716102edbSEunchul Kim { 80816102edbSEunchul Kim u32 cfg, cfg_ext; 80916102edbSEunchul Kim 8106be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "range[%d]bypass[%d]up_h[%d]up_v[%d]\n", 811cbc4c33dSYoungJun Cho sc->range, sc->bypass, sc->up_h, sc->up_v); 8126be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "hratio[%d]vratio[%d]\n", 813cbc4c33dSYoungJun Cho sc->hratio, sc->vratio); 81416102edbSEunchul Kim 815acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CISCCTRL); 81616102edbSEunchul Kim cfg &= ~(EXYNOS_CISCCTRL_SCALERBYPASS | 81716102edbSEunchul Kim EXYNOS_CISCCTRL_SCALEUP_H | EXYNOS_CISCCTRL_SCALEUP_V | 81816102edbSEunchul Kim EXYNOS_CISCCTRL_MAIN_V_RATIO_MASK | 81916102edbSEunchul Kim EXYNOS_CISCCTRL_MAIN_H_RATIO_MASK | 82016102edbSEunchul Kim EXYNOS_CISCCTRL_CSCR2Y_WIDE | 82116102edbSEunchul Kim EXYNOS_CISCCTRL_CSCY2R_WIDE); 82216102edbSEunchul Kim 82316102edbSEunchul Kim if (sc->range) 82416102edbSEunchul Kim cfg |= (EXYNOS_CISCCTRL_CSCR2Y_WIDE | 82516102edbSEunchul Kim EXYNOS_CISCCTRL_CSCY2R_WIDE); 82616102edbSEunchul Kim if (sc->bypass) 82716102edbSEunchul Kim cfg |= EXYNOS_CISCCTRL_SCALERBYPASS; 82816102edbSEunchul Kim if (sc->up_h) 82916102edbSEunchul Kim cfg |= EXYNOS_CISCCTRL_SCALEUP_H; 83016102edbSEunchul Kim if (sc->up_v) 83116102edbSEunchul Kim cfg |= EXYNOS_CISCCTRL_SCALEUP_V; 83216102edbSEunchul Kim 83316102edbSEunchul Kim cfg |= (EXYNOS_CISCCTRL_MAINHORRATIO((sc->hratio >> 6)) | 83416102edbSEunchul Kim EXYNOS_CISCCTRL_MAINVERRATIO((sc->vratio >> 6))); 835acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CISCCTRL); 83616102edbSEunchul Kim 837acd8afa8SAndrzej Hajda cfg_ext = fimc_read(ctx, EXYNOS_CIEXTEN); 83816102edbSEunchul Kim cfg_ext &= ~EXYNOS_CIEXTEN_MAINHORRATIO_EXT_MASK; 83916102edbSEunchul Kim cfg_ext &= ~EXYNOS_CIEXTEN_MAINVERRATIO_EXT_MASK; 84016102edbSEunchul Kim cfg_ext |= (EXYNOS_CIEXTEN_MAINHORRATIO_EXT(sc->hratio) | 84116102edbSEunchul Kim EXYNOS_CIEXTEN_MAINVERRATIO_EXT(sc->vratio)); 842acd8afa8SAndrzej Hajda fimc_write(ctx, cfg_ext, EXYNOS_CIEXTEN); 84316102edbSEunchul Kim } 84416102edbSEunchul Kim 8457a2d5c77SMarek Szyprowski static void fimc_dst_set_size(struct fimc_context *ctx, 8467a2d5c77SMarek Szyprowski struct exynos_drm_ipp_buffer *buf) 84716102edbSEunchul Kim { 8485d5657aaSMarek Szyprowski unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0]; 8497a2d5c77SMarek Szyprowski u32 cfg, cfg_ext; 85016102edbSEunchul Kim 8516be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "hsize[%d]vsize[%d]\n", real_width, 8526be90056SInki Dae buf->buf.height); 85316102edbSEunchul Kim 85416102edbSEunchul Kim /* original size */ 8555d5657aaSMarek Szyprowski cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(real_width) | 8567a2d5c77SMarek Szyprowski EXYNOS_ORGOSIZE_VERTICAL(buf->buf.height)); 85716102edbSEunchul Kim 858acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_ORGOSIZE); 85916102edbSEunchul Kim 8606be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "x[%d]y[%d]w[%d]h[%d]\n", buf->rect.x, 8616be90056SInki Dae buf->rect.y, 8627a2d5c77SMarek Szyprowski buf->rect.w, buf->rect.h); 86316102edbSEunchul Kim 86416102edbSEunchul Kim /* CSC ITU */ 865acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CIGCTRL); 86616102edbSEunchul Kim cfg &= ~EXYNOS_CIGCTRL_CSC_MASK; 86716102edbSEunchul Kim 8687a2d5c77SMarek Szyprowski if (buf->buf.width >= FIMC_WIDTH_ITU_709) 86916102edbSEunchul Kim cfg |= EXYNOS_CIGCTRL_CSC_ITU709; 87016102edbSEunchul Kim else 87116102edbSEunchul Kim cfg |= EXYNOS_CIGCTRL_CSC_ITU601; 87216102edbSEunchul Kim 873acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIGCTRL); 87416102edbSEunchul Kim 8757a2d5c77SMarek Szyprowski cfg_ext = fimc_read(ctx, EXYNOS_CITRGFMT); 87616102edbSEunchul Kim 87716102edbSEunchul Kim /* target image size */ 878acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CITRGFMT); 87916102edbSEunchul Kim cfg &= ~(EXYNOS_CITRGFMT_TARGETH_MASK | 88016102edbSEunchul Kim EXYNOS_CITRGFMT_TARGETV_MASK); 8817a2d5c77SMarek Szyprowski if (cfg_ext & EXYNOS_CITRGFMT_OUTROT90_CLOCKWISE) 8827a2d5c77SMarek Szyprowski cfg |= (EXYNOS_CITRGFMT_TARGETHSIZE(buf->rect.h) | 8837a2d5c77SMarek Szyprowski EXYNOS_CITRGFMT_TARGETVSIZE(buf->rect.w)); 8847a2d5c77SMarek Szyprowski else 8857a2d5c77SMarek Szyprowski cfg |= (EXYNOS_CITRGFMT_TARGETHSIZE(buf->rect.w) | 8867a2d5c77SMarek Szyprowski EXYNOS_CITRGFMT_TARGETVSIZE(buf->rect.h)); 887acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CITRGFMT); 88816102edbSEunchul Kim 88916102edbSEunchul Kim /* target area */ 8907a2d5c77SMarek Szyprowski cfg = EXYNOS_CITAREA_TARGET_AREA(buf->rect.w * buf->rect.h); 891acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CITAREA); 89216102edbSEunchul Kim 89316102edbSEunchul Kim /* offset Y(RGB), Cb, Cr */ 8947a2d5c77SMarek Szyprowski cfg = (EXYNOS_CIOYOFF_HORIZONTAL(buf->rect.x) | 8957a2d5c77SMarek Szyprowski EXYNOS_CIOYOFF_VERTICAL(buf->rect.y)); 896acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIOYOFF); 8977a2d5c77SMarek Szyprowski cfg = (EXYNOS_CIOCBOFF_HORIZONTAL(buf->rect.x) | 8987a2d5c77SMarek Szyprowski EXYNOS_CIOCBOFF_VERTICAL(buf->rect.y)); 899acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIOCBOFF); 9007a2d5c77SMarek Szyprowski cfg = (EXYNOS_CIOCROFF_HORIZONTAL(buf->rect.x) | 9017a2d5c77SMarek Szyprowski EXYNOS_CIOCROFF_VERTICAL(buf->rect.y)); 902acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIOCROFF); 90316102edbSEunchul Kim } 90416102edbSEunchul Kim 90556442d83SAndrzej Hajda static void fimc_dst_set_buf_seq(struct fimc_context *ctx, u32 buf_id, 9067a2d5c77SMarek Szyprowski bool enqueue) 90716102edbSEunchul Kim { 90872d465aaSAndrzej Hajda unsigned long flags; 90956442d83SAndrzej Hajda u32 buf_num; 91056442d83SAndrzej Hajda u32 cfg; 91116102edbSEunchul Kim 9126be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "buf_id[%d]enqueu[%d]\n", buf_id, enqueue); 91316102edbSEunchul Kim 91472d465aaSAndrzej Hajda spin_lock_irqsave(&ctx->lock, flags); 91516102edbSEunchul Kim 916acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_CIFCNTSEQ); 91716102edbSEunchul Kim 9187a2d5c77SMarek Szyprowski if (enqueue) 91956442d83SAndrzej Hajda cfg |= (1 << buf_id); 92056442d83SAndrzej Hajda else 92156442d83SAndrzej Hajda cfg &= ~(1 << buf_id); 92216102edbSEunchul Kim 923acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_CIFCNTSEQ); 92416102edbSEunchul Kim 92556442d83SAndrzej Hajda buf_num = hweight32(cfg); 92616102edbSEunchul Kim 9277a2d5c77SMarek Szyprowski if (enqueue && buf_num >= FIMC_BUF_START) 92856442d83SAndrzej Hajda fimc_mask_irq(ctx, true); 9297a2d5c77SMarek Szyprowski else if (!enqueue && buf_num <= FIMC_BUF_STOP) 9308b4609cdSAndrzej Hajda fimc_mask_irq(ctx, false); 93116102edbSEunchul Kim 93272d465aaSAndrzej Hajda spin_unlock_irqrestore(&ctx->lock, flags); 93316102edbSEunchul Kim } 93416102edbSEunchul Kim 9357a2d5c77SMarek Szyprowski static void fimc_dst_set_addr(struct fimc_context *ctx, 9367a2d5c77SMarek Szyprowski struct exynos_drm_ipp_buffer *buf) 93716102edbSEunchul Kim { 9387a2d5c77SMarek Szyprowski fimc_write(ctx, buf->dma_addr[0], EXYNOS_CIOYSA(0)); 9397a2d5c77SMarek Szyprowski fimc_write(ctx, buf->dma_addr[1], EXYNOS_CIOCBSA(0)); 9407a2d5c77SMarek Szyprowski fimc_write(ctx, buf->dma_addr[2], EXYNOS_CIOCRSA(0)); 94116102edbSEunchul Kim 9427a2d5c77SMarek Szyprowski fimc_dst_set_buf_seq(ctx, 0, true); 94316102edbSEunchul Kim } 94416102edbSEunchul Kim 9457a2d5c77SMarek Szyprowski static void fimc_stop(struct fimc_context *ctx); 94616102edbSEunchul Kim 94716102edbSEunchul Kim static irqreturn_t fimc_irq_handler(int irq, void *dev_id) 94816102edbSEunchul Kim { 94916102edbSEunchul Kim struct fimc_context *ctx = dev_id; 95016102edbSEunchul Kim int buf_id; 95116102edbSEunchul Kim 9526be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "fimc id[%d]\n", ctx->id); 95316102edbSEunchul Kim 95416102edbSEunchul Kim fimc_clear_irq(ctx); 95516102edbSEunchul Kim if (fimc_check_ovf(ctx)) 95616102edbSEunchul Kim return IRQ_NONE; 95716102edbSEunchul Kim 95816102edbSEunchul Kim if (!fimc_check_frame_end(ctx)) 95916102edbSEunchul Kim return IRQ_NONE; 96016102edbSEunchul Kim 96116102edbSEunchul Kim buf_id = fimc_get_buf_id(ctx); 96216102edbSEunchul Kim if (buf_id < 0) 96316102edbSEunchul Kim return IRQ_HANDLED; 96416102edbSEunchul Kim 9656be90056SInki Dae DRM_DEV_DEBUG_KMS(ctx->dev, "buf_id[%d]\n", buf_id); 96616102edbSEunchul Kim 9677a2d5c77SMarek Szyprowski if (ctx->task) { 9687a2d5c77SMarek Szyprowski struct exynos_drm_ipp_task *task = ctx->task; 96916102edbSEunchul Kim 9707a2d5c77SMarek Szyprowski ctx->task = NULL; 9717a2d5c77SMarek Szyprowski pm_runtime_mark_last_busy(ctx->dev); 9727a2d5c77SMarek Szyprowski pm_runtime_put_autosuspend(ctx->dev); 9737a2d5c77SMarek Szyprowski exynos_drm_ipp_task_done(task, 0); 9747a2d5c77SMarek Szyprowski } 9757a2d5c77SMarek Szyprowski 9767a2d5c77SMarek Szyprowski fimc_dst_set_buf_seq(ctx, buf_id, false); 9777a2d5c77SMarek Szyprowski fimc_stop(ctx); 97816102edbSEunchul Kim 97916102edbSEunchul Kim return IRQ_HANDLED; 98016102edbSEunchul Kim } 98116102edbSEunchul Kim 98216102edbSEunchul Kim static void fimc_clear_addr(struct fimc_context *ctx) 98316102edbSEunchul Kim { 98416102edbSEunchul Kim int i; 98516102edbSEunchul Kim 98616102edbSEunchul Kim for (i = 0; i < FIMC_MAX_SRC; i++) { 987acd8afa8SAndrzej Hajda fimc_write(ctx, 0, EXYNOS_CIIYSA(i)); 988acd8afa8SAndrzej Hajda fimc_write(ctx, 0, EXYNOS_CIICBSA(i)); 989acd8afa8SAndrzej Hajda fimc_write(ctx, 0, EXYNOS_CIICRSA(i)); 99016102edbSEunchul Kim } 99116102edbSEunchul Kim 99216102edbSEunchul Kim for (i = 0; i < FIMC_MAX_DST; i++) { 993acd8afa8SAndrzej Hajda fimc_write(ctx, 0, EXYNOS_CIOYSA(i)); 994acd8afa8SAndrzej Hajda fimc_write(ctx, 0, EXYNOS_CIOCBSA(i)); 995acd8afa8SAndrzej Hajda fimc_write(ctx, 0, EXYNOS_CIOCRSA(i)); 99616102edbSEunchul Kim } 99716102edbSEunchul Kim } 99816102edbSEunchul Kim 9997a2d5c77SMarek Szyprowski static void fimc_reset(struct fimc_context *ctx) 100016102edbSEunchul Kim { 100116102edbSEunchul Kim /* reset h/w block */ 1002b5c0b552SJoongMock Shin fimc_sw_reset(ctx); 100316102edbSEunchul Kim 100416102edbSEunchul Kim /* reset scaler capability */ 100516102edbSEunchul Kim memset(&ctx->sc, 0x0, sizeof(ctx->sc)); 100616102edbSEunchul Kim 100716102edbSEunchul Kim fimc_clear_addr(ctx); 100816102edbSEunchul Kim } 100916102edbSEunchul Kim 10107a2d5c77SMarek Szyprowski static void fimc_start(struct fimc_context *ctx) 101116102edbSEunchul Kim { 101216102edbSEunchul Kim u32 cfg0, cfg1; 101316102edbSEunchul Kim 10148b4609cdSAndrzej Hajda fimc_mask_irq(ctx, true); 101516102edbSEunchul Kim 10167a2d5c77SMarek Szyprowski /* If set true, we can save jpeg about screen */ 101716102edbSEunchul Kim fimc_handle_jpeg(ctx, false); 101816102edbSEunchul Kim fimc_set_scaler(ctx, &ctx->sc); 101916102edbSEunchul Kim 10207a2d5c77SMarek Szyprowski fimc_set_type_ctrl(ctx); 102116102edbSEunchul Kim fimc_handle_lastend(ctx, false); 102216102edbSEunchul Kim 102316102edbSEunchul Kim /* setup dma */ 1024acd8afa8SAndrzej Hajda cfg0 = fimc_read(ctx, EXYNOS_MSCTRL); 102516102edbSEunchul Kim cfg0 &= ~EXYNOS_MSCTRL_INPUT_MASK; 102616102edbSEunchul Kim cfg0 |= EXYNOS_MSCTRL_INPUT_MEMORY; 1027acd8afa8SAndrzej Hajda fimc_write(ctx, cfg0, EXYNOS_MSCTRL); 102816102edbSEunchul Kim 102916102edbSEunchul Kim /* Reset status */ 1030acd8afa8SAndrzej Hajda fimc_write(ctx, 0x0, EXYNOS_CISTATUS); 103116102edbSEunchul Kim 1032acd8afa8SAndrzej Hajda cfg0 = fimc_read(ctx, EXYNOS_CIIMGCPT); 103316102edbSEunchul Kim cfg0 &= ~EXYNOS_CIIMGCPT_IMGCPTEN_SC; 103416102edbSEunchul Kim cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN_SC; 103516102edbSEunchul Kim 103616102edbSEunchul Kim /* Scaler */ 1037acd8afa8SAndrzej Hajda cfg1 = fimc_read(ctx, EXYNOS_CISCCTRL); 103816102edbSEunchul Kim cfg1 &= ~EXYNOS_CISCCTRL_SCAN_MASK; 103916102edbSEunchul Kim cfg1 |= (EXYNOS_CISCCTRL_PROGRESSIVE | 104016102edbSEunchul Kim EXYNOS_CISCCTRL_SCALERSTART); 104116102edbSEunchul Kim 1042acd8afa8SAndrzej Hajda fimc_write(ctx, cfg1, EXYNOS_CISCCTRL); 104316102edbSEunchul Kim 104416102edbSEunchul Kim /* Enable image capture*/ 104516102edbSEunchul Kim cfg0 |= EXYNOS_CIIMGCPT_IMGCPTEN; 1046acd8afa8SAndrzej Hajda fimc_write(ctx, cfg0, EXYNOS_CIIMGCPT); 104716102edbSEunchul Kim 104816102edbSEunchul Kim /* Disable frame end irq */ 1049acd8afa8SAndrzej Hajda fimc_clear_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_END_DISABLE); 105016102edbSEunchul Kim 1051acd8afa8SAndrzej Hajda fimc_clear_bits(ctx, EXYNOS_CIOCTRL, EXYNOS_CIOCTRL_WEAVE_MASK); 105216102edbSEunchul Kim 1053acd8afa8SAndrzej Hajda fimc_set_bits(ctx, EXYNOS_MSCTRL, EXYNOS_MSCTRL_ENVID); 105416102edbSEunchul Kim } 105516102edbSEunchul Kim 10567a2d5c77SMarek Szyprowski static void fimc_stop(struct fimc_context *ctx) 105716102edbSEunchul Kim { 105816102edbSEunchul Kim u32 cfg; 105916102edbSEunchul Kim 106016102edbSEunchul Kim /* Source clear */ 1061acd8afa8SAndrzej Hajda cfg = fimc_read(ctx, EXYNOS_MSCTRL); 106216102edbSEunchul Kim cfg &= ~EXYNOS_MSCTRL_INPUT_MASK; 106316102edbSEunchul Kim cfg &= ~EXYNOS_MSCTRL_ENVID; 1064acd8afa8SAndrzej Hajda fimc_write(ctx, cfg, EXYNOS_MSCTRL); 106516102edbSEunchul Kim 10668b4609cdSAndrzej Hajda fimc_mask_irq(ctx, false); 106716102edbSEunchul Kim 106816102edbSEunchul Kim /* reset sequence */ 1069acd8afa8SAndrzej Hajda fimc_write(ctx, 0x0, EXYNOS_CIFCNTSEQ); 107016102edbSEunchul Kim 107116102edbSEunchul Kim /* Scaler disable */ 1072acd8afa8SAndrzej Hajda fimc_clear_bits(ctx, EXYNOS_CISCCTRL, EXYNOS_CISCCTRL_SCALERSTART); 107316102edbSEunchul Kim 107416102edbSEunchul Kim /* Disable image capture */ 1075acd8afa8SAndrzej Hajda fimc_clear_bits(ctx, EXYNOS_CIIMGCPT, 1076acd8afa8SAndrzej Hajda EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN); 107716102edbSEunchul Kim 107816102edbSEunchul Kim /* Enable frame end irq */ 1079acd8afa8SAndrzej Hajda fimc_set_bits(ctx, EXYNOS_CIGCTRL, EXYNOS_CIGCTRL_IRQ_END_DISABLE); 108016102edbSEunchul Kim } 108116102edbSEunchul Kim 10827a2d5c77SMarek Szyprowski static int fimc_commit(struct exynos_drm_ipp *ipp, 10837a2d5c77SMarek Szyprowski struct exynos_drm_ipp_task *task) 10847a2d5c77SMarek Szyprowski { 10857a2d5c77SMarek Szyprowski struct fimc_context *ctx = 10867a2d5c77SMarek Szyprowski container_of(ipp, struct fimc_context, ipp); 10877a2d5c77SMarek Szyprowski 10887a2d5c77SMarek Szyprowski pm_runtime_get_sync(ctx->dev); 10897a2d5c77SMarek Szyprowski ctx->task = task; 10907a2d5c77SMarek Szyprowski 10917a2d5c77SMarek Szyprowski fimc_src_set_fmt(ctx, task->src.buf.fourcc, task->src.buf.modifier); 10927a2d5c77SMarek Szyprowski fimc_src_set_size(ctx, &task->src); 10937a2d5c77SMarek Szyprowski fimc_src_set_transf(ctx, DRM_MODE_ROTATE_0); 10947a2d5c77SMarek Szyprowski fimc_src_set_addr(ctx, &task->src); 10957a2d5c77SMarek Szyprowski fimc_dst_set_fmt(ctx, task->dst.buf.fourcc, task->dst.buf.modifier); 10967a2d5c77SMarek Szyprowski fimc_dst_set_transf(ctx, task->transform.rotation); 10977a2d5c77SMarek Szyprowski fimc_dst_set_size(ctx, &task->dst); 10987a2d5c77SMarek Szyprowski fimc_dst_set_addr(ctx, &task->dst); 10997a2d5c77SMarek Szyprowski fimc_set_prescaler(ctx, &ctx->sc, &task->src.rect, &task->dst.rect); 11007a2d5c77SMarek Szyprowski fimc_start(ctx); 11017a2d5c77SMarek Szyprowski 11027a2d5c77SMarek Szyprowski return 0; 11037a2d5c77SMarek Szyprowski } 11047a2d5c77SMarek Szyprowski 11057a2d5c77SMarek Szyprowski static void fimc_abort(struct exynos_drm_ipp *ipp, 11067a2d5c77SMarek Szyprowski struct exynos_drm_ipp_task *task) 11077a2d5c77SMarek Szyprowski { 11087a2d5c77SMarek Szyprowski struct fimc_context *ctx = 11097a2d5c77SMarek Szyprowski container_of(ipp, struct fimc_context, ipp); 11107a2d5c77SMarek Szyprowski 11117a2d5c77SMarek Szyprowski fimc_reset(ctx); 11127a2d5c77SMarek Szyprowski 11137a2d5c77SMarek Szyprowski if (ctx->task) { 11147a2d5c77SMarek Szyprowski struct exynos_drm_ipp_task *task = ctx->task; 11157a2d5c77SMarek Szyprowski 11167a2d5c77SMarek Szyprowski ctx->task = NULL; 11177a2d5c77SMarek Szyprowski pm_runtime_mark_last_busy(ctx->dev); 11187a2d5c77SMarek Szyprowski pm_runtime_put_autosuspend(ctx->dev); 11197a2d5c77SMarek Szyprowski exynos_drm_ipp_task_done(task, -EIO); 11207a2d5c77SMarek Szyprowski } 11217a2d5c77SMarek Szyprowski } 11227a2d5c77SMarek Szyprowski 11237a2d5c77SMarek Szyprowski static struct exynos_drm_ipp_funcs ipp_funcs = { 11247a2d5c77SMarek Szyprowski .commit = fimc_commit, 11257a2d5c77SMarek Szyprowski .abort = fimc_abort, 11267a2d5c77SMarek Szyprowski }; 11277a2d5c77SMarek Szyprowski 11287a2d5c77SMarek Szyprowski static int fimc_bind(struct device *dev, struct device *master, void *data) 11297a2d5c77SMarek Szyprowski { 11307a2d5c77SMarek Szyprowski struct fimc_context *ctx = dev_get_drvdata(dev); 11317a2d5c77SMarek Szyprowski struct drm_device *drm_dev = data; 11327a2d5c77SMarek Szyprowski struct exynos_drm_ipp *ipp = &ctx->ipp; 11337a2d5c77SMarek Szyprowski 11347a2d5c77SMarek Szyprowski ctx->drm_dev = drm_dev; 11358b955034SInki Dae ipp->drm_dev = drm_dev; 113629cbf24aSAndrzej Hajda exynos_drm_register_dma(drm_dev, dev); 11377a2d5c77SMarek Szyprowski 11388b955034SInki Dae exynos_drm_ipp_register(dev, ipp, &ipp_funcs, 11397a2d5c77SMarek Szyprowski DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE | 11407a2d5c77SMarek Szyprowski DRM_EXYNOS_IPP_CAP_SCALE | DRM_EXYNOS_IPP_CAP_CONVERT, 11417a2d5c77SMarek Szyprowski ctx->formats, ctx->num_formats, "fimc"); 11427a2d5c77SMarek Szyprowski 11437a2d5c77SMarek Szyprowski dev_info(dev, "The exynos fimc has been probed successfully\n"); 11447a2d5c77SMarek Szyprowski 11457a2d5c77SMarek Szyprowski return 0; 11467a2d5c77SMarek Szyprowski } 11477a2d5c77SMarek Szyprowski 11487a2d5c77SMarek Szyprowski static void fimc_unbind(struct device *dev, struct device *master, 11497a2d5c77SMarek Szyprowski void *data) 11507a2d5c77SMarek Szyprowski { 11517a2d5c77SMarek Szyprowski struct fimc_context *ctx = dev_get_drvdata(dev); 11527a2d5c77SMarek Szyprowski struct drm_device *drm_dev = data; 11537a2d5c77SMarek Szyprowski struct exynos_drm_ipp *ipp = &ctx->ipp; 11547a2d5c77SMarek Szyprowski 11558b955034SInki Dae exynos_drm_ipp_unregister(dev, ipp); 115623755696SAndrzej Hajda exynos_drm_unregister_dma(drm_dev, dev); 11577a2d5c77SMarek Szyprowski } 11587a2d5c77SMarek Szyprowski 11597a2d5c77SMarek Szyprowski static const struct component_ops fimc_component_ops = { 11607a2d5c77SMarek Szyprowski .bind = fimc_bind, 11617a2d5c77SMarek Szyprowski .unbind = fimc_unbind, 11627a2d5c77SMarek Szyprowski }; 11637a2d5c77SMarek Szyprowski 1164e5f86839SSylwester Nawrocki static void fimc_put_clocks(struct fimc_context *ctx) 1165e5f86839SSylwester Nawrocki { 1166e5f86839SSylwester Nawrocki int i; 1167e5f86839SSylwester Nawrocki 1168e5f86839SSylwester Nawrocki for (i = 0; i < FIMC_CLKS_MAX; i++) { 1169e5f86839SSylwester Nawrocki if (IS_ERR(ctx->clocks[i])) 1170e5f86839SSylwester Nawrocki continue; 1171e5f86839SSylwester Nawrocki clk_put(ctx->clocks[i]); 1172e5f86839SSylwester Nawrocki ctx->clocks[i] = ERR_PTR(-EINVAL); 1173e5f86839SSylwester Nawrocki } 1174e5f86839SSylwester Nawrocki } 1175e5f86839SSylwester Nawrocki 1176e5f86839SSylwester Nawrocki static int fimc_setup_clocks(struct fimc_context *ctx) 1177e5f86839SSylwester Nawrocki { 11787a2d5c77SMarek Szyprowski struct device *fimc_dev = ctx->dev; 1179e5f86839SSylwester Nawrocki struct device *dev; 1180e5f86839SSylwester Nawrocki int ret, i; 1181e5f86839SSylwester Nawrocki 1182e5f86839SSylwester Nawrocki for (i = 0; i < FIMC_CLKS_MAX; i++) 1183e5f86839SSylwester Nawrocki ctx->clocks[i] = ERR_PTR(-EINVAL); 1184e5f86839SSylwester Nawrocki 1185e5f86839SSylwester Nawrocki for (i = 0; i < FIMC_CLKS_MAX; i++) { 1186e5f86839SSylwester Nawrocki if (i == FIMC_CLK_WB_A || i == FIMC_CLK_WB_B) 1187e5f86839SSylwester Nawrocki dev = fimc_dev->parent; 1188e5f86839SSylwester Nawrocki else 1189e5f86839SSylwester Nawrocki dev = fimc_dev; 1190e5f86839SSylwester Nawrocki 1191e5f86839SSylwester Nawrocki ctx->clocks[i] = clk_get(dev, fimc_clock_names[i]); 1192e5f86839SSylwester Nawrocki if (IS_ERR(ctx->clocks[i])) { 1193e5f86839SSylwester Nawrocki ret = PTR_ERR(ctx->clocks[i]); 1194e5f86839SSylwester Nawrocki dev_err(fimc_dev, "failed to get clock: %s\n", 1195e5f86839SSylwester Nawrocki fimc_clock_names[i]); 1196e5f86839SSylwester Nawrocki goto e_clk_free; 1197e5f86839SSylwester Nawrocki } 1198e5f86839SSylwester Nawrocki } 1199e5f86839SSylwester Nawrocki 1200e5f86839SSylwester Nawrocki ret = clk_prepare_enable(ctx->clocks[FIMC_CLK_LCLK]); 1201e5f86839SSylwester Nawrocki if (!ret) 1202e5f86839SSylwester Nawrocki return ret; 1203e5f86839SSylwester Nawrocki e_clk_free: 1204e5f86839SSylwester Nawrocki fimc_put_clocks(ctx); 1205e5f86839SSylwester Nawrocki return ret; 1206e5f86839SSylwester Nawrocki } 1207e5f86839SSylwester Nawrocki 12087a2d5c77SMarek Szyprowski int exynos_drm_check_fimc_device(struct device *dev) 12095186fc5eSSylwester Nawrocki { 121019832055SDan Carpenter int id = of_alias_get_id(dev->of_node, "fimc"); 12115186fc5eSSylwester Nawrocki 12127a2d5c77SMarek Szyprowski if (id >= 0 && (BIT(id) & fimc_mask)) 12135186fc5eSSylwester Nawrocki return 0; 12147a2d5c77SMarek Szyprowski return -ENODEV; 12155186fc5eSSylwester Nawrocki } 12165186fc5eSSylwester Nawrocki 12177a2d5c77SMarek Szyprowski static const unsigned int fimc_formats[] = { 12187a2d5c77SMarek Szyprowski DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565, 12197a2d5c77SMarek Szyprowski DRM_FORMAT_NV12, DRM_FORMAT_NV16, DRM_FORMAT_NV21, DRM_FORMAT_NV61, 12207a2d5c77SMarek Szyprowski DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU, 12217a2d5c77SMarek Szyprowski DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422, 12227a2d5c77SMarek Szyprowski DRM_FORMAT_YUV444, 12237a2d5c77SMarek Szyprowski }; 12247a2d5c77SMarek Szyprowski 12257a2d5c77SMarek Szyprowski static const unsigned int fimc_tiled_formats[] = { 12267a2d5c77SMarek Szyprowski DRM_FORMAT_NV12, DRM_FORMAT_NV21, 12277a2d5c77SMarek Szyprowski }; 12287a2d5c77SMarek Szyprowski 12297a2d5c77SMarek Szyprowski static const struct drm_exynos_ipp_limit fimc_4210_limits_v1[] = { 12307a2d5c77SMarek Szyprowski { IPP_SIZE_LIMIT(BUFFER, .h = { 16, 8192, 8 }, .v = { 16, 8192, 2 }) }, 12317a2d5c77SMarek Szyprowski { IPP_SIZE_LIMIT(AREA, .h = { 16, 4224, 2 }, .v = { 16, 0, 2 }) }, 12327a2d5c77SMarek Szyprowski { IPP_SIZE_LIMIT(ROTATED, .h = { 128, 1920 }, .v = { 128, 0 }) }, 12337a2d5c77SMarek Szyprowski { IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 }, 12347a2d5c77SMarek Szyprowski .v = { (1 << 16) / 64, (1 << 16) * 64 }) }, 12357a2d5c77SMarek Szyprowski }; 12367a2d5c77SMarek Szyprowski 12377a2d5c77SMarek Szyprowski static const struct drm_exynos_ipp_limit fimc_4210_limits_v2[] = { 12387a2d5c77SMarek Szyprowski { IPP_SIZE_LIMIT(BUFFER, .h = { 16, 8192, 8 }, .v = { 16, 8192, 2 }) }, 12397a2d5c77SMarek Szyprowski { IPP_SIZE_LIMIT(AREA, .h = { 16, 1920, 2 }, .v = { 16, 0, 2 }) }, 12407a2d5c77SMarek Szyprowski { IPP_SIZE_LIMIT(ROTATED, .h = { 128, 1366 }, .v = { 128, 0 }) }, 12417a2d5c77SMarek Szyprowski { IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 }, 12427a2d5c77SMarek Szyprowski .v = { (1 << 16) / 64, (1 << 16) * 64 }) }, 12437a2d5c77SMarek Szyprowski }; 12447a2d5c77SMarek Szyprowski 12457a2d5c77SMarek Szyprowski static const struct drm_exynos_ipp_limit fimc_4210_limits_tiled_v1[] = { 12467a2d5c77SMarek Szyprowski { IPP_SIZE_LIMIT(BUFFER, .h = { 128, 1920, 128 }, .v = { 32, 1920, 32 }) }, 12477a2d5c77SMarek Szyprowski { IPP_SIZE_LIMIT(AREA, .h = { 128, 1920, 2 }, .v = { 128, 0, 2 }) }, 12487a2d5c77SMarek Szyprowski { IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 }, 12497a2d5c77SMarek Szyprowski .v = { (1 << 16) / 64, (1 << 16) * 64 }) }, 12507a2d5c77SMarek Szyprowski }; 12517a2d5c77SMarek Szyprowski 12527a2d5c77SMarek Szyprowski static const struct drm_exynos_ipp_limit fimc_4210_limits_tiled_v2[] = { 12537a2d5c77SMarek Szyprowski { IPP_SIZE_LIMIT(BUFFER, .h = { 128, 1920, 128 }, .v = { 32, 1920, 32 }) }, 12547a2d5c77SMarek Szyprowski { IPP_SIZE_LIMIT(AREA, .h = { 128, 1366, 2 }, .v = { 128, 0, 2 }) }, 12557a2d5c77SMarek Szyprowski { IPP_SCALE_LIMIT(.h = { (1 << 16) / 64, (1 << 16) * 64 }, 12567a2d5c77SMarek Szyprowski .v = { (1 << 16) / 64, (1 << 16) * 64 }) }, 12577a2d5c77SMarek Szyprowski }; 12587a2d5c77SMarek Szyprowski 125956550d94SGreg Kroah-Hartman static int fimc_probe(struct platform_device *pdev) 126016102edbSEunchul Kim { 12617a2d5c77SMarek Szyprowski const struct drm_exynos_ipp_limit *limits; 12627a2d5c77SMarek Szyprowski struct exynos_drm_ipp_formats *formats; 126316102edbSEunchul Kim struct device *dev = &pdev->dev; 126416102edbSEunchul Kim struct fimc_context *ctx; 126516102edbSEunchul Kim struct resource *res; 126616102edbSEunchul Kim int ret; 12677a2d5c77SMarek Szyprowski int i, j, num_limits, num_formats; 126816102edbSEunchul Kim 12697a2d5c77SMarek Szyprowski if (exynos_drm_check_fimc_device(dev) != 0) 12705186fc5eSSylwester Nawrocki return -ENODEV; 127116102edbSEunchul Kim 127216102edbSEunchul Kim ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 127316102edbSEunchul Kim if (!ctx) 127416102edbSEunchul Kim return -ENOMEM; 127516102edbSEunchul Kim 12767a2d5c77SMarek Szyprowski ctx->dev = dev; 12777a2d5c77SMarek Szyprowski ctx->id = of_alias_get_id(dev->of_node, "fimc"); 12785186fc5eSSylwester Nawrocki 12797a2d5c77SMarek Szyprowski /* construct formats/limits array */ 12807a2d5c77SMarek Szyprowski num_formats = ARRAY_SIZE(fimc_formats) + ARRAY_SIZE(fimc_tiled_formats); 1281a86854d0SKees Cook formats = devm_kcalloc(dev, num_formats, sizeof(*formats), 1282a86854d0SKees Cook GFP_KERNEL); 12837a2d5c77SMarek Szyprowski if (!formats) 12847a2d5c77SMarek Szyprowski return -ENOMEM; 12855186fc5eSSylwester Nawrocki 12867a2d5c77SMarek Szyprowski /* linear formats */ 12877a2d5c77SMarek Szyprowski if (ctx->id < 3) { 12887a2d5c77SMarek Szyprowski limits = fimc_4210_limits_v1; 12897a2d5c77SMarek Szyprowski num_limits = ARRAY_SIZE(fimc_4210_limits_v1); 12907a2d5c77SMarek Szyprowski } else { 12917a2d5c77SMarek Szyprowski limits = fimc_4210_limits_v2; 12927a2d5c77SMarek Szyprowski num_limits = ARRAY_SIZE(fimc_4210_limits_v2); 12935186fc5eSSylwester Nawrocki } 12947a2d5c77SMarek Szyprowski for (i = 0; i < ARRAY_SIZE(fimc_formats); i++) { 12957a2d5c77SMarek Szyprowski formats[i].fourcc = fimc_formats[i]; 12967a2d5c77SMarek Szyprowski formats[i].type = DRM_EXYNOS_IPP_FORMAT_SOURCE | 12977a2d5c77SMarek Szyprowski DRM_EXYNOS_IPP_FORMAT_DESTINATION; 12987a2d5c77SMarek Szyprowski formats[i].limits = limits; 12997a2d5c77SMarek Szyprowski formats[i].num_limits = num_limits; 13007a2d5c77SMarek Szyprowski } 13017a2d5c77SMarek Szyprowski 13027a2d5c77SMarek Szyprowski /* tiled formats */ 13037a2d5c77SMarek Szyprowski if (ctx->id < 3) { 13047a2d5c77SMarek Szyprowski limits = fimc_4210_limits_tiled_v1; 13057a2d5c77SMarek Szyprowski num_limits = ARRAY_SIZE(fimc_4210_limits_tiled_v1); 13067a2d5c77SMarek Szyprowski } else { 13077a2d5c77SMarek Szyprowski limits = fimc_4210_limits_tiled_v2; 13087a2d5c77SMarek Szyprowski num_limits = ARRAY_SIZE(fimc_4210_limits_tiled_v2); 13097a2d5c77SMarek Szyprowski } 13107a2d5c77SMarek Szyprowski for (j = i, i = 0; i < ARRAY_SIZE(fimc_tiled_formats); j++, i++) { 13117a2d5c77SMarek Szyprowski formats[j].fourcc = fimc_tiled_formats[i]; 13127a2d5c77SMarek Szyprowski formats[j].modifier = DRM_FORMAT_MOD_SAMSUNG_64_32_TILE; 13137a2d5c77SMarek Szyprowski formats[j].type = DRM_EXYNOS_IPP_FORMAT_SOURCE | 13147a2d5c77SMarek Szyprowski DRM_EXYNOS_IPP_FORMAT_DESTINATION; 13157a2d5c77SMarek Szyprowski formats[j].limits = limits; 13167a2d5c77SMarek Szyprowski formats[j].num_limits = num_limits; 13177a2d5c77SMarek Szyprowski } 13187a2d5c77SMarek Szyprowski 13197a2d5c77SMarek Szyprowski ctx->formats = formats; 13207a2d5c77SMarek Szyprowski ctx->num_formats = num_formats; 13215186fc5eSSylwester Nawrocki 132216102edbSEunchul Kim /* resource memory */ 132316102edbSEunchul Kim ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1324d4ed6025SThierry Reding ctx->regs = devm_ioremap_resource(dev, ctx->regs_res); 1325d4ed6025SThierry Reding if (IS_ERR(ctx->regs)) 1326d4ed6025SThierry Reding return PTR_ERR(ctx->regs); 132716102edbSEunchul Kim 132816102edbSEunchul Kim /* resource irq */ 132916102edbSEunchul Kim res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 133016102edbSEunchul Kim if (!res) { 133116102edbSEunchul Kim dev_err(dev, "failed to request irq resource.\n"); 133215b3263eSSachin Kamat return -ENOENT; 133316102edbSEunchul Kim } 133416102edbSEunchul Kim 13357a2d5c77SMarek Szyprowski ret = devm_request_irq(dev, res->start, fimc_irq_handler, 13367a2d5c77SMarek Szyprowski 0, dev_name(dev), ctx); 133716102edbSEunchul Kim if (ret < 0) { 133816102edbSEunchul Kim dev_err(dev, "failed to request irq.\n"); 133915b3263eSSachin Kamat return ret; 134016102edbSEunchul Kim } 134116102edbSEunchul Kim 1342e5f86839SSylwester Nawrocki ret = fimc_setup_clocks(ctx); 1343e5f86839SSylwester Nawrocki if (ret < 0) 1344dcb9a7c7SSeung-Woo Kim return ret; 134516102edbSEunchul Kim 134672d465aaSAndrzej Hajda spin_lock_init(&ctx->lock); 134716102edbSEunchul Kim platform_set_drvdata(pdev, ctx); 134816102edbSEunchul Kim 13497a2d5c77SMarek Szyprowski pm_runtime_use_autosuspend(dev); 13507a2d5c77SMarek Szyprowski pm_runtime_set_autosuspend_delay(dev, FIMC_AUTOSUSPEND_DELAY); 135116102edbSEunchul Kim pm_runtime_enable(dev); 135216102edbSEunchul Kim 13537a2d5c77SMarek Szyprowski ret = component_add(dev, &fimc_component_ops); 13547a2d5c77SMarek Szyprowski if (ret) 1355e5f86839SSylwester Nawrocki goto err_pm_dis; 135616102edbSEunchul Kim 1357d873ab99SSeung-Woo Kim dev_info(dev, "drm fimc registered successfully.\n"); 135816102edbSEunchul Kim 135916102edbSEunchul Kim return 0; 136016102edbSEunchul Kim 1361e5f86839SSylwester Nawrocki err_pm_dis: 13627a2d5c77SMarek Szyprowski pm_runtime_dont_use_autosuspend(dev); 136316102edbSEunchul Kim pm_runtime_disable(dev); 1364e5f86839SSylwester Nawrocki fimc_put_clocks(ctx); 136587acdde5SSachin Kamat 136616102edbSEunchul Kim return ret; 136716102edbSEunchul Kim } 136816102edbSEunchul Kim 136956550d94SGreg Kroah-Hartman static int fimc_remove(struct platform_device *pdev) 137016102edbSEunchul Kim { 137116102edbSEunchul Kim struct device *dev = &pdev->dev; 137216102edbSEunchul Kim struct fimc_context *ctx = get_fimc_context(dev); 137316102edbSEunchul Kim 13747a2d5c77SMarek Szyprowski component_del(dev, &fimc_component_ops); 13757a2d5c77SMarek Szyprowski pm_runtime_dont_use_autosuspend(dev); 13767a2d5c77SMarek Szyprowski pm_runtime_disable(dev); 137716102edbSEunchul Kim 1378e5f86839SSylwester Nawrocki fimc_put_clocks(ctx); 137916102edbSEunchul Kim 138016102edbSEunchul Kim return 0; 138116102edbSEunchul Kim } 138216102edbSEunchul Kim 1383641a2fefSThierry Reding #ifdef CONFIG_PM 138416102edbSEunchul Kim static int fimc_runtime_suspend(struct device *dev) 138516102edbSEunchul Kim { 138616102edbSEunchul Kim struct fimc_context *ctx = get_fimc_context(dev); 138716102edbSEunchul Kim 13886be90056SInki Dae DRM_DEV_DEBUG_KMS(dev, "id[%d]\n", ctx->id); 13897a2d5c77SMarek Szyprowski clk_disable_unprepare(ctx->clocks[FIMC_CLK_GATE]); 13907a2d5c77SMarek Szyprowski return 0; 139116102edbSEunchul Kim } 139216102edbSEunchul Kim 139316102edbSEunchul Kim static int fimc_runtime_resume(struct device *dev) 139416102edbSEunchul Kim { 139516102edbSEunchul Kim struct fimc_context *ctx = get_fimc_context(dev); 139616102edbSEunchul Kim 13976be90056SInki Dae DRM_DEV_DEBUG_KMS(dev, "id[%d]\n", ctx->id); 13987a2d5c77SMarek Szyprowski return clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]); 139916102edbSEunchul Kim } 140016102edbSEunchul Kim #endif 140116102edbSEunchul Kim 140216102edbSEunchul Kim static const struct dev_pm_ops fimc_pm_ops = { 1403479f1254SMarek Szyprowski SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 1404479f1254SMarek Szyprowski pm_runtime_force_resume) 140516102edbSEunchul Kim SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL) 140616102edbSEunchul Kim }; 140716102edbSEunchul Kim 14085186fc5eSSylwester Nawrocki static const struct of_device_id fimc_of_match[] = { 14095186fc5eSSylwester Nawrocki { .compatible = "samsung,exynos4210-fimc" }, 14105186fc5eSSylwester Nawrocki { .compatible = "samsung,exynos4212-fimc" }, 14115186fc5eSSylwester Nawrocki { }, 14125186fc5eSSylwester Nawrocki }; 141339b58a39SSjoerd Simons MODULE_DEVICE_TABLE(of, fimc_of_match); 14145186fc5eSSylwester Nawrocki 141516102edbSEunchul Kim struct platform_driver fimc_driver = { 141616102edbSEunchul Kim .probe = fimc_probe, 141756550d94SGreg Kroah-Hartman .remove = fimc_remove, 141816102edbSEunchul Kim .driver = { 14195186fc5eSSylwester Nawrocki .of_match_table = fimc_of_match, 142016102edbSEunchul Kim .name = "exynos-drm-fimc", 142116102edbSEunchul Kim .owner = THIS_MODULE, 142216102edbSEunchul Kim .pm = &fimc_pm_ops, 142316102edbSEunchul Kim }, 142416102edbSEunchul Kim }; 1425