linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Maxime Ripard <maxime.ripard@free-electrons.com>
To: Mike Turquette <mturquette@baylibre.com>,
	Stephen Boyd <sboyd@codeaurora.org>,
	David Airlie <airlied@linux.ie>,
	Thierry Reding <thierry.reding@gmail.com>
Cc: devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, linux-clk@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linux-sunxi@googlegroups.com,
	Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
	Chen-Yu Tsai <wens@csie.org>, Hans de Goede <hdegoede@redhat.com>,
	Alexander Kaplan <alex@nextthing.co>,
	Wynter Woods <wynter@nextthing.co>,
	Boris Brezillon <boris.brezillon@free-electrons.com>,
	Thomas Petazzoni <thomas.petazzoni@free-electrons.com>,
	Rob Clark <robdclark@gmail.com>, Daniel Vetter <daniel@ffwll.ch>,
	Maxime Ripard <maxime.ripard@free-electrons.com>
Subject: [PATCH 10/19] drm: sun4i: Add RGB output
Date: Fri, 30 Oct 2015 15:20:56 +0100	[thread overview]
Message-ID: <1446214865-3972-11-git-send-email-maxime.ripard@free-electrons.com> (raw)
In-Reply-To: <1446214865-3972-1-git-send-email-maxime.ripard@free-electrons.com>

One of the A10 display pipeline possible output is an RGB interface to
drive LCD panels directly. This is done through the first channel of the
TCON that will output our video signals directly.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/Makefile    |   2 +
 drivers/gpu/drm/sun4i/sun4i_drv.c |   9 +-
 drivers/gpu/drm/sun4i/sun4i_rgb.c | 243 ++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_rgb.h |  18 +++
 4 files changed, 271 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_rgb.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_rgb.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index bc2df12beb42..4d230b658a05 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -5,4 +5,6 @@ sun4i-drm-y += sun4i_framebuffer.o
 sun4i-drm-y += sun4i_layer.o
 sun4i-drm-y += sun4i_tcon.o
 
+sun4i-drm-y += sun4i_rgb.o
+
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index fc26f3903f52..f2c9c8a2eb75 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -20,6 +20,7 @@
 #include "sun4i_drv.h"
 #include "sun4i_framebuffer.h"
 #include "sun4i_layer.h"
+#include "sun4i_rgb.h"
 #include "sun4i_tcon.h"
 
 static void sun4i_drv_preclose(struct drm_device *drm,
@@ -127,13 +128,18 @@ static int sun4i_drv_load(struct drm_device *drm, unsigned long flags)
 	}
 
 	/* Create our outputs */
+	ret = sun4i_rgb_init(drm);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't create our RGB output\n");
+		goto err_free_crtc;
+	}
 
 	/* Create our framebuffer */
 	drv->fbdev = sun4i_framebuffer_init(drm);
 	if (IS_ERR(drv->fbdev)) {
 		dev_err(drm->dev, "Couldn't create our framebuffer\n");
 		ret = PTR_ERR(drv->fbdev);
-		goto err_free_crtc;
+		goto err_free_rgb;
 	}
 
 	/* Enable connectors polling */
@@ -141,6 +147,7 @@ static int sun4i_drv_load(struct drm_device *drm, unsigned long flags)
 
 	return 0;
 
+err_free_rgb:
 err_free_crtc:
 err_free_layers:
 err_free_tcon:
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
new file mode 100644
index 000000000000..426b16b26aec
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2015 Free Electrons
+ * Copyright (C) 2015 NextThing Co
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
+
+#include "sun4i_drv.h"
+#include "sun4i_tcon.h"
+
+struct sun4i_rgb {
+	struct drm_connector	connector;
+	struct drm_encoder	encoder;
+	struct drm_panel	*panel;
+
+	struct sun4i_drv	*drv;
+
+	bool			enabled;
+};
+
+static inline struct sun4i_rgb *
+drm_connector_to_sun4i_rgb(struct drm_connector *connector)
+{
+	return container_of(connector, struct sun4i_rgb,
+			    connector);
+}
+
+static inline struct sun4i_rgb *
+drm_encoder_to_sun4i_rgb(struct drm_encoder *encoder)
+{
+	return container_of(encoder, struct sun4i_rgb,
+			    encoder);
+}
+
+static int sun4i_rgb_get_modes(struct drm_connector *connector)
+{
+	struct sun4i_rgb *rgb =
+		drm_connector_to_sun4i_rgb(connector);
+
+	return rgb->panel->funcs->get_modes(rgb->panel);
+}
+
+static int sun4i_rgb_mode_valid(struct drm_connector *connector,
+				struct drm_display_mode *mode)
+{
+	DRM_DEBUG_DRIVER("Validating modes...\n");
+
+	if ((mode->hsync_start < 1) || (mode->hsync_start > 0x3ff) ||
+	    (mode->htotal < 1) || (mode->htotal > 0xfff))
+		return MODE_H_ILLEGAL;
+
+	DRM_DEBUG_DRIVER("Horizontal parameters OK\n");
+
+	if ((mode->vsync_start < 1) || (mode->vsync_start > 0x3ff) ||
+	    (mode->vtotal < 1) || (mode->vtotal > 0xfff))
+		return MODE_V_ILLEGAL;
+
+	DRM_DEBUG_DRIVER("Vertical parameters OK\n");
+
+	return MODE_OK;
+}
+
+static struct drm_encoder *
+sun4i_rgb_best_encoder(struct drm_connector *connector)
+{
+	struct sun4i_rgb *rgb =
+		drm_connector_to_sun4i_rgb(connector);
+
+	return &rgb->encoder;
+}
+
+static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = {
+	.get_modes	= sun4i_rgb_get_modes,
+	.mode_valid	= sun4i_rgb_mode_valid,
+	.best_encoder	= sun4i_rgb_best_encoder,
+};
+
+static enum drm_connector_status
+sun4i_rgb_connector_detect(struct drm_connector *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static void
+sun4i_rgb_connector_destroy(struct drm_connector *connector)
+{
+	struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
+
+	drm_panel_detach(rgb->panel);
+	drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs sun4i_rgb_con_funcs = {
+	.dpms			= drm_atomic_helper_connector_dpms,
+	.detect			= sun4i_rgb_connector_detect,
+	.fill_modes		= drm_helper_probe_single_connector_modes,
+	.destroy		= sun4i_rgb_connector_destroy,
+	.reset			= drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state	= drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
+};
+
+static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
+{
+	struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
+	struct sun4i_drv *drv = rgb->drv;
+	struct sun4i_tcon *tcon = drv->tcon;
+
+	if (rgb->enabled)
+		return;
+
+	DRM_DEBUG_DRIVER("Enabling RGB output\n");
+
+	drm_panel_enable(rgb->panel);
+	sun4i_tcon_enable_channel(tcon, 0);
+
+	rgb->enabled = true;
+}
+
+static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
+{
+	struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
+	struct sun4i_drv *drv = rgb->drv;
+	struct sun4i_tcon *tcon = drv->tcon;
+
+	if (!rgb->enabled)
+		return;
+
+	DRM_DEBUG_DRIVER("Disabling RGB output\n");
+
+	sun4i_tcon_disable_channel(tcon, 0);
+	drm_panel_disable(rgb->panel);
+
+	rgb->enabled = false;
+}
+
+static bool sun4i_rgb_encoder_mode_fixup(struct drm_encoder *encoder,
+					 const struct drm_display_mode *mode,
+					 struct drm_display_mode *adjusted)
+{
+	return true;
+}
+
+static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
+				       struct drm_display_mode *mode,
+				       struct drm_display_mode *adjusted_mode)
+{
+	struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
+	struct sun4i_drv *drv = rgb->drv;
+	struct sun4i_tcon *tcon = drv->tcon;
+
+	sun4i_tcon0_mode_set(tcon, mode);
+
+	clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
+}
+
+static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {
+	.mode_fixup	= sun4i_rgb_encoder_mode_fixup,
+	.mode_set	= sun4i_rgb_encoder_mode_set,
+	.disable	= sun4i_rgb_encoder_disable,
+	.enable		= sun4i_rgb_encoder_enable,
+};
+
+static void sun4i_rgb_enc_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+}
+
+static struct drm_encoder_funcs sun4i_rgb_enc_funcs = {
+	.destroy	= sun4i_rgb_enc_destroy,
+};
+
+int sun4i_rgb_init(struct drm_device *drm)
+{
+	struct sun4i_drv *drv = drm->dev_private;
+	struct sun4i_rgb *rgb;
+	struct device_node *np;
+	int ret;
+
+	rgb = devm_kzalloc(drm->dev, sizeof(*rgb), GFP_KERNEL);
+	if (!rgb)
+		return -ENOMEM;
+	rgb->drv = drv;
+
+	np = of_parse_phandle(drm->dev->of_node, "allwinner,panel", 0);
+	if (!np) {
+		dev_err(drm->dev, "Couldn't find our panel DT node\n");
+		return -ENODEV;
+	}
+
+	rgb->panel = of_drm_find_panel(np);
+	if (!rgb->panel) {
+		dev_err(drm->dev, "Couldn't find our panel\n");
+		return -EPROBE_DEFER;
+	}
+
+	drm_encoder_helper_add(&rgb->encoder,
+			       &sun4i_rgb_enc_helper_funcs);
+	ret = drm_encoder_init(drm,
+			       &rgb->encoder,
+			       &sun4i_rgb_enc_funcs,
+			       DRM_MODE_ENCODER_NONE);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't initialise the rgb encoder\n");
+		goto err_out;
+	}
+
+	/* The RGB encoder can only work with the TCON channel 0 */
+	rgb->encoder.possible_crtcs = BIT(0);
+
+	drm_connector_helper_add(&rgb->connector,
+				 &sun4i_rgb_con_helper_funcs);
+	ret = drm_connector_init(drm, &rgb->connector,
+				 &sun4i_rgb_con_funcs,
+				 DRM_MODE_CONNECTOR_Unknown);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't initialise the rgb connector\n");
+		goto err_cleanup_connector;
+	}
+
+	drm_mode_connector_attach_encoder(&rgb->connector, &rgb->encoder);
+
+	drm_panel_attach(rgb->panel, &rgb->connector);
+
+	return 0;
+
+err_cleanup_connector:
+	drm_encoder_cleanup(&rgb->encoder);
+err_out:
+	return ret;
+}
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.h b/drivers/gpu/drm/sun4i/sun4i_rgb.h
new file mode 100644
index 000000000000..7c4da4c8acdd
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2015 Free Electrons
+ * Copyright (C) 2015 NextThing Co
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#ifndef _SUN4I_RGB_H_
+#define _SUN4I_RGB_H_
+
+int sun4i_rgb_init(struct drm_device *drm);
+
+#endif /* _SUN4I_RGB_H_ */
-- 
2.6.2


  parent reply	other threads:[~2015-10-30 14:22 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
2015-10-30 14:20 ` [PATCH 01/19] clk: sunxi: Add display clock Maxime Ripard
2015-10-30 21:29   ` Stephen Boyd
2015-11-06 23:39     ` Maxime Ripard
2015-11-12 20:31       ` Stephen Boyd
2015-11-19 15:42         ` Maxime Ripard
2015-10-31 10:28   ` Chen-Yu Tsai
2015-11-06 19:42     ` Maxime Ripard
2015-10-30 14:20 ` [PATCH 02/19] clk: sunxi: Add PLL3 clock Maxime Ripard
2015-10-30 21:32   ` Stephen Boyd
2015-10-30 14:20 ` [PATCH 03/19] clk: sunxi: Add TCON channel0 clock Maxime Ripard
2015-10-31 10:19   ` Chen-Yu Tsai
2015-11-06 22:11     ` Maxime Ripard
2015-10-30 14:20 ` [PATCH 04/19] clk: sunxi: Add TCON channel1 clock Maxime Ripard
2015-10-30 21:37   ` Stephen Boyd
2015-11-07  0:11     ` Maxime Ripard
2015-10-31  9:53   ` Chen-Yu Tsai
2015-11-07  0:01     ` Maxime Ripard
2015-11-09  3:36       ` Chen-Yu Tsai
2015-11-19 15:35         ` Maxime Ripard
2015-10-30 14:20 ` [PATCH 05/19] clk: sunxi: add DRAM gates Maxime Ripard
2015-11-09  4:18   ` Chen-Yu Tsai
2015-11-13  8:08     ` Chen-Yu Tsai
2015-11-19 15:43       ` Maxime Ripard
2015-10-30 14:20 ` [PATCH 06/19] clk: sunxi: Add Allwinner R8 AHB gates support Maxime Ripard
2015-10-30 16:01   ` Chen-Yu Tsai
2015-10-30 16:33     ` Hans de Goede
2015-10-30 14:20 ` [PATCH 07/19] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS Maxime Ripard
2015-10-30 17:32   ` Thierry Reding
2015-11-07  0:44     ` Maxime Ripard
2015-10-30 14:20 ` [PATCH 08/19] drm: Add Allwinner A10 Display Engine support Maxime Ripard
2015-10-30 14:44   ` Daniel Vetter
2015-11-11 22:14     ` Maxime Ripard
2015-11-16 15:04       ` Daniel Vetter
2015-10-30 14:20 ` [PATCH 09/19] drm: sun4i: Add DT bindings documentation Maxime Ripard
2015-10-30 16:40   ` Rob Herring
2015-10-30 17:37     ` Thierry Reding
2015-11-01 14:28       ` Rob Herring
2015-11-06 22:32     ` Maxime Ripard
2015-10-30 14:20 ` Maxime Ripard [this message]
2015-10-30 14:20 ` [PATCH 11/19] drm: sun4i: Add composite output Maxime Ripard
2015-11-02  2:53   ` [linux-sunxi] " Jonathan Liu
2015-11-07  0:35     ` Maxime Ripard
2015-10-30 14:20 ` [PATCH 12/19] drm: sun4i: tv: Add PAL output standard Maxime Ripard
2015-10-30 14:20 ` [PATCH 13/19] drm: sun4i: tv: Add NTSC " Maxime Ripard
2015-10-30 14:21 ` [PATCH 14/19] ARM: sun5i: dt: Add pll3 and pll7 clocks Maxime Ripard
2015-11-09  4:24   ` Chen-Yu Tsai
2015-10-30 14:21 ` [PATCH 15/19] ARM: sun5i: dt: Add display and TCON clocks Maxime Ripard
2015-10-30 14:21 ` [PATCH 16/19] ARM: sun5i: dt: Add DRAM gates Maxime Ripard
2015-10-30 14:21 ` [PATCH 17/19] ARM: sun5i: dt: Add display blocks to the DTSI Maxime Ripard
2015-10-30 14:21 ` [PATCH 18/19] ARM: sun5i: r8: Add AHB gates " Maxime Ripard
2015-10-30 14:21 ` [PATCH 19/19] ARM: sun5i: chip: Enable the TV Encoder Maxime Ripard
2015-10-30 15:20   ` Chen-Yu Tsai
2015-11-06 19:37     ` Maxime Ripard
2015-10-30 14:52 ` [PATCH 00/19] drm: Add Allwinner A10 display engine support Daniel Vetter
2015-11-12  5:12   ` Maxime Ripard
2015-11-09  3:43 ` Chen-Yu Tsai

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=1446214865-3972-11-git-send-email-maxime.ripard@free-electrons.com \
    --to=maxime.ripard@free-electrons.com \
    --cc=airlied@linux.ie \
    --cc=alex@nextthing.co \
    --cc=boris.brezillon@free-electrons.com \
    --cc=daniel@ffwll.ch \
    --cc=devicetree@vger.kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=hdegoede@redhat.com \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sunxi@googlegroups.com \
    --cc=mturquette@baylibre.com \
    --cc=robdclark@gmail.com \
    --cc=sboyd@codeaurora.org \
    --cc=thierry.reding@gmail.com \
    --cc=thomas.petazzoni@free-electrons.com \
    --cc=wens@csie.org \
    --cc=wynter@nextthing.co \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).