[RFC 2/4] drm: exynos: add MDNIE post processor

Ajay Kumar ajaykumar.rs at samsung.com
Wed Mar 19 07:22:53 PDT 2014


Add post processor ops for MDNIE and their support functions.
Expose an interface for the FIMD to register MDNIE PP.

Signed-off-by: Ajay Kumar <ajaykumar.rs at samsung.com>
Signed-off-by: Shirish S <s.shirish at samsung.com>
Signed-off-by: Rahul Sharma <rahul.sharma at samsung.com>
---
 drivers/gpu/drm/exynos/Makefile            |   2 +-
 drivers/gpu/drm/exynos/exynos_mdnie.c      | 707 +++++++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_mdnie_regs.h | 154 +++++++
 3 files changed, 862 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/exynos/exynos_mdnie.c
 create mode 100644 drivers/gpu/drm/exynos/exynos_mdnie_regs.h

diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 02dde22..653eab5 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -10,7 +10,7 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \
 
 exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
-exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)	+= exynos_drm_fimd.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)	+= exynos_drm_fimd.o exynos_mdnie.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DSI)	+= exynos_drm_dsi.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DP)	+= exynos_dp_core.o exynos_dp_reg.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)	+= exynos_hdmi.o exynos_mixer.o
diff --git a/drivers/gpu/drm/exynos/exynos_mdnie.c b/drivers/gpu/drm/exynos/exynos_mdnie.c
new file mode 100644
index 0000000..a043853
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_mdnie.c
@@ -0,0 +1,707 @@
+/* drivers/gpu/drm/exynos/exynos_mdnie.c
+ *
+ * Samsung mDNIe driver
+ *
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd.
+ *
+ * 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/clk.h>
+#include <linux/errno.h>
+#include <linux/of_device.h>
+
+#include <video/samsung_fimd.h>
+
+#include <drm/drmP.h>
+
+#include "exynos_drm_drv.h"
+#include "exynos_fimd_pp.h"
+#include "exynos_mdnie_regs.h"
+
+#define GAMMA_RAMP_LENGTH	17
+#define COLOR_COMPONENTS	3
+
+#define MDNIE_ON	1
+#define MDNIE_OFF	0
+
+#define PARAM_IN_RANGE(r, p, l, u)					\
+	do {							\
+		r = ((p >= l) && (p <= u)) ? 0 : 1;		\
+		if (r) \
+			DRM_ERROR("Wrong param: %s:%llu\n", #p, (u64)p); \
+	} while (0)
+
+struct exynos_mdnie_drm_gamma {
+	u8 gamma_r[GAMMA_RAMP_LENGTH];
+	u8 gamma_g[GAMMA_RAMP_LENGTH];
+	u8 gamma_b[GAMMA_RAMP_LENGTH];
+};
+
+struct mdnie_conf_params {
+	u32					modules_enabled;
+	struct exynos_mdnie_drm_gamma		gamma_params;
+	struct drm_exynos_mdnie_window		win;
+	struct drm_mode_color_reproduction	cr_params;
+	struct drm_mode_color_saturation	cs_params;
+	struct drm_mode_edge_enhancement	de_params;
+};
+
+struct mdnie_context {
+	struct mdnie_conf_params		params;
+	struct clk				*mdnie_mux_clk;
+	struct clk				*mdnie_bus_clk;
+	struct clk				*mdnie_src_clk;
+	struct clk				*sclk_mout_fimd;
+	void __iomem				*exynos_mdnie_base;
+	void __iomem				*sysreg_disp1blk;
+	struct drm_display_mode			mode;
+};
+
+static void exynos_mdnie_unmask(struct mdnie_context *mdnie)
+{
+	writel(!MDNIE_RELEASE_RFF_MASK_REGISTERS,
+			mdnie->exynos_mdnie_base +
+			MDNIE_RELEASE_RFF * sizeof(u32));
+}
+
+static u32 mdnie_read(struct mdnie_context *mdnie, u32 reg)
+{
+	return readl(mdnie->exynos_mdnie_base + reg * sizeof(u32)) &
+			MDNIE_REG_WIDTH;
+}
+
+static void mdnie_write(struct mdnie_context *mdnie, u32 reg, u32 val)
+{
+	writel(val & MDNIE_REG_WIDTH, mdnie->exynos_mdnie_base +
+			(reg & MDNIE_REG_OFFSET_LIMIT) * sizeof(u32));
+
+	exynos_mdnie_unmask(mdnie);
+}
+
+static void exynos_mdnie_bank_sel(struct mdnie_context *mdnie, int bank)
+{
+	if (bank)
+		writel(MDNIE_TOP_R0_BANK1_SEL |
+			MDNIE_TOP_R0_SHADOW_SEL ,
+			mdnie->exynos_mdnie_base);
+	else
+		writel(MDNIE_TOP_R0_BANK0_SEL |
+			MDNIE_TOP_R0_SHADOW_SEL ,
+			mdnie->exynos_mdnie_base);
+
+	exynos_mdnie_unmask(mdnie);
+}
+
+static int exynos_mdnie_set_size(struct mdnie_context *mdnie)
+{
+	unsigned int cfg;
+
+	if ((mdnie->mode.crtc_hdisplay > MDNIE_TOP_RSIZE_MAX) ||
+			(mdnie->mode.crtc_vdisplay > MDNIE_TOP_RSIZE_MAX))
+		return -EINVAL;
+
+	exynos_mdnie_bank_sel(mdnie, 0);
+
+	/* Input Data Unmask */
+	cfg = mdnie_read(mdnie, MDNIE_TOP_R1);
+	cfg &= ~(MDNIE_TOP_R1_MASK_INPUT_DATA_ENABLE);
+	cfg &= ~(MDNIE_TOP_R1_MASK_INPUT_HSYNC);
+	mdnie_write(mdnie, MDNIE_TOP_R1, cfg);
+
+	/* LCD width */
+	mdnie_write(mdnie, MDNIE_TOP_RIHSIZE,
+			mdnie->mode.crtc_hdisplay);
+
+	/* LCD height */
+	mdnie_write(mdnie, MDNIE_TOP_RIVSIZE,
+			mdnie->mode.crtc_vdisplay);
+	return 0;
+}
+
+static void mdnie_set_all_modules_off(struct mdnie_context *mdnie)
+{
+	u32 val;
+
+	val = mdnie_read(mdnie, MDNIE_TOP_R8);
+	val &= ~(MDNIE_TOP_R8_DITH_MODULE_ON |
+		MDNIE_TOP_R8_ABC_MODULE_ON |
+		MDNIE_TOP_R8_SCR_MODULE_ON |
+		MDNIE_TOP_R8_CC_MODULE_ON |
+		MDNIE_TOP_R8_CS_MODULE_ON |
+		MDNIE_TOP_R8_DE_MODULE_ON);
+	mdnie_write(mdnie, MDNIE_TOP_R8, val);
+
+	val = mdnie_read(mdnie, MDNIE_TOP_R9);
+	val &= ~(MDNIE_TOP_R9_MCM_MODULE_ON);
+	mdnie_write(mdnie, MDNIE_TOP_R9, val);
+
+	val = mdnie_read(mdnie, MDNIE_TOP_RA);
+	val &= ~(MDNIE_TOP_RA_UC_MODULE_ON);
+	mdnie_write(mdnie, MDNIE_TOP_RA, val);
+}
+
+static void mdnie_set_req_modules_on(struct mdnie_context *mdnie)
+{
+	u32 val;
+
+	val = mdnie_read(mdnie, MDNIE_TOP_R8);
+	if (mdnie->params.modules_enabled & BIT(MDNIE_COLOR_REPRODUCTION))
+		val |= MDNIE_TOP_R8_SCR_MODULE_ON;
+	if (mdnie->params.modules_enabled & BIT(MDNIE_CURVE_CONTROL))
+		val |= MDNIE_TOP_R8_CC_MODULE_ON;
+	if (mdnie->params.modules_enabled & BIT(MDNIE_COLOR_SATURATION))
+		val |= MDNIE_TOP_R8_CS_MODULE_ON;
+	if (mdnie->params.modules_enabled & BIT(MDNIE_DETAIL_ENHANCEMENT))
+		val |= MDNIE_TOP_R8_DE_MODULE_ON;
+
+	mdnie_write(mdnie, MDNIE_TOP_R8, val);
+}
+
+static int mdnie_set_color_saturation_params(
+		struct mdnie_context *mdnie,
+		const struct drm_mode_color_saturation *params)
+{
+	int ret;
+
+	PARAM_IN_RANGE(ret, params->hue_gain_red, HG_MIN, HG_MAX);
+	PARAM_IN_RANGE(ret, params->hue_gain_green, HG_MIN, HG_MAX);
+	PARAM_IN_RANGE(ret, params->hue_gain_blue, HG_MIN, HG_MAX);
+	PARAM_IN_RANGE(ret, params->hue_gain_cyan, HG_MIN, HG_MAX);
+	PARAM_IN_RANGE(ret, params->hue_gain_magenta, HG_MIN, HG_MAX);
+	PARAM_IN_RANGE(ret, params->hue_gain_yellow, HG_MIN, HG_MAX);
+	PARAM_IN_RANGE(ret, params->hue_gain_overall, HG_MIN, HG_MAX);
+
+	if (ret)
+		return -EINVAL;
+
+	memcpy(&mdnie->params.cs_params, params, sizeof(*params));
+
+	return 0;
+}
+
+static int mdnie_set_color_reproduction_params(
+		struct mdnie_context *mdnie,
+		const struct drm_mode_color_reproduction *params)
+{
+	int ret;
+
+	PARAM_IN_RANGE(ret, params->red_rgb[0], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->red_rgb[1], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->red_rgb[2], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->green_rgb[0], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->green_rgb[1], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->green_rgb[2], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->blue_rgb[0], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->blue_rgb[1], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->blue_rgb[2], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->cyan_rgb[0], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->cyan_rgb[1], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->cyan_rgb[2], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->magenta_rgb[0], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->magenta_rgb[1], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->magenta_rgb[2], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->yellow_rgb[0], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->yellow_rgb[1], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->yellow_rgb[2], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->white_rgb[0], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->white_rgb[1], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->white_rgb[2], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->black_rgb[0], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->black_rgb[1], CC_MIN, CC_MAX);
+	PARAM_IN_RANGE(ret, params->black_rgb[2], CC_MIN, CC_MAX);
+
+	if (ret)
+		return -EINVAL;
+
+	memcpy(&mdnie->params.cr_params, params, sizeof(*params));
+	return 0;
+}
+
+static int mdnie_set_edge_enhancement_params(
+		struct mdnie_context *mdnie,
+		const struct drm_mode_edge_enhancement *params)
+{
+	int ret;
+
+	PARAM_IN_RANGE(ret, params->edge_th, TH_MIN, TH_MAX);
+	PARAM_IN_RANGE(ret, params->background_th, TH_MIN, TH_MAX);
+	PARAM_IN_RANGE(ret, params->pg_edge, GAIN_MIN, GAIN_MAX);
+	PARAM_IN_RANGE(ret, params->pg_flat, GAIN_MIN, GAIN_MAX);
+	PARAM_IN_RANGE(ret, params->pg_background, GAIN_MIN, GAIN_MAX);
+	PARAM_IN_RANGE(ret, params->ng_edge, GAIN_MIN, GAIN_MAX);
+	PARAM_IN_RANGE(ret, params->ng_flat, GAIN_MIN, GAIN_MAX);
+	PARAM_IN_RANGE(ret, params->ng_background, GAIN_MIN, GAIN_MAX);
+
+	if (ret)
+		return -EINVAL;
+
+	memcpy(&mdnie->params.de_params, params, sizeof(*params));
+	return 0;
+}
+
+static int mdnie_set_window_params(
+		struct mdnie_context *mdnie,
+		const struct drm_exynos_mdnie_window *params)
+{
+	int ret;
+
+	PARAM_IN_RANGE(ret, params->win_x, X_MIN, X_MAX);
+	PARAM_IN_RANGE(ret, params->win_y, Y_MIN, Y_MAX);
+	PARAM_IN_RANGE(ret, params->win_w, params->win_x, X_MAX);
+	PARAM_IN_RANGE(ret, params->win_h, params->win_y, Y_MAX);
+
+	if (ret)
+		return -EINVAL;
+
+	memcpy(&mdnie->params.win, params, sizeof(*params));
+	return 0;
+}
+
+static int mdnie_enable_sub_modules(struct mdnie_context *mdnie,
+		uint64_t module_en)
+{
+	uint64_t mask;
+	int ret;
+
+	mask = BIT(MDNIE_COLOR_REPRODUCTION) |
+		BIT(MDNIE_CURVE_CONTROL) |
+		BIT(MDNIE_COLOR_SATURATION) |
+		BIT(MDNIE_DETAIL_ENHANCEMENT);
+
+	ret = module_en & ~mask;
+
+	if (ret)
+		return -EINVAL;
+
+	mdnie->params.modules_enabled = (uint32_t)module_en;
+	return 0;
+}
+
+static void mdnie_apply_de_params(struct mdnie_context *mdnie)
+{
+	struct drm_mode_edge_enhancement de = mdnie->params.de_params;
+
+	/* remains contant for all mdnie modes */
+	u32 max_out_ratio = 0x1000;
+	u32 min_out_ratio = 0x0100;
+
+	mdnie_write(mdnie, MDNIE_DE_TH_EDGE, de.edge_th);
+	mdnie_write(mdnie, MDNIE_DE_TH_BKG, de.background_th);
+	mdnie_write(mdnie, MDNIE_DE_GAINPOS_EDGE, de.pg_edge);
+	mdnie_write(mdnie, MDNIE_DE_GAINPOS_FLAT, de.pg_flat);
+	mdnie_write(mdnie, MDNIE_DE_GAINPOS_BKG, de.pg_background);
+	mdnie_write(mdnie, MDNIE_DE_GAINNEG_EDGE, de.ng_edge);
+	mdnie_write(mdnie, MDNIE_DE_GAINNEG_FLAT, de.ng_flat);
+	mdnie_write(mdnie, MDNIE_DE_GAINNEG_BKG, de.ng_background);
+	mdnie_write(mdnie, MDNIE_DE_MAX_RATIO, max_out_ratio);
+	mdnie_write(mdnie, MDNIE_DE_MIN_RATIO, min_out_ratio);
+}
+
+static void mdnie_apply_cs_params(struct mdnie_context *mdnie)
+{
+	struct drm_mode_color_saturation cs = mdnie->params.cs_params;
+
+	mdnie_write(mdnie, MDNIE_CS_RED_YELLOW_HUE_GAIN,
+		MDNIE_CS_RED_HUE_GAIN(cs.hue_gain_red) |
+		MDNIE_CS_YELLOW_HUE_GAIN(cs.hue_gain_yellow));
+
+	mdnie_write(mdnie, MDNIE_CS_GREEN_CYAN_HUE_GAIN,
+		MDNIE_CS_GREEN_HUE_GAIN(cs.hue_gain_green) |
+		MDNIE_CS_CYAN_HUE_GAIN(cs.hue_gain_cyan));
+
+	mdnie_write(mdnie, MDNIE_CS_BLUE_MAG_HUE_GAIN,
+		MDNIE_CS_BLUE_HUE_GAIN(cs.hue_gain_blue) |
+		MDNIE_CS_MAGENTA_HUE_GAIN(cs.hue_gain_magenta));
+
+	mdnie_write(mdnie, MDNIE_CS_OVERALL_HUE_GAIN_REG,
+		mdnie_read(mdnie, MDNIE_CS_OVERALL_HUE_GAIN_REG) |
+		MDNIE_CS_OVERALL_HUE_GAIN(cs.hue_gain_overall));
+}
+
+static void mdnie_apply_cc_gamma_params(struct mdnie_context *mdnie)
+{
+	struct exynos_mdnie_drm_gamma *cc = &mdnie->params.gamma_params;
+	u32 i, val;
+	u8 strength = MDNIE_DEFAULT_CC_STRENGTH;
+	u8 gamma_channel = RGB_GAMMA_R;
+
+	val = mdnie_read(mdnie, MDNIE_CC_CHSEL_STRENGTH);
+	val &= ~(MDNIE_CC_CHSEL_MASK);
+	val |= MDNIE_CC_CHSEL(gamma_channel);
+	val &= ~(MDNIE_CC_STRENGTH_MASK);
+	val |= MDNIE_CC_STRENGTH(strength);
+	mdnie_write(mdnie, MDNIE_CC_CHSEL_STRENGTH, val);
+
+	mdnie_write(mdnie, MDNIE_CC_GAMMA_RED_0_REG, cc->gamma_r[0]);
+	for (i = 1; i <= 8; i++)
+		mdnie_write(mdnie,
+			MDNIE_CC_GAMMA_RED_0_REG + i,
+			MDNIE_CC_GAMMA_MSB(cc->gamma_r[i]) |
+			MDNIE_CC_GAMMA_LSB(cc->gamma_r[i + 8]));
+
+	mdnie_write(mdnie, MDNIE_CC_GAMMA_GREEN_0_REG, cc->gamma_g[0]);
+	for (i = 1; i <= 8; i++)
+		mdnie_write(mdnie,
+			MDNIE_CC_GAMMA_GREEN_0_REG + i,
+			MDNIE_CC_GAMMA_MSB(cc->gamma_g[i]) |
+			MDNIE_CC_GAMMA_LSB(cc->gamma_g[i + 8]));
+
+	mdnie_write(mdnie, MDNIE_CC_GAMMA_BLUE_0_REG, cc->gamma_b[0]);
+	for (i = 1; i <= 8; i++)
+		mdnie_write(mdnie,
+			MDNIE_CC_GAMMA_BLUE_0_REG + i,
+			MDNIE_CC_GAMMA_MSB(cc->gamma_b[i]) |
+			MDNIE_CC_GAMMA_LSB(cc->gamma_b[i + 8]));
+}
+
+static void mdnie_apply_cr_params(struct mdnie_context *mdnie)
+{
+	struct drm_mode_color_reproduction cr = mdnie->params.cr_params;
+
+	mdnie_write(mdnie, MDNIE_SCR_R_R,
+			MDNIE_SCR_MSB(cr.red_rgb[0]) |
+			MDNIE_SCR_LSB(cr.cyan_rgb[0]));
+
+	mdnie_write(mdnie, MDNIE_SCR_R_G,
+			MDNIE_SCR_MSB(cr.red_rgb[1]) |
+			MDNIE_SCR_LSB(cr.cyan_rgb[1]));
+
+	mdnie_write(mdnie, MDNIE_SCR_R_B,
+			MDNIE_SCR_MSB(cr.red_rgb[2]) |
+			MDNIE_SCR_LSB(cr.cyan_rgb[2]));
+
+	mdnie_write(mdnie, MDNIE_SCR_G_R,
+			MDNIE_SCR_MSB(cr.green_rgb[0]) |
+			MDNIE_SCR_LSB(cr.magenta_rgb[0]));
+
+	mdnie_write(mdnie, MDNIE_SCR_G_G,
+			MDNIE_SCR_MSB(cr.green_rgb[1]) |
+			MDNIE_SCR_LSB(cr.magenta_rgb[1]));
+
+	mdnie_write(mdnie, MDNIE_SCR_G_B,
+			MDNIE_SCR_MSB(cr.green_rgb[2]) |
+			MDNIE_SCR_LSB(cr.magenta_rgb[2]));
+
+	mdnie_write(mdnie, MDNIE_SCR_B_R,
+			MDNIE_SCR_MSB(cr.blue_rgb[0]) |
+			MDNIE_SCR_LSB(cr.yellow_rgb[0]));
+
+	mdnie_write(mdnie, MDNIE_SCR_B_G,
+			MDNIE_SCR_MSB(cr.blue_rgb[1]) |
+			MDNIE_SCR_LSB(cr.yellow_rgb[1]));
+
+	mdnie_write(mdnie, MDNIE_SCR_B_B,
+			MDNIE_SCR_MSB(cr.blue_rgb[2]) |
+			MDNIE_SCR_LSB(cr.yellow_rgb[2]));
+
+	mdnie_write(mdnie, MDNIE_SCR_K_R,
+			MDNIE_SCR_MSB(cr.black_rgb[0]) |
+			MDNIE_SCR_LSB(cr.white_rgb[0]));
+
+	mdnie_write(mdnie, MDNIE_SCR_K_G,
+			MDNIE_SCR_MSB(cr.black_rgb[1]) |
+			MDNIE_SCR_LSB(cr.white_rgb[1]));
+
+	mdnie_write(mdnie, MDNIE_SCR_K_B,
+			MDNIE_SCR_MSB(cr.black_rgb[2]) |
+			MDNIE_SCR_LSB(cr.white_rgb[2]));
+}
+
+static int exynos_mdnie_update(struct mdnie_context *mdnie)
+{
+	/* Bank 0 controls */
+	exynos_mdnie_bank_sel(mdnie, 0);
+
+	mdnie_set_all_modules_off(mdnie);
+	mdnie_set_req_modules_on(mdnie);
+
+	if (mdnie->params.modules_enabled & BIT(MDNIE_DETAIL_ENHANCEMENT))
+		mdnie_apply_de_params(mdnie);
+	if (mdnie->params.modules_enabled & BIT(MDNIE_COLOR_SATURATION))
+		mdnie_apply_cs_params(mdnie);
+
+	/* Bank 1 controls */
+	exynos_mdnie_bank_sel(mdnie, 1);
+
+	if (mdnie->params.modules_enabled & BIT(MDNIE_CURVE_CONTROL))
+		mdnie_apply_cc_gamma_params(mdnie);
+	if (mdnie->params.modules_enabled & BIT(MDNIE_COLOR_REPRODUCTION))
+		mdnie_apply_cr_params(mdnie);
+
+	return 0;
+}
+
+static void exynos_fimd_mdnie_cfg(struct mdnie_context *mdnie, int mdnie_on)
+{
+	u32 val = readl(mdnie->sysreg_disp1blk);
+
+	val &= ~EXYNOS_FIFORST_DISP1;		/* DISP1_BLK FIFO reset */
+	val &= ~EXYNOS_CLEAR_DISP0;		/* Clear DISP0 */
+	val &= ~EXYNOS_VT_DISP1_MASK;
+	val |= EXYNOS_VT_DISP1_RGB;		/* Set RGB interface */
+
+	val |= EXYNOS_FIFORST_DISP1;
+
+	if (mdnie_on) {
+		val &= ~EXYNOS_FIMDBYPASS_DISP1;	/* MIE, MDNIE path */
+		val |= EXYNOS_MDNIE_SEL;		/* MDNIE */
+		val |= EXYNOS_MDNIE_ENABLE;		/* ENABLE */
+	} else {
+		val |= EXYNOS_FIMDBYPASS_DISP1;		/* FIMD path */
+		val &= ~EXYNOS_MDNIE_SEL;		/* Clear MDNIE */
+		val &= ~EXYNOS_MDNIE_ENABLE;		/* Clear MDNIE ENABLE */
+	}
+	writel(val, mdnie->sysreg_disp1blk);
+}
+
+static int exynos_mdnie_power_on(void *pp_ctx)
+{
+	struct mdnie_context *mdnie = pp_ctx;
+	int ret = 0;
+
+	exynos_fimd_mdnie_cfg(mdnie, MDNIE_ON);
+
+	ret = clk_prepare_enable(mdnie->mdnie_bus_clk);
+	if (ret < 0) {
+		DRM_ERROR("failed to enable mdnie bus clk [%d]\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(mdnie->mdnie_src_clk);
+	if (ret < 0) {
+		DRM_ERROR("failed to enable mdnie src clk [%d]\n", ret);
+		clk_disable_unprepare(mdnie->mdnie_bus_clk);
+		return ret;
+	}
+
+	ret = exynos_mdnie_set_size(mdnie);
+	exynos_mdnie_update(mdnie);
+
+	return ret;
+}
+
+static int exynos_mdnie_power_off(void *pp_ctx)
+{
+	struct mdnie_context *mdnie = pp_ctx;
+
+	clk_disable_unprepare(mdnie->mdnie_src_clk);
+	clk_disable_unprepare(mdnie->mdnie_bus_clk);
+
+	exynos_fimd_mdnie_cfg(mdnie, MDNIE_OFF);
+
+	return 0;
+}
+
+static int exynos_mdnie_set_property(struct drm_device *drm_dev,
+		void *pp_ctx, struct drm_property *property, uint64_t val)
+{
+	struct mdnie_context *mdnie = pp_ctx;
+	struct drm_property_blob *blob;
+	struct drm_mode_object *blob_obj;
+	int ret = 0;
+
+	DRM_DEBUG("[PROP:%s, VALUE:%llu]\n", property->name, val);
+
+	if (drm_dev->mode_config.color_saturation_property == property) {
+		blob = drm_dev->mode_config.color_saturation_blob_ptr;
+		ret = mdnie_set_color_saturation_params(mdnie,
+			(struct drm_mode_color_saturation *)blob->data);
+		if (ret)
+			return ret;
+	}
+
+	if (drm_dev->mode_config.color_reproduction_property == property) {
+		blob = drm_dev->mode_config.color_reproduction_blob_ptr;
+		mdnie_set_color_reproduction_params(mdnie,
+			(struct drm_mode_color_reproduction *)blob->data);
+		if (ret)
+			return ret;
+	}
+
+	if (drm_dev->mode_config.edge_enhancement_property == property) {
+		blob = drm_dev->mode_config.edge_enhancement_blob_ptr;
+		mdnie_set_edge_enhancement_params(mdnie,
+			(struct drm_mode_edge_enhancement *)blob->data);
+		if (ret)
+			return ret;
+	}
+
+	if (!strcmp("mdnie_window", property->name)) {
+		blob_obj = drm_mode_object_find(drm_dev, val,
+				DRM_MODE_OBJECT_BLOB);
+		blob = obj_to_blob(blob_obj);
+
+		mdnie_set_window_params(mdnie,
+			(struct drm_exynos_mdnie_window *)blob->data);
+		if (ret)
+			return ret;
+	}
+
+	if (!strcmp("mdnie_modules_enable", property->name)) {
+		mdnie_enable_sub_modules(mdnie, val);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int exynos_mdnie_set_gamma(void *pp_ctx, u16 *r, u16 *g,
+		u16 *b, uint32_t start, uint32_t size)
+{
+	struct mdnie_context *mdnie = pp_ctx;
+	struct exynos_mdnie_drm_gamma *gamma = &mdnie->params.gamma_params;
+	int i, ret;
+
+	DRM_DEBUG("[LENGTH :%u]\n", size);
+
+	if (size > GAMMA_RAMP_LENGTH)
+		return -EINVAL;
+
+	for (i = 0; i < size; i++) {
+		PARAM_IN_RANGE(ret, r[i], CC_MIN, CC_MAX);
+		PARAM_IN_RANGE(ret, g[i], CC_MIN, CC_MAX);
+		PARAM_IN_RANGE(ret, b[i], CC_MIN, CC_MAX);
+	}
+
+	if (ret)
+		return -EINVAL;
+
+	for (i = 0; i < size; i++) {
+		gamma->gamma_r[i] = r[i];
+		gamma->gamma_g[i] = g[i];
+		gamma->gamma_b[i] = b[i];
+	}
+
+	return 0;
+}
+
+void exynos_mdnie_mode_set(void *pp_ctx,
+			const struct drm_display_mode *in_mode)
+{
+	struct mdnie_context *mdnie = pp_ctx;
+
+	DRM_DEBUG("[MODE :%s]\n", in_mode->name);
+
+	/* preserve mode everytime for later use */
+	drm_mode_copy(&mdnie->mode, in_mode);
+}
+
+static struct exynos_fimd_pp_ops mdnie_ops = {
+	.power_on = exynos_mdnie_power_on,
+	.power_off = exynos_mdnie_power_off,
+	.set_property = exynos_mdnie_set_property,
+	.set_gamma = exynos_mdnie_set_gamma,
+	.mode_set = exynos_mdnie_mode_set,
+};
+
+static struct exynos_fimd_pp mdnie_pp = {
+	.ops = &mdnie_ops,
+};
+
+static int dt_parse_disp1blk_cfg(struct device *dev, u32 *disp1blk_addr)
+{
+	struct device_node *np = dev->of_node;
+
+	if (of_property_read_u32(np, "samsung,disp1blk-cfg", disp1blk_addr)) {
+		DRM_INFO("No DISP1BLK_CFG property present, "
+			"MDNIE feature will be disabled\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int exynos_iomap_disp1blk(struct mdnie_context *mdnie,
+			u32 disp1blk_addr)
+{
+	mdnie->sysreg_disp1blk = ioremap(disp1blk_addr, 4);
+	if (!mdnie->sysreg_disp1blk) {
+		DRM_ERROR("failed to ioremap DISP1BLK_CFG\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+int exynos_mdnie_init(struct device *dev, struct exynos_fimd_pp **pp)
+{
+	struct device_node *np = dev->of_node;
+	struct device_node *mdnie_np;
+	struct mdnie_context *mdnie = NULL;
+	u32 disp1blk_phyaddr;
+	int ret = 0;
+	u32 buf[2];
+
+	mdnie_np = of_parse_phandle(np, "samsung,mdnie", 0);
+	if (!mdnie_np) {
+		DRM_INFO("No mdnie node present, "
+				"MDNIE feature will be disabled\n");
+		ret = -EINVAL;
+		goto err0;
+	}
+
+	if (of_property_read_u32_array(mdnie_np, "reg", buf, 2)) {
+		DRM_ERROR("failed to get base address for MDNIE\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	mdnie = kzalloc(sizeof(struct mdnie_context), GFP_KERNEL);
+	if (!mdnie) {
+		DRM_ERROR("failed to allocate mdnie\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	mdnie->exynos_mdnie_base = ioremap(buf[0], buf[1]);
+	if (!mdnie->exynos_mdnie_base) {
+		DRM_ERROR("failed to ioremap mdnie device\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	if (dt_parse_disp1blk_cfg(dev, &disp1blk_phyaddr)) {
+		DRM_ERROR("failed to get disp1blk property.\n");
+		ret = -ENODEV;
+		goto err1;
+	}
+
+	if (exynos_iomap_disp1blk(mdnie, disp1blk_phyaddr)) {
+		DRM_ERROR("failed to iopmap disp1blk sysreg.\n");
+		ret = -ENODEV;
+		goto err1;
+	}
+
+	/* Setup MDNIE clocks */
+	mdnie->mdnie_bus_clk = devm_clk_get(dev, "mdnie");
+	if (IS_ERR(mdnie->mdnie_bus_clk)) {
+		DRM_ERROR("failed to get mdnie bus clock\n");
+		ret = PTR_ERR(mdnie->mdnie_bus_clk);
+		goto err1;
+	}
+
+	mdnie->mdnie_src_clk = devm_clk_get(dev, "sclk_mdnie");
+	if (IS_ERR(mdnie->mdnie_src_clk)) {
+		DRM_ERROR("failed to get mdnie_src_clk\n");
+		ret = PTR_ERR(mdnie->mdnie_src_clk);
+		goto err1;
+	}
+
+	mdnie_pp.ctx = mdnie;
+	*pp = &mdnie_pp;
+
+	DRM_INFO("MDNIE initialzation done\n");
+
+	return 0;
+
+err1:
+	kfree(mdnie);
+err0:
+	return ret;
+}
+EXPORT_SYMBOL(exynos_mdnie_init);
diff --git a/drivers/gpu/drm/exynos/exynos_mdnie_regs.h b/drivers/gpu/drm/exynos/exynos_mdnie_regs.h
new file mode 100644
index 0000000..66a8edc
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_mdnie_regs.h
@@ -0,0 +1,154 @@
+/* drivers/gpu/drm/exynos/exynos_mdnie_regs.h
+ *
+ * Header file for Samsung (MDNIE) driver
+ *
+ * Copyright (c) 2014 Samsung Electronics
+ *	http://www.samsungsemi.com/
+ *
+ * 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 __REGS_MDNIE_H__
+#define __REGS_MDNIE_H__
+
+/* Exynos DISP1BLK_CFG register */
+#define EXYNOS_MDNIE_ENABLE			(1 << 0)
+#define EXYNOS_MDNIE_SEL			(1 << 14)
+#define EXYNOS_FIMDBYPASS_DISP1			(1 << 15)
+#define EXYNOS_FIFORST_DISP1			(1 << 23)
+#define EXYNOS_CLEAR_DISP0			(1 << 27)
+#define EXYNOS_VT_DISP1_MASK			(3 << 24)
+#define EXYNOS_VT_DISP1_RGB			(0 << 24)
+#define EXYNOS_VT_DISP1_I80			(1 << 24)
+
+#define MDNIE_REG_WIDTH				0xFFFF
+#define MDNIE_REG_OFFSET_LIMIT			0xFF
+
+/* BANK 0: MODULE_TOP */
+#define MDNIE_TOP_R0				0x0000
+#define MDNIE_TOP_R0_BANK0_SEL			(0 << 0)
+#define MDNIE_TOP_R0_BANK1_SEL			(1 << 0)
+#define MDNIE_TOP_R0_SHADOW_SEL			(1 << 3)
+#define MDNIE_TOP_R1				0x0001
+#define MDNIE_TOP_R1_MASK_INPUT_DATA_ENABLE	(1 << 10)
+#define MDNIE_TOP_R1_MASK_INPUT_HSYNC		(1 << 9)
+#define MDNIE_TOP_RIHSIZE			0x0003
+#define MDNIE_TOP_RSIZE_MAX			2560
+#define MDNIE_TOP_RIVSIZE			0x0004
+#define MDNIE_TOP_R8				0x0008
+#define MDNIE_TOP_R8_DITH_MODULE_ON		(1 << 13)
+#define MDNIE_TOP_R8_ABC_MODULE_ON		(1 << 11)
+#define MDNIE_TOP_R8_SCR_MODULE_ON		(1 << 9)
+#define MDNIE_TOP_R8_CC_MODULE_ON		(1 << 8)
+#define MDNIE_TOP_R8_CS_MODULE_ON		(1 << 5)
+#define MDNIE_TOP_R8_DE_MODULE_ON		(1 << 4)
+#define MDNIE_TOP_R9				0x0009
+#define MDNIE_TOP_R9_MCM_MODULE_ON		(1 << 0)
+#define MDNIE_TOP_RA				0x000A
+#define MDNIE_TOP_RA_UC_MODULE_ON		(1 << 0)
+#define MDNIE_TOP_RB				0x000B
+
+/* BANK 0: MODULE_DE */
+#define MDNIE_DE_TH_EDGE				0xB0
+#define MDNIE_DE_TH_BKG				0xB1
+#define MDNIE_DE_TH_MAX				2047
+
+#define MDNIE_DE_GAINPOS_EDGE			0xB2
+#define MDNIE_DE_GAINPOS_FLAT			0xB3
+#define MDNIE_DE_GAINPOS_BKG			0xB4
+#define MDNIE_DE_GAINNEG_EDGE			0xB5
+#define MDNIE_DE_GAINNEG_FLAT			0xB6
+#define MDNIE_DE_GAINNEG_BKG			0xB7
+#define MDNIE_DE_GAIN_MAX			8191
+
+#define MDNIE_DE_MAX_RATIO			0xB8
+#define MDNIE_DE_MAX_RATIO_MIN			1024
+#define MDNIE_DE_MAX_RATIO_MAX			65535
+#define MDNIE_DE_MIN_RATIO			0xB9
+#define MDNIE_DE_MIN_RATIO_MIN			0
+#define MDNIE_DE_MIN_RATIO_MAX			1024
+#define MDNIE_DE_RBA				0xBA
+#define MDNIE_DE_RBA_MAXPLUS(x)			((x & 0xFF) << 8)
+#define MDNIE_DE_RBA_MAXMINUS(x)			((x & 0xFF) << 0)
+
+/* BANK 0: MODULE_CS */
+#define MDNIE_CS_RED_YELLOW_HUE_GAIN		0xC0
+#define MDNIE_CS_RED_HUE_GAIN(x)			((x & 0x3F) << 8)
+#define MDNIE_CS_YELLOW_HUE_GAIN(x)		((x & 0x3F) << 0)
+#define MDNIE_CS_GREEN_CYAN_HUE_GAIN		0xC1
+#define MDNIE_CS_GREEN_HUE_GAIN(x)		((x & 0x3F) << 8)
+#define MDNIE_CS_CYAN_HUE_GAIN(x)		((x & 0x3F) << 0)
+#define MDNIE_CS_BLUE_MAG_HUE_GAIN		0xC2
+#define MDNIE_CS_BLUE_HUE_GAIN(x)		((x & 0x3F) << 8)
+#define MDNIE_CS_MAGENTA_HUE_GAIN(x)		((x & 0x3F) << 0)
+#define MDNIE_CS_OVERALL_HUE_GAIN_REG		0xC3
+#define MDNIE_CS_OVERALL_HUE_GAIN(x)		((x & 0x3F) << 8)
+#define MDNIE_CS_HUE_GAIN_MAX			0x3F
+
+/* BANK 0: RELEASE0 */
+#define MDNIE_RELEASE_RFF			0x00FF
+#define MDNIE_RELEASE_RFF_MASK_REGISTERS		(1 << 0)
+
+/* BANK 1: MODULE_CC */
+#define MDNIE_CC_CHSEL_STRENGTH			0x13F
+#define MDNIE_CC_CHSEL_MASK			((0x3 << 0x8))
+#define MDNIE_CC_CHSEL(x)			((x) << 0x8)
+#define MDNIE_CC_STRENGTH_MASK			0xFF
+#define MDNIE_CC_STRENGTH(x)			(x << 0)
+#define MDNIE_DEFAULT_CC_STRENGTH		0x80
+
+/* Gamma Ramp */
+#define MDNIE_CC_GAMMA_RED_0_REG			0x140
+#define MDNIE_CC_GAMMA_GREEN_0_REG		0x150
+#define MDNIE_CC_GAMMA_BLUE_0_REG		0x160
+#define MDNIE_CC_GAMMA_MSB(x)			((x & 0xFF) << 8)
+#define MDNIE_CC_GAMMA_LSB(x)			((x & 0xFF) << 0)
+
+/* MODULE SCRPLUS */
+#define MDNIE_SCR_GCC_ONOFF			0x170
+#define MDNIE_SCR_GCC_ON				(1 << 0)
+#define MDNIE_SCR_R_R				0x171
+#define MDNIE_SCR_R_G				0x172
+#define MDNIE_SCR_R_B				0x173
+#define MDNIE_SCR_G_R				0x174
+#define MDNIE_SCR_G_G				0x175
+#define MDNIE_SCR_G_B				0x176
+#define MDNIE_SCR_B_R				0x177
+#define MDNIE_SCR_B_G				0x178
+#define MDNIE_SCR_B_B				0x179
+#define MDNIE_SCR_K_R				0x17A
+#define MDNIE_SCR_K_G				0x17B
+#define MDNIE_SCR_K_B				0x17C
+#define MDNIE_SCR_MSB(x)				((x & 0xFF) << 8)
+#define MDNIE_SCR_LSB(x)				((x & 0xFF) << 0)
+
+/*  Hue gain ranges */
+#define HG_MIN			0
+#define HG_MAX			63
+
+/*  Color Component ranges */
+#define CC_MIN			0
+#define CC_MAX			255
+
+/*  threshold ranges */
+#define TH_MIN			0
+#define TH_MAX			2047
+
+/*  pos/neg gain ranges */
+#define GAIN_MIN		0
+#define GAIN_MAX		8191
+
+/*  window ranges */
+#define X_MIN			0
+#define X_MAX			1920
+#define Y_MIN			0
+#define Y_MAX			1080
+
+/*  gamma modes */
+#define RGB_GAMMA_R		0
+#define R_GAMMA_R		1
+#define Y_GAMMA_R		2
+
+#endif
-- 
1.8.1.2



More information about the dri-devel mailing list