OK, I know what you mean. I talk about GSC feature with Inki.Dae. I will re-send our final source instead of first commit. please one more time review about next RFC v3.
Thank's BR Eunchul Kim On 12/11/2012 05:31 PM, Joonyoung Shim wrote: > Hi, > > I want to see only just current codes, not for future. > > > On 12/11/2012 04:47 PM, Eunchul Kim wrote: >> Thank's your comments >> >> I answer your comments. please check that. >> >> Thank's >> >> BR >> >> Eunchul Kim >> >> On 12/11/2012 02:49 PM, Joonyoung Shim wrote: >>> Hi, >>> >>> On 12/10/2012 10:45 PM, Eunchul Kim wrote: >>>> GSC is stand for General SCaler and supports supports >>>> image scaler/rotator/crop/flip/csc and input/output DMA operations. >>>> input DMA reads image data from the memory. >>>> output DMA writes image data to memory. >>>> GSC supports image rotation and imag effect functions, also supports >>>> writeback and display output operations. >>>> >>> >>> Please align lines in paragraph. >> >> - like this ? "GSC supports image rotation and imag effect functions, >> also supports writeback and display output operations." >> > > You can get follow result if you use vi when you make commit using "git > commit -s" > > GSC is stand for General SCaler and supports supports image > scaler/rotator/crop/flip/csc and input/output DMA operations. input DMA > reads image data from the memory. output DMA writes image data to > memory. GSC supports image rotation and imag effect functions, also > supports writeback and display output operations. - I will check that. > >>> >>>> >>>> Signed-off-by: Eunchul Kim <chulspro.kim at samsung.com> >>>> Signed-off-by: Jinyoung Jeon <jy0.jeon at samsung.com> >>>> --- >>>> drivers/gpu/drm/exynos/Kconfig | 5 + >>>> drivers/gpu/drm/exynos/Makefile | 1 + >>>> drivers/gpu/drm/exynos/exynos_drm_drv.c | 15 + >>>> drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 + >>>> drivers/gpu/drm/exynos/exynos_drm_gsc.c | 1476 >>>> +++++++++++++++++++++++++++++++ >>>> drivers/gpu/drm/exynos/exynos_drm_gsc.h | 35 + >>>> drivers/gpu/drm/exynos/regs-gsc.h | 295 ++++++ >>>> include/drm/exynos_drm.h | 15 + >>>> 8 files changed, 1843 insertions(+), 0 deletions(-) >>>> create mode 100644 drivers/gpu/drm/exynos/exynos_drm_gsc.c >>>> create mode 100644 drivers/gpu/drm/exynos/exynos_drm_gsc.h >>>> create mode 100644 drivers/gpu/drm/exynos/regs-gsc.h >>>> >>>> diff --git a/drivers/gpu/drm/exynos/Kconfig >>>> b/drivers/gpu/drm/exynos/Kconfig >>>> index 4860835..c93d776 100644 >>>> --- a/drivers/gpu/drm/exynos/Kconfig >>>> +++ b/drivers/gpu/drm/exynos/Kconfig >>>> @@ -64,3 +64,8 @@ config DRM_EXYNOS_ROTATOR >>>> help >>>> Choose this option if you want to use Exynos Rotator for DRM. >>>> +config DRM_EXYNOS_GSC >>>> + bool "Exynos DRM GSC" >>>> + depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 >>>> + help >>>> + Choose this option if you want to use Exynos GSC for DRM. >>>> diff --git a/drivers/gpu/drm/exynos/Makefile >>>> b/drivers/gpu/drm/exynos/Makefile >>>> index 3b70668..639b49e 100644 >>>> --- a/drivers/gpu/drm/exynos/Makefile >>>> +++ b/drivers/gpu/drm/exynos/Makefile >>>> @@ -19,5 +19,6 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += >>>> exynos_drm_g2d.o >>>> exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o >>>> exynosdrm-$(CONFIG_DRM_EXYNOS_FIMC) += exynos_drm_fimc.o >>>> exynosdrm-$(CONFIG_DRM_EXYNOS_ROTATOR) += exynos_drm_rotator.o >>>> +exynosdrm-$(CONFIG_DRM_EXYNOS_GSC) += exynos_drm_gsc.o >>>> obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o >>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c >>>> b/drivers/gpu/drm/exynos/exynos_drm_drv.c >>>> index 09d884b..e0a8e80 100644 >>>> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c >>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c >>>> @@ -384,6 +384,12 @@ static int __init exynos_drm_init(void) >>>> goto out_rotator; >>>> #endif >>>> +#ifdef CONFIG_DRM_EXYNOS_GSC >>>> + ret = platform_driver_register(&gsc_driver); >>>> + if (ret < 0) >>>> + goto out_gsc; >>>> +#endif >>>> + >>>> #ifdef CONFIG_DRM_EXYNOS_IPP >>>> ret = platform_driver_register(&ipp_driver); >>>> if (ret < 0) >>>> @@ -412,6 +418,11 @@ out_drm: >>>> out_ipp: >>>> #endif >>>> +#ifdef CONFIG_DRM_EXYNOS_GSC >>>> + platform_driver_unregister(&gsc_driver); >>>> +out_gsc: >>>> +#endif >>>> + >>>> #ifdef CONFIG_DRM_EXYNOS_ROTATOR >>>> platform_driver_unregister(&rotator_driver); >>>> out_rotator: >>>> @@ -462,6 +473,10 @@ static void __exit exynos_drm_exit(void) >>>> platform_driver_unregister(&ipp_driver); >>>> #endif >>>> +#ifdef CONFIG_DRM_EXYNOS_GSC >>>> + platform_driver_unregister(&gsc_driver); >>>> +#endif >>>> + >>>> #ifdef CONFIG_DRM_EXYNOS_ROTATOR >>>> platform_driver_unregister(&rotator_driver); >>>> #endif >>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h >>>> b/drivers/gpu/drm/exynos/exynos_drm_drv.h >>>> index a74e37c..afe556c 100644 >>>> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h >>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h >>>> @@ -354,5 +354,6 @@ extern struct platform_driver vidi_driver; >>>> extern struct platform_driver g2d_driver; >>>> extern struct platform_driver fimc_driver; >>>> extern struct platform_driver rotator_driver; >>>> +extern struct platform_driver gsc_driver; >>>> extern struct platform_driver ipp_driver; >>>> #endif >>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c >>>> b/drivers/gpu/drm/exynos/exynos_drm_gsc.c >>>> new file mode 100644 >>>> index 0000000..614365e >>>> --- /dev/null >>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c >>>> @@ -0,0 +1,1476 @@ >>>> +/* >>>> + * Copyright (C) 2012 Samsung Electronics Co.Ltd >>>> + * Authors: >>>> + * Eunchul Kim <chulspro.kim at samsung.com> >>>> + * Jinyoung Jeon <jy0.jeon at samsung.com> >>>> + * Sangmin Lee <lsmin.lee at 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/module.h> >>>> +#include <linux/platform_device.h> >>>> +#include <linux/clk.h> >>>> +#include <linux/pm_runtime.h> >>>> +#include <plat/map-base.h> >>>> + >>>> +#include <drm/drmP.h> >>>> +#include <drm/exynos_drm.h> >>>> +#include "regs-gsc.h" >>>> +#include "exynos_drm_drv.h" >>>> +#include "exynos_drm_gem.h" >>> >>> Does this driver need to include exynos_drm_drv.h and exynos_drm_gem.h? >> >> - No need. I removed it(fimc, gsc, rotator, sc). >> >>> >>>> +#include "exynos_drm_ipp.h" >>>> +#include "exynos_drm_gsc.h" >>>> + >>>> +/* >>>> + * GSC is stand for General SCaler and >>>> + * supports image scaler/rotator and input/output DMA operations. >>>> + * input DMA reads image data from the memory. >>>> + * output DMA writes image data to memory. >>>> + * GSC supports image rotation and image effect functions. >>>> + */ >>>> + >>>> +#define GSC_MAX_DEVS 4 >>>> +#define GSC_MAX_SRC 8 >>>> +#define GSC_MAX_DST 32 >>>> +#define GSC_RESET_TIMEOUT 50 >>>> +#define GSC_CLK_RATE 166750000 >>>> +#define GSC_BUF_STOP 1 >>>> +#define GSC_BUF_START 2 >>>> +#define GSC_REG_SZ 32 >>>> +#define GSC_WIDTH_ITU_709 1280 >>>> + >>>> +#define get_gsc_context(dev) >>>> platform_get_drvdata(to_platform_device(dev)) >>>> +#define get_ctx_from_ippdrv(ippdrv) container_of(ippdrv,\ >>>> + struct gsc_context, ippdrv); >>>> +#define gsc_read(offset) readl(ctx->regs + (offset)); >>>> +#define gsc_write(cfg, offset) writel(cfg, ctx->regs + (offset)); >>>> + >>>> +enum gsc_wb { >>>> + GSC_WB_NONE, >>>> + GSC_WB_A, >>>> + GSC_WB_B, >>>> +}; >>>> + >>> >>> Is this enum used? >> >> - No need. remove it. >> >>> >>>> +/* >>>> + * A structure of scaler. >>>> + * >>>> + * @range: narrow, wide. >>>> + * @pre_shfactor: pre sclaer shift factor. >>>> + * @pre_hratio: horizontal ratio of the prescaler. >>>> + * @pre_vratio: vertical ratio of the prescaler. >>>> + * @main_hratio: the main scaler's horizontal ratio. >>>> + * @main_vratio: the main scaler's vertical ratio. >>>> + */ >>>> +struct gsc_scaler { >>>> + bool range; >>>> + u32 pre_shfactor; >>>> + u32 pre_hratio; >>>> + u32 pre_vratio; >>>> + unsigned long main_hratio; >>>> + unsigned long main_vratio; >>>> +}; >>>> + >>>> +/* >>>> + * A structure of scaler capability. >>>> + * >>>> + * find user manual 49.2 features. >>>> + * @tile_w: tile mode or rotation width. >>>> + * @tile_h: tile mode or rotation height. >>>> + * @w: other cases width. >>>> + * @h: other cases height. >>>> + */ >>>> +struct gsc_capability { >>>> + /* tile or rotation */ >>>> + u32 tile_w; >>>> + u32 tile_h; >>>> + /* other cases */ >>>> + u32 w; >>>> + u32 h; >>>> +}; >>>> + >>>> +/* >>>> + * A structure of gsc context. >>>> + * >>>> + * @ippdrv: prepare initialization using ippdrv. >>>> + * @regs_res: register resources. >>>> + * @regs: memory mapped io registers. >>>> + * @lock: locking of operations. >>>> + * @gsc_clk: gsc clock. >>>> + * @sc: scaler infomations. >>>> + * @capa: scaler capability. >>>> + * @id: gsc id. >>>> + * @irq: irq number. >>>> + * @suspended: qos operations. >>>> + */ >>>> +struct gsc_context { >>>> + struct exynos_drm_ippdrv ippdrv; >>>> + struct resource *regs_res; >>>> + void __iomem *regs; >>>> + spinlock_t lock; >>>> + struct clk *gsc_clk; >>>> + struct gsc_scaler sc; >>>> + struct gsc_capability *capa; >>>> + int id; >>>> + int irq; >>>> + bool suspended; >>>> +}; >>>> + >>>> +struct gsc_capability gsc51_capa[GSC_MAX_DEVS] = { >>> >>> static const? >> >> - done. >> >>> >>>> + { >>>> + .tile_w = 2048, >>>> + .tile_h = 2048, >>>> + .w = 4800, >>>> + .h = 3344, >>>> + }, { >>>> + .tile_w = 2048, >>>> + .tile_h = 2048, >>>> + .w = 4800, >>>> + .h = 3344, >>>> + }, { >>>> + .tile_w = 2048, >>>> + .tile_h = 2048, >>>> + .w = 4800, >>>> + .h = 3344, >>>> + }, { >>>> + .tile_w = 2048, >>>> + .tile_h = 2048, >>>> + .w = 4800, >>>> + .h = 3344, >>>> + }, >>>> +}; >>> >>> All have same values. Meaningful? >> >> - GSC case no need. combine it. >> >>> >>>> + >>>> +static int gsc_sw_reset(struct gsc_context *ctx) >>>> +{ >>>> + u32 cfg; >>>> + int count = GSC_RESET_TIMEOUT; >>>> + >>>> + DRM_DEBUG_KMS("%s\n", __func__); >>>> + >>>> + /* s/w reset */ >>>> + cfg = (GSC_SW_RESET_SRESET); >>>> + gsc_write(cfg, GSC_SW_RESET); >>>> + >>>> + /* wait s/w reset complete */ >>>> + while (count--) { >>>> + cfg = gsc_read(GSC_SW_RESET); >>>> + if (!cfg) >>>> + break; >>>> + usleep_range(1000, 2000); >>>> + } >>>> + >>>> + if (cfg) { >>>> + DRM_ERROR("failed to reset gsc h/w.\n"); >>>> + return -EBUSY; >>>> + } >>>> + >>>> + /* display fifo reset */ >>>> + cfg = readl(SYSREG_GSCBLK_CFG0); >>>> + /* >>>> + * GSCBLK Pixel asyncy FIFO S/W reset sequence >>>> + * set PXLASYNC_SW_RESET as 0 then, >>>> + * set PXLASYNC_SW_RESET as 1 again >>>> + */ >>>> + cfg &= ~GSC_PXLASYNC_RST(ctx->id); >>>> + writel(cfg, SYSREG_GSCBLK_CFG0); >>>> + cfg |= GSC_PXLASYNC_RST(ctx->id); >>>> + writel(cfg, SYSREG_GSCBLK_CFG0); >>>> + >>>> + /* pixel async reset */ >>>> + cfg = readl(SYSREG_DISP1BLK_CFG); >>>> + /* >>>> + * DISPBLK1 FIFO S/W reset sequence >>>> + * set FIFORST_DISP1 as 0 then, >>>> + * set FIFORST_DISP1 as 1 again >>>> + */ >>>> + cfg &= ~FIFORST_DISP1; >>>> + writel(cfg, SYSREG_DISP1BLK_CFG); >>>> + cfg |= FIFORST_DISP1; >>>> + writel(cfg, SYSREG_DISP1BLK_CFG); >>>> + >>>> + /* reset sequence */ >>>> + cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK); >>>> + cfg |= (GSC_IN_BASE_ADDR_MASK | >>>> + GSC_IN_BASE_ADDR_PINGPONG(0)); >>>> + gsc_write(cfg, GSC_IN_BASE_ADDR_Y_MASK); >>>> + gsc_write(cfg, GSC_IN_BASE_ADDR_CB_MASK); >>>> + gsc_write(cfg, GSC_IN_BASE_ADDR_CR_MASK); >>>> + >>>> + cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK); >>>> + cfg |= (GSC_OUT_BASE_ADDR_MASK | >>>> + GSC_OUT_BASE_ADDR_PINGPONG(0)); >>>> + gsc_write(cfg, GSC_OUT_BASE_ADDR_Y_MASK); >>>> + gsc_write(cfg, GSC_OUT_BASE_ADDR_CB_MASK); >>>> + gsc_write(cfg, GSC_OUT_BASE_ADDR_CR_MASK); >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static void gsc_set_gscblk_fimd_wb(struct gsc_context *ctx, bool >>>> enable) >>>> +{ >>>> + u32 gscblk_cfg; >>>> + >>>> + DRM_DEBUG_KMS("%s\n", __func__); >>>> + >>>> + gscblk_cfg = readl(SYSREG_GSCBLK_CFG1); >>>> + >>>> + if (enable) >>>> + gscblk_cfg |= GSC_BLK_DISP1WB_DEST(ctx->id) | >>>> + GSC_BLK_GSCL_WB_IN_SRC_SEL(ctx->id) | >>>> + GSC_BLK_SW_RESET_WB_DEST(ctx->id); >>>> + else >>>> + gscblk_cfg |= GSC_BLK_PXLASYNC_LO_MASK_WB(ctx->id); >>>> + >>>> + writel(gscblk_cfg, SYSREG_GSCBLK_CFG1); >>>> +} >>>> + >>>> +static void gsc_handle_irq(struct gsc_context *ctx, bool enable, >>>> + bool overflow, bool done) >>>> +{ >>>> + u32 cfg; >>>> + >>>> + DRM_DEBUG_KMS("%s:enable[%d]overflow[%d]level[%d]\n", __func__, >>>> + enable, overflow, done); >>>> + >>>> + cfg = gsc_read(GSC_IRQ); >>>> + cfg |= (GSC_IRQ_OR_MASK | GSC_IRQ_FRMDONE_MASK); >>>> + >>>> + if (enable) { >>>> + cfg |= GSC_IRQ_ENABLE; >>>> + if (overflow) >>>> + cfg &= ~GSC_IRQ_OR_MASK; >>>> + if (done) >>>> + cfg &= ~GSC_IRQ_FRMDONE_MASK; >>>> + } else >>>> + cfg &= ~GSC_IRQ_ENABLE; >>>> + >>>> + gsc_write(cfg, GSC_IRQ); >>>> +} >>> >>> Are there other cases overflow is true or done is false? This driver >>> uses this function only for enable argument. Please don't make >>> unnecessary function. >> >> - yes, I already seperated this function in our local git. >> I will send patch commit. we seperated all case. >> >>> >>>> + >>>> + >>>> +static int gsc_src_set_fmt(struct device *dev, u32 fmt) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; >>>> + u32 cfg; >>>> + >>>> + DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt); >>>> + >>>> + cfg = gsc_read(GSC_IN_CON); >>>> + cfg &= ~(GSC_IN_RGB_TYPE_MASK | GSC_IN_YUV422_1P_ORDER_MASK | >>>> + GSC_IN_CHROMA_ORDER_MASK | GSC_IN_FORMAT_MASK | >>>> + GSC_IN_TILE_TYPE_MASK | GSC_IN_TILE_MODE); >>>> + >>>> + switch (fmt) { >>>> + case DRM_FORMAT_RGB565: >>>> + cfg |= GSC_IN_RGB565; >>>> + break; >>>> + case DRM_FORMAT_XRGB8888: >>>> + cfg |= GSC_IN_XRGB8888; >>>> + break; >>>> + case DRM_FORMAT_YUYV: >>>> + cfg |= (GSC_IN_YUV422_1P | >>>> + GSC_IN_YUV422_1P_ORDER_LSB_Y | >>>> + GSC_IN_CHROMA_ORDER_CBCR); >>>> + break; >>>> + case DRM_FORMAT_YVYU: >>>> + cfg |= (GSC_IN_YUV422_1P | >>>> + GSC_IN_YUV422_1P_ORDER_LSB_Y | >>>> + GSC_IN_CHROMA_ORDER_CRCB); >>>> + break; >>>> + case DRM_FORMAT_UYVY: >>>> + cfg |= (GSC_IN_YUV422_1P | >>>> + GSC_IN_YUV422_1P_OEDER_LSB_C | >>>> + GSC_IN_CHROMA_ORDER_CBCR); >>>> + break; >>>> + case DRM_FORMAT_VYUY: >>>> + cfg |= (GSC_IN_YUV422_1P | >>>> + GSC_IN_YUV422_1P_OEDER_LSB_C | >>>> + GSC_IN_CHROMA_ORDER_CRCB); >>>> + break; >>>> + case DRM_FORMAT_NV21: >>>> + case DRM_FORMAT_NV61: >>>> + cfg |= (GSC_IN_CHROMA_ORDER_CRCB | >>>> + GSC_IN_YUV420_2P); >>>> + break; >>>> + case DRM_FORMAT_YUV422: >>>> + cfg |= GSC_IN_YUV422_3P; >>>> + break; >>>> + case DRM_FORMAT_YUV420: >>>> + case DRM_FORMAT_YVU420: >>>> + cfg |= GSC_IN_YUV420_3P; >>>> + break; >>>> + case DRM_FORMAT_NV12: >>>> + case DRM_FORMAT_NV16: >>>> + cfg |= (GSC_IN_CHROMA_ORDER_CBCR | >>>> + GSC_IN_YUV420_2P); >>>> + break; >>>> + case DRM_FORMAT_NV12MT: >>>> + cfg |= (GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE); >>>> + break; >>>> + default: >>>> + dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt); >>>> + return -EINVAL; >>>> + } >>>> + >>>> + gsc_write(cfg, GSC_IN_CON); >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static int gsc_src_set_transf(struct device *dev, >>>> + enum drm_exynos_degree degree, >>>> + enum drm_exynos_flip flip) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; >>>> + u32 cfg; >>>> + >>>> + DRM_DEBUG_KMS("%s:degree[%d]flip[0x%x]\n", __func__, >>>> + degree, flip); >>>> + >>>> + cfg = gsc_read(GSC_IN_CON); >>>> + cfg &= ~GSC_IN_ROT_MASK; >>>> + >>>> + switch (degree) { >>>> + case EXYNOS_DRM_DEGREE_0: >>>> + if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) >>>> + cfg |= GSC_IN_ROT_XFLIP; >>>> + if (flip & EXYNOS_DRM_FLIP_VERTICAL) >>>> + cfg |= GSC_IN_ROT_YFLIP; >>>> + break; >>>> + case EXYNOS_DRM_DEGREE_90: >>>> + if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) >>>> + cfg |= GSC_IN_ROT_90_XFLIP; >>>> + else if (flip & EXYNOS_DRM_FLIP_VERTICAL) >>>> + cfg |= GSC_IN_ROT_90_YFLIP; >>>> + else >>>> + cfg |= GSC_IN_ROT_90; >>>> + break; >>>> + case EXYNOS_DRM_DEGREE_180: >>>> + cfg |= GSC_IN_ROT_180; >>>> + break; >>>> + case EXYNOS_DRM_DEGREE_270: >>>> + cfg |= GSC_IN_ROT_270; >>>> + break; >>>> + default: >>>> + dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); >>>> + return -EINVAL; >>>> + } >>>> + >>>> + gsc_write(cfg, GSC_IN_CON); >>>> + >>>> + return cfg ? 1 : 0; >>>> +} >>>> + >>>> +static int gsc_src_set_size(struct device *dev, int swap, >>>> + struct drm_exynos_pos *pos, struct drm_exynos_sz *sz) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + struct drm_exynos_pos img_pos = *pos; >>>> + struct drm_exynos_sz img_sz = *sz; >>>> + u32 cfg; >>>> + >>>> + /* ToDo: check width and height */ >>> >>> Please remove this comment. If needs, implement now. >> >> - remove it, no need - we already have check_property. >> >>> >>>> + if (swap) { >>>> + img_pos.w = pos->h; >>>> + img_pos.h = pos->w; >>>> + img_sz.hsize = sz->vsize; >>>> + img_sz.vsize = sz->hsize; >>>> + } >>>> + >>>> + DRM_DEBUG_KMS("%s:x[%d]y[%d]w[%d]h[%d]\n", >>>> + __func__, pos->x, pos->y, pos->w, pos->h); >>>> + >>>> + /* pixel offset */ >>>> + cfg = (GSC_SRCIMG_OFFSET_X(img_pos.x) | >>>> + GSC_SRCIMG_OFFSET_Y(img_pos.y)); >>>> + gsc_write(cfg, GSC_SRCIMG_OFFSET); >>>> + >>>> + /* cropped size */ >>>> + cfg = (GSC_CROPPED_WIDTH(img_pos.w) | >>>> + GSC_CROPPED_HEIGHT(img_pos.h)); >>>> + gsc_write(cfg, GSC_CROPPED_SIZE); >>>> + >>>> + DRM_DEBUG_KMS("%s:swap[%d]hsize[%d]vsize[%d]\n", >>>> + __func__, swap, sz->hsize, sz->vsize); >>>> + >>>> + /* original size */ >>>> + cfg = gsc_read(GSC_SRCIMG_SIZE); >>>> + cfg &= ~(GSC_SRCIMG_HEIGHT_MASK | >>>> + GSC_SRCIMG_WIDTH_MASK); >>>> + >>>> + cfg |= (GSC_SRCIMG_WIDTH(sz->hsize) | >>>> + GSC_SRCIMG_HEIGHT(sz->vsize)); >>>> + >>>> + gsc_write(cfg, GSC_SRCIMG_SIZE); >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static int gsc_src_set_buf_seq(struct gsc_context *ctx, u32 buf_id, >>>> + enum drm_exynos_ipp_buf_type buf_type) >>>> +{ >>>> + struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; >>>> + bool masked; >>>> + u32 cfg; >>>> + u32 mask = 0x00000001 << buf_id; >>>> + >>>> + DRM_DEBUG_KMS("%s:buf_id[%d]buf_type[%d]\n", __func__, >>>> + buf_id, buf_type); >>>> + >>>> + /* mask register set */ >>>> + cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK); >>>> + >>>> + switch (buf_type) { >>>> + case IPP_BUF_ENQUEUE: >>>> + masked = false; >>>> + break; >>>> + case IPP_BUF_DEQUEUE: >>>> + masked = true; >>>> + break; >>>> + default: >>>> + dev_err(ippdrv->dev, "invalid buf ctrl parameter.\n"); >>>> + return -EINVAL; >>>> + } >>>> + >>>> + /* sequence id */ >>>> + cfg &= (~mask); >>>> + cfg |= masked << buf_id; >>>> + gsc_write(cfg, GSC_IN_BASE_ADDR_Y_MASK); >>>> + gsc_write(cfg, GSC_IN_BASE_ADDR_CB_MASK); >>>> + gsc_write(cfg, GSC_IN_BASE_ADDR_CR_MASK); >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static int gsc_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 gsc_context *ctx = get_gsc_context(dev); >>>> + struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; >>>> + struct drm_exynos_ipp_cmd_node *c_node = ippdrv->cmd; >>>> + struct drm_exynos_ipp_property *property; >>>> + >>>> + if (!c_node) { >>>> + DRM_ERROR("failed to get c_node.\n"); >>>> + return -EINVAL; >>>> + } >>>> + >>>> + property = &c_node->property; >>>> + if (!property) { >>>> + DRM_ERROR("failed to get property.\n"); >>>> + return -EINVAL; >>>> + } >>>> + >>>> + DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__, >>>> + property->prop_id, buf_id, buf_type); >>>> + >>>> + if (buf_id > GSC_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: >>>> + gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_Y], >>>> + GSC_IN_BASE_ADDR_Y(buf_id)); >>>> + gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB], >>>> + GSC_IN_BASE_ADDR_CB(buf_id)); >>>> + gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR], >>>> + GSC_IN_BASE_ADDR_CR(buf_id)); >>>> + break; >>>> + case IPP_BUF_DEQUEUE: >>>> + gsc_write(0x0, GSC_IN_BASE_ADDR_Y(buf_id)); >>>> + gsc_write(0x0, GSC_IN_BASE_ADDR_CB(buf_id)); >>>> + gsc_write(0x0, GSC_IN_BASE_ADDR_CR(buf_id)); >>>> + break; >>>> + default: >>>> + /* bypass */ >>>> + break; >>>> + } >>>> + >>>> + return gsc_src_set_buf_seq(ctx, buf_id, buf_type); >>>> +} >>>> + >>>> +static struct exynos_drm_ipp_ops gsc_src_ops = { >>>> + .set_fmt = gsc_src_set_fmt, >>>> + .set_transf = gsc_src_set_transf, >>>> + .set_size = gsc_src_set_size, >>>> + .set_addr = gsc_src_set_addr, >>>> +}; >>>> + >>>> +static int gsc_dst_set_fmt(struct device *dev, u32 fmt) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; >>>> + u32 cfg; >>>> + >>>> + DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt); >>>> + >>>> + cfg = gsc_read(GSC_OUT_CON); >>>> + cfg &= ~(GSC_OUT_RGB_TYPE_MASK | GSC_OUT_YUV422_1P_ORDER_MASK | >>>> + GSC_OUT_CHROMA_ORDER_MASK | GSC_OUT_FORMAT_MASK | >>>> + GSC_OUT_TILE_TYPE_MASK | GSC_OUT_TILE_MODE); >>>> + >>>> + switch (fmt) { >>>> + case DRM_FORMAT_RGB565: >>>> + cfg |= GSC_OUT_RGB565; >>>> + break; >>>> + case DRM_FORMAT_XRGB8888: >>>> + cfg |= GSC_OUT_XRGB8888; >>>> + break; >>>> + case DRM_FORMAT_YUYV: >>>> + cfg |= (GSC_OUT_YUV422_1P | >>>> + GSC_OUT_YUV422_1P_ORDER_LSB_Y | >>>> + GSC_OUT_CHROMA_ORDER_CBCR); >>>> + break; >>>> + case DRM_FORMAT_YVYU: >>>> + cfg |= (GSC_OUT_YUV422_1P | >>>> + GSC_OUT_YUV422_1P_ORDER_LSB_Y | >>>> + GSC_OUT_CHROMA_ORDER_CRCB); >>>> + break; >>>> + case DRM_FORMAT_UYVY: >>>> + cfg |= (GSC_OUT_YUV422_1P | >>>> + GSC_OUT_YUV422_1P_OEDER_LSB_C | >>>> + GSC_OUT_CHROMA_ORDER_CBCR); >>>> + break; >>>> + case DRM_FORMAT_VYUY: >>>> + cfg |= (GSC_OUT_YUV422_1P | >>>> + GSC_OUT_YUV422_1P_OEDER_LSB_C | >>>> + GSC_OUT_CHROMA_ORDER_CRCB); >>>> + break; >>>> + case DRM_FORMAT_NV21: >>>> + case DRM_FORMAT_NV61: >>>> + cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | >>>> + GSC_OUT_YUV420_2P); >>>> + break; >>>> + case DRM_FORMAT_YUV422: >>>> + case DRM_FORMAT_YUV420: >>>> + case DRM_FORMAT_YVU420: >>>> + cfg |= GSC_OUT_YUV420_3P; >>>> + break; >>>> + case DRM_FORMAT_NV12: >>>> + case DRM_FORMAT_NV16: >>>> + cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | >>>> + GSC_OUT_YUV420_2P); >>>> + break; >>>> + case DRM_FORMAT_NV12MT: >>>> + cfg |= (GSC_OUT_TILE_C_16x8 | GSC_OUT_TILE_MODE); >>>> + break; >>>> + default: >>>> + dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt); >>>> + return -EINVAL; >>>> + } >>>> + >>>> + gsc_write(cfg, GSC_OUT_CON); >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static int gsc_dst_set_transf(struct device *dev, >>>> + enum drm_exynos_degree degree, >>>> + enum drm_exynos_flip flip) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; >>>> + u32 cfg; >>>> + >>>> + DRM_DEBUG_KMS("%s:degree[%d]flip[0x%x]\n", __func__, >>>> + degree, flip); >>>> + >>>> + cfg = gsc_read(GSC_IN_CON); >>>> + cfg &= ~GSC_IN_ROT_MASK; >>>> + >>>> + switch (degree) { >>>> + case EXYNOS_DRM_DEGREE_0: >>>> + if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) >>>> + cfg |= GSC_IN_ROT_XFLIP; >>>> + if (flip & EXYNOS_DRM_FLIP_VERTICAL) >>>> + cfg |= GSC_IN_ROT_YFLIP; >>>> + break; >>>> + case EXYNOS_DRM_DEGREE_90: >>>> + if (flip & EXYNOS_DRM_FLIP_HORIZONTAL) >>>> + cfg |= GSC_IN_ROT_90_XFLIP; >>>> + else if (flip & EXYNOS_DRM_FLIP_VERTICAL) >>>> + cfg |= GSC_IN_ROT_90_YFLIP; >>>> + else >>>> + cfg |= GSC_IN_ROT_90; >>>> + break; >>>> + case EXYNOS_DRM_DEGREE_180: >>>> + cfg |= GSC_IN_ROT_180; >>>> + break; >>>> + case EXYNOS_DRM_DEGREE_270: >>>> + cfg |= GSC_IN_ROT_270; >>>> + break; >>>> + default: >>>> + dev_err(ippdrv->dev, "inavlid degree value %d.\n", degree); >>>> + return -EINVAL; >>>> + } >>>> + >>>> + gsc_write(cfg, GSC_IN_CON); >>>> + >>>> + return cfg ? 1 : 0; >>>> +} >>>> + >>>> +static int gsc_get_ratio_shift(u32 src, u32 dst, u32 *ratio, u32 >>>> *shift) >>>> +{ >>>> + DRM_DEBUG_KMS("%s:src[%d]dst[%d]\n", __func__, src, dst); >>>> + >>>> + if (src >= dst * 64) { >>>> + DRM_ERROR("failed to make ratio and shift.\n"); >>>> + return -EINVAL; >>>> + } else if (src >= dst * 32) { >>>> + *ratio = 32; >>>> + *shift = 5; >>>> + } else if (src >= dst * 16) { >>>> + *ratio = 16; >>>> + *shift = 4; >>>> + } else if (src >= dst * 8) { >>>> + *ratio = 8; >>>> + *shift = 3; >>>> + } else if (src >= dst * 4) { >>>> + *ratio = 4; >>>> + *shift = 2; >>>> + } else if (src >= dst * 2) { >>>> + *ratio = 2; >>>> + *shift = 1; >>>> + } else { >>>> + *ratio = 1; >>>> + *shift = 0; >>>> + } >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static int gsc_set_prescaler(struct gsc_context *ctx, struct >>>> gsc_scaler *sc, >>>> + struct drm_exynos_pos *src, struct drm_exynos_pos *dst) >>>> +{ >>>> + struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; >>>> + u32 cfg, cfg_ext; >>>> + u32 hfactor, vfactor; >>>> + u32 src_w, src_h, dst_w, dst_h; >>>> + int ret = 0; >>>> + >>>> + cfg_ext = gsc_read(GSC_IN_CON); >>>> + if (cfg_ext & GSC_IN_ROT_90) { >>>> + src_w = src->h; >>>> + src_h = src->w; >>>> + } else{ >>>> + src_w = src->w; >>>> + src_h = src->h; >>>> + } >>>> + >>>> + cfg_ext = gsc_read(GSC_OUT_CON); >>>> + if (cfg_ext & GSC_IN_ROT_90) { >>>> + dst_w = dst->h; >>>> + dst_h = dst->w; >>>> + } else{ >>>> + dst_w = dst->w; >>>> + dst_h = dst->h; >>>> + } >>>> + >>>> + ret = gsc_get_ratio_shift(src_w, dst_w, &sc->pre_hratio, >>>> &hfactor); >>>> + if (ret) { >>>> + dev_err(ippdrv->dev, "failed to get ratio horizontal.\n"); >>>> + return ret; >>>> + } >>>> + >>>> + ret = gsc_get_ratio_shift(src_h, dst_h, &sc->pre_vratio, >>>> &vfactor); >>>> + if (ret) { >>>> + dev_err(ippdrv->dev, "failed to get ratio vertical.\n"); >>>> + return ret; >>>> + } >>>> + >>>> + >>>> DRM_DEBUG_KMS("%s:pre_hratio[%d]hfactor[%d]pre_vratio[%d]vfactor[%d]\n", >>>> >>>> + __func__, sc->pre_hratio, hfactor, sc->pre_vratio, vfactor); >>>> + >>>> + sc->main_hratio = (src_w << 16) / (dst_w << hfactor); >>>> + sc->main_vratio = (src_h << 16) / (dst_h << vfactor); >>>> + DRM_DEBUG_KMS("%s:main_hratio[%ld]main_vratio[%ld]\n", >>>> + __func__, sc->main_hratio, sc->main_vratio); >>>> + >>>> + sc->pre_shfactor = 10 - (hfactor + vfactor); >>>> + DRM_DEBUG_KMS("%s:pre_shfactor[%d]\n", __func__, >>>> + sc->pre_shfactor); >>>> + >>>> + cfg = (GSC_PRESC_SHFACTOR(sc->pre_shfactor) | >>>> + GSC_PRESC_H_RATIO(sc->pre_hratio) | >>>> + GSC_PRESC_V_RATIO(sc->pre_vratio)); >>>> + gsc_write(cfg, GSC_PRE_SCALE_RATIO); >>>> + >>>> + return ret; >>>> +} >>>> + >>>> +static void gsc_set_scaler(struct gsc_context *ctx, struct gsc_scaler >>>> *sc) >>>> +{ >>>> + u32 cfg; >>>> + >>>> + DRM_DEBUG_KMS("%s:main_hratio[%ld]main_vratio[%ld]\n", >>>> + __func__, sc->main_hratio, sc->main_vratio); >>>> + >>>> + cfg = GSC_MAIN_H_RATIO_VALUE(sc->main_hratio); >>>> + gsc_write(cfg, GSC_MAIN_H_RATIO); >>>> + >>>> + cfg = GSC_MAIN_V_RATIO_VALUE(sc->main_vratio); >>>> + gsc_write(cfg, GSC_MAIN_V_RATIO); >>>> +} >>>> + >>>> +static int gsc_dst_set_size(struct device *dev, int swap, >>>> + struct drm_exynos_pos *pos, struct drm_exynos_sz *sz) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + struct drm_exynos_pos img_pos = *pos; >>>> + struct drm_exynos_sz img_sz = *sz; >>>> + struct gsc_scaler *sc = &ctx->sc; >>>> + u32 cfg; >>>> + >>>> + DRM_DEBUG_KMS("%s:swap[%d]x[%d]y[%d]w[%d]h[%d]\n", >>>> + __func__, swap, pos->x, pos->y, pos->w, pos->h); >>>> + >>>> + if (swap) { >>>> + img_pos.w = pos->h; >>>> + img_pos.h = pos->w; >>>> + img_sz.hsize = sz->vsize; >>>> + img_sz.vsize = sz->hsize; >>>> + } >>>> + >>>> + /* pixel offset */ >>>> + cfg = (GSC_DSTIMG_OFFSET_X(img_pos.x) | >>>> + GSC_DSTIMG_OFFSET_Y(img_pos.y)); >>>> + gsc_write(cfg, GSC_DSTIMG_OFFSET); >>>> + >>>> + /* scaled size */ >>>> + cfg = (GSC_SCALED_WIDTH(pos->w) | GSC_SCALED_HEIGHT(pos->h)); >>>> + gsc_write(cfg, GSC_SCALED_SIZE); >>>> + >>>> + DRM_DEBUG_KMS("%s:hsize[%d]vsize[%d]\n", >>>> + __func__, sz->hsize, sz->vsize); >>>> + >>>> + /* original size */ >>>> + cfg = gsc_read(GSC_DSTIMG_SIZE); >>>> + cfg &= ~(GSC_DSTIMG_HEIGHT_MASK | >>>> + GSC_DSTIMG_WIDTH_MASK); >>>> + cfg |= (GSC_DSTIMG_WIDTH(img_sz.hsize) | >>>> + GSC_DSTIMG_HEIGHT(img_sz.vsize)); >>>> + gsc_write(cfg, GSC_DSTIMG_SIZE); >>>> + >>>> + cfg = gsc_read(GSC_OUT_CON); >>>> + cfg &= ~GSC_OUT_RGB_TYPE_MASK; >>>> + >>>> + if (pos->w >= GSC_WIDTH_ITU_709) >>>> + if (sc->range) >>>> + cfg |= GSC_OUT_RGB_HD_WIDE; >>>> + else >>>> + cfg |= GSC_OUT_RGB_HD_NARROW; >>>> + else >>>> + if (sc->range) >>>> + cfg |= GSC_OUT_RGB_SD_WIDE; >>>> + else >>>> + cfg |= GSC_OUT_RGB_SD_NARROW; >>>> + >>>> + gsc_write(cfg, GSC_OUT_CON); >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static int gsc_dst_get_buf_seq(struct gsc_context *ctx) >>>> +{ >>>> + u32 cfg, i, buf_num = GSC_REG_SZ; >>>> + u32 mask = 0x00000001; >>>> + >>>> + cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK); >>>> + >>>> + for (i = 0; i < GSC_REG_SZ; i++) >>>> + if (cfg & (mask << i)) >>>> + buf_num--; >>>> + >>>> + DRM_DEBUG_KMS("%s:buf_num[%d]\n", __func__, buf_num); >>>> + >>>> + return buf_num; >>>> +} >>>> + >>>> +static int gsc_dst_set_buf_seq(struct gsc_context *ctx, u32 buf_id, >>>> + enum drm_exynos_ipp_buf_type buf_type) >>>> +{ >>>> + struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; >>>> + bool masked; >>>> + u32 cfg; >>>> + u32 mask = 0x00000001 << buf_id; >>>> + unsigned long flags; >>>> + int ret = 0; >>>> + >>>> + DRM_DEBUG_KMS("%s:buf_id[%d]buf_type[%d]\n", __func__, >>>> + buf_id, buf_type); >>>> + >>>> + spin_lock_irqsave(&ctx->lock, flags); >>>> + >>>> + /* mask register set */ >>>> + cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK); >>>> + >>>> + switch (buf_type) { >>>> + case IPP_BUF_ENQUEUE: >>>> + masked = false; >>>> + break; >>>> + case IPP_BUF_DEQUEUE: >>>> + masked = true; >>>> + break; >>>> + default: >>>> + dev_err(ippdrv->dev, "invalid buf ctrl parameter.\n"); >>>> + ret = -EINVAL; >>>> + goto err_unlock; >>>> + } >>>> + >>>> + /* sequence id */ >>>> + cfg &= (~mask); >>>> + cfg |= masked << buf_id; >>>> + gsc_write(cfg, GSC_OUT_BASE_ADDR_Y_MASK); >>>> + gsc_write(cfg, GSC_OUT_BASE_ADDR_CB_MASK); >>>> + gsc_write(cfg, GSC_OUT_BASE_ADDR_CR_MASK); >>>> + >>>> + /* interrupt enable */ >>>> + if (buf_type == IPP_BUF_ENQUEUE && >>>> + gsc_dst_get_buf_seq(ctx) >= GSC_BUF_START) >>>> + gsc_handle_irq(ctx, true, false, true); >>>> + >>>> + /* interrupt disable */ >>>> + if (buf_type == IPP_BUF_DEQUEUE && >>>> + gsc_dst_get_buf_seq(ctx) <= GSC_BUF_STOP) >>>> + gsc_handle_irq(ctx, false, false, true); >>>> + >>>> +err_unlock: >>>> + spin_unlock_irqrestore(&ctx->lock, flags); >>>> + return ret; >>>> +} >>>> + >>>> +static int gsc_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 gsc_context *ctx = get_gsc_context(dev); >>>> + struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; >>>> + struct drm_exynos_ipp_cmd_node *c_node = ippdrv->cmd; >>>> + struct drm_exynos_ipp_property *property; >>>> + >>>> + if (!c_node) { >>>> + DRM_ERROR("failed to get c_node.\n"); >>>> + return -EINVAL; >>>> + } >>>> + >>>> + property = &c_node->property; >>>> + if (!property) { >>>> + DRM_ERROR("failed to get property.\n"); >>>> + return -EINVAL; >>>> + } >>>> + >>>> + DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__, >>>> + property->prop_id, buf_id, buf_type); >>>> + >>>> + if (buf_id > GSC_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: >>>> + gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_Y], >>>> + GSC_OUT_BASE_ADDR_Y(buf_id)); >>>> + gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_CB], >>>> + GSC_OUT_BASE_ADDR_CB(buf_id)); >>>> + gsc_write(buf_info->base[EXYNOS_DRM_PLANAR_CR], >>>> + GSC_OUT_BASE_ADDR_CR(buf_id)); >>>> + break; >>>> + case IPP_BUF_DEQUEUE: >>>> + gsc_write(0x0, GSC_OUT_BASE_ADDR_Y(buf_id)); >>>> + gsc_write(0x0, GSC_OUT_BASE_ADDR_CB(buf_id)); >>>> + gsc_write(0x0, GSC_OUT_BASE_ADDR_CR(buf_id)); >>>> + break; >>>> + default: >>>> + /* bypass */ >>>> + break; >>>> + } >>>> + >>>> + return gsc_dst_set_buf_seq(ctx, buf_id, buf_type); >>>> +} >>>> + >>>> +static struct exynos_drm_ipp_ops gsc_dst_ops = { >>>> + .set_fmt = gsc_dst_set_fmt, >>>> + .set_transf = gsc_dst_set_transf, >>>> + .set_size = gsc_dst_set_size, >>>> + .set_addr = gsc_dst_set_addr, >>>> +}; >>>> + >>>> +static int gsc_power_on(struct gsc_context *ctx, bool enable) >>> >>> This function controls clock but this function name is "power", also >>> this has two controls - on and off but i can know only "on" operation >>> from this function name. >> >> - how about gsc_clk_ctrl() ? is it good ? >> > > It's good. - done. > >>> >>>> +{ >>>> + DRM_DEBUG_KMS("%s:\n", __func__); >>>> + >>>> + if (enable) { >>>> + clk_enable(ctx->gsc_clk); >>>> + /* ToDo : wb_b_clk */ >>> >>> What is the wb_b_clk? Please remove meaningless comment. >> >> - Writeback operation is not finished. so, added ToDo >> I will change comments. >> >>> >>>> + ctx->suspended = false; >>>> + } else { >>>> + clk_disable(ctx->gsc_clk); >>>> + /* ToDo : wb_b_clk */ >>> >>> Ditto. >> >> - Ditto. >> >>> >>>> + ctx->suspended = true; >>>> + } >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static irqreturn_t gsc_irq_handler(int irq, void *dev_id) >>>> +{ >>>> + struct gsc_context *ctx = dev_id; >>>> + struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; >>>> + struct drm_exynos_ipp_cmd_node *c_node = ippdrv->cmd; >>>> + struct drm_exynos_ipp_event_work *event_work = >>>> + c_node->event_work; >>>> + u32 cfg, status; >>>> + int buf_id = 0; >>>> + >>>> + DRM_DEBUG_KMS("%s:gsc id[%d]\n", __func__, ctx->id); >>>> + >>>> + status = gsc_read(GSC_IRQ); >>>> + if (status & GSC_IRQ_STATUS_OR_IRQ) { >>>> + dev_err(ippdrv->dev, "occured overflow at %d, status 0x%x.\n", >>>> + ctx->id, status); >>>> + return IRQ_NONE; >>>> + } >>>> + >>>> + if (status & GSC_IRQ_STATUS_OR_FRM_DONE) { >>>> + dev_err(ippdrv->dev, "occured frame done at %d, status >>>> 0x%x.\n", >>>> + ctx->id, status); >>>> + /* ToDo: Frame control */ >>>> + } >>>> + >>>> + cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK); >>>> + buf_id = GSC_IN_CURR_GET_INDEX(cfg); >>>> + if (buf_id < 0) >>>> + return IRQ_HANDLED; >>>> + >>>> + DRM_DEBUG_KMS("%s:buf_id[%d]\n", __func__, buf_id); >>>> + >>>> + if (gsc_dst_set_buf_seq(ctx, buf_id, IPP_BUF_DEQUEUE) < 0) { >>>> + DRM_ERROR("failed to dequeue.\n"); >>>> + return IRQ_HANDLED; >>>> + } >>>> + >>>> + event_work->ippdrv = ippdrv; >>>> + event_work->buf_id[EXYNOS_DRM_OPS_DST] = buf_id; >>>> + queue_work(ippdrv->event_workq, (struct work_struct *)event_work); >>>> + >>>> + return IRQ_HANDLED; >>>> +} >>>> + >>>> +static int gsc_init_prop_list(struct drm_exynos_ipp_prop_list >>>> **prop_list) >>> >>> Any reason using double pointer? >> >> - Is it some problem ? >> > > I think no need to use double pointer. Use just pointer. - changed it. > >>> >>>> +{ >>>> + DRM_DEBUG_KMS("%s\n", __func__); >>>> + >>>> + if (!prop_list) { >>>> + DRM_ERROR("empty prop_list.\n"); >>>> + return -EINVAL; >>>> + } >>>> + >>>> + *prop_list = kzalloc(sizeof(**prop_list), GFP_KERNEL); >>>> + if (!*prop_list) { >>>> + DRM_ERROR("failed to alloc property list.\n"); >>>> + return -ENOMEM; >>>> + } >>>> + /*ToDo : fix supported function list*/ >>>> + (*prop_list)->version = 1; >>>> + (*prop_list)->writeback = 1; >>>> + (*prop_list)->refresh_min = 12; >>>> + (*prop_list)->refresh_max = 60; >>>> + (*prop_list)->flip = (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 = 8192; >>>> + (*prop_list)->crop_max.vsize = 8192; >>>> + (*prop_list)->crop_min.hsize = 32; >>>> + (*prop_list)->crop_min.vsize = 32; >>>> + (*prop_list)->scale = 1; >>>> + (*prop_list)->scale_max.hsize = 4224; >>>> + (*prop_list)->scale_max.vsize = 4224; >>>> + (*prop_list)->scale_min.hsize = 32; >>>> + (*prop_list)->scale_min.vsize = 32; >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static int gsc_ippdrv_check_property(struct device *dev, >>>> + struct drm_exynos_ipp_property *property) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; >>>> + struct drm_exynos_ipp_prop_list *pp = ippdrv->prop_list; >>>> + struct drm_exynos_ipp_config *config; >>>> + struct drm_exynos_pos *pos; >>>> + struct drm_exynos_sz *sz; >>>> + bool swap; >>>> + int i; >>>> + >>>> + DRM_DEBUG_KMS("%s\n", __func__); >>>> + >>>> + 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 */ >>>> + switch (config->flip) { >>>> + case EXYNOS_DRM_FLIP_NONE: >>>> + case EXYNOS_DRM_FLIP_VERTICAL: >>>> + case EXYNOS_DRM_FLIP_HORIZONTAL: >>>> + /* No problem */ >>>> + break; >>>> + default: >>>> + 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 int gsc_ippdrv_reset(struct device *dev) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + int ret; >>>> + >>>> + DRM_DEBUG_KMS("%s\n", __func__); >>>> + >>>> + /* reset h/w block */ >>>> + ret = gsc_sw_reset(ctx); >>>> + if (ret < 0) { >>>> + dev_err(dev, "failed to reset hardware.\n"); >>>> + return ret; >>>> + } >>>> + >>>> + memset(&ctx->sc, 0x0, sizeof(ctx->sc)); >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static int gsc_check_prepare(struct gsc_context *ctx) >>>> +{ >>>> + /* ToDo: check prepare using read register */ >>>> + DRM_DEBUG_KMS("%s\n", __func__); >>>> + >>>> + return 0; >>>> +} >>> >>> Please remove dummy function. >> >> - no dummy function. we need integrate check prepare at the future. >> > > But now is dummy function. Please implement or remove. - hmm ~ I think check_prepare needed. but we don't consider about check register scope and use case. because we just use in our platform. so, I want to make TODO about this function. please one more comment about my answer. (I think in this case use "ToDo") > >>> >>>> + >>>> +static int gsc_ippdrv_start(struct device *dev, enum >>>> drm_exynos_ipp_cmd cmd) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; >>>> + struct drm_exynos_ipp_cmd_node *c_node = ippdrv->cmd; >>>> + 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; >>>> + u32 cfg; >>>> + int ret, i; >>>> + >>>> + DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, cmd); >>>> + >>>> + if (!c_node) { >>>> + DRM_ERROR("failed to get c_node.\n"); >>>> + return -EINVAL; >>>> + } >>>> + >>>> + property = &c_node->property; >>>> + if (!property) { >>>> + DRM_ERROR("failed to get property.\n"); >>>> + return -EINVAL; >>>> + } >>>> + >>>> + ret = gsc_check_prepare(ctx); >>>> + if (ret) { >>>> + dev_err(dev, "failed to check prepare.\n"); >>>> + return ret; >>>> + } >>>> + >>>> + gsc_handle_irq(ctx, true, false, true); >>>> + >>>> + /* ToDo: window size, prescaler config */ >>> >>> What? Implement or remove this. >> >> - We have changed commit in local git don't worry. >> >>> >>>> + for_each_ipp_ops(i) { >>>> + config = &property->config[i]; >>>> + img_pos[i] = config->pos; >>>> + } >>>> + >>>> + switch (cmd) { >>>> + case IPP_CMD_M2M: >>>> + /* bypass */ >>>> + break; >>>> + case IPP_CMD_WB: >>>> + /* ToDo: need to replace the property structure. */ >>>> + set_wb.enable = 1; >>>> + set_wb.refresh = property->reserved; >>>> + gsc_set_gscblk_fimd_wb(ctx, set_wb.enable); >>>> + 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; >>>> + } >>>> + >>>> + ret = gsc_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; >>>> + } >>>> + >>>> + gsc_set_scaler(ctx, &ctx->sc); >>>> + >>>> + cfg = gsc_read(GSC_ENABLE); >>>> + cfg |= GSC_ENABLE_ON; >>>> + gsc_write(cfg, GSC_ENABLE); >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static void gsc_ippdrv_stop(struct device *dev, enum >>>> drm_exynos_ipp_cmd cmd) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + struct drm_exynos_ipp_set_wb set_wb = {0, 0}; >>>> + u32 cfg; >>>> + >>>> + DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, cmd); >>>> + >>>> + switch (cmd) { >>>> + case IPP_CMD_M2M: >>>> + /* bypass */ >>>> + break; >>>> + case IPP_CMD_WB: >>>> + gsc_set_gscblk_fimd_wb(ctx, set_wb.enable); >>>> + exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void >>>> *)&set_wb); >>>> + break; >>>> + case IPP_CMD_OUTPUT: >>>> + default: >>>> + dev_err(dev, "invalid operations.\n"); >>>> + break; >>>> + } >>>> + >>>> + gsc_handle_irq(ctx, false, false, true); >>>> + >>>> + /* reset sequence */ >>>> + gsc_write(0xff, GSC_OUT_BASE_ADDR_Y_MASK); >>>> + gsc_write(0xff, GSC_OUT_BASE_ADDR_CB_MASK); >>>> + gsc_write(0xff, GSC_OUT_BASE_ADDR_CR_MASK); >>>> + >>>> + cfg = gsc_read(GSC_ENABLE); >>>> + cfg &= ~GSC_ENABLE_ON; >>>> + gsc_write(cfg, GSC_ENABLE); >>>> +} >>>> + >>>> +static int __devinit gsc_probe(struct platform_device *pdev) >>>> +{ >>>> + struct device *dev = &pdev->dev; >>>> + struct gsc_context *ctx; >>>> + struct resource *res; >>>> + struct exynos_drm_ippdrv *ippdrv; >>>> + struct exynos_drm_gsc_pdata *pdata; >>>> + int ret = -EINVAL; >>>> + >>>> + pdata = pdev->dev.platform_data; >>>> + if (!pdata) { >>>> + dev_err(dev, "no platform data specified.\n"); >>>> + return -EINVAL; >>>> + } >>> >>> Where does pdata uses? >> >> - for the future. >> > > If doesn't use it now, please remove. - OK, removed it. > >>> >>>> + >>>> + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); >>>> + if (!ctx) >>>> + return -ENOMEM; >>>> + >>>> + /* clock control */ >>>> + ctx->gsc_clk = clk_get(dev, "gscl"); >>>> + if (IS_ERR(ctx->gsc_clk)) { >>>> + dev_err(dev, "failed to get gsc clock.\n"); >>>> + ret = PTR_ERR(ctx->gsc_clk); >>>> + goto err_ctx; >>>> + } >>>> + >>>> + /* resource memory */ >>>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >>>> + if (!res) { >>>> + dev_err(dev, "failed to find registers.\n"); >>>> + ret = -ENOENT; >>>> + goto err_clk; >>>> + } >>>> + >>>> + ctx->regs_res = request_mem_region(res->start, resource_size(res), >>>> + dev_name(dev)); >>>> + if (!ctx->regs_res) { >>>> + dev_err(dev, "failed to claim register region.\n"); >>>> + ret = -ENOENT; >>>> + goto err_clk; >>>> + } >>>> + >>>> + ctx->regs = ioremap(res->start, resource_size(res)); >>>> + if (!ctx->regs) { >>>> + dev_err(dev, "failed to map registers.\n"); >>>> + ret = -ENXIO; >>>> + goto err_req_region; >>>> + } >>>> + >>> >>> Use devm_request_and_ioremap(). >> >> - I think devm_request_and_ioremap() need to change another module also. >> so, I want to change at this time. >> >>> >>>> + /* resource irq */ >>>> + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); >>>> + if (!res) { >>>> + dev_err(dev, "failed to request irq resource.\n"); >>>> + goto err_get_regs; >>>> + } >>>> + >>>> + ctx->irq = res->start; >>>> + ret = request_threaded_irq(ctx->irq, NULL, gsc_irq_handler, >>>> + IRQF_ONESHOT, "drm_gsc", ctx); >>> >>> Use devm_request_irq. Do you have any reason using IRQF_ONESHOT flag? >> >> - defence of multiple interrupt. >> > > OK. > >>> >>>> + if (ret < 0) { >>>> + dev_err(dev, "failed to request irq.\n"); >>>> + goto err_get_regs; >>>> + } >>>> + >>>> + /* context initailization */ >>>> + ctx->id = pdev->id; >>>> + ctx->capa = gsc51_capa; >>>> + if (!ctx->capa) { >>>> + dev_err(dev, "failed to get capability.\n"); >>>> + goto err_get_irq; >>>> + } >>> >>> Where does capa uses? >> >> - at the future. >> > > Please remove. Later if it needs, make patch for it. - removed it. > >>> >>>> + >>>> + /* ToDo: iommu enable */ >>> >>> Please remove this comment, rather make TODO list at the top. >> >> - removed it. >> >>> >>>> + ippdrv = &ctx->ippdrv; >>>> + ippdrv->dev = dev; >>>> + ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &gsc_src_ops; >>>> + ippdrv->ops[EXYNOS_DRM_OPS_DST] = &gsc_dst_ops; >>>> + ippdrv->check_property = gsc_ippdrv_check_property; >>>> + ippdrv->reset = gsc_ippdrv_reset; >>>> + ippdrv->start = gsc_ippdrv_start; >>>> + ippdrv->stop = gsc_ippdrv_stop; >>>> + ret = gsc_init_prop_list(&ippdrv->prop_list); >>>> + if (ret < 0) { >>>> + dev_err(dev, "failed to init property list.\n"); >>>> + goto err_get_irq; >>>> + } >>>> + >>>> + DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id, >>>> + (int)ippdrv); >>>> + >>>> + spin_lock_init(&ctx->lock); >>>> + 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 gsc device.\n"); >>>> + goto err_ippdrv_register; >>>> + } >>>> + >>>> + dev_info(&pdev->dev, "drm gsc registered successfully.\n"); >>>> + >>>> + return 0; >>>> + >>>> +err_ippdrv_register: >>>> + kfree(ippdrv->prop_list); >>>> + pm_runtime_disable(dev); >>>> + free_irq(ctx->irq, ctx); >>>> +err_get_irq: >>>> + free_irq(ctx->irq, ctx); >>>> +err_get_regs: >>>> + iounmap(ctx->regs); >>>> +err_req_region: >>>> + release_resource(ctx->regs_res); >>>> + kfree(ctx->regs_res); >>>> +err_clk: >>>> + clk_put(ctx->gsc_clk); >>>> +err_ctx: >>>> + kfree(ctx); >>>> + return ret; >>>> +} >>>> + >>>> +static int __devexit gsc_remove(struct platform_device *pdev) >>>> +{ >>>> + struct device *dev = &pdev->dev; >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv; >>>> + >>>> + kfree(ippdrv->prop_list); >>>> + exynos_drm_ippdrv_unregister(ippdrv); >>>> + >>>> + pm_runtime_set_suspended(dev); >>>> + pm_runtime_disable(dev); >>>> + >>>> + free_irq(ctx->irq, ctx); >>>> + iounmap(ctx->regs); >>>> + release_resource(ctx->regs_res); >>>> + kfree(ctx->regs_res); >>>> + >>>> + clk_put(ctx->gsc_clk); >>>> + >>>> + kfree(ctx); >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +#ifdef CONFIG_PM_SLEEP >>>> +static int gsc_suspend(struct device *dev) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + >>>> + DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id); >>>> + if (pm_runtime_suspended(dev)) >>>> + return 0; >>>> + /* ToDo */ >>>> + return gsc_power_on(ctx, false); >>>> +} >>>> + >>>> +static int gsc_resume(struct device *dev) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + >>>> + DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id); >>>> + if (!pm_runtime_suspended(dev)) >>>> + return gsc_power_on(ctx, true); >>>> + /* ToDo */ >>> >>> Please remove this comment, rather make TODO list at the top. >> >> - move to top. >> >>> >>>> + return 0; >>>> +} >>>> +#endif >>>> + >>>> +#ifdef CONFIG_PM_RUNTIME >>>> +static int gsc_runtime_suspend(struct device *dev) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + >>>> + DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id); >>>> + /* ToDo */ >>> >>> Ditto. >>> >>>> + return gsc_power_on(ctx, false); >>>> +} >>>> + >>>> +static int gsc_runtime_resume(struct device *dev) >>>> +{ >>>> + struct gsc_context *ctx = get_gsc_context(dev); >>>> + >>>> + DRM_DEBUG_KMS("%s:id[%d]\n", __FILE__, ctx->id); >>>> + /* ToDo */ >>> >>> Ditto. >>> >>>> + return gsc_power_on(ctx, true); >>>> +} >>>> +#endif >>> >>> If runtime PM isn't enabled, how do we control clock? >>> >>>> + >>>> +static const struct dev_pm_ops gsc_pm_ops = { >>>> + SET_SYSTEM_SLEEP_PM_OPS(gsc_suspend, gsc_resume) >>>> + SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL) >>>> +}; >>>> + >>>> +/* ToDo: need to check use case platform_device_id */ >>>> +struct platform_driver gsc_driver = { >>>> + .probe = gsc_probe, >>>> + .remove = __devexit_p(gsc_remove), >>>> + .driver = { >>>> + .name = "exynos-drm-gsc", >>>> + .owner = THIS_MODULE, >>>> + .pm = &gsc_pm_ops, >>>> + }, >>>> +}; >>>> + >>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.h >>>> b/drivers/gpu/drm/exynos/exynos_drm_gsc.h >>>> new file mode 100644 >>>> index 0000000..6c999e3 >>>> --- /dev/null >>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.h >>>> @@ -0,0 +1,35 @@ >>>> +/* >>>> + * Copyright (c) 2012 Samsung Electronics Co., Ltd. >>>> + * >>>> + * Authors: >>>> + * Eunchul Kim <chulspro.kim at samsung.com> >>>> + * Jinyoung Jeon <jy0.jeon at samsung.com> >>>> + * Sangmin Lee <lsmin.lee at samsung.com> >>>> + * >>>> + * Permission is hereby granted, free of charge, to any person >>>> obtaining a >>>> + * copy of this software and associated documentation files (the >>>> "Software"), >>>> + * to deal in the Software without restriction, including without >>>> limitation >>>> + * the rights to use, copy, modify, merge, publish, distribute, >>>> sublicense, >>>> + * and/or sell copies of the Software, and to permit persons to >>>> whom the >>>> + * Software is furnished to do so, subject to the following >>>> conditions: >>>> + * >>>> + * The above copyright notice and this permission notice (including >>>> the next >>>> + * paragraph) shall be included in all copies or substantial portions >>>> of the >>>> + * Software. >>>> + * >>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >>>> EXPRESS OR >>>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF >>>> MERCHANTABILITY, >>>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT >>>> SHALL >>>> + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, >>>> DAMAGES OR >>>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR >>>> OTHERWISE, >>>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE >>>> USE OR >>>> + * OTHER DEALINGS IN THE SOFTWARE. >>>> + */ >>>> + >>>> +#ifndef _EXYNOS_DRM_GSC_H_ >>>> +#define _EXYNOS_DRM_GSC_H_ >>>> + >>>> +/* ToDo */ >>>> + >>>> +#endif /* _EXYNOS_DRM_GSC_H_ */ >>>> + >>>> diff --git a/drivers/gpu/drm/exynos/regs-gsc.h >>>> b/drivers/gpu/drm/exynos/regs-gsc.h >>>> new file mode 100644 >>>> index 0000000..ed297b5 >>>> --- /dev/null >>>> +++ b/drivers/gpu/drm/exynos/regs-gsc.h >>>> @@ -0,0 +1,295 @@ >>>> +/* linux/drivers/gpu/drm/exynos/regs-gsc.h >>>> + * >>>> + * Copyright (c) 2012 Samsung Electronics Co., Ltd. >>>> + * http://www.samsung.com >>>> + * >>>> + * Register definition file for Samsung G-Scaler driver >>>> + * >>>> + * This program is free software; you can redistribute it and/or >>>> modify >>>> + * it under the terms of the GNU General Public License version 2 as >>>> + * published by the Free Software Foundation. >>>> + */ >>>> + >>>> +#ifndef EXYNOS_REGS_GSC_H_ >>>> +#define EXYNOS_REGS_GSC_H_ >>>> + >>>> +/* SYSCON. GSCBLK_CFG */ >>>> +#include <plat/map-base.h> >>>> +#include <plat/cpu.h> >>>> +#define SYSREG_DISP1BLK_CFG (S3C_VA_SYS + 0x0214) >>>> +#define FIFORST_DISP1 (1 << 23) >>>> +#define GSC_OUT_MIXER0 (1 << 7) >>>> +#define GSC_OUT_MIXER0_GSC3 (3 << 5) >>>> +#define SYSREG_GSCBLK_CFG0 (S3C_VA_SYS + 0x0220) >>>> +#define GSC_OUT_DST_FIMD_SEL(x) (1 << (8 + 2 * (x))) >>>> +#define GSC_OUT_DST_MXR_SEL(x) (2 << (8 + 2 * (x))) >>>> +#define GSC_PXLASYNC_RST(x) (1 << (x)) >>>> +#define PXLASYNC_LO_MASK_CAMIF_TOP (1 << 20) >>>> +#define SYSREG_GSCBLK_CFG1 (S3C_VA_SYS + 0x0224) >>>> +#define GSC_BLK_DISP1WB_DEST(x) (x << 10) >>>> +#define GSC_BLK_SW_RESET_WB_DEST(x) (1 << (18 + x)) >>>> +#define GSC_BLK_PXLASYNC_LO_MASK_WB(x) (0 << (14 + x)) >>>> +#define GSC_BLK_GSCL_WB_IN_SRC_SEL(x) (1 << (2 * x)) >>>> +#define SYSREG_GSCBLK_CFG2 (S3C_VA_SYS + 0x2000) >>>> +#define PXLASYNC_LO_MASK_CAMIF_GSCL(x) (1 << (x)) >>>> + >>> >>> This is arch specific register and please don't control directly in the >>> driver. >>> Please refer other drivers how handles them. >> >> - I think one more time about this header. >> I will fixed your comment at next patch. >> >>> >>>> +/* G-Scaler enable */ >>>> +#define GSC_ENABLE 0x00 >>>> +#define GSC_ENABLE_PP_UPDATE_TIME_MASK (1 << 9) >>>> +#define GSC_ENABLE_PP_UPDATE_TIME_CURR (0 << 9) >>>> +#define GSC_ENABLE_PP_UPDATE_TIME_EOPAS (1 << 9) >>>> +#define GSC_ENABLE_CLK_GATE_MODE_MASK (1 << 8) >>>> +#define GSC_ENABLE_CLK_GATE_MODE_FREE (1 << 8) >>>> +#define GSC_ENABLE_IPC_MODE_MASK (1 << 7) >>>> +#define GSC_ENABLE_NORM_MODE (0 << 7) >>>> +#define GSC_ENABLE_IPC_MODE (1 << 7) >>>> +#define GSC_ENABLE_PP_UPDATE_MODE_MASK (1 << 6) >>>> +#define GSC_ENABLE_PP_UPDATE_FIRE_MODE (1 << 6) >>>> +#define GSC_ENABLE_IN_PP_UPDATE (1 << 5) >>>> +#define GSC_ENABLE_ON_CLEAR_MASK (1 << 4) >>>> +#define GSC_ENABLE_ON_CLEAR_ONESHOT (1 << 4) >>>> +#define GSC_ENABLE_QOS_ENABLE (1 << 3) >>>> +#define GSC_ENABLE_OP_STATUS (1 << 2) >>>> +#define GSC_ENABLE_SFR_UPDATE (1 << 1) >>>> +#define GSC_ENABLE_ON (1 << 0) >>>> + >>>> +/* G-Scaler S/W reset */ >>>> +#define GSC_SW_RESET 0x04 >>>> +#define GSC_SW_RESET_SRESET (1 << 0) >>>> + >>>> +/* G-Scaler IRQ */ >>>> +#define GSC_IRQ 0x08 >>>> +#define GSC_IRQ_STATUS_OR_IRQ (1 << 17) >>>> +#define GSC_IRQ_STATUS_OR_FRM_DONE (1 << 16) >>>> +#define GSC_IRQ_OR_MASK (1 << 2) >>>> +#define GSC_IRQ_FRMDONE_MASK (1 << 1) >>>> +#define GSC_IRQ_ENABLE (1 << 0) >>>> + >>>> +/* G-Scaler input control */ >>>> +#define GSC_IN_CON 0x10 >>>> +#define GSC_IN_CHROM_STRIDE_SEL_MASK (1 << 20) >>>> +#define GSC_IN_CHROM_STRIDE_SEPAR (1 << 20) >>>> +#define GSC_IN_RB_SWAP_MASK (1 << 19) >>>> +#define GSC_IN_RB_SWAP (1 << 19) >>>> +#define GSC_IN_ROT_MASK (7 << 16) >>>> +#define GSC_IN_ROT_270 (7 << 16) >>>> +#define GSC_IN_ROT_90_YFLIP (6 << 16) >>>> +#define GSC_IN_ROT_90_XFLIP (5 << 16) >>>> +#define GSC_IN_ROT_90 (4 << 16) >>>> +#define GSC_IN_ROT_180 (3 << 16) >>>> +#define GSC_IN_ROT_YFLIP (2 << 16) >>>> +#define GSC_IN_ROT_XFLIP (1 << 16) >>>> +#define GSC_IN_RGB_TYPE_MASK (3 << 14) >>>> +#define GSC_IN_RGB_HD_WIDE (3 << 14) >>>> +#define GSC_IN_RGB_HD_NARROW (2 << 14) >>>> +#define GSC_IN_RGB_SD_WIDE (1 << 14) >>>> +#define GSC_IN_RGB_SD_NARROW (0 << 14) >>>> +#define GSC_IN_YUV422_1P_ORDER_MASK (1 << 13) >>>> +#define GSC_IN_YUV422_1P_ORDER_LSB_Y (0 << 13) >>>> +#define GSC_IN_YUV422_1P_OEDER_LSB_C (1 << 13) >>>> +#define GSC_IN_CHROMA_ORDER_MASK (1 << 12) >>>> +#define GSC_IN_CHROMA_ORDER_CBCR (0 << 12) >>>> +#define GSC_IN_CHROMA_ORDER_CRCB (1 << 12) >>>> +#define GSC_IN_FORMAT_MASK (7 << 8) >>>> +#define GSC_IN_XRGB8888 (0 << 8) >>>> +#define GSC_IN_RGB565 (1 << 8) >>>> +#define GSC_IN_YUV420_2P (2 << 8) >>>> +#define GSC_IN_YUV420_3P (3 << 8) >>>> +#define GSC_IN_YUV422_1P (4 << 8) >>>> +#define GSC_IN_YUV422_2P (5 << 8) >>>> +#define GSC_IN_YUV422_3P (6 << 8) >>>> +#define GSC_IN_TILE_TYPE_MASK (1 << 4) >>>> +#define GSC_IN_TILE_C_16x8 (0 << 4) >>>> +#define GSC_IN_TILE_C_16x16 (1 << 4) >>>> +#define GSC_IN_TILE_MODE (1 << 3) >>>> +#define GSC_IN_LOCAL_SEL_MASK (3 << 1) >>>> +#define GSC_IN_LOCAL_CAM3 (3 << 1) >>>> +#define GSC_IN_LOCAL_FIMD_WB (2 << 1) >>>> +#define GSC_IN_LOCAL_CAM1 (1 << 1) >>>> +#define GSC_IN_LOCAL_CAM0 (0 << 1) >>>> +#define GSC_IN_PATH_MASK (1 << 0) >>>> +#define GSC_IN_PATH_LOCAL (1 << 0) >>>> +#define GSC_IN_PATH_MEMORY (0 << 0) >>>> + >>>> +/* G-Scaler source image size */ >>>> +#define GSC_SRCIMG_SIZE 0x14 >>>> +#define GSC_SRCIMG_HEIGHT_MASK (0x1fff << 16) >>>> +#define GSC_SRCIMG_HEIGHT(x) ((x) << 16) >>>> +#define GSC_SRCIMG_WIDTH_MASK (0x3fff << 0) >>>> +#define GSC_SRCIMG_WIDTH(x) ((x) << 0) >>>> + >>>> +/* G-Scaler source image offset */ >>>> +#define GSC_SRCIMG_OFFSET 0x18 >>>> +#define GSC_SRCIMG_OFFSET_Y_MASK (0x1fff << 16) >>>> +#define GSC_SRCIMG_OFFSET_Y(x) ((x) << 16) >>>> +#define GSC_SRCIMG_OFFSET_X_MASK (0x1fff << 0) >>>> +#define GSC_SRCIMG_OFFSET_X(x) ((x) << 0) >>>> + >>>> +/* G-Scaler cropped source image size */ >>>> +#define GSC_CROPPED_SIZE 0x1C >>>> +#define GSC_CROPPED_HEIGHT_MASK (0x1fff << 16) >>>> +#define GSC_CROPPED_HEIGHT(x) ((x) << 16) >>>> +#define GSC_CROPPED_WIDTH_MASK (0x1fff << 0) >>>> +#define GSC_CROPPED_WIDTH(x) ((x) << 0) >>>> + >>>> +/* G-Scaler output control */ >>>> +#define GSC_OUT_CON 0x20 >>>> +#define GSC_OUT_GLOBAL_ALPHA_MASK (0xff << 24) >>>> +#define GSC_OUT_GLOBAL_ALPHA(x) ((x) << 24) >>>> +#define GSC_OUT_CHROM_STRIDE_SEL_MASK (1 << 13) >>>> +#define GSC_OUT_CHROM_STRIDE_SEPAR (1 << 13) >>>> +#define GSC_OUT_RB_SWAP_MASK (1 << 12) >>>> +#define GSC_OUT_RB_SWAP (1 << 12) >>>> +#define GSC_OUT_RGB_TYPE_MASK (3 << 10) >>>> +#define GSC_OUT_RGB_HD_NARROW (3 << 10) >>>> +#define GSC_OUT_RGB_HD_WIDE (2 << 10) >>>> +#define GSC_OUT_RGB_SD_NARROW (1 << 10) >>>> +#define GSC_OUT_RGB_SD_WIDE (0 << 10) >>>> +#define GSC_OUT_YUV422_1P_ORDER_MASK (1 << 9) >>>> +#define GSC_OUT_YUV422_1P_ORDER_LSB_Y (0 << 9) >>>> +#define GSC_OUT_YUV422_1P_OEDER_LSB_C (1 << 9) >>>> +#define GSC_OUT_CHROMA_ORDER_MASK (1 << 8) >>>> +#define GSC_OUT_CHROMA_ORDER_CBCR (0 << 8) >>>> +#define GSC_OUT_CHROMA_ORDER_CRCB (1 << 8) >>>> +#define GSC_OUT_FORMAT_MASK (7 << 4) >>>> +#define GSC_OUT_XRGB8888 (0 << 4) >>>> +#define GSC_OUT_RGB565 (1 << 4) >>>> +#define GSC_OUT_YUV420_2P (2 << 4) >>>> +#define GSC_OUT_YUV420_3P (3 << 4) >>>> +#define GSC_OUT_YUV422_1P (4 << 4) >>>> +#define GSC_OUT_YUV422_2P (5 << 4) >>>> +#define GSC_OUT_YUV444 (7 << 4) >>>> +#define GSC_OUT_TILE_TYPE_MASK (1 << 2) >>>> +#define GSC_OUT_TILE_C_16x8 (0 << 2) >>>> +#define GSC_OUT_TILE_C_16x16 (1 << 2) >>>> +#define GSC_OUT_TILE_MODE (1 << 1) >>>> +#define GSC_OUT_PATH_MASK (1 << 0) >>>> +#define GSC_OUT_PATH_LOCAL (1 << 0) >>>> +#define GSC_OUT_PATH_MEMORY (0 << 0) >>>> + >>>> +/* G-Scaler scaled destination image size */ >>>> +#define GSC_SCALED_SIZE 0x24 >>>> +#define GSC_SCALED_HEIGHT_MASK (0x1fff << 16) >>>> +#define GSC_SCALED_HEIGHT(x) ((x) << 16) >>>> +#define GSC_SCALED_WIDTH_MASK (0x1fff << 0) >>>> +#define GSC_SCALED_WIDTH(x) ((x) << 0) >>>> + >>>> +/* G-Scaler pre scale ratio */ >>>> +#define GSC_PRE_SCALE_RATIO 0x28 >>>> +#define GSC_PRESC_SHFACTOR_MASK (7 << 28) >>>> +#define GSC_PRESC_SHFACTOR(x) ((x) << 28) >>>> +#define GSC_PRESC_V_RATIO_MASK (7 << 16) >>>> +#define GSC_PRESC_V_RATIO(x) ((x) << 16) >>>> +#define GSC_PRESC_H_RATIO_MASK (7 << 0) >>>> +#define GSC_PRESC_H_RATIO(x) ((x) << 0) >>>> + >>>> +/* G-Scaler main scale horizontal ratio */ >>>> +#define GSC_MAIN_H_RATIO 0x2C >>>> +#define GSC_MAIN_H_RATIO_MASK (0xfffff << 0) >>>> +#define GSC_MAIN_H_RATIO_VALUE(x) ((x) << 0) >>>> + >>>> +/* G-Scaler main scale vertical ratio */ >>>> +#define GSC_MAIN_V_RATIO 0x30 >>>> +#define GSC_MAIN_V_RATIO_MASK (0xfffff << 0) >>>> +#define GSC_MAIN_V_RATIO_VALUE(x) ((x) << 0) >>>> + >>>> +/* G-Scaler input chrominance stride */ >>>> +#define GSC_IN_CHROM_STRIDE 0x3C >>>> +#define GSC_IN_CHROM_STRIDE_MASK (0x3fff << 0) >>>> +#define GSC_IN_CHROM_STRIDE_VALUE(x) ((x) << 0) >>>> + >>>> +/* G-Scaler destination image size */ >>>> +#define GSC_DSTIMG_SIZE 0x40 >>>> +#define GSC_DSTIMG_HEIGHT_MASK (0x1fff << 16) >>>> +#define GSC_DSTIMG_HEIGHT(x) ((x) << 16) >>>> +#define GSC_DSTIMG_WIDTH_MASK (0x1fff << 0) >>>> +#define GSC_DSTIMG_WIDTH(x) ((x) << 0) >>>> + >>>> +/* G-Scaler destination image offset */ >>>> +#define GSC_DSTIMG_OFFSET 0x44 >>>> +#define GSC_DSTIMG_OFFSET_Y_MASK (0x1fff << 16) >>>> +#define GSC_DSTIMG_OFFSET_Y(x) ((x) << 16) >>>> +#define GSC_DSTIMG_OFFSET_X_MASK (0x1fff << 0) >>>> +#define GSC_DSTIMG_OFFSET_X(x) ((x) << 0) >>>> + >>>> +/* G-Scaler output chrominance stride */ >>>> +#define GSC_OUT_CHROM_STRIDE 0x48 >>>> +#define GSC_OUT_CHROM_STRIDE_MASK (0x3fff << 0) >>>> +#define GSC_OUT_CHROM_STRIDE_VALUE(x) ((x) << 0) >>>> + >>>> +/* G-Scaler input y address mask */ >>>> +#define GSC_IN_BASE_ADDR_Y_MASK 0x4C >>>> +/* G-Scaler input y base address */ >>>> +#define GSC_IN_BASE_ADDR_Y(n) (0x50 + (n) * 0x4) >>>> +/* G-Scaler input y base current address */ >>>> +#define GSC_IN_BASE_ADDR_Y_CUR(n) (0x60 + (n) * 0x4) >>>> + >>>> +/* G-Scaler input cb address mask */ >>>> +#define GSC_IN_BASE_ADDR_CB_MASK 0x7C >>>> +/* G-Scaler input cb base address */ >>>> +#define GSC_IN_BASE_ADDR_CB(n) (0x80 + (n) * 0x4) >>>> +/* G-Scaler input cb base current address */ >>>> +#define GSC_IN_BASE_ADDR_CB_CUR(n) (0x90 + (n) * 0x4) >>>> + >>>> +/* G-Scaler input cr address mask */ >>>> +#define GSC_IN_BASE_ADDR_CR_MASK 0xAC >>>> +/* G-Scaler input cr base address */ >>>> +#define GSC_IN_BASE_ADDR_CR(n) (0xB0 + (n) * 0x4) >>>> +/* G-Scaler input cr base current address */ >>>> +#define GSC_IN_BASE_ADDR_CR_CUR(n) (0xC0 + (n) * 0x4) >>>> + >>>> +/* G-Scaler input address mask */ >>>> +#define GSC_IN_CURR_ADDR_INDEX (0xf << 24) >>>> +#define GSC_IN_CURR_GET_INDEX(x) ((x) >> 24) >>>> +#define GSC_IN_BASE_ADDR_PINGPONG(x) ((x) << 16) >>>> +#define GSC_IN_BASE_ADDR_MASK (0xff << 0) >>>> + >>>> +/* G-Scaler output y address mask */ >>>> +#define GSC_OUT_BASE_ADDR_Y_MASK 0x10C >>>> +/* G-Scaler output y base address */ >>>> +#define GSC_OUT_BASE_ADDR_Y(n) (0x110 + (n) * 0x4) >>>> + >>>> +/* G-Scaler output cb address mask */ >>>> +#define GSC_OUT_BASE_ADDR_CB_MASK 0x15C >>>> +/* G-Scaler output cb base address */ >>>> +#define GSC_OUT_BASE_ADDR_CB(n) (0x160 + (n) * 0x4) >>>> + >>>> +/* G-Scaler output cr address mask */ >>>> +#define GSC_OUT_BASE_ADDR_CR_MASK 0x1AC >>>> +/* G-Scaler output cr base address */ >>>> +#define GSC_OUT_BASE_ADDR_CR(n) (0x1B0 + (n) * 0x4) >>>> + >>>> +/* G-Scaler output address mask */ >>>> +#define GSC_OUT_CURR_ADDR_INDEX (0xf << 24) >>>> +#define GSC_OUT_CURR_GET_INDEX(x) ((x) >> 24) >>>> +#define GSC_OUT_BASE_ADDR_PINGPONG(x) ((x) << 16) >>>> +#define GSC_OUT_BASE_ADDR_MASK (0xffff << 0) >>>> + >>>> +/* G-Scaler horizontal scaling filter */ >>>> +#define GSC_HCOEF(n, s, x) (0x300 + (n) * 0x4 + (s) * 0x30 + (x) * >>>> 0x300) >>>> + >>>> +/* G-Scaler vertical scaling filter */ >>>> +#define GSC_VCOEF(n, s, x) (0x200 + (n) * 0x4 + (s) * 0x30 + (x) * >>>> 0x300) >>>> + >>>> +/* G-Scaler BUS control */ >>>> +#define GSC_BUSCON 0xA78 >>>> +#define GSC_BUSCON_INT_TIME_MASK (1 << 8) >>>> +#define GSC_BUSCON_INT_DATA_TRANS (0 << 8) >>>> +#define GSC_BUSCON_INT_AXI_RESPONSE (1 << 8) >>>> +#define GSC_BUSCON_AWCACHE(x) ((x) << 4) >>>> +#define GSC_BUSCON_ARCACHE(x) ((x) << 0) >>>> + >>>> +/* G-Scaler V position */ >>>> +#define GSC_VPOSITION 0xA7C >>>> +#define GSC_VPOS_F(x) ((x) << 0) >>>> + >>>> + >>>> +/* G-Scaler clock initial count */ >>>> +#define GSC_CLK_INIT_COUNT 0xC00 >>>> +#define GSC_CLK_GATE_MODE_INIT_CNT(x) ((x) << 0) >>>> + >>>> +/* G-Scaler clock snoop count */ >>>> +#define GSC_CLK_SNOOP_COUNT 0xC04 >>>> +#define GSC_CLK_GATE_MODE_SNOOP_CNT(x) ((x) << 0) >>>> + >>>> +#endif /* EXYNOS_REGS_GSC_H_ */ >>>> diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h >>>> index 4d55b1f..f422a02 100644 >>>> --- a/include/drm/exynos_drm.h >>>> +++ b/include/drm/exynos_drm.h >>>> @@ -119,4 +119,19 @@ struct exynos_drm_fimc_pdata { >>>> enum exynos_drm_fimc_ver ver; >>>> }; >>>> +/* definition of chipset version */ >>>> +enum exynos_drm_gsc_ver { >>>> + GSC_EXYNOS_5250, >>>> + GSC_EXYNOS_5410, >>>> +}; >>>> + >>>> +/** >>>> + * Platform Specific Structure for DRM based GSC. >>>> + * >>>> + * @ver: current hardware block version. >>>> + */ >>>> +struct exynos_drm_gsc_pdata { >>>> + enum exynos_drm_gsc_ver ver; >>>> +}; >>> >>> Please don't use check version via platform data. Use DT or >>> platform_device_id. >> >> - Yes I know. but this case is different. same exynos5 have different >> version. >> so, I consider about this what is best. please waiting next patch. >> > > Could you explain about which exynos5 uses which gsc version? - minor version is different. I will remove it. > >>> >>>> + >>>> #endif /* _EXYNOS_DRM_H_ */ >>> >>> Thanks. >>> >> >> > > Thanks. > >