All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ajay Kumar <ajaykumar.rs@samsung.com>
To: dri-devel@lists.freedesktop.org, linux-samsung-soc@vger.kernel.org
Cc: inki.dae@samsung.com, seanpaul@google.com, ajaynumb@gmail.com,
	sw0312.kim@samsung.com, joshi@samsung.com,
	prashanth.g@samsung.com, marcheu@chromium.org,
	Ajay Kumar <ajaykumar.rs@samsung.com>,
	Shirish S <s.shirish@samsung.com>,
	Rahul Sharma <rahul.sharma@samsung.com>
Subject: [RFC 1/4] drm: exynos: Add infrastructure to support FIMD post processors
Date: Wed, 19 Mar 2014 19:52:52 +0530	[thread overview]
Message-ID: <1395238975-24600-2-git-send-email-ajaykumar.rs@samsung.com> (raw)
In-Reply-To: <1395238975-24600-1-git-send-email-ajaykumar.rs@samsung.com>

Exynos variants support post pocessors(PP) for FIMD (MDNIE and IELCD)
which work closely with fimd. These post processors have strict
dependency on FIMD for poweron/poweroff. This patch adds an
infrastructure in FIMD driver to accomodate such devices.

Added structure definition for FIMD PP and interfaces from FIMD
driver to control FIMD PP.

Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Signed-off-by: Shirish S <s.shirish@samsung.com>
Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_fimd.c | 162 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_fimd_pp.h  |  52 ++++++++++
 include/video/samsung_fimd.h             |   6 +-
 3 files changed, 219 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/exynos/exynos_fimd_pp.h

diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index a5511be..a584d8e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -30,6 +30,7 @@
 #include "exynos_drm_fbdev.h"
 #include "exynos_drm_crtc.h"
 #include "exynos_drm_iommu.h"
+#include "exynos_fimd_pp.h"
 
 /*
  * FIMD stands for Fully Interactive Mobile Display and
@@ -113,11 +114,14 @@ struct fimd_context {
 	void __iomem			*regs;
 	struct drm_display_mode		mode;
 	struct fimd_win_data		win_data[WINDOWS_NR];
+	struct list_head		fimd_pp_list;
 	unsigned int			default_win;
 	unsigned long			irq_flags;
 	u32				vidcon0;
 	u32				vidcon1;
 	bool				suspended;
+	bool				enable_pp;
+	bool				pp_running;
 	int				pipe;
 	wait_queue_head_t		wait_vsync_queue;
 	atomic_t			wait_vsync_event;
@@ -145,6 +149,12 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
 	return (struct fimd_driver_data *)of_id->data;
 }
 
+void fimd_add_pp_to_list(struct fimd_context *ctx,
+			struct exynos_fimd_pp *pp)
+{
+	list_add_tail(&pp->list, &ctx->fimd_pp_list);
+}
+
 static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
 			struct drm_device *drm_dev)
 {
@@ -214,17 +224,49 @@ static void fimd_mode_set(struct exynos_drm_manager *mgr,
 		const struct drm_display_mode *in_mode)
 {
 	struct fimd_context *ctx = mgr->ctx;
+	struct exynos_fimd_pp *pp_display;
 
 	drm_mode_copy(&ctx->mode, in_mode);
+
+	/* mode_set for the post processors*/
+	list_for_each_entry(pp_display, &ctx->fimd_pp_list, list)
+		if (pp_display->ops->mode_set)
+			pp_display->ops->mode_set(pp_display->ctx, in_mode);
+}
+
+static int fimd_wait_till_per_frame_off(struct fimd_context *ctx)
+{
+	unsigned int val = readl(ctx->regs + VIDCON0);
+	int count = 10;
+
+	val &= ~(VIDCON0_ENVID_F);
+	writel(val, ctx->regs + VIDCON0);
+
+	while (count) {
+		val = readl(ctx->regs + VIDCON0);
+		if ((val & VIDCON0_ENVID_F) == 0)
+			break;
+		mdelay(17);
+		count--;
+	}
+
+	if (count == 0) {
+		DRM_ERROR("FIMD per frame switch off TIMEDOUT\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
 }
 
 static void fimd_commit(struct exynos_drm_manager *mgr)
 {
 	struct fimd_context *ctx = mgr->ctx;
 	struct drm_display_mode *mode = &ctx->mode;
+	struct exynos_fimd_pp *pp_display;
 	struct fimd_driver_data *driver_data;
 	u32 val, clkdiv, vidcon1;
 	int hblank, vblank, vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd;
+	int ret = 0;
 
 	driver_data = ctx->driver_data;
 	if (ctx->suspended)
@@ -234,6 +276,30 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
 	if (mode->htotal == 0 || mode->vtotal == 0)
 		return;
 
+	/* The FIMD and the post processor(PP) poweroff calls below are needed
+	 * here to make sure that fimd_commit doesn't switch on the PPs twice
+	 * in a row. For proper working we need to keep fimd, and the PPs
+	 * off, before we start again. This flag "pp_running" will also help
+	 * in syncing any of the clock enable/disable calls in PP routines.
+	 */
+	if (ctx->enable_pp && ctx->pp_running) {
+		if (fimd_wait_till_per_frame_off(ctx))
+			DRM_ERROR("failed to switch off fimd per frame\n");
+		list_for_each_entry_reverse(pp_display, &ctx->fimd_pp_list,
+									list) {
+			if (pp_display->ops->power_off) {
+				ret = pp_display->ops->
+						power_off(pp_display->ctx);
+				if (ret) {
+					DRM_ERROR("fimd_pp switch off fail\n");
+					ctx->enable_pp = false;
+				} else {
+					ctx->pp_running = false;
+				}
+			}
+		}
+	}
+
 	/* setup polarity values */
 	vidcon1 = ctx->vidcon1;
 	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
@@ -286,10 +352,34 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
 	else
 		val &= ~VIDCON0_CLKDIR;	/* 1:1 clock */
 
+	writel(val, ctx->regs + VIDCON0);
+
+	if (ctx->enable_pp && !ctx->pp_running) {
+		/* set VCLK Free run control */
+		val = readl(ctx->regs + VIDCON0);
+		val |= VIDCON0_VCLKFREE;
+		writel(val, ctx->regs + VIDCON0);
+
+		/* post processor setup and poweron*/
+		list_for_each_entry(pp_display, &ctx->fimd_pp_list, list) {
+			if (pp_display->ops->power_on) {
+				ret = pp_display->ops->
+						power_on(pp_display->ctx);
+				if (ret) {
+					DRM_ERROR("fimd_pp poweron failed\n");
+					ctx->enable_pp = false;
+				} else {
+					ctx->pp_running = true;
+				}
+			}
+		}
+	}
+
 	/*
 	 * fields of register with prefix '_F' would be updated
 	 * at vsync(same as dma start)
 	 */
+	val = readl(ctx->regs + VIDCON0);
 	val |= VIDCON0_ENVID | VIDCON0_ENVID_F;
 	writel(val, ctx->regs + VIDCON0);
 }
@@ -749,6 +839,9 @@ static int fimd_poweron(struct exynos_drm_manager *mgr)
 		goto lcd_clk_err;
 	}
 
+	if (ctx->enable_pp)
+		writel(MDNIE_CLK_ENABLE, ctx->regs + DP_MDNIE_CLKCON);
+
 	/* if vblank was enabled status, enable it again. */
 	if (test_and_clear_bit(0, &ctx->irq_flags)) {
 		ret = fimd_enable_vblank(mgr);
@@ -776,6 +869,9 @@ bus_clk_err:
 static int fimd_poweroff(struct exynos_drm_manager *mgr)
 {
 	struct fimd_context *ctx = mgr->ctx;
+	struct exynos_fimd_pp *pp_display;
+	int ret = 0;
+
 
 	if (ctx->suspended)
 		return 0;
@@ -787,6 +883,27 @@ static int fimd_poweroff(struct exynos_drm_manager *mgr)
 	 */
 	fimd_window_suspend(mgr);
 
+	if (ctx->enable_pp && ctx->pp_running) {
+		if (fimd_wait_till_per_frame_off(ctx))
+			DRM_ERROR("failed to switch off fimd per frame\n");
+		list_for_each_entry_reverse(pp_display, &ctx->fimd_pp_list,
+									list) {
+			if (pp_display->ops->power_off) {
+				ret = pp_display->ops->
+						power_off(pp_display->ctx);
+				if (ret) {
+					DRM_ERROR("fimd_pp switch off fail\n");
+					ctx->enable_pp = false;
+				} else {
+					ctx->pp_running = false;
+				}
+			}
+		}
+	}
+
+	if (ctx->enable_pp)
+		writel(0, ctx->regs + DP_MDNIE_CLKCON);
+
 	clk_disable_unprepare(ctx->lcd_clk);
 	clk_disable_unprepare(ctx->bus_clk);
 
@@ -815,6 +932,47 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
 	}
 }
 
+static int fimd_set_property(void *in_ctx, struct drm_property *property,
+								uint64_t val)
+{
+	struct fimd_context *ctx = in_ctx;
+	struct exynos_fimd_pp *pp_display;
+	int ret;
+
+	list_for_each_entry(pp_display, &ctx->fimd_pp_list, list) {
+		if (pp_display->ops->set_property) {
+			ret = pp_display->ops->set_property(ctx->drm_dev,
+					pp_display->ctx, property, val);
+			if (ret) {
+				DRM_ERROR("pp set_property failed.\n");
+				return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int fimd_set_gamma(void *in_ctx, u16 *r, u16 *g, u16 *b,
+					uint32_t start, uint32_t size)
+{
+	struct fimd_context *ctx = in_ctx;
+	struct exynos_fimd_pp *pp_display;
+	int ret;
+
+	list_for_each_entry(pp_display, &ctx->fimd_pp_list, list) {
+		if (pp_display->ops->set_property)
+			ret = pp_display->ops->set_gamma(pp_display->ctx,
+							r, g, b, start, size);
+			if (ret) {
+				DRM_ERROR("pp set_gamma failed.\n");
+				return ret;
+			}
+	}
+
+	return 0;
+}
+
 static struct exynos_drm_manager_ops fimd_manager_ops = {
 	.dpms = fimd_dpms,
 	.mode_fixup = fimd_mode_fixup,
@@ -826,6 +984,8 @@ static struct exynos_drm_manager_ops fimd_manager_ops = {
 	.win_mode_set = fimd_win_mode_set,
 	.win_commit = fimd_win_commit,
 	.win_disable = fimd_win_disable,
+	.set_property = fimd_set_property,
+	.set_gamma = fimd_set_gamma,
 };
 
 static struct exynos_drm_manager fimd_manager = {
@@ -919,6 +1079,8 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
 	init_waitqueue_head(&ctx->wait_vsync_queue);
 	atomic_set(&ctx->wait_vsync_event, 0);
 
+	INIT_LIST_HEAD(&ctx->fimd_pp_list);
+
 	platform_set_drvdata(pdev, &fimd_manager);
 
 	fimd_manager.ctx = ctx;
diff --git a/drivers/gpu/drm/exynos/exynos_fimd_pp.h b/drivers/gpu/drm/exynos/exynos_fimd_pp.h
new file mode 100644
index 0000000..528d3cb
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_fimd_pp.h
@@ -0,0 +1,52 @@
+/* drivers/gpu/drm/exynos/exynos_fimd_pp.h
+ *
+ * Copyright (C) 2014 Samsung Electronics Co.Ltd
+ *
+ * Header file for FIMD post processors.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __EXYNOS_FIMD_H__
+#define __EXYNOS_FIMD_H__
+
+#include <drm/exynos_drm.h>
+
+/**
+ * Post Processor interfaces structure for DRM based FIMD.
+ *
+ * @power_on: setup the post processor.
+ * @power_off: power off the post processor.
+ * @mode_set: set video timings if needed by the post processor.
+ * @set_property: use crtc properties to set the post processor.
+ * @set_gamma: set gamma properties to post processor.
+ *
+ */
+struct exynos_fimd_pp_ops {
+	int (*power_on)(void *pp_ctx);
+	int (*power_off)(void *pp_ctx);
+	void (*mode_set)(void *pp_ctx, const struct drm_display_mode *in_mode);
+	int (*set_property)(struct drm_device *drm_dev, void *pp_ctx,
+				struct drm_property *property, uint64_t val);
+	int (*set_gamma)(void *pp_ctx, u16 *r,
+			u16 *g, u16 *b, uint32_t start, uint32_t size);
+};
+
+/*
+ * Exynos FIMD post processor structure
+ * @list: the list entry
+ * @ops: pointer to callbacks for post processor specific functionality
+ * @ctx: A pointer to the post processor's implementation specific context
+ *
+ */
+struct exynos_fimd_pp {
+	struct list_head list;
+	struct exynos_fimd_pp_ops *ops;
+	void *ctx;
+};
+
+#endif
diff --git a/include/video/samsung_fimd.h b/include/video/samsung_fimd.h
index b039320..3ff7cad 100644
--- a/include/video/samsung_fimd.h
+++ b/include/video/samsung_fimd.h
@@ -60,7 +60,7 @@
 #define VIDCON0_CLKVAL_F_SHIFT			6
 #define VIDCON0_CLKVAL_F_LIMIT			0xff
 #define VIDCON0_CLKVAL_F(_x)			((_x) << 6)
-#define VIDCON0_VLCKFREE			(1 << 5)
+#define VIDCON0_VCLKFREE			(1 << 5)
 #define VIDCON0_CLKDIR				(1 << 4)
 
 #define VIDCON0_CLKSEL_MASK			(0x3 << 2)
@@ -435,6 +435,10 @@
 #define BLENDCON_NEW_8BIT_ALPHA_VALUE		(1 << 0)
 #define BLENDCON_NEW_4BIT_ALPHA_VALUE		(0 << 0)
 
+/* DP_MDNIE_CLKCON */
+#define DP_MDNIE_CLKCON				0x27c
+#define MDNIE_CLK_ENABLE				0x3
+
 /* Notes on per-window bpp settings
  *
  * Value	Win0	 Win1	  Win2	   Win3	    Win 4
-- 
1.8.1.2

  reply	other threads:[~2014-03-19 14:22 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-19 14:22 [RFC 0/4] drm: exynos: Add drivers for MDNIE and IELCD Ajay Kumar
2014-03-19 14:22 ` Ajay Kumar [this message]
2014-03-31 12:04   ` [RFC 1/4] drm: exynos: Add infrastructure to support FIMD post processors Andrzej Hajda
2014-03-19 14:22 ` [RFC 2/4] drm: exynos: add MDNIE post processor Ajay Kumar
2014-03-19 17:21   ` Sachin Kamat
2014-03-21 14:30     ` Ajay kumar
2014-04-01  8:01   ` Andrzej Hajda
2014-03-19 14:22 ` [RFC 3/4] drm: exynos: add IELCD " Ajay Kumar
2014-03-21  8:42   ` Sachin Kamat
2014-03-21 15:44     ` Ajay kumar
2014-04-01  8:54   ` Andrzej Hajda
2014-03-19 14:22 ` [RFC 4/4] drm: exynos: add MDNIE and IELCD to FIMD pp list Ajay Kumar
2014-04-01  9:06   ` Andrzej Hajda
2014-04-01  9:23 ` [RFC 0/4] drm: exynos: Add drivers for MDNIE and IELCD Andrzej Hajda

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1395238975-24600-2-git-send-email-ajaykumar.rs@samsung.com \
    --to=ajaykumar.rs@samsung.com \
    --cc=ajaynumb@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=inki.dae@samsung.com \
    --cc=joshi@samsung.com \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=marcheu@chromium.org \
    --cc=prashanth.g@samsung.com \
    --cc=rahul.sharma@samsung.com \
    --cc=s.shirish@samsung.com \
    --cc=seanpaul@google.com \
    --cc=sw0312.kim@samsung.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.