162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012 Samsung Electronics Co.Ltd 462306a36Sopenharmony_ci * Authors: 562306a36Sopenharmony_ci * Eunchul Kim <chulspro.kim@samsung.com> 662306a36Sopenharmony_ci * Jinyoung Jeon <jy0.jeon@samsung.com> 762306a36Sopenharmony_ci * Sangmin Lee <lsmin.lee@samsung.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/component.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1462306a36Sopenharmony_ci#include <linux/of_device.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1762306a36Sopenharmony_ci#include <linux/regmap.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <drm/drm_fourcc.h> 2062306a36Sopenharmony_ci#include <drm/drm_print.h> 2162306a36Sopenharmony_ci#include <drm/exynos_drm.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "exynos_drm_drv.h" 2462306a36Sopenharmony_ci#include "exynos_drm_ipp.h" 2562306a36Sopenharmony_ci#include "regs-gsc.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * GSC stands for General SCaler and 2962306a36Sopenharmony_ci * supports image scaler/rotator and input/output DMA operations. 3062306a36Sopenharmony_ci * input DMA reads image data from the memory. 3162306a36Sopenharmony_ci * output DMA writes image data to memory. 3262306a36Sopenharmony_ci * GSC supports image rotation and image effect functions. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define GSC_MAX_CLOCKS 8 3762306a36Sopenharmony_ci#define GSC_MAX_SRC 4 3862306a36Sopenharmony_ci#define GSC_MAX_DST 16 3962306a36Sopenharmony_ci#define GSC_RESET_TIMEOUT 50 4062306a36Sopenharmony_ci#define GSC_BUF_STOP 1 4162306a36Sopenharmony_ci#define GSC_BUF_START 2 4262306a36Sopenharmony_ci#define GSC_REG_SZ 16 4362306a36Sopenharmony_ci#define GSC_WIDTH_ITU_709 1280 4462306a36Sopenharmony_ci#define GSC_SC_UP_MAX_RATIO 65536 4562306a36Sopenharmony_ci#define GSC_SC_DOWN_RATIO_7_8 74898 4662306a36Sopenharmony_ci#define GSC_SC_DOWN_RATIO_6_8 87381 4762306a36Sopenharmony_ci#define GSC_SC_DOWN_RATIO_5_8 104857 4862306a36Sopenharmony_ci#define GSC_SC_DOWN_RATIO_4_8 131072 4962306a36Sopenharmony_ci#define GSC_SC_DOWN_RATIO_3_8 174762 5062306a36Sopenharmony_ci#define GSC_SC_DOWN_RATIO_2_8 262144 5162306a36Sopenharmony_ci#define GSC_CROP_MAX 8192 5262306a36Sopenharmony_ci#define GSC_CROP_MIN 32 5362306a36Sopenharmony_ci#define GSC_SCALE_MAX 4224 5462306a36Sopenharmony_ci#define GSC_SCALE_MIN 32 5562306a36Sopenharmony_ci#define GSC_COEF_RATIO 7 5662306a36Sopenharmony_ci#define GSC_COEF_PHASE 9 5762306a36Sopenharmony_ci#define GSC_COEF_ATTR 16 5862306a36Sopenharmony_ci#define GSC_COEF_H_8T 8 5962306a36Sopenharmony_ci#define GSC_COEF_V_4T 4 6062306a36Sopenharmony_ci#define GSC_COEF_DEPTH 3 6162306a36Sopenharmony_ci#define GSC_AUTOSUSPEND_DELAY 2000 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define get_gsc_context(dev) dev_get_drvdata(dev) 6462306a36Sopenharmony_ci#define gsc_read(offset) readl(ctx->regs + (offset)) 6562306a36Sopenharmony_ci#define gsc_write(cfg, offset) writel(cfg, ctx->regs + (offset)) 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* 6862306a36Sopenharmony_ci * A structure of scaler. 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * @range: narrow, wide. 7162306a36Sopenharmony_ci * @pre_shfactor: pre sclaer shift factor. 7262306a36Sopenharmony_ci * @pre_hratio: horizontal ratio of the prescaler. 7362306a36Sopenharmony_ci * @pre_vratio: vertical ratio of the prescaler. 7462306a36Sopenharmony_ci * @main_hratio: the main scaler's horizontal ratio. 7562306a36Sopenharmony_ci * @main_vratio: the main scaler's vertical ratio. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_cistruct gsc_scaler { 7862306a36Sopenharmony_ci bool range; 7962306a36Sopenharmony_ci u32 pre_shfactor; 8062306a36Sopenharmony_ci u32 pre_hratio; 8162306a36Sopenharmony_ci u32 pre_vratio; 8262306a36Sopenharmony_ci unsigned long main_hratio; 8362306a36Sopenharmony_ci unsigned long main_vratio; 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* 8762306a36Sopenharmony_ci * A structure of gsc context. 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * @regs: memory mapped io registers. 9062306a36Sopenharmony_ci * @gsc_clk: gsc gate clock. 9162306a36Sopenharmony_ci * @sc: scaler infomations. 9262306a36Sopenharmony_ci * @id: gsc id. 9362306a36Sopenharmony_ci * @irq: irq number. 9462306a36Sopenharmony_ci * @rotation: supports rotation of src. 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_cistruct gsc_context { 9762306a36Sopenharmony_ci struct exynos_drm_ipp ipp; 9862306a36Sopenharmony_ci struct drm_device *drm_dev; 9962306a36Sopenharmony_ci void *dma_priv; 10062306a36Sopenharmony_ci struct device *dev; 10162306a36Sopenharmony_ci struct exynos_drm_ipp_task *task; 10262306a36Sopenharmony_ci struct exynos_drm_ipp_formats *formats; 10362306a36Sopenharmony_ci unsigned int num_formats; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci void __iomem *regs; 10662306a36Sopenharmony_ci const char **clk_names; 10762306a36Sopenharmony_ci struct clk *clocks[GSC_MAX_CLOCKS]; 10862306a36Sopenharmony_ci int num_clocks; 10962306a36Sopenharmony_ci struct gsc_scaler sc; 11062306a36Sopenharmony_ci int id; 11162306a36Sopenharmony_ci int irq; 11262306a36Sopenharmony_ci bool rotation; 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/** 11662306a36Sopenharmony_ci * struct gsc_driverdata - per device type driver data for init time. 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci * @limits: picture size limits array 11962306a36Sopenharmony_ci * @num_limits: number of items in the aforementioned array 12062306a36Sopenharmony_ci * @clk_names: names of clocks needed by this variant 12162306a36Sopenharmony_ci * @num_clocks: the number of clocks needed by this variant 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_cistruct gsc_driverdata { 12462306a36Sopenharmony_ci const struct drm_exynos_ipp_limit *limits; 12562306a36Sopenharmony_ci int num_limits; 12662306a36Sopenharmony_ci const char *clk_names[GSC_MAX_CLOCKS]; 12762306a36Sopenharmony_ci int num_clocks; 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* 8-tap Filter Coefficient */ 13162306a36Sopenharmony_cistatic const int h_coef_8t[GSC_COEF_RATIO][GSC_COEF_ATTR][GSC_COEF_H_8T] = { 13262306a36Sopenharmony_ci { /* Ratio <= 65536 (~8:8) */ 13362306a36Sopenharmony_ci { 0, 0, 0, 128, 0, 0, 0, 0 }, 13462306a36Sopenharmony_ci { -1, 2, -6, 127, 7, -2, 1, 0 }, 13562306a36Sopenharmony_ci { -1, 4, -12, 125, 16, -5, 1, 0 }, 13662306a36Sopenharmony_ci { -1, 5, -15, 120, 25, -8, 2, 0 }, 13762306a36Sopenharmony_ci { -1, 6, -18, 114, 35, -10, 3, -1 }, 13862306a36Sopenharmony_ci { -1, 6, -20, 107, 46, -13, 4, -1 }, 13962306a36Sopenharmony_ci { -2, 7, -21, 99, 57, -16, 5, -1 }, 14062306a36Sopenharmony_ci { -1, 6, -20, 89, 68, -18, 5, -1 }, 14162306a36Sopenharmony_ci { -1, 6, -20, 79, 79, -20, 6, -1 }, 14262306a36Sopenharmony_ci { -1, 5, -18, 68, 89, -20, 6, -1 }, 14362306a36Sopenharmony_ci { -1, 5, -16, 57, 99, -21, 7, -2 }, 14462306a36Sopenharmony_ci { -1, 4, -13, 46, 107, -20, 6, -1 }, 14562306a36Sopenharmony_ci { -1, 3, -10, 35, 114, -18, 6, -1 }, 14662306a36Sopenharmony_ci { 0, 2, -8, 25, 120, -15, 5, -1 }, 14762306a36Sopenharmony_ci { 0, 1, -5, 16, 125, -12, 4, -1 }, 14862306a36Sopenharmony_ci { 0, 1, -2, 7, 127, -6, 2, -1 } 14962306a36Sopenharmony_ci }, { /* 65536 < Ratio <= 74898 (~8:7) */ 15062306a36Sopenharmony_ci { 3, -8, 14, 111, 13, -8, 3, 0 }, 15162306a36Sopenharmony_ci { 2, -6, 7, 112, 21, -10, 3, -1 }, 15262306a36Sopenharmony_ci { 2, -4, 1, 110, 28, -12, 4, -1 }, 15362306a36Sopenharmony_ci { 1, -2, -3, 106, 36, -13, 4, -1 }, 15462306a36Sopenharmony_ci { 1, -1, -7, 103, 44, -15, 4, -1 }, 15562306a36Sopenharmony_ci { 1, 1, -11, 97, 53, -16, 4, -1 }, 15662306a36Sopenharmony_ci { 0, 2, -13, 91, 61, -16, 4, -1 }, 15762306a36Sopenharmony_ci { 0, 3, -15, 85, 69, -17, 4, -1 }, 15862306a36Sopenharmony_ci { 0, 3, -16, 77, 77, -16, 3, 0 }, 15962306a36Sopenharmony_ci { -1, 4, -17, 69, 85, -15, 3, 0 }, 16062306a36Sopenharmony_ci { -1, 4, -16, 61, 91, -13, 2, 0 }, 16162306a36Sopenharmony_ci { -1, 4, -16, 53, 97, -11, 1, 1 }, 16262306a36Sopenharmony_ci { -1, 4, -15, 44, 103, -7, -1, 1 }, 16362306a36Sopenharmony_ci { -1, 4, -13, 36, 106, -3, -2, 1 }, 16462306a36Sopenharmony_ci { -1, 4, -12, 28, 110, 1, -4, 2 }, 16562306a36Sopenharmony_ci { -1, 3, -10, 21, 112, 7, -6, 2 } 16662306a36Sopenharmony_ci }, { /* 74898 < Ratio <= 87381 (~8:6) */ 16762306a36Sopenharmony_ci { 2, -11, 25, 96, 25, -11, 2, 0 }, 16862306a36Sopenharmony_ci { 2, -10, 19, 96, 31, -12, 2, 0 }, 16962306a36Sopenharmony_ci { 2, -9, 14, 94, 37, -12, 2, 0 }, 17062306a36Sopenharmony_ci { 2, -8, 10, 92, 43, -12, 1, 0 }, 17162306a36Sopenharmony_ci { 2, -7, 5, 90, 49, -12, 1, 0 }, 17262306a36Sopenharmony_ci { 2, -5, 1, 86, 55, -12, 0, 1 }, 17362306a36Sopenharmony_ci { 2, -4, -2, 82, 61, -11, -1, 1 }, 17462306a36Sopenharmony_ci { 1, -3, -5, 77, 67, -9, -1, 1 }, 17562306a36Sopenharmony_ci { 1, -2, -7, 72, 72, -7, -2, 1 }, 17662306a36Sopenharmony_ci { 1, -1, -9, 67, 77, -5, -3, 1 }, 17762306a36Sopenharmony_ci { 1, -1, -11, 61, 82, -2, -4, 2 }, 17862306a36Sopenharmony_ci { 1, 0, -12, 55, 86, 1, -5, 2 }, 17962306a36Sopenharmony_ci { 0, 1, -12, 49, 90, 5, -7, 2 }, 18062306a36Sopenharmony_ci { 0, 1, -12, 43, 92, 10, -8, 2 }, 18162306a36Sopenharmony_ci { 0, 2, -12, 37, 94, 14, -9, 2 }, 18262306a36Sopenharmony_ci { 0, 2, -12, 31, 96, 19, -10, 2 } 18362306a36Sopenharmony_ci }, { /* 87381 < Ratio <= 104857 (~8:5) */ 18462306a36Sopenharmony_ci { -1, -8, 33, 80, 33, -8, -1, 0 }, 18562306a36Sopenharmony_ci { -1, -8, 28, 80, 37, -7, -2, 1 }, 18662306a36Sopenharmony_ci { 0, -8, 24, 79, 41, -7, -2, 1 }, 18762306a36Sopenharmony_ci { 0, -8, 20, 78, 46, -6, -3, 1 }, 18862306a36Sopenharmony_ci { 0, -8, 16, 76, 50, -4, -3, 1 }, 18962306a36Sopenharmony_ci { 0, -7, 13, 74, 54, -3, -4, 1 }, 19062306a36Sopenharmony_ci { 1, -7, 10, 71, 58, -1, -5, 1 }, 19162306a36Sopenharmony_ci { 1, -6, 6, 68, 62, 1, -5, 1 }, 19262306a36Sopenharmony_ci { 1, -6, 4, 65, 65, 4, -6, 1 }, 19362306a36Sopenharmony_ci { 1, -5, 1, 62, 68, 6, -6, 1 }, 19462306a36Sopenharmony_ci { 1, -5, -1, 58, 71, 10, -7, 1 }, 19562306a36Sopenharmony_ci { 1, -4, -3, 54, 74, 13, -7, 0 }, 19662306a36Sopenharmony_ci { 1, -3, -4, 50, 76, 16, -8, 0 }, 19762306a36Sopenharmony_ci { 1, -3, -6, 46, 78, 20, -8, 0 }, 19862306a36Sopenharmony_ci { 1, -2, -7, 41, 79, 24, -8, 0 }, 19962306a36Sopenharmony_ci { 1, -2, -7, 37, 80, 28, -8, -1 } 20062306a36Sopenharmony_ci }, { /* 104857 < Ratio <= 131072 (~8:4) */ 20162306a36Sopenharmony_ci { -3, 0, 35, 64, 35, 0, -3, 0 }, 20262306a36Sopenharmony_ci { -3, -1, 32, 64, 38, 1, -3, 0 }, 20362306a36Sopenharmony_ci { -2, -2, 29, 63, 41, 2, -3, 0 }, 20462306a36Sopenharmony_ci { -2, -3, 27, 63, 43, 4, -4, 0 }, 20562306a36Sopenharmony_ci { -2, -3, 24, 61, 46, 6, -4, 0 }, 20662306a36Sopenharmony_ci { -2, -3, 21, 60, 49, 7, -4, 0 }, 20762306a36Sopenharmony_ci { -1, -4, 19, 59, 51, 9, -4, -1 }, 20862306a36Sopenharmony_ci { -1, -4, 16, 57, 53, 12, -4, -1 }, 20962306a36Sopenharmony_ci { -1, -4, 14, 55, 55, 14, -4, -1 }, 21062306a36Sopenharmony_ci { -1, -4, 12, 53, 57, 16, -4, -1 }, 21162306a36Sopenharmony_ci { -1, -4, 9, 51, 59, 19, -4, -1 }, 21262306a36Sopenharmony_ci { 0, -4, 7, 49, 60, 21, -3, -2 }, 21362306a36Sopenharmony_ci { 0, -4, 6, 46, 61, 24, -3, -2 }, 21462306a36Sopenharmony_ci { 0, -4, 4, 43, 63, 27, -3, -2 }, 21562306a36Sopenharmony_ci { 0, -3, 2, 41, 63, 29, -2, -2 }, 21662306a36Sopenharmony_ci { 0, -3, 1, 38, 64, 32, -1, -3 } 21762306a36Sopenharmony_ci }, { /* 131072 < Ratio <= 174762 (~8:3) */ 21862306a36Sopenharmony_ci { -1, 8, 33, 48, 33, 8, -1, 0 }, 21962306a36Sopenharmony_ci { -1, 7, 31, 49, 35, 9, -1, -1 }, 22062306a36Sopenharmony_ci { -1, 6, 30, 49, 36, 10, -1, -1 }, 22162306a36Sopenharmony_ci { -1, 5, 28, 48, 38, 12, -1, -1 }, 22262306a36Sopenharmony_ci { -1, 4, 26, 48, 39, 13, 0, -1 }, 22362306a36Sopenharmony_ci { -1, 3, 24, 47, 41, 15, 0, -1 }, 22462306a36Sopenharmony_ci { -1, 2, 23, 47, 42, 16, 0, -1 }, 22562306a36Sopenharmony_ci { -1, 2, 21, 45, 43, 18, 1, -1 }, 22662306a36Sopenharmony_ci { -1, 1, 19, 45, 45, 19, 1, -1 }, 22762306a36Sopenharmony_ci { -1, 1, 18, 43, 45, 21, 2, -1 }, 22862306a36Sopenharmony_ci { -1, 0, 16, 42, 47, 23, 2, -1 }, 22962306a36Sopenharmony_ci { -1, 0, 15, 41, 47, 24, 3, -1 }, 23062306a36Sopenharmony_ci { -1, 0, 13, 39, 48, 26, 4, -1 }, 23162306a36Sopenharmony_ci { -1, -1, 12, 38, 48, 28, 5, -1 }, 23262306a36Sopenharmony_ci { -1, -1, 10, 36, 49, 30, 6, -1 }, 23362306a36Sopenharmony_ci { -1, -1, 9, 35, 49, 31, 7, -1 } 23462306a36Sopenharmony_ci }, { /* 174762 < Ratio <= 262144 (~8:2) */ 23562306a36Sopenharmony_ci { 2, 13, 30, 38, 30, 13, 2, 0 }, 23662306a36Sopenharmony_ci { 2, 12, 29, 38, 30, 14, 3, 0 }, 23762306a36Sopenharmony_ci { 2, 11, 28, 38, 31, 15, 3, 0 }, 23862306a36Sopenharmony_ci { 2, 10, 26, 38, 32, 16, 4, 0 }, 23962306a36Sopenharmony_ci { 1, 10, 26, 37, 33, 17, 4, 0 }, 24062306a36Sopenharmony_ci { 1, 9, 24, 37, 34, 18, 5, 0 }, 24162306a36Sopenharmony_ci { 1, 8, 24, 37, 34, 19, 5, 0 }, 24262306a36Sopenharmony_ci { 1, 7, 22, 36, 35, 20, 6, 1 }, 24362306a36Sopenharmony_ci { 1, 6, 21, 36, 36, 21, 6, 1 }, 24462306a36Sopenharmony_ci { 1, 6, 20, 35, 36, 22, 7, 1 }, 24562306a36Sopenharmony_ci { 0, 5, 19, 34, 37, 24, 8, 1 }, 24662306a36Sopenharmony_ci { 0, 5, 18, 34, 37, 24, 9, 1 }, 24762306a36Sopenharmony_ci { 0, 4, 17, 33, 37, 26, 10, 1 }, 24862306a36Sopenharmony_ci { 0, 4, 16, 32, 38, 26, 10, 2 }, 24962306a36Sopenharmony_ci { 0, 3, 15, 31, 38, 28, 11, 2 }, 25062306a36Sopenharmony_ci { 0, 3, 14, 30, 38, 29, 12, 2 } 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci}; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/* 4-tap Filter Coefficient */ 25562306a36Sopenharmony_cistatic const int v_coef_4t[GSC_COEF_RATIO][GSC_COEF_ATTR][GSC_COEF_V_4T] = { 25662306a36Sopenharmony_ci { /* Ratio <= 65536 (~8:8) */ 25762306a36Sopenharmony_ci { 0, 128, 0, 0 }, 25862306a36Sopenharmony_ci { -4, 127, 5, 0 }, 25962306a36Sopenharmony_ci { -6, 124, 11, -1 }, 26062306a36Sopenharmony_ci { -8, 118, 19, -1 }, 26162306a36Sopenharmony_ci { -8, 111, 27, -2 }, 26262306a36Sopenharmony_ci { -8, 102, 37, -3 }, 26362306a36Sopenharmony_ci { -8, 92, 48, -4 }, 26462306a36Sopenharmony_ci { -7, 81, 59, -5 }, 26562306a36Sopenharmony_ci { -6, 70, 70, -6 }, 26662306a36Sopenharmony_ci { -5, 59, 81, -7 }, 26762306a36Sopenharmony_ci { -4, 48, 92, -8 }, 26862306a36Sopenharmony_ci { -3, 37, 102, -8 }, 26962306a36Sopenharmony_ci { -2, 27, 111, -8 }, 27062306a36Sopenharmony_ci { -1, 19, 118, -8 }, 27162306a36Sopenharmony_ci { -1, 11, 124, -6 }, 27262306a36Sopenharmony_ci { 0, 5, 127, -4 } 27362306a36Sopenharmony_ci }, { /* 65536 < Ratio <= 74898 (~8:7) */ 27462306a36Sopenharmony_ci { 8, 112, 8, 0 }, 27562306a36Sopenharmony_ci { 4, 111, 14, -1 }, 27662306a36Sopenharmony_ci { 1, 109, 20, -2 }, 27762306a36Sopenharmony_ci { -2, 105, 27, -2 }, 27862306a36Sopenharmony_ci { -3, 100, 34, -3 }, 27962306a36Sopenharmony_ci { -5, 93, 43, -3 }, 28062306a36Sopenharmony_ci { -5, 86, 51, -4 }, 28162306a36Sopenharmony_ci { -5, 77, 60, -4 }, 28262306a36Sopenharmony_ci { -5, 69, 69, -5 }, 28362306a36Sopenharmony_ci { -4, 60, 77, -5 }, 28462306a36Sopenharmony_ci { -4, 51, 86, -5 }, 28562306a36Sopenharmony_ci { -3, 43, 93, -5 }, 28662306a36Sopenharmony_ci { -3, 34, 100, -3 }, 28762306a36Sopenharmony_ci { -2, 27, 105, -2 }, 28862306a36Sopenharmony_ci { -2, 20, 109, 1 }, 28962306a36Sopenharmony_ci { -1, 14, 111, 4 } 29062306a36Sopenharmony_ci }, { /* 74898 < Ratio <= 87381 (~8:6) */ 29162306a36Sopenharmony_ci { 16, 96, 16, 0 }, 29262306a36Sopenharmony_ci { 12, 97, 21, -2 }, 29362306a36Sopenharmony_ci { 8, 96, 26, -2 }, 29462306a36Sopenharmony_ci { 5, 93, 32, -2 }, 29562306a36Sopenharmony_ci { 2, 89, 39, -2 }, 29662306a36Sopenharmony_ci { 0, 84, 46, -2 }, 29762306a36Sopenharmony_ci { -1, 79, 53, -3 }, 29862306a36Sopenharmony_ci { -2, 73, 59, -2 }, 29962306a36Sopenharmony_ci { -2, 66, 66, -2 }, 30062306a36Sopenharmony_ci { -2, 59, 73, -2 }, 30162306a36Sopenharmony_ci { -3, 53, 79, -1 }, 30262306a36Sopenharmony_ci { -2, 46, 84, 0 }, 30362306a36Sopenharmony_ci { -2, 39, 89, 2 }, 30462306a36Sopenharmony_ci { -2, 32, 93, 5 }, 30562306a36Sopenharmony_ci { -2, 26, 96, 8 }, 30662306a36Sopenharmony_ci { -2, 21, 97, 12 } 30762306a36Sopenharmony_ci }, { /* 87381 < Ratio <= 104857 (~8:5) */ 30862306a36Sopenharmony_ci { 22, 84, 22, 0 }, 30962306a36Sopenharmony_ci { 18, 85, 26, -1 }, 31062306a36Sopenharmony_ci { 14, 84, 31, -1 }, 31162306a36Sopenharmony_ci { 11, 82, 36, -1 }, 31262306a36Sopenharmony_ci { 8, 79, 42, -1 }, 31362306a36Sopenharmony_ci { 6, 76, 47, -1 }, 31462306a36Sopenharmony_ci { 4, 72, 52, 0 }, 31562306a36Sopenharmony_ci { 2, 68, 58, 0 }, 31662306a36Sopenharmony_ci { 1, 63, 63, 1 }, 31762306a36Sopenharmony_ci { 0, 58, 68, 2 }, 31862306a36Sopenharmony_ci { 0, 52, 72, 4 }, 31962306a36Sopenharmony_ci { -1, 47, 76, 6 }, 32062306a36Sopenharmony_ci { -1, 42, 79, 8 }, 32162306a36Sopenharmony_ci { -1, 36, 82, 11 }, 32262306a36Sopenharmony_ci { -1, 31, 84, 14 }, 32362306a36Sopenharmony_ci { -1, 26, 85, 18 } 32462306a36Sopenharmony_ci }, { /* 104857 < Ratio <= 131072 (~8:4) */ 32562306a36Sopenharmony_ci { 26, 76, 26, 0 }, 32662306a36Sopenharmony_ci { 22, 76, 30, 0 }, 32762306a36Sopenharmony_ci { 19, 75, 34, 0 }, 32862306a36Sopenharmony_ci { 16, 73, 38, 1 }, 32962306a36Sopenharmony_ci { 13, 71, 43, 1 }, 33062306a36Sopenharmony_ci { 10, 69, 47, 2 }, 33162306a36Sopenharmony_ci { 8, 66, 51, 3 }, 33262306a36Sopenharmony_ci { 6, 63, 55, 4 }, 33362306a36Sopenharmony_ci { 5, 59, 59, 5 }, 33462306a36Sopenharmony_ci { 4, 55, 63, 6 }, 33562306a36Sopenharmony_ci { 3, 51, 66, 8 }, 33662306a36Sopenharmony_ci { 2, 47, 69, 10 }, 33762306a36Sopenharmony_ci { 1, 43, 71, 13 }, 33862306a36Sopenharmony_ci { 1, 38, 73, 16 }, 33962306a36Sopenharmony_ci { 0, 34, 75, 19 }, 34062306a36Sopenharmony_ci { 0, 30, 76, 22 } 34162306a36Sopenharmony_ci }, { /* 131072 < Ratio <= 174762 (~8:3) */ 34262306a36Sopenharmony_ci { 29, 70, 29, 0 }, 34362306a36Sopenharmony_ci { 26, 68, 32, 2 }, 34462306a36Sopenharmony_ci { 23, 67, 36, 2 }, 34562306a36Sopenharmony_ci { 20, 66, 39, 3 }, 34662306a36Sopenharmony_ci { 17, 65, 43, 3 }, 34762306a36Sopenharmony_ci { 15, 63, 46, 4 }, 34862306a36Sopenharmony_ci { 12, 61, 50, 5 }, 34962306a36Sopenharmony_ci { 10, 58, 53, 7 }, 35062306a36Sopenharmony_ci { 8, 56, 56, 8 }, 35162306a36Sopenharmony_ci { 7, 53, 58, 10 }, 35262306a36Sopenharmony_ci { 5, 50, 61, 12 }, 35362306a36Sopenharmony_ci { 4, 46, 63, 15 }, 35462306a36Sopenharmony_ci { 3, 43, 65, 17 }, 35562306a36Sopenharmony_ci { 3, 39, 66, 20 }, 35662306a36Sopenharmony_ci { 2, 36, 67, 23 }, 35762306a36Sopenharmony_ci { 2, 32, 68, 26 } 35862306a36Sopenharmony_ci }, { /* 174762 < Ratio <= 262144 (~8:2) */ 35962306a36Sopenharmony_ci { 32, 64, 32, 0 }, 36062306a36Sopenharmony_ci { 28, 63, 34, 3 }, 36162306a36Sopenharmony_ci { 25, 62, 37, 4 }, 36262306a36Sopenharmony_ci { 22, 62, 40, 4 }, 36362306a36Sopenharmony_ci { 19, 61, 43, 5 }, 36462306a36Sopenharmony_ci { 17, 59, 46, 6 }, 36562306a36Sopenharmony_ci { 15, 58, 48, 7 }, 36662306a36Sopenharmony_ci { 13, 55, 51, 9 }, 36762306a36Sopenharmony_ci { 11, 53, 53, 11 }, 36862306a36Sopenharmony_ci { 9, 51, 55, 13 }, 36962306a36Sopenharmony_ci { 7, 48, 58, 15 }, 37062306a36Sopenharmony_ci { 6, 46, 59, 17 }, 37162306a36Sopenharmony_ci { 5, 43, 61, 19 }, 37262306a36Sopenharmony_ci { 4, 40, 62, 22 }, 37362306a36Sopenharmony_ci { 4, 37, 62, 25 }, 37462306a36Sopenharmony_ci { 3, 34, 63, 28 } 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci}; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic int gsc_sw_reset(struct gsc_context *ctx) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci u32 cfg; 38162306a36Sopenharmony_ci int count = GSC_RESET_TIMEOUT; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* s/w reset */ 38462306a36Sopenharmony_ci cfg = (GSC_SW_RESET_SRESET); 38562306a36Sopenharmony_ci gsc_write(cfg, GSC_SW_RESET); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* wait s/w reset complete */ 38862306a36Sopenharmony_ci while (count--) { 38962306a36Sopenharmony_ci cfg = gsc_read(GSC_SW_RESET); 39062306a36Sopenharmony_ci if (!cfg) 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci usleep_range(1000, 2000); 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (cfg) { 39662306a36Sopenharmony_ci DRM_DEV_ERROR(ctx->dev, "failed to reset gsc h/w.\n"); 39762306a36Sopenharmony_ci return -EBUSY; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* reset sequence */ 40162306a36Sopenharmony_ci cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK); 40262306a36Sopenharmony_ci cfg |= (GSC_IN_BASE_ADDR_MASK | 40362306a36Sopenharmony_ci GSC_IN_BASE_ADDR_PINGPONG(0)); 40462306a36Sopenharmony_ci gsc_write(cfg, GSC_IN_BASE_ADDR_Y_MASK); 40562306a36Sopenharmony_ci gsc_write(cfg, GSC_IN_BASE_ADDR_CB_MASK); 40662306a36Sopenharmony_ci gsc_write(cfg, GSC_IN_BASE_ADDR_CR_MASK); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK); 40962306a36Sopenharmony_ci cfg |= (GSC_OUT_BASE_ADDR_MASK | 41062306a36Sopenharmony_ci GSC_OUT_BASE_ADDR_PINGPONG(0)); 41162306a36Sopenharmony_ci gsc_write(cfg, GSC_OUT_BASE_ADDR_Y_MASK); 41262306a36Sopenharmony_ci gsc_write(cfg, GSC_OUT_BASE_ADDR_CB_MASK); 41362306a36Sopenharmony_ci gsc_write(cfg, GSC_OUT_BASE_ADDR_CR_MASK); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic void gsc_handle_irq(struct gsc_context *ctx, bool enable, 41962306a36Sopenharmony_ci bool overflow, bool done) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci u32 cfg; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "enable[%d]overflow[%d]level[%d]\n", 42462306a36Sopenharmony_ci enable, overflow, done); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci cfg = gsc_read(GSC_IRQ); 42762306a36Sopenharmony_ci cfg |= (GSC_IRQ_OR_MASK | GSC_IRQ_FRMDONE_MASK); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (enable) 43062306a36Sopenharmony_ci cfg |= GSC_IRQ_ENABLE; 43162306a36Sopenharmony_ci else 43262306a36Sopenharmony_ci cfg &= ~GSC_IRQ_ENABLE; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (overflow) 43562306a36Sopenharmony_ci cfg &= ~GSC_IRQ_OR_MASK; 43662306a36Sopenharmony_ci else 43762306a36Sopenharmony_ci cfg |= GSC_IRQ_OR_MASK; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (done) 44062306a36Sopenharmony_ci cfg &= ~GSC_IRQ_FRMDONE_MASK; 44162306a36Sopenharmony_ci else 44262306a36Sopenharmony_ci cfg |= GSC_IRQ_FRMDONE_MASK; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci gsc_write(cfg, GSC_IRQ); 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci u32 cfg; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci cfg = gsc_read(GSC_IN_CON); 45562306a36Sopenharmony_ci cfg &= ~(GSC_IN_RGB_TYPE_MASK | GSC_IN_YUV422_1P_ORDER_MASK | 45662306a36Sopenharmony_ci GSC_IN_CHROMA_ORDER_MASK | GSC_IN_FORMAT_MASK | 45762306a36Sopenharmony_ci GSC_IN_TILE_TYPE_MASK | GSC_IN_TILE_MODE | 45862306a36Sopenharmony_ci GSC_IN_CHROM_STRIDE_SEL_MASK | GSC_IN_RB_SWAP_MASK); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci switch (fmt) { 46162306a36Sopenharmony_ci case DRM_FORMAT_RGB565: 46262306a36Sopenharmony_ci cfg |= GSC_IN_RGB565; 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci case DRM_FORMAT_XRGB8888: 46562306a36Sopenharmony_ci case DRM_FORMAT_ARGB8888: 46662306a36Sopenharmony_ci cfg |= GSC_IN_XRGB8888; 46762306a36Sopenharmony_ci break; 46862306a36Sopenharmony_ci case DRM_FORMAT_BGRX8888: 46962306a36Sopenharmony_ci cfg |= (GSC_IN_XRGB8888 | GSC_IN_RB_SWAP); 47062306a36Sopenharmony_ci break; 47162306a36Sopenharmony_ci case DRM_FORMAT_YUYV: 47262306a36Sopenharmony_ci cfg |= (GSC_IN_YUV422_1P | 47362306a36Sopenharmony_ci GSC_IN_YUV422_1P_ORDER_LSB_Y | 47462306a36Sopenharmony_ci GSC_IN_CHROMA_ORDER_CBCR); 47562306a36Sopenharmony_ci break; 47662306a36Sopenharmony_ci case DRM_FORMAT_YVYU: 47762306a36Sopenharmony_ci cfg |= (GSC_IN_YUV422_1P | 47862306a36Sopenharmony_ci GSC_IN_YUV422_1P_ORDER_LSB_Y | 47962306a36Sopenharmony_ci GSC_IN_CHROMA_ORDER_CRCB); 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci case DRM_FORMAT_UYVY: 48262306a36Sopenharmony_ci cfg |= (GSC_IN_YUV422_1P | 48362306a36Sopenharmony_ci GSC_IN_YUV422_1P_OEDER_LSB_C | 48462306a36Sopenharmony_ci GSC_IN_CHROMA_ORDER_CBCR); 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci case DRM_FORMAT_VYUY: 48762306a36Sopenharmony_ci cfg |= (GSC_IN_YUV422_1P | 48862306a36Sopenharmony_ci GSC_IN_YUV422_1P_OEDER_LSB_C | 48962306a36Sopenharmony_ci GSC_IN_CHROMA_ORDER_CRCB); 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci case DRM_FORMAT_NV21: 49262306a36Sopenharmony_ci cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_2P); 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci case DRM_FORMAT_NV61: 49562306a36Sopenharmony_ci cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV422_2P); 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci case DRM_FORMAT_YUV422: 49862306a36Sopenharmony_ci cfg |= GSC_IN_YUV422_3P; 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci case DRM_FORMAT_YUV420: 50162306a36Sopenharmony_ci cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P); 50262306a36Sopenharmony_ci break; 50362306a36Sopenharmony_ci case DRM_FORMAT_YVU420: 50462306a36Sopenharmony_ci cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_3P); 50562306a36Sopenharmony_ci break; 50662306a36Sopenharmony_ci case DRM_FORMAT_NV12: 50762306a36Sopenharmony_ci cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_2P); 50862306a36Sopenharmony_ci break; 50962306a36Sopenharmony_ci case DRM_FORMAT_NV16: 51062306a36Sopenharmony_ci cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV422_2P); 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (tiled) 51562306a36Sopenharmony_ci cfg |= (GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci gsc_write(cfg, GSC_IN_CON); 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic void gsc_src_set_transf(struct gsc_context *ctx, unsigned int rotation) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci unsigned int degree = rotation & DRM_MODE_ROTATE_MASK; 52362306a36Sopenharmony_ci u32 cfg; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci cfg = gsc_read(GSC_IN_CON); 52662306a36Sopenharmony_ci cfg &= ~GSC_IN_ROT_MASK; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci switch (degree) { 52962306a36Sopenharmony_ci case DRM_MODE_ROTATE_0: 53062306a36Sopenharmony_ci if (rotation & DRM_MODE_REFLECT_X) 53162306a36Sopenharmony_ci cfg |= GSC_IN_ROT_XFLIP; 53262306a36Sopenharmony_ci if (rotation & DRM_MODE_REFLECT_Y) 53362306a36Sopenharmony_ci cfg |= GSC_IN_ROT_YFLIP; 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci case DRM_MODE_ROTATE_90: 53662306a36Sopenharmony_ci cfg |= GSC_IN_ROT_90; 53762306a36Sopenharmony_ci if (rotation & DRM_MODE_REFLECT_X) 53862306a36Sopenharmony_ci cfg |= GSC_IN_ROT_XFLIP; 53962306a36Sopenharmony_ci if (rotation & DRM_MODE_REFLECT_Y) 54062306a36Sopenharmony_ci cfg |= GSC_IN_ROT_YFLIP; 54162306a36Sopenharmony_ci break; 54262306a36Sopenharmony_ci case DRM_MODE_ROTATE_180: 54362306a36Sopenharmony_ci cfg |= GSC_IN_ROT_180; 54462306a36Sopenharmony_ci if (rotation & DRM_MODE_REFLECT_X) 54562306a36Sopenharmony_ci cfg &= ~GSC_IN_ROT_XFLIP; 54662306a36Sopenharmony_ci if (rotation & DRM_MODE_REFLECT_Y) 54762306a36Sopenharmony_ci cfg &= ~GSC_IN_ROT_YFLIP; 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci case DRM_MODE_ROTATE_270: 55062306a36Sopenharmony_ci cfg |= GSC_IN_ROT_270; 55162306a36Sopenharmony_ci if (rotation & DRM_MODE_REFLECT_X) 55262306a36Sopenharmony_ci cfg &= ~GSC_IN_ROT_XFLIP; 55362306a36Sopenharmony_ci if (rotation & DRM_MODE_REFLECT_Y) 55462306a36Sopenharmony_ci cfg &= ~GSC_IN_ROT_YFLIP; 55562306a36Sopenharmony_ci break; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci gsc_write(cfg, GSC_IN_CON); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci ctx->rotation = (cfg & GSC_IN_ROT_90) ? 1 : 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic void gsc_src_set_size(struct gsc_context *ctx, 56462306a36Sopenharmony_ci struct exynos_drm_ipp_buffer *buf) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci struct gsc_scaler *sc = &ctx->sc; 56762306a36Sopenharmony_ci u32 cfg; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* pixel offset */ 57062306a36Sopenharmony_ci cfg = (GSC_SRCIMG_OFFSET_X(buf->rect.x) | 57162306a36Sopenharmony_ci GSC_SRCIMG_OFFSET_Y(buf->rect.y)); 57262306a36Sopenharmony_ci gsc_write(cfg, GSC_SRCIMG_OFFSET); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* cropped size */ 57562306a36Sopenharmony_ci cfg = (GSC_CROPPED_WIDTH(buf->rect.w) | 57662306a36Sopenharmony_ci GSC_CROPPED_HEIGHT(buf->rect.h)); 57762306a36Sopenharmony_ci gsc_write(cfg, GSC_CROPPED_SIZE); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* original size */ 58062306a36Sopenharmony_ci cfg = gsc_read(GSC_SRCIMG_SIZE); 58162306a36Sopenharmony_ci cfg &= ~(GSC_SRCIMG_HEIGHT_MASK | 58262306a36Sopenharmony_ci GSC_SRCIMG_WIDTH_MASK); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci cfg |= (GSC_SRCIMG_WIDTH(buf->buf.pitch[0] / buf->format->cpp[0]) | 58562306a36Sopenharmony_ci GSC_SRCIMG_HEIGHT(buf->buf.height)); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci gsc_write(cfg, GSC_SRCIMG_SIZE); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci cfg = gsc_read(GSC_IN_CON); 59062306a36Sopenharmony_ci cfg &= ~GSC_IN_RGB_TYPE_MASK; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (buf->rect.w >= GSC_WIDTH_ITU_709) 59362306a36Sopenharmony_ci if (sc->range) 59462306a36Sopenharmony_ci cfg |= GSC_IN_RGB_HD_WIDE; 59562306a36Sopenharmony_ci else 59662306a36Sopenharmony_ci cfg |= GSC_IN_RGB_HD_NARROW; 59762306a36Sopenharmony_ci else 59862306a36Sopenharmony_ci if (sc->range) 59962306a36Sopenharmony_ci cfg |= GSC_IN_RGB_SD_WIDE; 60062306a36Sopenharmony_ci else 60162306a36Sopenharmony_ci cfg |= GSC_IN_RGB_SD_NARROW; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci gsc_write(cfg, GSC_IN_CON); 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic void gsc_src_set_buf_seq(struct gsc_context *ctx, u32 buf_id, 60762306a36Sopenharmony_ci bool enqueue) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci bool masked = !enqueue; 61062306a36Sopenharmony_ci u32 cfg; 61162306a36Sopenharmony_ci u32 mask = 0x00000001 << buf_id; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* mask register set */ 61462306a36Sopenharmony_ci cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci /* sequence id */ 61762306a36Sopenharmony_ci cfg &= ~mask; 61862306a36Sopenharmony_ci cfg |= masked << buf_id; 61962306a36Sopenharmony_ci gsc_write(cfg, GSC_IN_BASE_ADDR_Y_MASK); 62062306a36Sopenharmony_ci gsc_write(cfg, GSC_IN_BASE_ADDR_CB_MASK); 62162306a36Sopenharmony_ci gsc_write(cfg, GSC_IN_BASE_ADDR_CR_MASK); 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cistatic void gsc_src_set_addr(struct gsc_context *ctx, u32 buf_id, 62562306a36Sopenharmony_ci struct exynos_drm_ipp_buffer *buf) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci /* address register set */ 62862306a36Sopenharmony_ci gsc_write(buf->dma_addr[0], GSC_IN_BASE_ADDR_Y(buf_id)); 62962306a36Sopenharmony_ci gsc_write(buf->dma_addr[1], GSC_IN_BASE_ADDR_CB(buf_id)); 63062306a36Sopenharmony_ci gsc_write(buf->dma_addr[2], GSC_IN_BASE_ADDR_CR(buf_id)); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci gsc_src_set_buf_seq(ctx, buf_id, true); 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci u32 cfg; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "fmt[0x%x]\n", fmt); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci cfg = gsc_read(GSC_OUT_CON); 64262306a36Sopenharmony_ci cfg &= ~(GSC_OUT_RGB_TYPE_MASK | GSC_OUT_YUV422_1P_ORDER_MASK | 64362306a36Sopenharmony_ci GSC_OUT_CHROMA_ORDER_MASK | GSC_OUT_FORMAT_MASK | 64462306a36Sopenharmony_ci GSC_OUT_CHROM_STRIDE_SEL_MASK | GSC_OUT_RB_SWAP_MASK | 64562306a36Sopenharmony_ci GSC_OUT_GLOBAL_ALPHA_MASK); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci switch (fmt) { 64862306a36Sopenharmony_ci case DRM_FORMAT_RGB565: 64962306a36Sopenharmony_ci cfg |= GSC_OUT_RGB565; 65062306a36Sopenharmony_ci break; 65162306a36Sopenharmony_ci case DRM_FORMAT_ARGB8888: 65262306a36Sopenharmony_ci case DRM_FORMAT_XRGB8888: 65362306a36Sopenharmony_ci cfg |= (GSC_OUT_XRGB8888 | GSC_OUT_GLOBAL_ALPHA(0xff)); 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci case DRM_FORMAT_BGRX8888: 65662306a36Sopenharmony_ci cfg |= (GSC_OUT_XRGB8888 | GSC_OUT_RB_SWAP); 65762306a36Sopenharmony_ci break; 65862306a36Sopenharmony_ci case DRM_FORMAT_YUYV: 65962306a36Sopenharmony_ci cfg |= (GSC_OUT_YUV422_1P | 66062306a36Sopenharmony_ci GSC_OUT_YUV422_1P_ORDER_LSB_Y | 66162306a36Sopenharmony_ci GSC_OUT_CHROMA_ORDER_CBCR); 66262306a36Sopenharmony_ci break; 66362306a36Sopenharmony_ci case DRM_FORMAT_YVYU: 66462306a36Sopenharmony_ci cfg |= (GSC_OUT_YUV422_1P | 66562306a36Sopenharmony_ci GSC_OUT_YUV422_1P_ORDER_LSB_Y | 66662306a36Sopenharmony_ci GSC_OUT_CHROMA_ORDER_CRCB); 66762306a36Sopenharmony_ci break; 66862306a36Sopenharmony_ci case DRM_FORMAT_UYVY: 66962306a36Sopenharmony_ci cfg |= (GSC_OUT_YUV422_1P | 67062306a36Sopenharmony_ci GSC_OUT_YUV422_1P_OEDER_LSB_C | 67162306a36Sopenharmony_ci GSC_OUT_CHROMA_ORDER_CBCR); 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci case DRM_FORMAT_VYUY: 67462306a36Sopenharmony_ci cfg |= (GSC_OUT_YUV422_1P | 67562306a36Sopenharmony_ci GSC_OUT_YUV422_1P_OEDER_LSB_C | 67662306a36Sopenharmony_ci GSC_OUT_CHROMA_ORDER_CRCB); 67762306a36Sopenharmony_ci break; 67862306a36Sopenharmony_ci case DRM_FORMAT_NV21: 67962306a36Sopenharmony_ci cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_2P); 68062306a36Sopenharmony_ci break; 68162306a36Sopenharmony_ci case DRM_FORMAT_NV61: 68262306a36Sopenharmony_ci cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV422_2P); 68362306a36Sopenharmony_ci break; 68462306a36Sopenharmony_ci case DRM_FORMAT_YUV422: 68562306a36Sopenharmony_ci cfg |= GSC_OUT_YUV422_3P; 68662306a36Sopenharmony_ci break; 68762306a36Sopenharmony_ci case DRM_FORMAT_YUV420: 68862306a36Sopenharmony_ci cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P); 68962306a36Sopenharmony_ci break; 69062306a36Sopenharmony_ci case DRM_FORMAT_YVU420: 69162306a36Sopenharmony_ci cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_3P); 69262306a36Sopenharmony_ci break; 69362306a36Sopenharmony_ci case DRM_FORMAT_NV12: 69462306a36Sopenharmony_ci cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_2P); 69562306a36Sopenharmony_ci break; 69662306a36Sopenharmony_ci case DRM_FORMAT_NV16: 69762306a36Sopenharmony_ci cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV422_2P); 69862306a36Sopenharmony_ci break; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (tiled) 70262306a36Sopenharmony_ci cfg |= (GSC_IN_TILE_C_16x8 | GSC_OUT_TILE_MODE); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci gsc_write(cfg, GSC_OUT_CON); 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic int gsc_get_ratio_shift(struct gsc_context *ctx, u32 src, u32 dst, 70862306a36Sopenharmony_ci u32 *ratio) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "src[%d]dst[%d]\n", src, dst); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci if (src >= dst * 8) { 71362306a36Sopenharmony_ci DRM_DEV_ERROR(ctx->dev, "failed to make ratio and shift.\n"); 71462306a36Sopenharmony_ci return -EINVAL; 71562306a36Sopenharmony_ci } else if (src >= dst * 4) 71662306a36Sopenharmony_ci *ratio = 4; 71762306a36Sopenharmony_ci else if (src >= dst * 2) 71862306a36Sopenharmony_ci *ratio = 2; 71962306a36Sopenharmony_ci else 72062306a36Sopenharmony_ci *ratio = 1; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci return 0; 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_cistatic void gsc_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *shfactor) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci if (hratio == 4 && vratio == 4) 72862306a36Sopenharmony_ci *shfactor = 4; 72962306a36Sopenharmony_ci else if ((hratio == 4 && vratio == 2) || 73062306a36Sopenharmony_ci (hratio == 2 && vratio == 4)) 73162306a36Sopenharmony_ci *shfactor = 3; 73262306a36Sopenharmony_ci else if ((hratio == 4 && vratio == 1) || 73362306a36Sopenharmony_ci (hratio == 1 && vratio == 4) || 73462306a36Sopenharmony_ci (hratio == 2 && vratio == 2)) 73562306a36Sopenharmony_ci *shfactor = 2; 73662306a36Sopenharmony_ci else if (hratio == 1 && vratio == 1) 73762306a36Sopenharmony_ci *shfactor = 0; 73862306a36Sopenharmony_ci else 73962306a36Sopenharmony_ci *shfactor = 1; 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_cistatic int gsc_set_prescaler(struct gsc_context *ctx, struct gsc_scaler *sc, 74362306a36Sopenharmony_ci struct drm_exynos_ipp_task_rect *src, 74462306a36Sopenharmony_ci struct drm_exynos_ipp_task_rect *dst) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci u32 cfg; 74762306a36Sopenharmony_ci u32 src_w, src_h, dst_w, dst_h; 74862306a36Sopenharmony_ci int ret = 0; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci src_w = src->w; 75162306a36Sopenharmony_ci src_h = src->h; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (ctx->rotation) { 75462306a36Sopenharmony_ci dst_w = dst->h; 75562306a36Sopenharmony_ci dst_h = dst->w; 75662306a36Sopenharmony_ci } else { 75762306a36Sopenharmony_ci dst_w = dst->w; 75862306a36Sopenharmony_ci dst_h = dst->h; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci ret = gsc_get_ratio_shift(ctx, src_w, dst_w, &sc->pre_hratio); 76262306a36Sopenharmony_ci if (ret) { 76362306a36Sopenharmony_ci DRM_DEV_ERROR(ctx->dev, "failed to get ratio horizontal.\n"); 76462306a36Sopenharmony_ci return ret; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci ret = gsc_get_ratio_shift(ctx, src_h, dst_h, &sc->pre_vratio); 76862306a36Sopenharmony_ci if (ret) { 76962306a36Sopenharmony_ci DRM_DEV_ERROR(ctx->dev, "failed to get ratio vertical.\n"); 77062306a36Sopenharmony_ci return ret; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "pre_hratio[%d]pre_vratio[%d]\n", 77462306a36Sopenharmony_ci sc->pre_hratio, sc->pre_vratio); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci sc->main_hratio = (src_w << 16) / dst_w; 77762306a36Sopenharmony_ci sc->main_vratio = (src_h << 16) / dst_h; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "main_hratio[%ld]main_vratio[%ld]\n", 78062306a36Sopenharmony_ci sc->main_hratio, sc->main_vratio); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci gsc_get_prescaler_shfactor(sc->pre_hratio, sc->pre_vratio, 78362306a36Sopenharmony_ci &sc->pre_shfactor); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "pre_shfactor[%d]\n", sc->pre_shfactor); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci cfg = (GSC_PRESC_SHFACTOR(sc->pre_shfactor) | 78862306a36Sopenharmony_ci GSC_PRESC_H_RATIO(sc->pre_hratio) | 78962306a36Sopenharmony_ci GSC_PRESC_V_RATIO(sc->pre_vratio)); 79062306a36Sopenharmony_ci gsc_write(cfg, GSC_PRE_SCALE_RATIO); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci return ret; 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_cistatic void gsc_set_h_coef(struct gsc_context *ctx, unsigned long main_hratio) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci int i, j, k, sc_ratio; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (main_hratio <= GSC_SC_UP_MAX_RATIO) 80062306a36Sopenharmony_ci sc_ratio = 0; 80162306a36Sopenharmony_ci else if (main_hratio <= GSC_SC_DOWN_RATIO_7_8) 80262306a36Sopenharmony_ci sc_ratio = 1; 80362306a36Sopenharmony_ci else if (main_hratio <= GSC_SC_DOWN_RATIO_6_8) 80462306a36Sopenharmony_ci sc_ratio = 2; 80562306a36Sopenharmony_ci else if (main_hratio <= GSC_SC_DOWN_RATIO_5_8) 80662306a36Sopenharmony_ci sc_ratio = 3; 80762306a36Sopenharmony_ci else if (main_hratio <= GSC_SC_DOWN_RATIO_4_8) 80862306a36Sopenharmony_ci sc_ratio = 4; 80962306a36Sopenharmony_ci else if (main_hratio <= GSC_SC_DOWN_RATIO_3_8) 81062306a36Sopenharmony_ci sc_ratio = 5; 81162306a36Sopenharmony_ci else 81262306a36Sopenharmony_ci sc_ratio = 6; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci for (i = 0; i < GSC_COEF_PHASE; i++) 81562306a36Sopenharmony_ci for (j = 0; j < GSC_COEF_H_8T; j++) 81662306a36Sopenharmony_ci for (k = 0; k < GSC_COEF_DEPTH; k++) 81762306a36Sopenharmony_ci gsc_write(h_coef_8t[sc_ratio][i][j], 81862306a36Sopenharmony_ci GSC_HCOEF(i, j, k)); 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic void gsc_set_v_coef(struct gsc_context *ctx, unsigned long main_vratio) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci int i, j, k, sc_ratio; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci if (main_vratio <= GSC_SC_UP_MAX_RATIO) 82662306a36Sopenharmony_ci sc_ratio = 0; 82762306a36Sopenharmony_ci else if (main_vratio <= GSC_SC_DOWN_RATIO_7_8) 82862306a36Sopenharmony_ci sc_ratio = 1; 82962306a36Sopenharmony_ci else if (main_vratio <= GSC_SC_DOWN_RATIO_6_8) 83062306a36Sopenharmony_ci sc_ratio = 2; 83162306a36Sopenharmony_ci else if (main_vratio <= GSC_SC_DOWN_RATIO_5_8) 83262306a36Sopenharmony_ci sc_ratio = 3; 83362306a36Sopenharmony_ci else if (main_vratio <= GSC_SC_DOWN_RATIO_4_8) 83462306a36Sopenharmony_ci sc_ratio = 4; 83562306a36Sopenharmony_ci else if (main_vratio <= GSC_SC_DOWN_RATIO_3_8) 83662306a36Sopenharmony_ci sc_ratio = 5; 83762306a36Sopenharmony_ci else 83862306a36Sopenharmony_ci sc_ratio = 6; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci for (i = 0; i < GSC_COEF_PHASE; i++) 84162306a36Sopenharmony_ci for (j = 0; j < GSC_COEF_V_4T; j++) 84262306a36Sopenharmony_ci for (k = 0; k < GSC_COEF_DEPTH; k++) 84362306a36Sopenharmony_ci gsc_write(v_coef_4t[sc_ratio][i][j], 84462306a36Sopenharmony_ci GSC_VCOEF(i, j, k)); 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic void gsc_set_scaler(struct gsc_context *ctx, struct gsc_scaler *sc) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci u32 cfg; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "main_hratio[%ld]main_vratio[%ld]\n", 85262306a36Sopenharmony_ci sc->main_hratio, sc->main_vratio); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci gsc_set_h_coef(ctx, sc->main_hratio); 85562306a36Sopenharmony_ci cfg = GSC_MAIN_H_RATIO_VALUE(sc->main_hratio); 85662306a36Sopenharmony_ci gsc_write(cfg, GSC_MAIN_H_RATIO); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci gsc_set_v_coef(ctx, sc->main_vratio); 85962306a36Sopenharmony_ci cfg = GSC_MAIN_V_RATIO_VALUE(sc->main_vratio); 86062306a36Sopenharmony_ci gsc_write(cfg, GSC_MAIN_V_RATIO); 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic void gsc_dst_set_size(struct gsc_context *ctx, 86462306a36Sopenharmony_ci struct exynos_drm_ipp_buffer *buf) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci struct gsc_scaler *sc = &ctx->sc; 86762306a36Sopenharmony_ci u32 cfg; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci /* pixel offset */ 87062306a36Sopenharmony_ci cfg = (GSC_DSTIMG_OFFSET_X(buf->rect.x) | 87162306a36Sopenharmony_ci GSC_DSTIMG_OFFSET_Y(buf->rect.y)); 87262306a36Sopenharmony_ci gsc_write(cfg, GSC_DSTIMG_OFFSET); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci /* scaled size */ 87562306a36Sopenharmony_ci if (ctx->rotation) 87662306a36Sopenharmony_ci cfg = (GSC_SCALED_WIDTH(buf->rect.h) | 87762306a36Sopenharmony_ci GSC_SCALED_HEIGHT(buf->rect.w)); 87862306a36Sopenharmony_ci else 87962306a36Sopenharmony_ci cfg = (GSC_SCALED_WIDTH(buf->rect.w) | 88062306a36Sopenharmony_ci GSC_SCALED_HEIGHT(buf->rect.h)); 88162306a36Sopenharmony_ci gsc_write(cfg, GSC_SCALED_SIZE); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* original size */ 88462306a36Sopenharmony_ci cfg = gsc_read(GSC_DSTIMG_SIZE); 88562306a36Sopenharmony_ci cfg &= ~(GSC_DSTIMG_HEIGHT_MASK | GSC_DSTIMG_WIDTH_MASK); 88662306a36Sopenharmony_ci cfg |= GSC_DSTIMG_WIDTH(buf->buf.pitch[0] / buf->format->cpp[0]) | 88762306a36Sopenharmony_ci GSC_DSTIMG_HEIGHT(buf->buf.height); 88862306a36Sopenharmony_ci gsc_write(cfg, GSC_DSTIMG_SIZE); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci cfg = gsc_read(GSC_OUT_CON); 89162306a36Sopenharmony_ci cfg &= ~GSC_OUT_RGB_TYPE_MASK; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (buf->rect.w >= GSC_WIDTH_ITU_709) 89462306a36Sopenharmony_ci if (sc->range) 89562306a36Sopenharmony_ci cfg |= GSC_OUT_RGB_HD_WIDE; 89662306a36Sopenharmony_ci else 89762306a36Sopenharmony_ci cfg |= GSC_OUT_RGB_HD_NARROW; 89862306a36Sopenharmony_ci else 89962306a36Sopenharmony_ci if (sc->range) 90062306a36Sopenharmony_ci cfg |= GSC_OUT_RGB_SD_WIDE; 90162306a36Sopenharmony_ci else 90262306a36Sopenharmony_ci cfg |= GSC_OUT_RGB_SD_NARROW; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci gsc_write(cfg, GSC_OUT_CON); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic int gsc_dst_get_buf_seq(struct gsc_context *ctx) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci u32 cfg, i, buf_num = GSC_REG_SZ; 91062306a36Sopenharmony_ci u32 mask = 0x00000001; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci for (i = 0; i < GSC_REG_SZ; i++) 91562306a36Sopenharmony_ci if (cfg & (mask << i)) 91662306a36Sopenharmony_ci buf_num--; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "buf_num[%d]\n", buf_num); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci return buf_num; 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_cistatic void gsc_dst_set_buf_seq(struct gsc_context *ctx, u32 buf_id, 92462306a36Sopenharmony_ci bool enqueue) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci bool masked = !enqueue; 92762306a36Sopenharmony_ci u32 cfg; 92862306a36Sopenharmony_ci u32 mask = 0x00000001 << buf_id; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci /* mask register set */ 93162306a36Sopenharmony_ci cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* sequence id */ 93462306a36Sopenharmony_ci cfg &= ~mask; 93562306a36Sopenharmony_ci cfg |= masked << buf_id; 93662306a36Sopenharmony_ci gsc_write(cfg, GSC_OUT_BASE_ADDR_Y_MASK); 93762306a36Sopenharmony_ci gsc_write(cfg, GSC_OUT_BASE_ADDR_CB_MASK); 93862306a36Sopenharmony_ci gsc_write(cfg, GSC_OUT_BASE_ADDR_CR_MASK); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci /* interrupt enable */ 94162306a36Sopenharmony_ci if (enqueue && gsc_dst_get_buf_seq(ctx) >= GSC_BUF_START) 94262306a36Sopenharmony_ci gsc_handle_irq(ctx, true, false, true); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* interrupt disable */ 94562306a36Sopenharmony_ci if (!enqueue && gsc_dst_get_buf_seq(ctx) <= GSC_BUF_STOP) 94662306a36Sopenharmony_ci gsc_handle_irq(ctx, false, false, true); 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_cistatic void gsc_dst_set_addr(struct gsc_context *ctx, 95062306a36Sopenharmony_ci u32 buf_id, struct exynos_drm_ipp_buffer *buf) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci /* address register set */ 95362306a36Sopenharmony_ci gsc_write(buf->dma_addr[0], GSC_OUT_BASE_ADDR_Y(buf_id)); 95462306a36Sopenharmony_ci gsc_write(buf->dma_addr[1], GSC_OUT_BASE_ADDR_CB(buf_id)); 95562306a36Sopenharmony_ci gsc_write(buf->dma_addr[2], GSC_OUT_BASE_ADDR_CR(buf_id)); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci gsc_dst_set_buf_seq(ctx, buf_id, true); 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cistatic int gsc_get_src_buf_index(struct gsc_context *ctx) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci u32 cfg, curr_index, i; 96362306a36Sopenharmony_ci u32 buf_id = GSC_MAX_SRC; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "gsc id[%d]\n", ctx->id); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK); 96862306a36Sopenharmony_ci curr_index = GSC_IN_CURR_GET_INDEX(cfg); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci for (i = curr_index; i < GSC_MAX_SRC; i++) { 97162306a36Sopenharmony_ci if (!((cfg >> i) & 0x1)) { 97262306a36Sopenharmony_ci buf_id = i; 97362306a36Sopenharmony_ci break; 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "cfg[0x%x]curr_index[%d]buf_id[%d]\n", cfg, 97862306a36Sopenharmony_ci curr_index, buf_id); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci if (buf_id == GSC_MAX_SRC) { 98162306a36Sopenharmony_ci DRM_DEV_ERROR(ctx->dev, "failed to get in buffer index.\n"); 98262306a36Sopenharmony_ci return -EINVAL; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci gsc_src_set_buf_seq(ctx, buf_id, false); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci return buf_id; 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic int gsc_get_dst_buf_index(struct gsc_context *ctx) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci u32 cfg, curr_index, i; 99362306a36Sopenharmony_ci u32 buf_id = GSC_MAX_DST; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "gsc id[%d]\n", ctx->id); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK); 99862306a36Sopenharmony_ci curr_index = GSC_OUT_CURR_GET_INDEX(cfg); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci for (i = curr_index; i < GSC_MAX_DST; i++) { 100162306a36Sopenharmony_ci if (!((cfg >> i) & 0x1)) { 100262306a36Sopenharmony_ci buf_id = i; 100362306a36Sopenharmony_ci break; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci if (buf_id == GSC_MAX_DST) { 100862306a36Sopenharmony_ci DRM_DEV_ERROR(ctx->dev, "failed to get out buffer index.\n"); 100962306a36Sopenharmony_ci return -EINVAL; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci gsc_dst_set_buf_seq(ctx, buf_id, false); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "cfg[0x%x]curr_index[%d]buf_id[%d]\n", cfg, 101562306a36Sopenharmony_ci curr_index, buf_id); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci return buf_id; 101862306a36Sopenharmony_ci} 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_cistatic irqreturn_t gsc_irq_handler(int irq, void *dev_id) 102162306a36Sopenharmony_ci{ 102262306a36Sopenharmony_ci struct gsc_context *ctx = dev_id; 102362306a36Sopenharmony_ci u32 status; 102462306a36Sopenharmony_ci int err = 0; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "gsc id[%d]\n", ctx->id); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci status = gsc_read(GSC_IRQ); 102962306a36Sopenharmony_ci if (status & GSC_IRQ_STATUS_OR_IRQ) { 103062306a36Sopenharmony_ci dev_err(ctx->dev, "occurred overflow at %d, status 0x%x.\n", 103162306a36Sopenharmony_ci ctx->id, status); 103262306a36Sopenharmony_ci err = -EINVAL; 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci if (status & GSC_IRQ_STATUS_OR_FRM_DONE) { 103662306a36Sopenharmony_ci int src_buf_id, dst_buf_id; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci dev_dbg(ctx->dev, "occurred frame done at %d, status 0x%x.\n", 103962306a36Sopenharmony_ci ctx->id, status); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci src_buf_id = gsc_get_src_buf_index(ctx); 104262306a36Sopenharmony_ci dst_buf_id = gsc_get_dst_buf_index(ctx); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(ctx->dev, "buf_id_src[%d]buf_id_dst[%d]\n", 104562306a36Sopenharmony_ci src_buf_id, dst_buf_id); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci if (src_buf_id < 0 || dst_buf_id < 0) 104862306a36Sopenharmony_ci err = -EINVAL; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci if (ctx->task) { 105262306a36Sopenharmony_ci struct exynos_drm_ipp_task *task = ctx->task; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci ctx->task = NULL; 105562306a36Sopenharmony_ci pm_runtime_mark_last_busy(ctx->dev); 105662306a36Sopenharmony_ci pm_runtime_put_autosuspend(ctx->dev); 105762306a36Sopenharmony_ci exynos_drm_ipp_task_done(task, err); 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci return IRQ_HANDLED; 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_cistatic int gsc_reset(struct gsc_context *ctx) 106462306a36Sopenharmony_ci{ 106562306a36Sopenharmony_ci struct gsc_scaler *sc = &ctx->sc; 106662306a36Sopenharmony_ci int ret; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci /* reset h/w block */ 106962306a36Sopenharmony_ci ret = gsc_sw_reset(ctx); 107062306a36Sopenharmony_ci if (ret < 0) { 107162306a36Sopenharmony_ci dev_err(ctx->dev, "failed to reset hardware.\n"); 107262306a36Sopenharmony_ci return ret; 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* scaler setting */ 107662306a36Sopenharmony_ci memset(&ctx->sc, 0x0, sizeof(ctx->sc)); 107762306a36Sopenharmony_ci sc->range = true; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci return 0; 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_cistatic void gsc_start(struct gsc_context *ctx) 108362306a36Sopenharmony_ci{ 108462306a36Sopenharmony_ci u32 cfg; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci gsc_handle_irq(ctx, true, false, true); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci /* enable one shot */ 108962306a36Sopenharmony_ci cfg = gsc_read(GSC_ENABLE); 109062306a36Sopenharmony_ci cfg &= ~(GSC_ENABLE_ON_CLEAR_MASK | 109162306a36Sopenharmony_ci GSC_ENABLE_CLK_GATE_MODE_MASK); 109262306a36Sopenharmony_ci cfg |= GSC_ENABLE_ON_CLEAR_ONESHOT; 109362306a36Sopenharmony_ci gsc_write(cfg, GSC_ENABLE); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci /* src dma memory */ 109662306a36Sopenharmony_ci cfg = gsc_read(GSC_IN_CON); 109762306a36Sopenharmony_ci cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK); 109862306a36Sopenharmony_ci cfg |= GSC_IN_PATH_MEMORY; 109962306a36Sopenharmony_ci gsc_write(cfg, GSC_IN_CON); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci /* dst dma memory */ 110262306a36Sopenharmony_ci cfg = gsc_read(GSC_OUT_CON); 110362306a36Sopenharmony_ci cfg |= GSC_OUT_PATH_MEMORY; 110462306a36Sopenharmony_ci gsc_write(cfg, GSC_OUT_CON); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci gsc_set_scaler(ctx, &ctx->sc); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci cfg = gsc_read(GSC_ENABLE); 110962306a36Sopenharmony_ci cfg |= GSC_ENABLE_ON; 111062306a36Sopenharmony_ci gsc_write(cfg, GSC_ENABLE); 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic int gsc_commit(struct exynos_drm_ipp *ipp, 111462306a36Sopenharmony_ci struct exynos_drm_ipp_task *task) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci struct gsc_context *ctx = container_of(ipp, struct gsc_context, ipp); 111762306a36Sopenharmony_ci int ret; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(ctx->dev); 112062306a36Sopenharmony_ci if (ret < 0) { 112162306a36Sopenharmony_ci dev_err(ctx->dev, "failed to enable GScaler device.\n"); 112262306a36Sopenharmony_ci return ret; 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci ctx->task = task; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci ret = gsc_reset(ctx); 112862306a36Sopenharmony_ci if (ret) { 112962306a36Sopenharmony_ci pm_runtime_put_autosuspend(ctx->dev); 113062306a36Sopenharmony_ci ctx->task = NULL; 113162306a36Sopenharmony_ci return ret; 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci gsc_src_set_fmt(ctx, task->src.buf.fourcc, task->src.buf.modifier); 113562306a36Sopenharmony_ci gsc_src_set_transf(ctx, task->transform.rotation); 113662306a36Sopenharmony_ci gsc_src_set_size(ctx, &task->src); 113762306a36Sopenharmony_ci gsc_src_set_addr(ctx, 0, &task->src); 113862306a36Sopenharmony_ci gsc_dst_set_fmt(ctx, task->dst.buf.fourcc, task->dst.buf.modifier); 113962306a36Sopenharmony_ci gsc_dst_set_size(ctx, &task->dst); 114062306a36Sopenharmony_ci gsc_dst_set_addr(ctx, 0, &task->dst); 114162306a36Sopenharmony_ci gsc_set_prescaler(ctx, &ctx->sc, &task->src.rect, &task->dst.rect); 114262306a36Sopenharmony_ci gsc_start(ctx); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci return 0; 114562306a36Sopenharmony_ci} 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_cistatic void gsc_abort(struct exynos_drm_ipp *ipp, 114862306a36Sopenharmony_ci struct exynos_drm_ipp_task *task) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci struct gsc_context *ctx = 115162306a36Sopenharmony_ci container_of(ipp, struct gsc_context, ipp); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci gsc_reset(ctx); 115462306a36Sopenharmony_ci if (ctx->task) { 115562306a36Sopenharmony_ci struct exynos_drm_ipp_task *task = ctx->task; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci ctx->task = NULL; 115862306a36Sopenharmony_ci pm_runtime_mark_last_busy(ctx->dev); 115962306a36Sopenharmony_ci pm_runtime_put_autosuspend(ctx->dev); 116062306a36Sopenharmony_ci exynos_drm_ipp_task_done(task, -EIO); 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci} 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_cistatic struct exynos_drm_ipp_funcs ipp_funcs = { 116562306a36Sopenharmony_ci .commit = gsc_commit, 116662306a36Sopenharmony_ci .abort = gsc_abort, 116762306a36Sopenharmony_ci}; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_cistatic int gsc_bind(struct device *dev, struct device *master, void *data) 117062306a36Sopenharmony_ci{ 117162306a36Sopenharmony_ci struct gsc_context *ctx = dev_get_drvdata(dev); 117262306a36Sopenharmony_ci struct drm_device *drm_dev = data; 117362306a36Sopenharmony_ci struct exynos_drm_ipp *ipp = &ctx->ipp; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci ctx->drm_dev = drm_dev; 117662306a36Sopenharmony_ci ctx->drm_dev = drm_dev; 117762306a36Sopenharmony_ci exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci exynos_drm_ipp_register(dev, ipp, &ipp_funcs, 118062306a36Sopenharmony_ci DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE | 118162306a36Sopenharmony_ci DRM_EXYNOS_IPP_CAP_SCALE | DRM_EXYNOS_IPP_CAP_CONVERT, 118262306a36Sopenharmony_ci ctx->formats, ctx->num_formats, "gsc"); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci dev_info(dev, "The exynos gscaler has been probed successfully\n"); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci return 0; 118762306a36Sopenharmony_ci} 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_cistatic void gsc_unbind(struct device *dev, struct device *master, 119062306a36Sopenharmony_ci void *data) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci struct gsc_context *ctx = dev_get_drvdata(dev); 119362306a36Sopenharmony_ci struct drm_device *drm_dev = data; 119462306a36Sopenharmony_ci struct exynos_drm_ipp *ipp = &ctx->ipp; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci exynos_drm_ipp_unregister(dev, ipp); 119762306a36Sopenharmony_ci exynos_drm_unregister_dma(drm_dev, dev, &ctx->dma_priv); 119862306a36Sopenharmony_ci} 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_cistatic const struct component_ops gsc_component_ops = { 120162306a36Sopenharmony_ci .bind = gsc_bind, 120262306a36Sopenharmony_ci .unbind = gsc_unbind, 120362306a36Sopenharmony_ci}; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_cistatic const unsigned int gsc_formats[] = { 120662306a36Sopenharmony_ci DRM_FORMAT_ARGB8888, 120762306a36Sopenharmony_ci DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565, DRM_FORMAT_BGRX8888, 120862306a36Sopenharmony_ci DRM_FORMAT_NV12, DRM_FORMAT_NV16, DRM_FORMAT_NV21, DRM_FORMAT_NV61, 120962306a36Sopenharmony_ci DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU, 121062306a36Sopenharmony_ci DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422, 121162306a36Sopenharmony_ci}; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_cistatic const unsigned int gsc_tiled_formats[] = { 121462306a36Sopenharmony_ci DRM_FORMAT_NV12, DRM_FORMAT_NV21, 121562306a36Sopenharmony_ci}; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_cistatic int gsc_probe(struct platform_device *pdev) 121862306a36Sopenharmony_ci{ 121962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 122062306a36Sopenharmony_ci struct gsc_driverdata *driver_data; 122162306a36Sopenharmony_ci struct exynos_drm_ipp_formats *formats; 122262306a36Sopenharmony_ci struct gsc_context *ctx; 122362306a36Sopenharmony_ci int num_formats, ret, i, j; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 122662306a36Sopenharmony_ci if (!ctx) 122762306a36Sopenharmony_ci return -ENOMEM; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci driver_data = (struct gsc_driverdata *)of_device_get_match_data(dev); 123062306a36Sopenharmony_ci ctx->dev = dev; 123162306a36Sopenharmony_ci ctx->num_clocks = driver_data->num_clocks; 123262306a36Sopenharmony_ci ctx->clk_names = driver_data->clk_names; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci /* construct formats/limits array */ 123562306a36Sopenharmony_ci num_formats = ARRAY_SIZE(gsc_formats) + ARRAY_SIZE(gsc_tiled_formats); 123662306a36Sopenharmony_ci formats = devm_kcalloc(dev, num_formats, sizeof(*formats), GFP_KERNEL); 123762306a36Sopenharmony_ci if (!formats) 123862306a36Sopenharmony_ci return -ENOMEM; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci /* linear formats */ 124162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(gsc_formats); i++) { 124262306a36Sopenharmony_ci formats[i].fourcc = gsc_formats[i]; 124362306a36Sopenharmony_ci formats[i].type = DRM_EXYNOS_IPP_FORMAT_SOURCE | 124462306a36Sopenharmony_ci DRM_EXYNOS_IPP_FORMAT_DESTINATION; 124562306a36Sopenharmony_ci formats[i].limits = driver_data->limits; 124662306a36Sopenharmony_ci formats[i].num_limits = driver_data->num_limits; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci /* tiled formats */ 125062306a36Sopenharmony_ci for (j = i, i = 0; i < ARRAY_SIZE(gsc_tiled_formats); j++, i++) { 125162306a36Sopenharmony_ci formats[j].fourcc = gsc_tiled_formats[i]; 125262306a36Sopenharmony_ci formats[j].modifier = DRM_FORMAT_MOD_SAMSUNG_16_16_TILE; 125362306a36Sopenharmony_ci formats[j].type = DRM_EXYNOS_IPP_FORMAT_SOURCE | 125462306a36Sopenharmony_ci DRM_EXYNOS_IPP_FORMAT_DESTINATION; 125562306a36Sopenharmony_ci formats[j].limits = driver_data->limits; 125662306a36Sopenharmony_ci formats[j].num_limits = driver_data->num_limits; 125762306a36Sopenharmony_ci } 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci ctx->formats = formats; 126062306a36Sopenharmony_ci ctx->num_formats = num_formats; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci /* clock control */ 126362306a36Sopenharmony_ci for (i = 0; i < ctx->num_clocks; i++) { 126462306a36Sopenharmony_ci ctx->clocks[i] = devm_clk_get(dev, ctx->clk_names[i]); 126562306a36Sopenharmony_ci if (IS_ERR(ctx->clocks[i])) { 126662306a36Sopenharmony_ci dev_err(dev, "failed to get clock: %s\n", 126762306a36Sopenharmony_ci ctx->clk_names[i]); 126862306a36Sopenharmony_ci return PTR_ERR(ctx->clocks[i]); 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci } 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci ctx->regs = devm_platform_ioremap_resource(pdev, 0); 127362306a36Sopenharmony_ci if (IS_ERR(ctx->regs)) 127462306a36Sopenharmony_ci return PTR_ERR(ctx->regs); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* resource irq */ 127762306a36Sopenharmony_ci ctx->irq = platform_get_irq(pdev, 0); 127862306a36Sopenharmony_ci if (ctx->irq < 0) 127962306a36Sopenharmony_ci return ctx->irq; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci ret = devm_request_irq(dev, ctx->irq, gsc_irq_handler, 0, 128262306a36Sopenharmony_ci dev_name(dev), ctx); 128362306a36Sopenharmony_ci if (ret < 0) { 128462306a36Sopenharmony_ci dev_err(dev, "failed to request irq.\n"); 128562306a36Sopenharmony_ci return ret; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci /* context initailization */ 128962306a36Sopenharmony_ci ctx->id = pdev->id; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci platform_set_drvdata(pdev, ctx); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 129462306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, GSC_AUTOSUSPEND_DELAY); 129562306a36Sopenharmony_ci pm_runtime_enable(dev); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci ret = component_add(dev, &gsc_component_ops); 129862306a36Sopenharmony_ci if (ret) 129962306a36Sopenharmony_ci goto err_pm_dis; 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci dev_info(dev, "drm gsc registered successfully.\n"); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci return 0; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_cierr_pm_dis: 130662306a36Sopenharmony_ci pm_runtime_dont_use_autosuspend(dev); 130762306a36Sopenharmony_ci pm_runtime_disable(dev); 130862306a36Sopenharmony_ci return ret; 130962306a36Sopenharmony_ci} 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cistatic int gsc_remove(struct platform_device *pdev) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci component_del(dev, &gsc_component_ops); 131662306a36Sopenharmony_ci pm_runtime_dont_use_autosuspend(dev); 131762306a36Sopenharmony_ci pm_runtime_disable(dev); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci return 0; 132062306a36Sopenharmony_ci} 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_cistatic int __maybe_unused gsc_runtime_suspend(struct device *dev) 132362306a36Sopenharmony_ci{ 132462306a36Sopenharmony_ci struct gsc_context *ctx = get_gsc_context(dev); 132562306a36Sopenharmony_ci int i; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(dev, "id[%d]\n", ctx->id); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci for (i = ctx->num_clocks - 1; i >= 0; i--) 133062306a36Sopenharmony_ci clk_disable_unprepare(ctx->clocks[i]); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci return 0; 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_cistatic int __maybe_unused gsc_runtime_resume(struct device *dev) 133662306a36Sopenharmony_ci{ 133762306a36Sopenharmony_ci struct gsc_context *ctx = get_gsc_context(dev); 133862306a36Sopenharmony_ci int i, ret; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci DRM_DEV_DEBUG_KMS(dev, "id[%d]\n", ctx->id); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci for (i = 0; i < ctx->num_clocks; i++) { 134362306a36Sopenharmony_ci ret = clk_prepare_enable(ctx->clocks[i]); 134462306a36Sopenharmony_ci if (ret) { 134562306a36Sopenharmony_ci while (--i >= 0) 134662306a36Sopenharmony_ci clk_disable_unprepare(ctx->clocks[i]); 134762306a36Sopenharmony_ci return ret; 134862306a36Sopenharmony_ci } 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci return 0; 135162306a36Sopenharmony_ci} 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_cistatic const struct dev_pm_ops gsc_pm_ops = { 135462306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 135562306a36Sopenharmony_ci pm_runtime_force_resume) 135662306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL) 135762306a36Sopenharmony_ci}; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_cistatic const struct drm_exynos_ipp_limit gsc_5250_limits[] = { 136062306a36Sopenharmony_ci { IPP_SIZE_LIMIT(BUFFER, .h = { 32, 4800, 8 }, .v = { 16, 3344, 8 }) }, 136162306a36Sopenharmony_ci { IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 2 }, .v = { 8, 3344, 2 }) }, 136262306a36Sopenharmony_ci { IPP_SIZE_LIMIT(ROTATED, .h = { 32, 2048 }, .v = { 16, 2048 }) }, 136362306a36Sopenharmony_ci { IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 }, 136462306a36Sopenharmony_ci .v = { (1 << 16) / 16, (1 << 16) * 8 }) }, 136562306a36Sopenharmony_ci}; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_cistatic const struct drm_exynos_ipp_limit gsc_5420_limits[] = { 136862306a36Sopenharmony_ci { IPP_SIZE_LIMIT(BUFFER, .h = { 32, 4800, 8 }, .v = { 16, 3344, 8 }) }, 136962306a36Sopenharmony_ci { IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 2 }, .v = { 8, 3344, 2 }) }, 137062306a36Sopenharmony_ci { IPP_SIZE_LIMIT(ROTATED, .h = { 16, 2016 }, .v = { 8, 2016 }) }, 137162306a36Sopenharmony_ci { IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 }, 137262306a36Sopenharmony_ci .v = { (1 << 16) / 16, (1 << 16) * 8 }) }, 137362306a36Sopenharmony_ci}; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_cistatic const struct drm_exynos_ipp_limit gsc_5433_limits[] = { 137662306a36Sopenharmony_ci { IPP_SIZE_LIMIT(BUFFER, .h = { 32, 8191, 16 }, .v = { 16, 8191, 2 }) }, 137762306a36Sopenharmony_ci { IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 1 }, .v = { 8, 3344, 1 }) }, 137862306a36Sopenharmony_ci { IPP_SIZE_LIMIT(ROTATED, .h = { 32, 2047 }, .v = { 8, 8191 }) }, 137962306a36Sopenharmony_ci { IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 }, 138062306a36Sopenharmony_ci .v = { (1 << 16) / 16, (1 << 16) * 8 }) }, 138162306a36Sopenharmony_ci}; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_cistatic struct gsc_driverdata gsc_exynos5250_drvdata = { 138462306a36Sopenharmony_ci .clk_names = {"gscl"}, 138562306a36Sopenharmony_ci .num_clocks = 1, 138662306a36Sopenharmony_ci .limits = gsc_5250_limits, 138762306a36Sopenharmony_ci .num_limits = ARRAY_SIZE(gsc_5250_limits), 138862306a36Sopenharmony_ci}; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_cistatic struct gsc_driverdata gsc_exynos5420_drvdata = { 139162306a36Sopenharmony_ci .clk_names = {"gscl"}, 139262306a36Sopenharmony_ci .num_clocks = 1, 139362306a36Sopenharmony_ci .limits = gsc_5420_limits, 139462306a36Sopenharmony_ci .num_limits = ARRAY_SIZE(gsc_5420_limits), 139562306a36Sopenharmony_ci}; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_cistatic struct gsc_driverdata gsc_exynos5433_drvdata = { 139862306a36Sopenharmony_ci .clk_names = {"pclk", "aclk", "aclk_xiu", "aclk_gsclbend"}, 139962306a36Sopenharmony_ci .num_clocks = 4, 140062306a36Sopenharmony_ci .limits = gsc_5433_limits, 140162306a36Sopenharmony_ci .num_limits = ARRAY_SIZE(gsc_5433_limits), 140262306a36Sopenharmony_ci}; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_cistatic const struct of_device_id exynos_drm_gsc_of_match[] = { 140562306a36Sopenharmony_ci { 140662306a36Sopenharmony_ci .compatible = "samsung,exynos5-gsc", 140762306a36Sopenharmony_ci .data = &gsc_exynos5250_drvdata, 140862306a36Sopenharmony_ci }, { 140962306a36Sopenharmony_ci .compatible = "samsung,exynos5250-gsc", 141062306a36Sopenharmony_ci .data = &gsc_exynos5250_drvdata, 141162306a36Sopenharmony_ci }, { 141262306a36Sopenharmony_ci .compatible = "samsung,exynos5420-gsc", 141362306a36Sopenharmony_ci .data = &gsc_exynos5420_drvdata, 141462306a36Sopenharmony_ci }, { 141562306a36Sopenharmony_ci .compatible = "samsung,exynos5433-gsc", 141662306a36Sopenharmony_ci .data = &gsc_exynos5433_drvdata, 141762306a36Sopenharmony_ci }, { 141862306a36Sopenharmony_ci }, 141962306a36Sopenharmony_ci}; 142062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, exynos_drm_gsc_of_match); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_cistruct platform_driver gsc_driver = { 142362306a36Sopenharmony_ci .probe = gsc_probe, 142462306a36Sopenharmony_ci .remove = gsc_remove, 142562306a36Sopenharmony_ci .driver = { 142662306a36Sopenharmony_ci .name = "exynos-drm-gsc", 142762306a36Sopenharmony_ci .owner = THIS_MODULE, 142862306a36Sopenharmony_ci .pm = &gsc_pm_ops, 142962306a36Sopenharmony_ci .of_match_table = exynos_drm_gsc_of_match, 143062306a36Sopenharmony_ci }, 143162306a36Sopenharmony_ci}; 1432