Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1686553 > unrolled thread

[PATCH 00/18] drm/sun4i: Allwinner MIPI-DSI support

Started byMaxime Ripard <maxime.ripard@free-electrons.com>
First post2017-07-13 16:20 +0200
Last post2017-07-14 05:20 +0200
Articles 20 on this page of 32 — 5 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 00/18] drm/sun4i: Allwinner MIPI-DSI support Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
    [PATCH 06/18] drm/sun4i: tcon: Don't rely on encoders to enable the TCON Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
      Re: [PATCH 06/18] drm/sun4i: tcon: Don't rely on encoders to enable  the TCON Chen-Yu Tsai <wens@csie.org> - 2017-07-14 05:50 +0200
    [PATCH 04/18] drm/sun4i: Remove useless atomic_check Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
      Re: [PATCH 04/18] drm/sun4i: Remove useless atomic_check Chen-Yu Tsai <wens@csie.org> - 2017-07-14 05:20 +0200
        Re: [PATCH 04/18] drm/sun4i: Remove useless atomic_check Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-17 10:50 +0200
    [PATCH 15/18] drm/panel: Add Huarui LHR050H41 panel driver Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
      Re: [PATCH 15/18] drm/panel: Add Huarui LHR050H41 panel driver Andrzej Hajda <a.hajda@samsung.com> - 2017-07-14 11:30 +0200
    [PATCH 08/18] drm/sun4i: tcon: Add TRI finish interrupt for vblank Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
      Re: [PATCH 08/18] drm/sun4i: tcon: Add TRI finish interrupt for vblank Chen-Yu Tsai <wens@csie.org> - 2017-07-14 06:00 +0200
    [PATCH 07/18] drm/sun4i: tcon: Don't rely on encoders to set the TCON mode Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
      Re: [PATCH 07/18] drm/sun4i: tcon: Don't rely on encoders to set the  TCON mode Chen-Yu Tsai <wens@csie.org> - 2017-07-14 06:00 +0200
    [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
      Re: [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup kbuild test robot <lkp@intel.com> - 2017-07-14 12:00 +0200
      Re: [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup Chen-Yu Tsai <wens@csie.org> - 2017-07-18 05:50 +0200
    [PATCH 16/18] arm: dts: sun8i: a33: Add the DSI-related nodes Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
    [PATCH 09/18] drm/sun4i: tcon: Adjust dotclock dividers range Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
      Re: [PATCH 09/18] drm/sun4i: tcon: Adjust dotclock dividers range Chen-Yu Tsai <wens@csie.org> - 2017-07-14 06:20 +0200
    [PATCH 17/18] arm: dts: sun8i: Add BananaPI M2-Magic DTS Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
      Re: [PATCH 17/18] arm: dts: sun8i: Add BananaPI M2-Magic DTS Chen-Yu Tsai <wens@csie.org> - 2017-07-14 06:50 +0200
        Re: [PATCH 17/18] arm: dts: sun8i: Add BananaPI M2-Magic DTS Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-17 11:10 +0200
    [PATCH 13/18] dt-bindings: vendor: Add Huarui Lighting Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
      Re: [PATCH 13/18] dt-bindings: vendor: Add Huarui Lighting Chen-Yu Tsai <wens@csie.org> - 2017-07-14 10:00 +0200
    [PATCH 01/18] regmap: mmio: Add function to attach a clock Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
      Re: [PATCH 01/18] regmap: mmio: Add function to attach a clock Mark Brown <broonie@kernel.org> - 2017-07-13 18:10 +0200
        Re: [PATCH 01/18] regmap: mmio: Add function to attach a clock Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-17 11:10 +0200
    [PATCH 02/18] drm/sun4i: Add if statement instead of depends on Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
      Re: [PATCH 02/18] drm/sun4i: Add if statement instead of depends on Chen-Yu Tsai <wens@csie.org> - 2017-07-14 05:10 +0200
        Re: [PATCH 02/18] drm/sun4i: Add if statement instead of depends on Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-17 10:50 +0200
    [PATCH 18/18] [DO NOT MERGE] arm: dts: sun8i: bpi-m2m: Add DSI display Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
    [PATCH 03/18] drm/sun4i: Realign Makefile padding and reorder it Maxime Ripard <maxime.ripard@free-electrons.com> - 2017-07-13 16:20 +0200
      Re: [PATCH 03/18] drm/sun4i: Realign Makefile padding and reorder it Chen-Yu Tsai <wens@csie.org> - 2017-07-14 05:20 +0200

Page 1 of 2  [1] 2  Next page →


#1686553 — [PATCH 00/18] drm/sun4i: Allwinner MIPI-DSI support

FromMaxime Ripard <maxime.ripard@free-electrons.com>
Date2017-07-13 16:20 +0200
Subject[PATCH 00/18] drm/sun4i: Allwinner MIPI-DSI support
Message-ID<u2N8d-6Ff-3@gated-at.bofh.it>
Hi,

Here is an preliminary version of the MIPI-DSI support for the Allwinner
SoCs.

This controller can be found on a number of recent SoCs, such as the
A31, A33 or the A64.

Given the sparse documentation, there's a number of obscure areas, but
the current implementation has been tested with a 4-lanes DSI panel on
an A33.

In order to support properly the DSI controller, we also had to rework a
bit the TCON code to ease the encoders support. The support is a bit rough
around the edges at the time, and some artifacts are still shown on the
screen for some reasons. Wider testing with different display will
hopefully nail those down.

It depends for the moment on the clock protection serie sent by Jerome
Brunet:
http://lists.infradead.org/pipermail/linux-amlogic/2017-June/004059.html

Let me know what you think,
Maxime

Maxime Ripard (18):
  regmap: mmio: Add function to attach a clock
  drm/sun4i: Add if statement instead of depends on
  drm/sun4i: Realign Makefile padding and reorder it
  drm/sun4i: Remove useless atomic_check
  drm/sun4i: tcon: remove unused function
  drm/sun4i: tcon: Don't rely on encoders to enable the TCON
  drm/sun4i: tcon: Don't rely on encoders to set the TCON mode
  drm/sun4i: tcon: Add TRI finish interrupt for vblank
  drm/sun4i: tcon: Adjust dotclock dividers range
  drm/sun4i: tcon: Move out the tcon0 common setup
  dt-bindings: display: Add Allwinner MIPI-DSI bindings
  drm/sun4i: Add Allwinner A31 MIPI-DSI controller support
  dt-bindings: vendor: Add Huarui Lighting
  dt-bindings: panel: Add Huarui LHR050H41 panel documentation
  drm/panel: Add Huarui LHR050H41 panel driver
  arm: dts: sun8i: a33: Add the DSI-related nodes
  arm: dts: sun8i: Add BananaPI M2-Magic DTS
  [DO NOT MERGE] arm: dts: sun8i: bpi-m2m: Add DSI display

 Documentation/devicetree/bindings/display/panel/huarui,lhr050h41.txt |   19 +-
 Documentation/devicetree/bindings/display/sunxi/sun6i-dsi.txt        |   85 ++++++-
 Documentation/devicetree/bindings/vendor-prefixes.txt                |    1 +-
 arch/arm/boot/dts/Makefile                                           |    1 +-
 arch/arm/boot/dts/sun8i-a33.dtsi                                     |   50 ++-
 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts                         |  360 ++++++++++++++++++++++++-
 drivers/base/regmap/regmap-mmio.c                                    |   24 ++-
 drivers/gpu/drm/panel/Kconfig                                        |    9 +-
 drivers/gpu/drm/panel/Makefile                                       |    1 +-
 drivers/gpu/drm/panel/panel-huarui-lhr050h41.c                       |  444 +++++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/Kconfig                                        |   17 +-
 drivers/gpu/drm/sun4i/Makefile                                       |   31 +-
 drivers/gpu/drm/sun4i/sun4i_crtc.c                                   |   33 +-
 drivers/gpu/drm/sun4i/sun4i_dotclock.c                               |   20 +-
 drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c                           |    1 +-
 drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c                               |   15 +-
 drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c                          |    1 +-
 drivers/gpu/drm/sun4i/sun4i_layer.c                                  |    7 +-
 drivers/gpu/drm/sun4i/sun4i_rgb.c                                    |   37 +--
 drivers/gpu/drm/sun4i/sun4i_tcon.c                                   |  275 ++++++++++++------
 drivers/gpu/drm/sun4i/sun4i_tcon.h                                   |   68 ++--
 drivers/gpu/drm/sun4i/sun4i_tv.c                                     |   20 +-
 drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c                              |  297 +++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c                               | 1098 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h                               |   67 ++++-
 include/linux/regmap.h                                               |    4 +-
 26 files changed, 2783 insertions(+), 202 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/panel/huarui,lhr050h41.txt
 create mode 100644 Documentation/devicetree/bindings/display/sunxi/sun6i-dsi.txt
 create mode 100644 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
 create mode 100644 drivers/gpu/drm/panel/panel-huarui-lhr050h41.c
 create mode 100644 drivers/gpu/drm/sun4i/sun6i_mipi_dphy.c
 create mode 100644 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
 create mode 100644 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h

base-commit: d3d855e7c4ffaaa6c2cb221849da65e979d8aa80
-- 
git-series 0.9.1

[toc] | [next] | [standalone]


#1686554 — [PATCH 06/18] drm/sun4i: tcon: Don't rely on encoders to enable the TCON

FromMaxime Ripard <maxime.ripard@free-electrons.com>
Date2017-07-13 16:20 +0200
Subject[PATCH 06/18] drm/sun4i: tcon: Don't rely on encoders to enable the TCON
Message-ID<u2N8e-6Ff-9@gated-at.bofh.it>
In reply to#1686553
So far, we've required all the TCON-connected encoders to call the TCON
enable and disable functions.

This was made this way because in the RGB/LVDS case, the TCON is the CRTC
and the encoder. However, in all the other cases (HDMI, TV, DSI, etc.), we
have another encoder down the road that needs to be programmed.

We also needed to know which channel the encoder is connected to, which is
encoder-specific.

The CRTC's enable and disable callbacks can work just fine for our use
case, and we can get the channel to use just by looking at the type of
encoder, since that is fixed. Implement those callbacks, which will
remove some of the encoder boilerplate.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_crtc.c     | 22 ++++++-
 drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c |  8 +--
 drivers/gpu/drm/sun4i/sun4i_rgb.c      | 14 +---
 drivers/gpu/drm/sun4i/sun4i_tcon.c     | 91 +++++++++++++--------------
 drivers/gpu/drm/sun4i/sun4i_tcon.h     | 10 +---
 drivers/gpu/drm/sun4i/sun4i_tv.c       |  6 +--
 6 files changed, 70 insertions(+), 81 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index f8c70439d1e2..30c7568dde5c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -30,6 +30,22 @@
 #include "sunxi_engine.h"
 #include "sun4i_tcon.h"
 
+/*
+ * While this isn't really working in the DRM theory, in practice we
+ * can only ever have one encoder per TCON since we have a mux in our
+ * TCON.
+ */
+static struct drm_encoder *sun4i_crtc_get_encoder(struct drm_crtc *crtc)
+{
+	struct drm_encoder *encoder;
+
+	drm_for_each_encoder(encoder, crtc->dev)
+		if (encoder->crtc == crtc)
+			return encoder;
+
+	return NULL;
+}
+
 static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
 				    struct drm_crtc_state *old_state)
 {
@@ -71,11 +87,12 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
 
 static void sun4i_crtc_disable(struct drm_crtc *crtc)
 {
+	struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
 
 	DRM_DEBUG_DRIVER("Disabling the CRTC\n");
 
-	sun4i_tcon_disable(scrtc->tcon);
+	sun4i_tcon_set_status(scrtc->tcon, encoder, false);
 
 	if (crtc->state->event && !crtc->state->active) {
 		spin_lock_irq(&crtc->dev->event_lock);
@@ -88,11 +105,12 @@ static void sun4i_crtc_disable(struct drm_crtc *crtc)
 
 static void sun4i_crtc_enable(struct drm_crtc *crtc)
 {
+	struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
 
 	DRM_DEBUG_DRIVER("Enabling the CRTC\n");
 
-	sun4i_tcon_enable(scrtc->tcon);
+	sun4i_tcon_set_status(scrtc->tcon, encoder, true);
 }
 
 static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index d3398f6250ef..06af2f6d0b31 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -85,8 +85,6 @@ static int sun4i_hdmi_atomic_check(struct drm_encoder *encoder,
 static void sun4i_hdmi_disable(struct drm_encoder *encoder)
 {
 	struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
-	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
-	struct sun4i_tcon *tcon = crtc->tcon;
 	u32 val;
 
 	DRM_DEBUG_DRIVER("Disabling the HDMI Output\n");
@@ -94,22 +92,16 @@ static void sun4i_hdmi_disable(struct drm_encoder *encoder)
 	val = readl(hdmi->base + SUN4I_HDMI_VID_CTRL_REG);
 	val &= ~SUN4I_HDMI_VID_CTRL_ENABLE;
 	writel(val, hdmi->base + SUN4I_HDMI_VID_CTRL_REG);
-
-	sun4i_tcon_channel_disable(tcon, 1);
 }
 
 static void sun4i_hdmi_enable(struct drm_encoder *encoder)
 {
 	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
 	struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
-	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
-	struct sun4i_tcon *tcon = crtc->tcon;
 	u32 val = 0;
 
 	DRM_DEBUG_DRIVER("Enabling the HDMI Output\n");
 
-	sun4i_tcon_channel_enable(tcon, 1);
-
 	sun4i_hdmi_setup_avi_infoframes(hdmi, mode);
 	val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
 	val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index 76362c09c608..ecce1f5b50ab 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -135,13 +135,10 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
 
 	DRM_DEBUG_DRIVER("Enabling RGB output\n");
 
-	if (!IS_ERR(tcon->panel))
+	if (!IS_ERR(tcon->panel)) {
 		drm_panel_prepare(tcon->panel);
-
-	sun4i_tcon_channel_enable(tcon, 0);
-
-	if (!IS_ERR(tcon->panel))
 		drm_panel_enable(tcon->panel);
+	}
 }
 
 static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
@@ -151,13 +148,10 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
 
 	DRM_DEBUG_DRIVER("Disabling RGB output\n");
 
-	if (!IS_ERR(tcon->panel))
+	if (!IS_ERR(tcon->panel)) {
 		drm_panel_disable(tcon->panel);
-
-	sun4i_tcon_channel_disable(tcon, 0);
-
-	if (!IS_ERR(tcon->panel))
 		drm_panel_unprepare(tcon->panel);
+	}
 }
 
 static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index d9791292553e..dc70bc2a42a5 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -14,6 +14,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder.h>
 #include <drm/drm_modes.h>
 #include <drm/drm_of.h>
 
@@ -32,66 +33,62 @@
 #include "sun4i_tcon.h"
 #include "sunxi_engine.h"
 
-void sun4i_tcon_disable(struct sun4i_tcon *tcon)
+static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
+					  bool enabled)
 {
-	DRM_DEBUG_DRIVER("Disabling TCON\n");
+	struct clk *clk;
 
-	/* Disable the TCON */
-	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
-			   SUN4I_TCON_GCTL_TCON_ENABLE, 0);
-}
-EXPORT_SYMBOL(sun4i_tcon_disable);
-
-void sun4i_tcon_enable(struct sun4i_tcon *tcon)
-{
-	DRM_DEBUG_DRIVER("Enabling TCON\n");
-
-	/* Enable the TCON */
-	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
-			   SUN4I_TCON_GCTL_TCON_ENABLE,
-			   SUN4I_TCON_GCTL_TCON_ENABLE);
-}
-EXPORT_SYMBOL(sun4i_tcon_enable);
-
-void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel)
-{
-	DRM_DEBUG_DRIVER("Disabling TCON channel %d\n", channel);
-
-	/* Disable the TCON's channel */
-	if (channel == 0) {
+	switch (channel) {
+	case 0:
 		regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
-				   SUN4I_TCON0_CTL_TCON_ENABLE, 0);
-		clk_disable_unprepare(tcon->dclk);
+				   SUN4I_TCON0_CTL_TCON_ENABLE,
+				   enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
+		clk = tcon->dclk;
+		break;
+	case 1:
+		WARN_ON(!tcon->quirks->has_channel_1);
+		regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
+				   SUN4I_TCON1_CTL_TCON_ENABLE,
+				   enabled ? SUN4I_TCON1_CTL_TCON_ENABLE : 0);
+		clk = tcon->sclk1;
+		break;
+	default:
+		DRM_DEBUG_DRIVER("Unknown channel... doing nothing\n");
 		return;
 	}
 
-	WARN_ON(!tcon->quirks->has_channel_1);
-	regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
-			   SUN4I_TCON1_CTL_TCON_ENABLE, 0);
-	clk_disable_unprepare(tcon->sclk1);
+	if (enabled)
+		clk_prepare_enable(clk);
+	else
+		clk_disable_unprepare(clk);
 }
-EXPORT_SYMBOL(sun4i_tcon_channel_disable);
 
-void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel)
+void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
+			   struct drm_encoder *encoder,
+			   bool enabled)
 {
-	DRM_DEBUG_DRIVER("Enabling TCON channel %d\n", channel);
-
-	/* Enable the TCON's channel */
-	if (channel == 0) {
-		regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
-				   SUN4I_TCON0_CTL_TCON_ENABLE,
-				   SUN4I_TCON0_CTL_TCON_ENABLE);
-		clk_prepare_enable(tcon->dclk);
+	int channel;
+
+	switch (encoder->encoder_type) {
+	case DRM_MODE_ENCODER_NONE:
+		channel = 0;
+		break;
+	case DRM_MODE_ENCODER_TMDS:
+	case DRM_MODE_ENCODER_TVDAC:
+		channel = 1;
+		break;
+	default:
+		DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
 		return;
 	}
 
-	WARN_ON(!tcon->quirks->has_channel_1);
-	regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
-			   SUN4I_TCON1_CTL_TCON_ENABLE,
-			   SUN4I_TCON1_CTL_TCON_ENABLE);
-	clk_prepare_enable(tcon->sclk1);
+	sun4i_tcon_channel_set_status(tcon, channel, enabled);
+
+	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
+			   SUN4I_TCON_GCTL_TCON_ENABLE,
+			   enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0);
 }
-EXPORT_SYMBOL(sun4i_tcon_channel_enable);
+EXPORT_SYMBOL(sun4i_tcon_set_status);
 
 void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
 {
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index 552c88ec16be..824732c90a2a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -183,15 +183,9 @@ struct sun4i_tcon {
 struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);
 struct drm_panel *sun4i_tcon_find_panel(struct device_node *node);
 
-/* Global Control */
-void sun4i_tcon_disable(struct sun4i_tcon *tcon);
-void sun4i_tcon_enable(struct sun4i_tcon *tcon);
-
-/* Channel Control */
-void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel);
-void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel);
-
 void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable);
+void sun4i_tcon_set_status(struct sun4i_tcon *crtc, struct drm_encoder *encoder,
+			   bool enable);
 
 /* Mode Related Controls */
 void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 73bfe7b1cd78..78d6cf77fdd3 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -345,12 +345,9 @@ static void sun4i_tv_disable(struct drm_encoder *encoder)
 {
 	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
 	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
-	struct sun4i_tcon *tcon = crtc->tcon;
 
 	DRM_DEBUG_DRIVER("Disabling the TV Output\n");
 
-	sun4i_tcon_channel_disable(tcon, 1);
-
 	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
 			   SUN4I_TVE_EN_ENABLE,
 			   0);
@@ -362,7 +359,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder)
 {
 	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
 	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
-	struct sun4i_tcon *tcon = crtc->tcon;
 
 	DRM_DEBUG_DRIVER("Enabling the TV Output\n");
 
@@ -371,8 +367,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder)
 	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
 			   SUN4I_TVE_EN_ENABLE,
 			   SUN4I_TVE_EN_ENABLE);
-
-	sun4i_tcon_channel_enable(tcon, 1);
 }
 
 static void sun4i_tv_mode_set(struct drm_encoder *encoder,
-- 
git-series 0.9.1

[toc] | [prev] | [next] | [standalone]


#1687050 — Re: [PATCH 06/18] drm/sun4i: tcon: Don't rely on encoders to enable the TCON

FromChen-Yu Tsai <wens@csie.org>
Date2017-07-14 05:50 +0200
SubjectRe: [PATCH 06/18] drm/sun4i: tcon: Don't rely on encoders to enable the TCON
Message-ID<u2ZM5-66v-3@gated-at.bofh.it>
In reply to#1686554
On Thu, Jul 13, 2017 at 10:13 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> So far, we've required all the TCON-connected encoders to call the TCON
> enable and disable functions.
>
> This was made this way because in the RGB/LVDS case, the TCON is the CRTC
> and the encoder. However, in all the other cases (HDMI, TV, DSI, etc.), we
> have another encoder down the road that needs to be programmed.
>
> We also needed to know which channel the encoder is connected to, which is
> encoder-specific.
>
> The CRTC's enable and disable callbacks can work just fine for our use
> case, and we can get the channel to use just by looking at the type of
> encoder, since that is fixed. Implement those callbacks, which will
> remove some of the encoder boilerplate.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Overall this looks good. A few minor comments below.

> ---
>  drivers/gpu/drm/sun4i/sun4i_crtc.c     | 22 ++++++-
>  drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c |  8 +--
>  drivers/gpu/drm/sun4i/sun4i_rgb.c      | 14 +---
>  drivers/gpu/drm/sun4i/sun4i_tcon.c     | 91 +++++++++++++--------------
>  drivers/gpu/drm/sun4i/sun4i_tcon.h     | 10 +---
>  drivers/gpu/drm/sun4i/sun4i_tv.c       |  6 +--
>  6 files changed, 70 insertions(+), 81 deletions(-)
>

[...]

>  static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index d9791292553e..dc70bc2a42a5 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -14,6 +14,7 @@
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_encoder.h>
>  #include <drm/drm_modes.h>
>  #include <drm/drm_of.h>
>
> @@ -32,66 +33,62 @@
>  #include "sun4i_tcon.h"
>  #include "sunxi_engine.h"
>
> -void sun4i_tcon_disable(struct sun4i_tcon *tcon)
> +static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
> +                                         bool enabled)
>  {
> -       DRM_DEBUG_DRIVER("Disabling TCON\n");
> +       struct clk *clk;
>
> -       /* Disable the TCON */
> -       regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
> -                          SUN4I_TCON_GCTL_TCON_ENABLE, 0);
> -}
> -EXPORT_SYMBOL(sun4i_tcon_disable);
> -
> -void sun4i_tcon_enable(struct sun4i_tcon *tcon)
> -{
> -       DRM_DEBUG_DRIVER("Enabling TCON\n");
> -
> -       /* Enable the TCON */
> -       regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
> -                          SUN4I_TCON_GCTL_TCON_ENABLE,
> -                          SUN4I_TCON_GCTL_TCON_ENABLE);
> -}
> -EXPORT_SYMBOL(sun4i_tcon_enable);
> -
> -void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel)
> -{
> -       DRM_DEBUG_DRIVER("Disabling TCON channel %d\n", channel);
> -
> -       /* Disable the TCON's channel */
> -       if (channel == 0) {
> +       switch (channel) {
> +       case 0:
>                 regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
> -                                  SUN4I_TCON0_CTL_TCON_ENABLE, 0);
> -               clk_disable_unprepare(tcon->dclk);
> +                                  SUN4I_TCON0_CTL_TCON_ENABLE,
> +                                  enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
> +               clk = tcon->dclk;
> +               break;
> +       case 1:
> +               WARN_ON(!tcon->quirks->has_channel_1);
> +               regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
> +                                  SUN4I_TCON1_CTL_TCON_ENABLE,
> +                                  enabled ? SUN4I_TCON1_CTL_TCON_ENABLE : 0);
> +               clk = tcon->sclk1;
> +               break;
> +       default:
> +               DRM_DEBUG_DRIVER("Unknown channel... doing nothing\n");
>                 return;
>         }
>
> -       WARN_ON(!tcon->quirks->has_channel_1);
> -       regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
> -                          SUN4I_TCON1_CTL_TCON_ENABLE, 0);
> -       clk_disable_unprepare(tcon->sclk1);
> +       if (enabled)
> +               clk_prepare_enable(clk);

I wonder if it's better to enable the clk before the TCON?

> +       else
> +               clk_disable_unprepare(clk);
>  }
> -EXPORT_SYMBOL(sun4i_tcon_channel_disable);
>
> -void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel)
> +void sun4i_tcon_set_status(struct sun4i_tcon *tcon,
> +                          struct drm_encoder *encoder,
> +                          bool enabled)
>  {
> -       DRM_DEBUG_DRIVER("Enabling TCON channel %d\n", channel);
> -
> -       /* Enable the TCON's channel */
> -       if (channel == 0) {
> -               regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
> -                                  SUN4I_TCON0_CTL_TCON_ENABLE,
> -                                  SUN4I_TCON0_CTL_TCON_ENABLE);
> -               clk_prepare_enable(tcon->dclk);
> +       int channel;
> +
> +       switch (encoder->encoder_type) {
> +       case DRM_MODE_ENCODER_NONE:
> +               channel = 0;
> +               break;
> +       case DRM_MODE_ENCODER_TMDS:
> +       case DRM_MODE_ENCODER_TVDAC:
> +               channel = 1;
> +               break;
> +       default:
> +               DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");

We could simply add all the possible types, and print a big warning
if someone does something unexpected. IMHO this is better than having
the user enable some hidden debug flag to figure why the display isn't
working properly.

>                 return;
>         }
>
> -       WARN_ON(!tcon->quirks->has_channel_1);
> -       regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
> -                          SUN4I_TCON1_CTL_TCON_ENABLE,
> -                          SUN4I_TCON1_CTL_TCON_ENABLE);
> -       clk_prepare_enable(tcon->sclk1);
> +       sun4i_tcon_channel_set_status(tcon, channel, enabled);
> +
> +       regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
> +                          SUN4I_TCON_GCTL_TCON_ENABLE,
> +                          enabled ? SUN4I_TCON_GCTL_TCON_ENABLE : 0);

The global enable bit should be set first.

Also the manual says "When it’s disabled, the module will be reset to
idle state."
so you might get away with just disabling the global enable bit and returning
directly after disabling the clock?

>  }
> -EXPORT_SYMBOL(sun4i_tcon_channel_enable);
> +EXPORT_SYMBOL(sun4i_tcon_set_status);

The TCON and CRTC code are part of the same module.
There is no need to export this function.

ChenYu

>
>  void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
>  {
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
> index 552c88ec16be..824732c90a2a 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
> @@ -183,15 +183,9 @@ struct sun4i_tcon {
>  struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);
>  struct drm_panel *sun4i_tcon_find_panel(struct device_node *node);
>
> -/* Global Control */
> -void sun4i_tcon_disable(struct sun4i_tcon *tcon);
> -void sun4i_tcon_enable(struct sun4i_tcon *tcon);
> -
> -/* Channel Control */
> -void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel);
> -void sun4i_tcon_channel_enable(struct sun4i_tcon *tcon, int channel);
> -
>  void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable);
> +void sun4i_tcon_set_status(struct sun4i_tcon *crtc, struct drm_encoder *encoder,
> +                          bool enable);
>
>  /* Mode Related Controls */
>  void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
> index 73bfe7b1cd78..78d6cf77fdd3 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tv.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
> @@ -345,12 +345,9 @@ static void sun4i_tv_disable(struct drm_encoder *encoder)
>  {
>         struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
>         struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
> -       struct sun4i_tcon *tcon = crtc->tcon;
>
>         DRM_DEBUG_DRIVER("Disabling the TV Output\n");
>
> -       sun4i_tcon_channel_disable(tcon, 1);
> -
>         regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
>                            SUN4I_TVE_EN_ENABLE,
>                            0);
> @@ -362,7 +359,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder)
>  {
>         struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
>         struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
> -       struct sun4i_tcon *tcon = crtc->tcon;
>
>         DRM_DEBUG_DRIVER("Enabling the TV Output\n");
>
> @@ -371,8 +367,6 @@ static void sun4i_tv_enable(struct drm_encoder *encoder)
>         regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
>                            SUN4I_TVE_EN_ENABLE,
>                            SUN4I_TVE_EN_ENABLE);
> -
> -       sun4i_tcon_channel_enable(tcon, 1);
>  }
>
>  static void sun4i_tv_mode_set(struct drm_encoder *encoder,
> --
> git-series 0.9.1

[toc] | [prev] | [next] | [standalone]


#1686555 — [PATCH 04/18] drm/sun4i: Remove useless atomic_check

FromMaxime Ripard <maxime.ripard@free-electrons.com>
Date2017-07-13 16:20 +0200
Subject[PATCH 04/18] drm/sun4i: Remove useless atomic_check
Message-ID<u2N8e-6Ff-11@gated-at.bofh.it>
In reply to#1686553
The atomic_check callback is optional, and we don't implement anything in
some parts of our drivers. Let's remove it.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_layer.c | 7 -------
 drivers/gpu/drm/sun4i/sun4i_rgb.c   | 8 --------
 drivers/gpu/drm/sun4i/sun4i_tv.c    | 8 --------
 3 files changed, 23 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index ead4f9d4c1ee..62b08cb47ccd 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -25,12 +25,6 @@ struct sun4i_plane_desc {
 	       uint32_t                nformats;
 };
 
-static int sun4i_backend_layer_atomic_check(struct drm_plane *plane,
-					    struct drm_plane_state *state)
-{
-	return 0;
-}
-
 static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
 					       struct drm_plane_state *old_state)
 {
@@ -53,7 +47,6 @@ static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
 }
 
 static struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
-	.atomic_check	= sun4i_backend_layer_atomic_check,
 	.atomic_disable	= sun4i_backend_layer_atomic_disable,
 	.atomic_update	= sun4i_backend_layer_atomic_update,
 };
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index 422b191faa77..76362c09c608 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -128,13 +128,6 @@ static struct drm_connector_funcs sun4i_rgb_con_funcs = {
 	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
 };
 
-static int sun4i_rgb_atomic_check(struct drm_encoder *encoder,
-				  struct drm_crtc_state *crtc_state,
-				  struct drm_connector_state *conn_state)
-{
-	return 0;
-}
-
 static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
 {
 	struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
@@ -182,7 +175,6 @@ static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
 }
 
 static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {
-	.atomic_check	= sun4i_rgb_atomic_check,
 	.mode_set	= sun4i_rgb_encoder_mode_set,
 	.disable	= sun4i_rgb_encoder_disable,
 	.enable		= sun4i_rgb_encoder_enable,
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 338b9e5bb2a3..73bfe7b1cd78 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -341,13 +341,6 @@ static void sun4i_tv_mode_to_drm_mode(const struct tv_mode *tv_mode,
 	mode->vtotal = mode->vsync_end  + tv_mode->vback_porch;
 }
 
-static int sun4i_tv_atomic_check(struct drm_encoder *encoder,
-				 struct drm_crtc_state *crtc_state,
-				 struct drm_connector_state *conn_state)
-{
-	return 0;
-}
-
 static void sun4i_tv_disable(struct drm_encoder *encoder)
 {
 	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
@@ -489,7 +482,6 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder,
 }
 
 static struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = {
-	.atomic_check	= sun4i_tv_atomic_check,
 	.disable	= sun4i_tv_disable,
 	.enable		= sun4i_tv_enable,
 	.mode_set	= sun4i_tv_mode_set,
-- 
git-series 0.9.1

[toc] | [prev] | [next] | [standalone]


#1687043 — Re: [PATCH 04/18] drm/sun4i: Remove useless atomic_check

FromChen-Yu Tsai <wens@csie.org>
Date2017-07-14 05:20 +0200
SubjectRe: [PATCH 04/18] drm/sun4i: Remove useless atomic_check
Message-ID<u2Zj3-5X9-7@gated-at.bofh.it>
In reply to#1686555
On Thu, Jul 13, 2017 at 10:12 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The atomic_check callback is optional, and we don't implement anything in
> some parts of our drivers. Let's remove it.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

[toc] | [prev] | [next] | [standalone]


#1688768 — Re: [PATCH 04/18] drm/sun4i: Remove useless atomic_check

FromMaxime Ripard <maxime.ripard@free-electrons.com>
Date2017-07-17 10:50 +0200
SubjectRe: [PATCH 04/18] drm/sun4i: Remove useless atomic_check
Message-ID<u49T4-2FF-23@gated-at.bofh.it>
In reply to#1687043

[Multipart message — attachments visible in raw view] — view raw

On Fri, Jul 14, 2017 at 11:15:18AM +0800, Chen-Yu Tsai wrote:
> On Thu, Jul 13, 2017 at 10:12 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > The atomic_check callback is optional, and we don't implement anything in
> > some parts of our drivers. Let's remove it.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> 
> Reviewed-by: Chen-Yu Tsai <wens@csie.org>

Applied, thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

[toc] | [prev] | [next] | [standalone]


#1686556 — [PATCH 15/18] drm/panel: Add Huarui LHR050H41 panel driver

FromMaxime Ripard <maxime.ripard@free-electrons.com>
Date2017-07-13 16:20 +0200
Subject[PATCH 15/18] drm/panel: Add Huarui LHR050H41 panel driver
Message-ID<u2N8e-6Ff-15@gated-at.bofh.it>
In reply to#1686553
The LHR050H41 panel is the panel shipped with the BananaPi M2-Magic. Add a
driver for it.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/panel/Kconfig                  |   9 +-
 drivers/gpu/drm/panel/Makefile                 |   1 +-
 drivers/gpu/drm/panel/panel-huarui-lhr050h41.c | 444 ++++++++++++++++++-
 3 files changed, 454 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-huarui-lhr050h41.c

diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index d84a031fae24..eaa6e102775a 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -28,6 +28,15 @@ config DRM_PANEL_SIMPLE
 	  that it can be automatically turned off when the panel goes into a
 	  low power state.
 
+config DRM_PANEL_HUARUI_LHR050H41
+	tristate "Huarui LHR050H41 panel"
+	depends on OF
+	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
+	help
+	  Say Y if you want to enable support for the Huarui Lighting
+	  LHR05041 DSI panel. The panel has a 1280x720 resolution.
+
 config DRM_PANEL_INNOLUX_P079ZCA
 	tristate "Innolux P079ZCA panel"
 	depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 9f6610d08b00..58de7a853898 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
 obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
+obj-$(CONFIG_DRM_PANEL_HUARUI_LHR050H41) += panel-huarui-lhr050h41.o
 obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
 obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
 obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
diff --git a/drivers/gpu/drm/panel/panel-huarui-lhr050h41.c b/drivers/gpu/drm/panel/panel-huarui-lhr050h41.c
new file mode 100644
index 000000000000..eb675eb9ee7d
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-huarui-lhr050h41.c
@@ -0,0 +1,444 @@
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/gpio/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+
+struct lhr050h41 {
+	struct drm_panel	panel;
+	struct mipi_dsi_device	*dsi;
+
+	struct backlight_device *backlight;
+	struct gpio_desc	*power;
+	struct gpio_desc	*reset;
+};
+
+static inline struct lhr050h41 *panel_to_lhr050h41(struct drm_panel *panel)
+{
+	return container_of(panel, struct lhr050h41, panel);
+}
+
+static int lhr050h41_switch_page(struct lhr050h41 *ctx, u8 page)
+{
+	u8 buf[4] = { 0xff, 0x98, 0x81, page };
+
+	return mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
+}
+
+static int lhr050h41_send_cmd_data(struct lhr050h41 *ctx, u8 cmd, u8 data)
+{
+	u8 buf[2] = { cmd, data };
+
+	return mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
+}
+
+static int lhr050h41_send_init_sequence(struct lhr050h41 *ctx)
+{
+	lhr050h41_switch_page(ctx, 3);
+
+	lhr050h41_send_cmd_data(ctx, 0x01, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x02, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x03, 0x73);
+	lhr050h41_send_cmd_data(ctx, 0x04, 0x03);
+	lhr050h41_send_cmd_data(ctx, 0x05, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x06, 0x06);
+	lhr050h41_send_cmd_data(ctx, 0x07, 0x06);
+	lhr050h41_send_cmd_data(ctx, 0x08, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x09, 0x18);
+	lhr050h41_send_cmd_data(ctx, 0x0a, 0x04);
+	lhr050h41_send_cmd_data(ctx, 0x0b, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x0c, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x0d, 0x03);
+	lhr050h41_send_cmd_data(ctx, 0x0e, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x0f, 0x25);
+	lhr050h41_send_cmd_data(ctx, 0x10, 0x25);
+	lhr050h41_send_cmd_data(ctx, 0x11, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x12, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x13, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x14, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x15, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x16, 0x0C);
+	lhr050h41_send_cmd_data(ctx, 0x17, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x18, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x19, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x1a, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x1b, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x1c, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x1d, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x1e, 0xC0);
+	lhr050h41_send_cmd_data(ctx, 0x1f, 0x80);
+	lhr050h41_send_cmd_data(ctx, 0x20, 0x04);
+	lhr050h41_send_cmd_data(ctx, 0x21, 0x01);
+	lhr050h41_send_cmd_data(ctx, 0x22, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x23, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x24, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x25, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x26, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x27, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x28, 0x33);
+	lhr050h41_send_cmd_data(ctx, 0x29, 0x03);
+	lhr050h41_send_cmd_data(ctx, 0x2a, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x2b, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x2c, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x2d, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x2e, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x2f, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x30, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x31, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x32, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x33, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x34, 0x04);
+	lhr050h41_send_cmd_data(ctx, 0x35, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x36, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x37, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x38, 0x3C);
+	lhr050h41_send_cmd_data(ctx, 0x39, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x3a, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x3b, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x3c, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x3d, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x3e, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x3f, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x40, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x41, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x42, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x43, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x44, 0x00);
+
+	lhr050h41_send_cmd_data(ctx, 0x50, 0x01);
+	lhr050h41_send_cmd_data(ctx, 0x51, 0x23);
+	lhr050h41_send_cmd_data(ctx, 0x52, 0x45);
+	lhr050h41_send_cmd_data(ctx, 0x53, 0x67);
+	lhr050h41_send_cmd_data(ctx, 0x54, 0x89);
+	lhr050h41_send_cmd_data(ctx, 0x55, 0xab);
+	lhr050h41_send_cmd_data(ctx, 0x56, 0x01);
+	lhr050h41_send_cmd_data(ctx, 0x57, 0x23);
+	lhr050h41_send_cmd_data(ctx, 0x58, 0x45);
+	lhr050h41_send_cmd_data(ctx, 0x59, 0x67);
+	lhr050h41_send_cmd_data(ctx, 0x5a, 0x89);
+	lhr050h41_send_cmd_data(ctx, 0x5b, 0xab);
+	lhr050h41_send_cmd_data(ctx, 0x5c, 0xcd);
+	lhr050h41_send_cmd_data(ctx, 0x5d, 0xef);
+
+	lhr050h41_send_cmd_data(ctx, 0x5e, 0x11);
+	lhr050h41_send_cmd_data(ctx, 0x5f, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x60, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x61, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x62, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x63, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x64, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x65, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x66, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x67, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x68, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x69, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x6a, 0x0C);
+	lhr050h41_send_cmd_data(ctx, 0x6b, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x6c, 0x0F);
+	lhr050h41_send_cmd_data(ctx, 0x6d, 0x0E);
+	lhr050h41_send_cmd_data(ctx, 0x6e, 0x0D);
+	lhr050h41_send_cmd_data(ctx, 0x6f, 0x06);
+	lhr050h41_send_cmd_data(ctx, 0x70, 0x07);
+	lhr050h41_send_cmd_data(ctx, 0x71, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x72, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x73, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x74, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x75, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x76, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x77, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x78, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x79, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x7a, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x7b, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x7c, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x7d, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x7e, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x7f, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x80, 0x0C);
+	lhr050h41_send_cmd_data(ctx, 0x81, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x82, 0x0F);
+	lhr050h41_send_cmd_data(ctx, 0x83, 0x0E);
+	lhr050h41_send_cmd_data(ctx, 0x84, 0x0D);
+	lhr050h41_send_cmd_data(ctx, 0x85, 0x06);
+	lhr050h41_send_cmd_data(ctx, 0x86, 0x07);
+	lhr050h41_send_cmd_data(ctx, 0x87, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x88, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x89, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x8A, 0x02);
+
+	lhr050h41_switch_page(ctx, 4);
+	lhr050h41_send_cmd_data(ctx, 0x6C, 0x15);
+	lhr050h41_send_cmd_data(ctx, 0x6E, 0x22);
+	lhr050h41_send_cmd_data(ctx, 0x6F, 0x33);
+	lhr050h41_send_cmd_data(ctx, 0x3A, 0xA4);
+	lhr050h41_send_cmd_data(ctx, 0x8D, 0x0D);
+	lhr050h41_send_cmd_data(ctx, 0x87, 0xBA);
+	lhr050h41_send_cmd_data(ctx, 0x26, 0x76);
+	lhr050h41_send_cmd_data(ctx, 0xB2, 0xD1);
+
+	lhr050h41_switch_page(ctx, 1);
+	lhr050h41_send_cmd_data(ctx, 0x22, 0x0A);
+	lhr050h41_send_cmd_data(ctx, 0x53, 0xDC);
+	lhr050h41_send_cmd_data(ctx, 0x55, 0xA7);
+	lhr050h41_send_cmd_data(ctx, 0x50, 0x78);
+	lhr050h41_send_cmd_data(ctx, 0x51, 0x78);
+	lhr050h41_send_cmd_data(ctx, 0x31, 0x02);
+	lhr050h41_send_cmd_data(ctx, 0x60, 0x14);
+	lhr050h41_send_cmd_data(ctx, 0xA0, 0x2A);
+	lhr050h41_send_cmd_data(ctx, 0xA1, 0x39);
+	lhr050h41_send_cmd_data(ctx, 0xA2, 0x46);
+	lhr050h41_send_cmd_data(ctx, 0xA3, 0x0e);
+	lhr050h41_send_cmd_data(ctx, 0xA4, 0x12);
+	lhr050h41_send_cmd_data(ctx, 0xA5, 0x25);
+	lhr050h41_send_cmd_data(ctx, 0xA6, 0x19);
+	lhr050h41_send_cmd_data(ctx, 0xA7, 0x1d);
+	lhr050h41_send_cmd_data(ctx, 0xA8, 0xa6);
+	lhr050h41_send_cmd_data(ctx, 0xA9, 0x1C);
+	lhr050h41_send_cmd_data(ctx, 0xAA, 0x29);
+	lhr050h41_send_cmd_data(ctx, 0xAB, 0x85);
+	lhr050h41_send_cmd_data(ctx, 0xAC, 0x1C);
+	lhr050h41_send_cmd_data(ctx, 0xAD, 0x1B);
+	lhr050h41_send_cmd_data(ctx, 0xAE, 0x51);
+	lhr050h41_send_cmd_data(ctx, 0xAF, 0x22);
+	lhr050h41_send_cmd_data(ctx, 0xB0, 0x2d);
+	lhr050h41_send_cmd_data(ctx, 0xB1, 0x4f);
+	lhr050h41_send_cmd_data(ctx, 0xB2, 0x59);
+	lhr050h41_send_cmd_data(ctx, 0xB3, 0x3F);
+	lhr050h41_send_cmd_data(ctx, 0xC0, 0x2A);
+	lhr050h41_send_cmd_data(ctx, 0xC1, 0x3a);
+	lhr050h41_send_cmd_data(ctx, 0xC2, 0x45);
+	lhr050h41_send_cmd_data(ctx, 0xC3, 0x0e);
+	lhr050h41_send_cmd_data(ctx, 0xC4, 0x11);
+	lhr050h41_send_cmd_data(ctx, 0xC5, 0x24);
+	lhr050h41_send_cmd_data(ctx, 0xC6, 0x1a);
+	lhr050h41_send_cmd_data(ctx, 0xC7, 0x1c);
+	lhr050h41_send_cmd_data(ctx, 0xC8, 0xaa);
+	lhr050h41_send_cmd_data(ctx, 0xC9, 0x1C);
+	lhr050h41_send_cmd_data(ctx, 0xCA, 0x29);
+	lhr050h41_send_cmd_data(ctx, 0xCB, 0x96);
+	lhr050h41_send_cmd_data(ctx, 0xCC, 0x1C);
+	lhr050h41_send_cmd_data(ctx, 0xCD, 0x1B);
+	lhr050h41_send_cmd_data(ctx, 0xCE, 0x51);
+	lhr050h41_send_cmd_data(ctx, 0xCF, 0x22);
+	lhr050h41_send_cmd_data(ctx, 0xD0, 0x2b);
+	lhr050h41_send_cmd_data(ctx, 0xD1, 0x4b);
+	lhr050h41_send_cmd_data(ctx, 0xD2, 0x59);
+	lhr050h41_send_cmd_data(ctx, 0xD3, 0x3F);
+
+	lhr050h41_switch_page(ctx, 0);
+	lhr050h41_send_cmd_data(ctx, 0x35, 0x00);
+	lhr050h41_send_cmd_data(ctx, 0x11, 0x00);
+
+	mdelay(120);
+
+	lhr050h41_send_cmd_data(ctx, 0x29, 0x00);
+
+	mdelay(20);
+
+	return 0;
+}
+
+static int lhr050h41_prepare(struct drm_panel *panel)
+{
+	struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
+
+	/* Power the panel */
+	gpiod_set_value(ctx->power, 1);
+	mdelay(5);
+
+	/* And reset it */
+	gpiod_set_value(ctx->reset, 1);
+	mdelay(20);
+
+	gpiod_set_value(ctx->reset, 0);
+	mdelay(20);
+
+	lhr050h41_send_init_sequence(ctx);
+
+	return 0;
+}
+
+static void lhr050h41_enable_bl(struct lhr050h41 *ctx, bool enable)
+{
+	if (!ctx->backlight)
+		return;
+
+	if (enable) {
+		ctx->backlight->props.state &= ~BL_CORE_FBBLANK;
+		ctx->backlight->props.power = FB_BLANK_UNBLANK;
+	} else {
+		ctx->backlight->props.power = FB_BLANK_POWERDOWN;
+		ctx->backlight->props.state |= BL_CORE_FBBLANK;
+	}
+
+	backlight_update_status(ctx->backlight);
+}
+
+static int lhr050h41_enable(struct drm_panel *panel)
+{
+	struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
+
+	lhr050h41_enable_bl(ctx, true);
+
+	return 0;
+}
+
+static int lhr050h41_disable(struct drm_panel *panel)
+{
+	struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
+
+	lhr050h41_enable_bl(ctx, false);
+
+	return mipi_dsi_dcs_set_display_off(ctx->dsi);
+}
+
+static int lhr050h41_unprepare(struct drm_panel *panel)
+{
+	struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
+
+	mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
+	gpiod_set_value(ctx->power, 0);
+	gpiod_set_value(ctx->reset, 1);
+
+	return 0;
+}
+
+static const struct drm_display_mode default_mode = {
+	.clock		= 62000,
+	.vrefresh	= 60,
+
+	.hdisplay	= 720,
+	.hsync_start	= 720 + 10,
+	.hsync_end	= 720 + 10 + 20,
+	.htotal		= 720 + 10 + 20 + 30,
+
+	.vdisplay	= 1280,
+	.vsync_start	= 1280 + 10,
+	.vsync_end	= 1280 + 10 + 10,
+	.vtotal		= 1280 + 10 + 10 + 20,
+};
+
+static int lhr050h41_get_modes(struct drm_panel *panel)
+{
+	struct drm_connector *connector = panel->connector;
+	struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_duplicate(panel->drm, &default_mode);
+	if (!mode) {
+		dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
+			default_mode.hdisplay, default_mode.vdisplay,
+			default_mode.vrefresh);
+		return -ENOMEM;
+	}
+
+	drm_mode_set_name(mode);
+
+	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+	drm_mode_probed_add(connector, mode);
+
+	panel->connector->display_info.width_mm = 62;
+	panel->connector->display_info.height_mm = 110;
+
+	return 1;
+}
+
+static const struct drm_panel_funcs lhr050h41_funcs = {
+	.prepare	= lhr050h41_prepare,
+	.unprepare	= lhr050h41_unprepare,
+	.enable		= lhr050h41_enable,
+	.disable	= lhr050h41_disable,
+	.get_modes	= lhr050h41_get_modes,
+};
+
+static int lhr050h41_dsi_probe(struct mipi_dsi_device *dsi)
+{
+	struct device_node *np;
+	struct lhr050h41 *ctx;
+	int ret;
+
+	ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+	mipi_dsi_set_drvdata(dsi, ctx);
+	ctx->dsi = dsi;
+
+	drm_panel_init(&ctx->panel);
+	ctx->panel.dev = &dsi->dev;
+	ctx->panel.funcs = &lhr050h41_funcs;
+
+	ctx->power = devm_gpiod_get(&dsi->dev, "power", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->power)) {
+		dev_err(&dsi->dev, "Couldn't get our power GPIO\n");
+		return PTR_ERR(ctx->power);
+	}
+
+	ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->reset)) {
+		dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
+		return PTR_ERR(ctx->reset);
+	}
+
+	np = of_parse_phandle(dsi->dev.of_node, "backlight", 0);
+	if (np) {
+		ctx->backlight = of_find_backlight_by_node(np);
+		of_node_put(np);
+
+		if (!ctx->backlight)
+			return -EPROBE_DEFER;
+	}
+
+	ret = drm_panel_add(&ctx->panel);
+	if (ret < 0)
+		return ret;
+
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->lanes = 4;
+
+	return mipi_dsi_attach(dsi);
+}
+
+static int lhr050h41_dsi_remove(struct mipi_dsi_device *dsi)
+{
+	struct lhr050h41 *ctx = mipi_dsi_get_drvdata(dsi);
+
+	mipi_dsi_detach(dsi);
+	drm_panel_remove(&ctx->panel);
+
+	if (ctx->backlight)
+		put_device(&ctx->backlight->dev);
+
+	return 0;
+}
+
+static const struct of_device_id lhr050h41_of_match[] = {
+	{ .compatible = "huarui,lhr050h41" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, lhr050h41_of_match);
+
+static struct mipi_dsi_driver lhr050h41_dsi_driver = {
+	.probe		= lhr050h41_dsi_probe,
+	.remove		= lhr050h41_dsi_remove,
+	.driver = {
+		.name		= "lhr050h41-dsi",
+		.of_match_table	= lhr050h41_of_match,
+	},
+};
+module_mipi_dsi_driver(lhr050h41_dsi_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Huarui LHR050H41 LCD Driver");
+MODULE_LICENSE("GPL v2");
-- 
git-series 0.9.1

[toc] | [prev] | [next] | [standalone]


#1687188 — Re: [PATCH 15/18] drm/panel: Add Huarui LHR050H41 panel driver

FromAndrzej Hajda <a.hajda@samsung.com>
Date2017-07-14 11:30 +0200
SubjectRe: [PATCH 15/18] drm/panel: Add Huarui LHR050H41 panel driver
Message-ID<u3559-1oP-33@gated-at.bofh.it>
In reply to#1686556
On 13.07.2017 16:13, Maxime Ripard wrote:
> The LHR050H41 panel is the panel shipped with the BananaPi M2-Magic. Add a
> driver for it.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/panel/Kconfig                  |   9 +-
>  drivers/gpu/drm/panel/Makefile                 |   1 +-
>  drivers/gpu/drm/panel/panel-huarui-lhr050h41.c | 444 ++++++++++++++++++-
>  3 files changed, 454 insertions(+)
>  create mode 100644 drivers/gpu/drm/panel/panel-huarui-lhr050h41.c
>
> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index d84a031fae24..eaa6e102775a 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -28,6 +28,15 @@ config DRM_PANEL_SIMPLE
>  	  that it can be automatically turned off when the panel goes into a
>  	  low power state.
>  
> +config DRM_PANEL_HUARUI_LHR050H41
> +	tristate "Huarui LHR050H41 panel"
> +	depends on OF
> +	depends on DRM_MIPI_DSI
> +	depends on BACKLIGHT_CLASS_DEVICE
> +	help
> +	  Say Y if you want to enable support for the Huarui Lighting
> +	  LHR05041 DSI panel. The panel has a 1280x720 resolution.
> +
>  config DRM_PANEL_INNOLUX_P079ZCA
>  	tristate "Innolux P079ZCA panel"
>  	depends on OF
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index 9f6610d08b00..58de7a853898 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -1,5 +1,6 @@
>  obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
>  obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
> +obj-$(CONFIG_DRM_PANEL_HUARUI_LHR050H41) += panel-huarui-lhr050h41.o
>  obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
>  obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
>  obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
> diff --git a/drivers/gpu/drm/panel/panel-huarui-lhr050h41.c b/drivers/gpu/drm/panel/panel-huarui-lhr050h41.c
> new file mode 100644
> index 000000000000..eb675eb9ee7d
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-huarui-lhr050h41.c
> @@ -0,0 +1,444 @@

No copyright/license/description at the beginning of the file.


> +#include <linux/backlight.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/fb.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +
> +#include <linux/gpio/consumer.h>

It can be put in alphabetical order.

> +
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_modes.h>
> +#include <drm/drm_panel.h>
> +
> +#include <video/mipi_display.h>
> +
> +struct lhr050h41 {
> +	struct drm_panel	panel;
> +	struct mipi_dsi_device	*dsi;
> +
> +	struct backlight_device *backlight;
> +	struct gpio_desc	*power;
> +	struct gpio_desc	*reset;
> +};
> +
> +static inline struct lhr050h41 *panel_to_lhr050h41(struct drm_panel *panel)
> +{
> +	return container_of(panel, struct lhr050h41, panel);
> +}
> +
> +static int lhr050h41_switch_page(struct lhr050h41 *ctx, u8 page)
> +{
> +	u8 buf[4] = { 0xff, 0x98, 0x81, page };
> +
> +	return mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
> +}
> +
> +static int lhr050h41_send_cmd_data(struct lhr050h41 *ctx, u8 cmd, u8 data)
> +{
> +	u8 buf[2] = { cmd, data };
> +
> +	return mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
> +}
> +
> +static int lhr050h41_send_init_sequence(struct lhr050h41 *ctx)
> +{
> +	lhr050h41_switch_page(ctx, 3);

No error checking, here and below in most places.

> +
> +	lhr050h41_send_cmd_data(ctx, 0x01, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x02, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x03, 0x73);
> +	lhr050h41_send_cmd_data(ctx, 0x04, 0x03);
> +	lhr050h41_send_cmd_data(ctx, 0x05, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x06, 0x06);
> +	lhr050h41_send_cmd_data(ctx, 0x07, 0x06);
> +	lhr050h41_send_cmd_data(ctx, 0x08, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x09, 0x18);
> +	lhr050h41_send_cmd_data(ctx, 0x0a, 0x04);
> +	lhr050h41_send_cmd_data(ctx, 0x0b, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x0c, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x0d, 0x03);
> +	lhr050h41_send_cmd_data(ctx, 0x0e, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x0f, 0x25);
> +	lhr050h41_send_cmd_data(ctx, 0x10, 0x25);
> +	lhr050h41_send_cmd_data(ctx, 0x11, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x12, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x13, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x14, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x15, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x16, 0x0C);
> +	lhr050h41_send_cmd_data(ctx, 0x17, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x18, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x19, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x1a, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x1b, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x1c, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x1d, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x1e, 0xC0);
> +	lhr050h41_send_cmd_data(ctx, 0x1f, 0x80);
> +	lhr050h41_send_cmd_data(ctx, 0x20, 0x04);
> +	lhr050h41_send_cmd_data(ctx, 0x21, 0x01);
> +	lhr050h41_send_cmd_data(ctx, 0x22, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x23, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x24, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x25, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x26, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x27, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x28, 0x33);
> +	lhr050h41_send_cmd_data(ctx, 0x29, 0x03);
> +	lhr050h41_send_cmd_data(ctx, 0x2a, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x2b, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x2c, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x2d, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x2e, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x2f, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x30, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x31, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x32, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x33, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x34, 0x04);
> +	lhr050h41_send_cmd_data(ctx, 0x35, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x36, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x37, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x38, 0x3C);
> +	lhr050h41_send_cmd_data(ctx, 0x39, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x3a, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x3b, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x3c, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x3d, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x3e, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x3f, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x40, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x41, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x42, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x43, 0x00);
> +	lhr050h41_send_cmd_data(ctx, 0x44, 0x00);
> +
> +	lhr050h41_send_cmd_data(ctx, 0x50, 0x01);
> +	lhr050h41_send_cmd_data(ctx, 0x51, 0x23);
> +	lhr050h41_send_cmd_data(ctx, 0x52, 0x45);
> +	lhr050h41_send_cmd_data(ctx, 0x53, 0x67);
> +	lhr050h41_send_cmd_data(ctx, 0x54, 0x89);
> +	lhr050h41_send_cmd_data(ctx, 0x55, 0xab);
> +	lhr050h41_send_cmd_data(ctx, 0x56, 0x01);
> +	lhr050h41_send_cmd_data(ctx, 0x57, 0x23);
> +	lhr050h41_send_cmd_data(ctx, 0x58, 0x45);
> +	lhr050h41_send_cmd_data(ctx, 0x59, 0x67);
> +	lhr050h41_send_cmd_data(ctx, 0x5a, 0x89);
> +	lhr050h41_send_cmd_data(ctx, 0x5b, 0xab);
> +	lhr050h41_send_cmd_data(ctx, 0x5c, 0xcd);
> +	lhr050h41_send_cmd_data(ctx, 0x5d, 0xef);
> +
> +	lhr050h41_send_cmd_data(ctx, 0x5e, 0x11);
> +	lhr050h41_send_cmd_data(ctx, 0x5f, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x60, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x61, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x62, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x63, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x64, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x65, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x66, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x67, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x68, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x69, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x6a, 0x0C);
> +	lhr050h41_send_cmd_data(ctx, 0x6b, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x6c, 0x0F);
> +	lhr050h41_send_cmd_data(ctx, 0x6d, 0x0E);
> +	lhr050h41_send_cmd_data(ctx, 0x6e, 0x0D);
> +	lhr050h41_send_cmd_data(ctx, 0x6f, 0x06);
> +	lhr050h41_send_cmd_data(ctx, 0x70, 0x07);
> +	lhr050h41_send_cmd_data(ctx, 0x71, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x72, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x73, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x74, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x75, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x76, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x77, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x78, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x79, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x7a, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x7b, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x7c, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x7d, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x7e, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x7f, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x80, 0x0C);
> +	lhr050h41_send_cmd_data(ctx, 0x81, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x82, 0x0F);
> +	lhr050h41_send_cmd_data(ctx, 0x83, 0x0E);
> +	lhr050h41_send_cmd_data(ctx, 0x84, 0x0D);
> +	lhr050h41_send_cmd_data(ctx, 0x85, 0x06);
> +	lhr050h41_send_cmd_data(ctx, 0x86, 0x07);
> +	lhr050h41_send_cmd_data(ctx, 0x87, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x88, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x89, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x8A, 0x02);
> +
> +	lhr050h41_switch_page(ctx, 4);
> +	lhr050h41_send_cmd_data(ctx, 0x6C, 0x15);
> +	lhr050h41_send_cmd_data(ctx, 0x6E, 0x22);
> +	lhr050h41_send_cmd_data(ctx, 0x6F, 0x33);
> +	lhr050h41_send_cmd_data(ctx, 0x3A, 0xA4);
> +	lhr050h41_send_cmd_data(ctx, 0x8D, 0x0D);
> +	lhr050h41_send_cmd_data(ctx, 0x87, 0xBA);
> +	lhr050h41_send_cmd_data(ctx, 0x26, 0x76);
> +	lhr050h41_send_cmd_data(ctx, 0xB2, 0xD1);
> +
> +	lhr050h41_switch_page(ctx, 1);
> +	lhr050h41_send_cmd_data(ctx, 0x22, 0x0A);
> +	lhr050h41_send_cmd_data(ctx, 0x53, 0xDC);
> +	lhr050h41_send_cmd_data(ctx, 0x55, 0xA7);
> +	lhr050h41_send_cmd_data(ctx, 0x50, 0x78);
> +	lhr050h41_send_cmd_data(ctx, 0x51, 0x78);
> +	lhr050h41_send_cmd_data(ctx, 0x31, 0x02);
> +	lhr050h41_send_cmd_data(ctx, 0x60, 0x14);
> +	lhr050h41_send_cmd_data(ctx, 0xA0, 0x2A);
> +	lhr050h41_send_cmd_data(ctx, 0xA1, 0x39);
> +	lhr050h41_send_cmd_data(ctx, 0xA2, 0x46);
> +	lhr050h41_send_cmd_data(ctx, 0xA3, 0x0e);
> +	lhr050h41_send_cmd_data(ctx, 0xA4, 0x12);
> +	lhr050h41_send_cmd_data(ctx, 0xA5, 0x25);
> +	lhr050h41_send_cmd_data(ctx, 0xA6, 0x19);
> +	lhr050h41_send_cmd_data(ctx, 0xA7, 0x1d);
> +	lhr050h41_send_cmd_data(ctx, 0xA8, 0xa6);
> +	lhr050h41_send_cmd_data(ctx, 0xA9, 0x1C);
> +	lhr050h41_send_cmd_data(ctx, 0xAA, 0x29);
> +	lhr050h41_send_cmd_data(ctx, 0xAB, 0x85);
> +	lhr050h41_send_cmd_data(ctx, 0xAC, 0x1C);
> +	lhr050h41_send_cmd_data(ctx, 0xAD, 0x1B);
> +	lhr050h41_send_cmd_data(ctx, 0xAE, 0x51);
> +	lhr050h41_send_cmd_data(ctx, 0xAF, 0x22);
> +	lhr050h41_send_cmd_data(ctx, 0xB0, 0x2d);
> +	lhr050h41_send_cmd_data(ctx, 0xB1, 0x4f);
> +	lhr050h41_send_cmd_data(ctx, 0xB2, 0x59);
> +	lhr050h41_send_cmd_data(ctx, 0xB3, 0x3F);
> +	lhr050h41_send_cmd_data(ctx, 0xC0, 0x2A);
> +	lhr050h41_send_cmd_data(ctx, 0xC1, 0x3a);
> +	lhr050h41_send_cmd_data(ctx, 0xC2, 0x45);
> +	lhr050h41_send_cmd_data(ctx, 0xC3, 0x0e);
> +	lhr050h41_send_cmd_data(ctx, 0xC4, 0x11);
> +	lhr050h41_send_cmd_data(ctx, 0xC5, 0x24);
> +	lhr050h41_send_cmd_data(ctx, 0xC6, 0x1a);
> +	lhr050h41_send_cmd_data(ctx, 0xC7, 0x1c);
> +	lhr050h41_send_cmd_data(ctx, 0xC8, 0xaa);
> +	lhr050h41_send_cmd_data(ctx, 0xC9, 0x1C);
> +	lhr050h41_send_cmd_data(ctx, 0xCA, 0x29);
> +	lhr050h41_send_cmd_data(ctx, 0xCB, 0x96);
> +	lhr050h41_send_cmd_data(ctx, 0xCC, 0x1C);
> +	lhr050h41_send_cmd_data(ctx, 0xCD, 0x1B);
> +	lhr050h41_send_cmd_data(ctx, 0xCE, 0x51);
> +	lhr050h41_send_cmd_data(ctx, 0xCF, 0x22);
> +	lhr050h41_send_cmd_data(ctx, 0xD0, 0x2b);
> +	lhr050h41_send_cmd_data(ctx, 0xD1, 0x4b);
> +	lhr050h41_send_cmd_data(ctx, 0xD2, 0x59);
> +	lhr050h41_send_cmd_data(ctx, 0xD3, 0x3F);

I think you can put all above codes into some array and call it in loop,
with error checking.

> +
> +	lhr050h41_switch_page(ctx, 0);
> +	lhr050h41_send_cmd_data(ctx, 0x35, 0x00);

mipi_dsi_dcs_set_tear_on

> +	lhr050h41_send_cmd_data(ctx, 0x11, 0x00);

mipi_dsi_dcs_exit_sleep_mode

> +
> +	mdelay(120);
I think it should be moved to enable callback, more about it below.
> +
> +	lhr050h41_send_cmd_data(ctx, 0x29, 0x00);

mipi_dsi_dcs_set_display_on

> +
> +	mdelay(20);
> +
> +	return 0;
> +}
> +
> +static int lhr050h41_prepare(struct drm_panel *panel)
> +{
> +	struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
> +
> +	/* Power the panel */
> +	gpiod_set_value(ctx->power, 1);
> +	mdelay(5);
> +
> +	/* And reset it */
> +	gpiod_set_value(ctx->reset, 1);
> +	mdelay(20);
> +
> +	gpiod_set_value(ctx->reset, 0);
> +	mdelay(20);
> +
> +	lhr050h41_send_init_sequence(ctx);
> +
> +	return 0;
> +}
> +
> +static void lhr050h41_enable_bl(struct lhr050h41 *ctx, bool enable)
> +{
> +	if (!ctx->backlight)
> +		return;
> +
> +	if (enable) {
> +		ctx->backlight->props.state &= ~BL_CORE_FBBLANK;
> +		ctx->backlight->props.power = FB_BLANK_UNBLANK;
> +	} else {
> +		ctx->backlight->props.power = FB_BLANK_POWERDOWN;
> +		ctx->backlight->props.state |= BL_CORE_FBBLANK;
> +	}
> +
> +	backlight_update_status(ctx->backlight);
> +}
> +
> +static int lhr050h41_enable(struct drm_panel *panel)
> +{
> +	struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
> +
> +	lhr050h41_enable_bl(ctx, true);
> +
> +	return 0;
> +}

Usually purpose of mdelay(120) is to wait for finishing initialization
and transmission of first frames to the panel.
So I guess mdelay(120) and mipi_dsi_dcs_set_display_on should be moved
to _enable callback, otherwise you risk having garbage on the screen at
start.

> +
> +static int lhr050h41_disable(struct drm_panel *panel)
> +{
> +	struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
> +
> +	lhr050h41_enable_bl(ctx, false);
> +
> +	return mipi_dsi_dcs_set_display_off(ctx->dsi);
> +}
> +
> +static int lhr050h41_unprepare(struct drm_panel *panel)
> +{
> +	struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
> +
> +	mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
> +	gpiod_set_value(ctx->power, 0);
> +	gpiod_set_value(ctx->reset, 1);
> +
> +	return 0;
> +}
> +
> +static const struct drm_display_mode default_mode = {
> +	.clock		= 62000,
> +	.vrefresh	= 60,
> +
> +	.hdisplay	= 720,
> +	.hsync_start	= 720 + 10,
> +	.hsync_end	= 720 + 10 + 20,
> +	.htotal		= 720 + 10 + 20 + 30,
> +
> +	.vdisplay	= 1280,
> +	.vsync_start	= 1280 + 10,
> +	.vsync_end	= 1280 + 10 + 10,
> +	.vtotal		= 1280 + 10 + 10 + 20,
> +};
> +
> +static int lhr050h41_get_modes(struct drm_panel *panel)
> +{
> +	struct drm_connector *connector = panel->connector;
> +	struct lhr050h41 *ctx = panel_to_lhr050h41(panel);
> +	struct drm_display_mode *mode;
> +
> +	mode = drm_mode_duplicate(panel->drm, &default_mode);
> +	if (!mode) {
> +		dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
> +			default_mode.hdisplay, default_mode.vdisplay,
> +			default_mode.vrefresh);
> +		return -ENOMEM;
> +	}
> +
> +	drm_mode_set_name(mode);
> +
> +	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
> +	drm_mode_probed_add(connector, mode);
> +
> +	panel->connector->display_info.width_mm = 62;
> +	panel->connector->display_info.height_mm = 110;
> +
> +	return 1;
> +}
> +
> +static const struct drm_panel_funcs lhr050h41_funcs = {
> +	.prepare	= lhr050h41_prepare,
> +	.unprepare	= lhr050h41_unprepare,
> +	.enable		= lhr050h41_enable,
> +	.disable	= lhr050h41_disable,
> +	.get_modes	= lhr050h41_get_modes,
> +};
> +
> +static int lhr050h41_dsi_probe(struct mipi_dsi_device *dsi)
> +{
> +	struct device_node *np;
> +	struct lhr050h41 *ctx;
> +	int ret;
> +
> +	ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx)
> +		return -ENOMEM;
> +	mipi_dsi_set_drvdata(dsi, ctx);
> +	ctx->dsi = dsi;
> +
> +	drm_panel_init(&ctx->panel);
> +	ctx->panel.dev = &dsi->dev;
> +	ctx->panel.funcs = &lhr050h41_funcs;
> +
> +	ctx->power = devm_gpiod_get(&dsi->dev, "power", GPIOD_OUT_LOW);
> +	if (IS_ERR(ctx->power)) {
> +		dev_err(&dsi->dev, "Couldn't get our power GPIO\n");
> +		return PTR_ERR(ctx->power);
> +	}
> +
> +	ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
> +	if (IS_ERR(ctx->reset)) {
> +		dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
> +		return PTR_ERR(ctx->reset);
> +	}
> +
> +	np = of_parse_phandle(dsi->dev.of_node, "backlight", 0);
> +	if (np) {
> +		ctx->backlight = of_find_backlight_by_node(np);
> +		of_node_put(np);
> +
> +		if (!ctx->backlight)
> +			return -EPROBE_DEFER;
> +	}
> +
> +	ret = drm_panel_add(&ctx->panel);
> +	if (ret < 0)
> +		return ret;
> +
> +	dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE;

I guess MIPI_DSI_MODE_VIDEO should be also here.

Regards
Andrzej

> +	dsi->format = MIPI_DSI_FMT_RGB888;
> +	dsi->lanes = 4;
> +
> +	return mipi_dsi_attach(dsi);
> +}
> +
> +static int lhr050h41_dsi_remove(struct mipi_dsi_device *dsi)
> +{
> +	struct lhr050h41 *ctx = mipi_dsi_get_drvdata(dsi);
> +
> +	mipi_dsi_detach(dsi);
> +	drm_panel_remove(&ctx->panel);
> +
> +	if (ctx->backlight)
> +		put_device(&ctx->backlight->dev);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id lhr050h41_of_match[] = {
> +	{ .compatible = "huarui,lhr050h41" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, lhr050h41_of_match);
> +
> +static struct mipi_dsi_driver lhr050h41_dsi_driver = {
> +	.probe		= lhr050h41_dsi_probe,
> +	.remove		= lhr050h41_dsi_remove,
> +	.driver = {
> +		.name		= "lhr050h41-dsi",
> +		.of_match_table	= lhr050h41_of_match,
> +	},
> +};
> +module_mipi_dsi_driver(lhr050h41_dsi_driver);
> +
> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
> +MODULE_DESCRIPTION("Huarui LHR050H41 LCD Driver");
> +MODULE_LICENSE("GPL v2");

[toc] | [prev] | [next] | [standalone]


#1686557 — [PATCH 08/18] drm/sun4i: tcon: Add TRI finish interrupt for vblank

FromMaxime Ripard <maxime.ripard@free-electrons.com>
Date2017-07-13 16:20 +0200
Subject[PATCH 08/18] drm/sun4i: tcon: Add TRI finish interrupt for vblank
Message-ID<u2N8e-6Ff-17@gated-at.bofh.it>
In reply to#1686553
The "CPU" (or Intel 8080) interface uses a different interrupt called
TRI_FINISH (most likely TRI being for trigger) to notify the end of frames,
and hence the VBLANK period.

And that interrupt to the possible VBLANK interrupts source.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_tcon.c |  9 ++++++---
 drivers/gpu/drm/sun4i/sun4i_tcon.h |  4 ++++
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index c4407910dfaf..a3bbf9994cfa 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -97,7 +97,8 @@ void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
 	DRM_DEBUG_DRIVER("%sabling VBLANK interrupt\n", enable ? "En" : "Dis");
 
 	mask = SUN4I_TCON_GINT0_VBLANK_ENABLE(0) |
-	       SUN4I_TCON_GINT0_VBLANK_ENABLE(1);
+		SUN4I_TCON_GINT0_VBLANK_ENABLE(1) |
+		SUN4I_TCON_GINT0_TCON0_TRI_FINISH_ENABLE;
 
 	if (enable)
 		val = mask;
@@ -336,7 +337,8 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
 	regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
 
 	if (!(status & (SUN4I_TCON_GINT0_VBLANK_INT(0) |
-			SUN4I_TCON_GINT0_VBLANK_INT(1))))
+			SUN4I_TCON_GINT0_VBLANK_INT(1) |
+			SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT)))
 		return IRQ_NONE;
 
 	drm_crtc_handle_vblank(&scrtc->crtc);
@@ -345,7 +347,8 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
 	/* Acknowledge the interrupt */
 	regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG,
 			   SUN4I_TCON_GINT0_VBLANK_INT(0) |
-			   SUN4I_TCON_GINT0_VBLANK_INT(1),
+			   SUN4I_TCON_GINT0_VBLANK_INT(1) |
+			   SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT,
 			   0);
 
 	return IRQ_HANDLED;
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index a318e5ccb612..b3582ee82855 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -28,7 +28,11 @@
 
 #define SUN4I_TCON_GINT0_REG			0x4
 #define SUN4I_TCON_GINT0_VBLANK_ENABLE(pipe)		BIT(31 - (pipe))
+#define SUN4I_TCON_GINT0_TCON0_TRI_FINISH_ENABLE	BIT(27)
+#define SUN4I_TCON_GINT0_TCON0_TRI_COUNTER_ENABLE	BIT(26)
 #define SUN4I_TCON_GINT0_VBLANK_INT(pipe)		BIT(15 - (pipe))
+#define SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT		BIT(11)
+#define SUN4I_TCON_GINT0_TCON0_TRI_COUNTER_INT		BIT(10)
 
 #define SUN4I_TCON_GINT1_REG			0x8
 #define SUN4I_TCON_FRM_CTL_REG			0x10
-- 
git-series 0.9.1

[toc] | [prev] | [next] | [standalone]


#1687056 — Re: [PATCH 08/18] drm/sun4i: tcon: Add TRI finish interrupt for vblank

FromChen-Yu Tsai <wens@csie.org>
Date2017-07-14 06:00 +0200
SubjectRe: [PATCH 08/18] drm/sun4i: tcon: Add TRI finish interrupt for vblank
Message-ID<u2ZVM-69C-13@gated-at.bofh.it>
In reply to#1686557
On Thu, Jul 13, 2017 at 10:13 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The "CPU" (or Intel 8080) interface uses a different interrupt called
> TRI_FINISH (most likely TRI being for trigger) to notify the end of frames,
> and hence the VBLANK period.
>
> And that interrupt to the possible VBLANK interrupts source.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

[toc] | [prev] | [next] | [standalone]


#1686558 — [PATCH 07/18] drm/sun4i: tcon: Don't rely on encoders to set the TCON mode

FromMaxime Ripard <maxime.ripard@free-electrons.com>
Date2017-07-13 16:20 +0200
Subject[PATCH 07/18] drm/sun4i: tcon: Don't rely on encoders to set the TCON mode
Message-ID<u2N8f-6Ff-19@gated-at.bofh.it>
In reply to#1686553
Just like we did for the TCON enable and disable, for historical reasons we
used to rely on the encoders calling the TCON mode_set function, while the
CRTC has a callback for that.

Let's implement it in order to reduce the boilerplate code.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_crtc.c          | 11 ++++-
 drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c  |  1 +-
 drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c      |  7 +---
 drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c |  1 +-
 drivers/gpu/drm/sun4i/sun4i_rgb.c           | 15 +------
 drivers/gpu/drm/sun4i/sun4i_tcon.c          | 56 ++++++++++------------
 drivers/gpu/drm/sun4i/sun4i_tcon.h          | 10 +----
 drivers/gpu/drm/sun4i/sun4i_tv.c            |  6 +--
 8 files changed, 40 insertions(+), 67 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index 30c7568dde5c..886595f579ab 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -113,11 +113,22 @@ static void sun4i_crtc_enable(struct drm_crtc *crtc)
 	sun4i_tcon_set_status(scrtc->tcon, encoder, true);
 }
 
+static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
+	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
+
+	sun4i_tcon_mode_set(scrtc->tcon, encoder, mode);
+}
+
+
 static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
 	.atomic_begin	= sun4i_crtc_atomic_begin,
 	.atomic_flush	= sun4i_crtc_atomic_flush,
 	.disable	= sun4i_crtc_disable,
 	.enable		= sun4i_crtc_enable,
+	.mode_set_nofb	= sun4i_crtc_mode_set_nofb,
 };
 
 static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
index 4692e8c345ed..7348bdbaa803 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
@@ -12,7 +12,6 @@
 
 #include <linux/clk-provider.h>
 
-#include "sun4i_tcon.h"
 #include "sun4i_hdmi.h"
 
 struct sun4i_ddc {
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index 06af2f6d0b31..67ef8acdb439 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -27,7 +27,6 @@
 #include "sun4i_crtc.h"
 #include "sun4i_drv.h"
 #include "sun4i_hdmi.h"
-#include "sun4i_tcon.h"
 
 #define DDC_SEGMENT_ADDR	0x30
 
@@ -119,15 +118,9 @@ static void sun4i_hdmi_mode_set(struct drm_encoder *encoder,
 				struct drm_display_mode *adjusted_mode)
 {
 	struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
-	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
-	struct sun4i_tcon *tcon = crtc->tcon;
 	unsigned int x, y;
 	u32 val;
 
-	sun4i_tcon1_mode_set(tcon, mode);
-	sun4i_tcon_set_mux(tcon, 1, encoder);
-
-	clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
 	clk_set_rate(hdmi->mod_clk, mode->crtc_clock * 1000);
 	clk_set_rate(hdmi->tmds_clk, mode->crtc_clock * 1000);
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
index 5cf2527bffc8..5b6727623037 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c
@@ -12,7 +12,6 @@
 
 #include <linux/clk-provider.h>
 
-#include "sun4i_tcon.h"
 #include "sun4i_hdmi.h"
 
 struct sun4i_tmds {
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index ecce1f5b50ab..9061e16e3088 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -154,22 +154,7 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
 	}
 }
 
-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_tcon *tcon = rgb->tcon;
-
-	sun4i_tcon0_mode_set(tcon, mode);
-	sun4i_tcon_set_mux(tcon, 0, encoder);
-
-	/* FIXME: This seems to be board specific */
-	clk_set_phase(tcon->dclk, 120);
-}
-
 static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {
-	.mode_set	= sun4i_rgb_encoder_mode_set,
 	.disable	= sun4i_rgb_encoder_disable,
 	.enable		= sun4i_rgb_encoder_enable,
 };
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index dc70bc2a42a5..c4407910dfaf 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -106,29 +106,6 @@ void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
 }
 EXPORT_SYMBOL(sun4i_tcon_enable_vblank);
 
-void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
-			struct drm_encoder *encoder)
-{
-	u32 val;
-
-	if (!tcon->quirks->has_unknown_mux)
-		return;
-
-	if (channel != 1)
-		return;
-
-	if (encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
-		val = 1;
-	else
-		val = 0;
-
-	/*
-	 * FIXME: Undocumented bits
-	 */
-	regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, val);
-}
-EXPORT_SYMBOL(sun4i_tcon_set_mux);
-
 static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
 				    int channel)
 {
@@ -147,8 +124,8 @@ static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
 	return delay;
 }
 
-void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
-			  struct drm_display_mode *mode)
+static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
+				 struct drm_display_mode *mode)
 {
 	unsigned int bp, hsync, vsync;
 	u8 clk_delay;
@@ -221,10 +198,9 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
 	/* Enable the output on the pins */
 	regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);
 }
-EXPORT_SYMBOL(sun4i_tcon0_mode_set);
 
-void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
-			  struct drm_display_mode *mode)
+static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
+				 struct drm_display_mode *mode)
 {
 	unsigned int bp, hsync, vsync, vtotal;
 	u8 clk_delay;
@@ -312,7 +288,29 @@ void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
 			   SUN4I_TCON_GCTL_IOMAP_MASK,
 			   SUN4I_TCON_GCTL_IOMAP_TCON1);
 }
-EXPORT_SYMBOL(sun4i_tcon1_mode_set);
+
+void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, struct drm_encoder *encoder,
+			 struct drm_display_mode *mode)
+{
+	switch (encoder->encoder_type) {
+	case DRM_MODE_ENCODER_NONE:
+		sun4i_tcon0_mode_set(tcon, mode);
+		break;
+	case DRM_MODE_ENCODER_TVDAC:
+		/*
+		 * FIXME: Undocumented bits
+		 */
+		if (tcon->quirks->has_unknown_mux)
+			regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, 1);
+		/* Fallthrough */
+	case DRM_MODE_ENCODER_TMDS:
+		sun4i_tcon1_mode_set(tcon, mode);
+		break;
+	default:
+		DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
+	}
+}
+EXPORT_SYMBOL(sun4i_tcon_mode_set);
 
 static void sun4i_tcon_finish_page_flip(struct drm_device *dev,
 					struct sun4i_crtc *scrtc)
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index 824732c90a2a..a318e5ccb612 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -184,15 +184,9 @@ struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);
 struct drm_panel *sun4i_tcon_find_panel(struct device_node *node);
 
 void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable);
+void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, struct drm_encoder *encoder,
+			 struct drm_display_mode *mode);
 void sun4i_tcon_set_status(struct sun4i_tcon *crtc, struct drm_encoder *encoder,
 			   bool enable);
 
-/* Mode Related Controls */
-void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
-			struct drm_encoder *encoder);
-void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
-			  struct drm_display_mode *mode);
-void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
-			  struct drm_display_mode *mode);
-
 #endif /* __SUN4I_TCON_H__ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 78d6cf77fdd3..69b9f8d98a13 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -24,7 +24,6 @@
 
 #include "sun4i_crtc.h"
 #include "sun4i_drv.h"
-#include "sun4i_tcon.h"
 #include "sunxi_engine.h"
 
 #define SUN4I_TVE_EN_REG		0x000
@@ -374,13 +373,8 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder,
 			      struct drm_display_mode *adjusted_mode)
 {
 	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
-	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
-	struct sun4i_tcon *tcon = crtc->tcon;
 	const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
 
-	sun4i_tcon1_mode_set(tcon, mode);
-	sun4i_tcon_set_mux(tcon, 1, encoder);
-
 	/* Enable and map the DAC to the output */
 	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
 			   SUN4I_TVE_EN_DAC_MAP_MASK,
-- 
git-series 0.9.1

[toc] | [prev] | [next] | [standalone]


#1687052 — Re: [PATCH 07/18] drm/sun4i: tcon: Don't rely on encoders to set the TCON mode

FromChen-Yu Tsai <wens@csie.org>
Date2017-07-14 06:00 +0200
SubjectRe: [PATCH 07/18] drm/sun4i: tcon: Don't rely on encoders to set the TCON mode
Message-ID<u2ZVL-69C-3@gated-at.bofh.it>
In reply to#1686558
On Thu, Jul 13, 2017 at 10:13 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Just like we did for the TCON enable and disable, for historical reasons we
> used to rely on the encoders calling the TCON mode_set function, while the
> CRTC has a callback for that.
>
> Let's implement it in order to reduce the boilerplate code.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_crtc.c          | 11 ++++-
>  drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c  |  1 +-
>  drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c      |  7 +---
>  drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c |  1 +-
>  drivers/gpu/drm/sun4i/sun4i_rgb.c           | 15 +------
>  drivers/gpu/drm/sun4i/sun4i_tcon.c          | 56 ++++++++++------------
>  drivers/gpu/drm/sun4i/sun4i_tcon.h          | 10 +----
>  drivers/gpu/drm/sun4i/sun4i_tv.c            |  6 +--
>  8 files changed, 40 insertions(+), 67 deletions(-)
>

[...]

> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index dc70bc2a42a5..c4407910dfaf 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -106,29 +106,6 @@ void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
>  }
>  EXPORT_SYMBOL(sun4i_tcon_enable_vblank);
>
> -void sun4i_tcon_set_mux(struct sun4i_tcon *tcon, int channel,
> -                       struct drm_encoder *encoder)
> -{
> -       u32 val;
> -
> -       if (!tcon->quirks->has_unknown_mux)
> -               return;
> -
> -       if (channel != 1)
> -               return;
> -
> -       if (encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
> -               val = 1;
> -       else
> -               val = 0;
> -
> -       /*
> -        * FIXME: Undocumented bits
> -        */
> -       regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, val);
> -}
> -EXPORT_SYMBOL(sun4i_tcon_set_mux);
> -
>  static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
>                                     int channel)
>  {
> @@ -147,8 +124,8 @@ static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
>         return delay;
>  }
>
> -void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> -                         struct drm_display_mode *mode)
> +static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> +                                struct drm_display_mode *mode)

Nit on the side: maybe we could mark mode as constant?
Since the function doesn't change it. Same applies to the
other mode_set functions. But this could be left to another
patch.

>  {
>         unsigned int bp, hsync, vsync;
>         u8 clk_delay;
> @@ -221,10 +198,9 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
>         /* Enable the output on the pins */
>         regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);
>  }
> -EXPORT_SYMBOL(sun4i_tcon0_mode_set);
>
> -void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
> -                         struct drm_display_mode *mode)
> +static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
> +                                struct drm_display_mode *mode)
>  {
>         unsigned int bp, hsync, vsync, vtotal;
>         u8 clk_delay;
> @@ -312,7 +288,29 @@ void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
>                            SUN4I_TCON_GCTL_IOMAP_MASK,
>                            SUN4I_TCON_GCTL_IOMAP_TCON1);
>  }
> -EXPORT_SYMBOL(sun4i_tcon1_mode_set);
> +
> +void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, struct drm_encoder *encoder,
> +                        struct drm_display_mode *mode)

(also mark encoder as const?)

> +{
> +       switch (encoder->encoder_type) {
> +       case DRM_MODE_ENCODER_NONE:
> +               sun4i_tcon0_mode_set(tcon, mode);
> +               break;
> +       case DRM_MODE_ENCODER_TVDAC:
> +               /*
> +                * FIXME: Undocumented bits
> +                */
> +               if (tcon->quirks->has_unknown_mux)
> +                       regmap_write(tcon->regs, SUN4I_TCON_MUX_CTRL_REG, 1);
> +               /* Fallthrough */
> +       case DRM_MODE_ENCODER_TMDS:
> +               sun4i_tcon1_mode_set(tcon, mode);

IIRC you need to clear the mux bit here. So ...

> +               break;
> +       default:
> +               DRM_DEBUG_DRIVER("Unknown encoder type, doing nothing...\n");
> +       }

I think keeping the muxing in a separate function would be cleaner.
The above is already slightly messy if you add the bit clearing part.
With all the other muxing possibilities in the other SoC this is
going to get really messy.

> +}
> +EXPORT_SYMBOL(sun4i_tcon_mode_set);
>
>  static void sun4i_tcon_finish_page_flip(struct drm_device *dev,
>                                         struct sun4i_crtc *scrtc)

[...]

Thanks for working on this. Now we've decoupled the TCON/CRTC code
from all the encoders.

Regards
ChenYu

[toc] | [prev] | [next] | [standalone]


#1686560 — [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup

FromMaxime Ripard <maxime.ripard@free-electrons.com>
Date2017-07-13 16:20 +0200
Subject[PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup
Message-ID<u2N8f-6Ff-21@gated-at.bofh.it>
In reply to#1686553
Some channel0 setup has to be done, no matter what the output interface is
(RGB, CPU, LVDS). Move that code into a common function in order to avoid
duplication.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_tcon.c | 26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index a3bbf9994cfa..f051862d635e 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -125,15 +125,26 @@ static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
 	return delay;
 }
 
-static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
-				 struct drm_display_mode *mode)
+static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
+					struct drm_display_mode *mode)
+{
+	/* Configure the dot clock */
+	clk_set_rate_protect(tcon->dclk, mode->crtc_clock * 1000);
+
+	/* Set the resolution */
+	regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
+		     SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
+		     SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
+}
+
+static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
+				     struct drm_display_mode *mode)
 {
 	unsigned int bp, hsync, vsync;
 	u8 clk_delay;
 	u32 val = 0;
 
-	/* Configure the dot clock */
-	clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
+	sun4i_tcon0_mode_set_common(tcon, mode);
 
 	/* Adjust clock delay */
 	clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
@@ -141,11 +152,6 @@ static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
 			   SUN4I_TCON0_CTL_CLK_DELAY_MASK,
 			   SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
 
-	/* Set the resolution */
-	regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
-		     SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
-		     SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
-
 	/*
 	 * This is called a backporch in the register documentation,
 	 * but it really is the back porch + hsync
@@ -295,7 +301,7 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, struct drm_encoder *encoder,
 {
 	switch (encoder->encoder_type) {
 	case DRM_MODE_ENCODER_NONE:
-		sun4i_tcon0_mode_set(tcon, mode);
+		sun4i_tcon0_mode_set_rgb(tcon, mode);
 		break;
 	case DRM_MODE_ENCODER_TVDAC:
 		/*
-- 
git-series 0.9.1

[toc] | [prev] | [next] | [standalone]


#1687222 — Re: [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup

Fromkbuild test robot <lkp@intel.com>
Date2017-07-14 12:00 +0200
SubjectRe: [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup
Message-ID<u35ya-1D9-21@gated-at.bofh.it>
In reply to#1686560

[Multipart message — attachments visible in raw view] — view raw

Hi Maxime,

[auto build test ERROR on next-20170710]
[cannot apply to mripard/sunxi/for-next robh/for-next regmap/for-next v4.12 v4.12-rc7 v4.12-rc6 v4.12]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Maxime-Ripard/drm-sun4i-Allwinner-MIPI-DSI-support/20170714-123103
config: arm-sunxi_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm 

All errors (new ones prefixed by >>):

   drivers/gpu/drm/sun4i/sun4i_tcon.c: In function 'sun4i_tcon0_mode_set_common':
>> drivers/gpu/drm/sun4i/sun4i_tcon.c:132:2: error: implicit declaration of function 'clk_set_rate_protect' [-Werror=implicit-function-declaration]
     clk_set_rate_protect(tcon->dclk, mode->crtc_clock * 1000);
     ^~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/clk_set_rate_protect +132 drivers/gpu/drm/sun4i/sun4i_tcon.c

   127	
   128	static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
   129						struct drm_display_mode *mode)
   130	{
   131		/* Configure the dot clock */
 > 132		clk_set_rate_protect(tcon->dclk, mode->crtc_clock * 1000);
   133	
   134		/* Set the resolution */
   135		regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
   136			     SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
   137			     SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
   138	}
   139	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[toc] | [prev] | [next] | [standalone]


#1689645 — Re: [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup

FromChen-Yu Tsai <wens@csie.org>
Date2017-07-18 05:50 +0200
SubjectRe: [PATCH 10/18] drm/sun4i: tcon: Move out the tcon0 common setup
Message-ID<u4rGi-5CQ-1@gated-at.bofh.it>
In reply to#1686560
On Thu, Jul 13, 2017 at 10:13 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Some channel0 setup has to be done, no matter what the output interface is
> (RGB, CPU, LVDS). Move that code into a common function in order to avoid
> duplication.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_tcon.c | 26 ++++++++++++++++----------
>  1 file changed, 16 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index a3bbf9994cfa..f051862d635e 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -125,15 +125,26 @@ static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
>         return delay;
>  }
>
> -static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> -                                struct drm_display_mode *mode)
> +static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
> +                                       struct drm_display_mode *mode)
> +{
> +       /* Configure the dot clock */
> +       clk_set_rate_protect(tcon->dclk, mode->crtc_clock * 1000);

I'd prefer not changing APIs in a code move. It also means we could
apply this sooner than later. Otherwise,

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

> +
> +       /* Set the resolution */
> +       regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
> +                    SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
> +                    SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
> +}
> +
> +static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
> +                                    struct drm_display_mode *mode)
>  {
>         unsigned int bp, hsync, vsync;
>         u8 clk_delay;
>         u32 val = 0;
>
> -       /* Configure the dot clock */
> -       clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
> +       sun4i_tcon0_mode_set_common(tcon, mode);
>
>         /* Adjust clock delay */
>         clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
> @@ -141,11 +152,6 @@ static void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
>                            SUN4I_TCON0_CTL_CLK_DELAY_MASK,
>                            SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
>
> -       /* Set the resolution */
> -       regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
> -                    SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
> -                    SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
> -
>         /*
>          * This is called a backporch in the register documentation,
>          * but it really is the back porch + hsync
> @@ -295,7 +301,7 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon, struct drm_encoder *encoder,
>  {
>         switch (encoder->encoder_type) {
>         case DRM_MODE_ENCODER_NONE:
> -               sun4i_tcon0_mode_set(tcon, mode);
> +               sun4i_tcon0_mode_set_rgb(tcon, mode);
>                 break;
>         case DRM_MODE_ENCODER_TVDAC:
>                 /*
> --
> git-series 0.9.1

[toc] | [prev] | [next] | [standalone]


#1686561 — [PATCH 16/18] arm: dts: sun8i: a33: Add the DSI-related nodes

FromMaxime Ripard <maxime.ripard@free-electrons.com>
Date2017-07-13 16:20 +0200
Subject[PATCH 16/18] arm: dts: sun8i: a33: Add the DSI-related nodes
Message-ID<u2N8f-6Ff-25@gated-at.bofh.it>
In reply to#1686553
The A33 has a MIPI-DSI block, along with its D-PHY. Let's add it in order
to use it in the relevant boards.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/sun8i-a33.dtsi | 50 ++++++++++++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
index 22660919bd08..18d1bf9f8e84 100644
--- a/arch/arm/boot/dts/sun8i-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a33.dtsi
@@ -236,10 +236,14 @@
 					#address-cells = <1>;
 					#size-cells = <0>;
 					reg = <1>;
+
+					tcon0_out_dsi0: endpoint@1 {
+						reg = <1>;
+						remote-endpoint = <&dsi0_in_tcon0>;
+					};
 				};
 			};
 		};
-
 		crypto: crypto-engine@01c15000 {
 			compatible = "allwinner,sun4i-a10-crypto";
 			reg = <0x01c15000 0x1000>;
@@ -280,6 +284,50 @@
 			#io-channel-cells = <0>;
 		};
 
+		dsi0: dsi@01ca0000 {
+			compatible = "allwinner,sun6i-a31-mipi-dsi";
+			reg = <0x01ca0000 0x1000>;
+			interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_MIPI_DSI>,
+				 <&ccu CLK_DSI_SCLK>;
+			clock-names = "bus", "mod";
+			resets = <&ccu RST_BUS_MIPI_DSI>;
+			phys = <&dphy0>;
+			phy-names = "dphy";
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				dsi0_in: port@0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					dsi0_in_tcon0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&tcon0_out_dsi0>;
+					};
+				};
+			};
+		};
+
+		dphy0: d-phy@01ca1000 {
+			compatible = "allwinner,sun6i-a31-mipi-dphy";
+			reg = <0x01ca1000 0x1000>;
+			clocks = <&ccu CLK_BUS_MIPI_DSI>,
+				 <&ccu CLK_DSI_DPHY>;
+			clock-names = "bus", "mod";
+			resets = <&ccu RST_BUS_MIPI_DSI>;
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			#phy-cells = <0>;
+		};
+
 		fe0: display-frontend@01e00000 {
 			compatible = "allwinner,sun8i-a33-display-frontend";
 			reg = <0x01e00000 0x20000>;
-- 
git-series 0.9.1

[toc] | [prev] | [next] | [standalone]


#1686562 — [PATCH 09/18] drm/sun4i: tcon: Adjust dotclock dividers range

FromMaxime Ripard <maxime.ripard@free-electrons.com>
Date2017-07-13 16:20 +0200
Subject[PATCH 09/18] drm/sun4i: tcon: Adjust dotclock dividers range
Message-ID<u2N8f-6Ff-29@gated-at.bofh.it>
In reply to#1686553
It seems like the dotclock dividers are a bit less strict range, and can
operate even with a smaller than 6 divider. Loose the boundaries a bit.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_dotclock.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
index d401156490f3..0b844c0dd102 100644
--- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c
+++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
@@ -77,7 +77,25 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
 	u8 best_div = 1;
 	int i;
 
-	for (i = 6; i <= 127; i++) {
+	/*
+	 * There's something odd here.
+	 *
+	 * In the A13 user manual, this is stated to be >= 6 when
+	 * dclk1 and dclk2 are used (without any hint on how to use
+	 * them), and >= 4 when only dclk is used.
+	 *
+	 * In the A33 user manual, when only dclk is used, it is set
+	 * to be >= 6 in the former case, and >= 1 in the
+	 * latter. There's also some (obscure) explanations about the
+	 * dclk1 and dclk2 vs dclk that seems to be in the upper 4
+	 * bits. What those clocks are and what bit does what is not
+	 * really clear.
+	 *
+	 * On the A33 however, while something lower than 4 works, it
+	 * does have a few artifacts. Let's not use those values, and
+	 * see how it goes.
+	 */
+	for (i = 4; i <= 127; i++) {
 		unsigned long ideal = rate * i;
 		unsigned long rounded;
 
-- 
git-series 0.9.1

[toc] | [prev] | [next] | [standalone]


#1687060 — Re: [PATCH 09/18] drm/sun4i: tcon: Adjust dotclock dividers range

FromChen-Yu Tsai <wens@csie.org>
Date2017-07-14 06:20 +0200
SubjectRe: [PATCH 09/18] drm/sun4i: tcon: Adjust dotclock dividers range
Message-ID<u30f7-6xU-1@gated-at.bofh.it>
In reply to#1686562
On Thu, Jul 13, 2017 at 10:13 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> It seems like the dotclock dividers are a bit less strict range, and can
> operate even with a smaller than 6 divider. Loose the boundaries a bit.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/sun4i_dotclock.c | 20 +++++++++++++++++++-
>  1 file changed, 19 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
> index d401156490f3..0b844c0dd102 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
> @@ -77,7 +77,25 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
>         u8 best_div = 1;
>         int i;
>
> -       for (i = 6; i <= 127; i++) {
> +       /*
> +        * There's something odd here.
> +        *
> +        * In the A13 user manual, this is stated to be >= 6 when
> +        * dclk1 and dclk2 are used (without any hint on how to use
> +        * them), and >= 4 when only dclk is used.

You set it in TCON0_IO_POL_REG, which sets the clock phase delay.
I think we were setting this before, but you removed it as part of
the previous TCON clean up patches?

In the A33, there are even more options, like DCLK / 2 (with 0 or 90
degree phase delay).

> +        *
> +        * In the A33 user manual, when only dclk is used, it is set
> +        * to be >= 6 in the former case, and >= 1 in the
> +        * latter. There's also some (obscure) explanations about the
> +        * dclk1 and dclk2 vs dclk that seems to be in the upper 4
> +        * bits. What those clocks are and what bit does what is not
> +        * really clear.

Looks like mux bits to me. How they differ from TCON0_IO_POL_REG is
beyond me ATM.

ChenYu

> +        *
> +        * On the A33 however, while something lower than 4 works, it
> +        * does have a few artifacts. Let's not use those values, and
> +        * see how it goes.
> +        */
> +       for (i = 4; i <= 127; i++) {
>                 unsigned long ideal = rate * i;
>                 unsigned long rounded;
>
> --
> git-series 0.9.1

[toc] | [prev] | [next] | [standalone]


#1686564 — [PATCH 17/18] arm: dts: sun8i: Add BananaPI M2-Magic DTS

FromMaxime Ripard <maxime.ripard@free-electrons.com>
Date2017-07-13 16:20 +0200
Subject[PATCH 17/18] arm: dts: sun8i: Add BananaPI M2-Magic DTS
Message-ID<u2N8f-6Ff-33@gated-at.bofh.it>
In reply to#1686553
The Bananapi M2-Magic is a board with an A33, a USB host and USB OTG
connectors, and 8GB eMMC, an AP6212 WiFi/Bluetooth chip and connectors for
DSI, CSI and GPIOs.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/Makefile                   |   1 +-
 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts | 321 ++++++++++++++++++++-
 2 files changed, 322 insertions(+)
 create mode 100644 arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 4b17f35dc9a7..e0d77ab79f5f 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -918,6 +918,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \
 	sun8i-h3-orangepi-pc-plus.dtb \
 	sun8i-h3-orangepi-plus.dtb \
 	sun8i-h3-orangepi-plus2e.dtb \
+	sun8i-r16-bananapi-m2m.dtb \
 	sun8i-r16-parrot.dtb \
 	sun8i-v3s-licheepi-zero.dtb \
 	sun8i-v3s-licheepi-zero-dock.dtb
diff --git a/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
new file mode 100644
index 000000000000..eaf09666720d
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-r16-bananapi-m2m.dts
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2017 Free Electrons <maxime.ripard@free-electrons.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This file 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.
+ *
+ *     This file is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun8i-a33.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "BananaPi M2 Magic";
+	compatible = "sinovoip,bananapi-m2m", "allwinner,sun8i-a33";
+
+	aliases {
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		i2c2 = &i2c2;
+		serial0 = &uart0;
+		serial1 = &uart1;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		blue {
+			label = "bpi-m2m:blue:usr";
+			gpios = <&pio 2 7 GPIO_ACTIVE_LOW>;
+		};
+
+		green {
+			label = "bpi-m2m:green:usr";
+			gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>;
+		};
+
+		red {
+			label = "bpi-m2m:red:power";
+			gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
+			default-state = "on";
+		};
+	};
+
+	reg_vcc5v0: vcc5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	wifi_pwrseq: wifi_pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&r_pio 0 6 GPIO_ACTIVE_LOW>; /* PL06 */
+	};
+};
+
+&codec {
+	status = "okay";
+};
+
+&cpu0 {
+	cpu-supply = <&reg_dcdc3>;
+};
+
+&cpu0_opp_table {
+	opp@1104000000 {
+		opp-hz = /bits/ 64 <1104000000>;
+		opp-microvolt = <1320000>;
+		clock-latency-ns = <244144>; /* 8 32k periods */
+	};
+
+	opp@1200000000 {
+		opp-hz = /bits/ 64 <1200000000>;
+		opp-microvolt = <1320000>;
+		clock-latency-ns = <244144>; /* 8 32k periods */
+	};
+};
+
+&dai {
+	status = "okay";
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+/* This is the i2c bus exposed on the DSI connector for the touch panel */
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins_a>;
+	status = "disabled";
+};
+
+/* This is the i2c bus exposed on the GPIO header */
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins_a>;
+	status = "disabled";
+};
+
+/* This is the i2c bus exposed on the CSI connector to control the sensor */
+&i2c2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins_a>;
+	status = "disabled";
+};
+
+&mmc0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins_a>;
+	vmmc-supply = <&reg_dcdc1>;
+	bus-width = <4>;
+	cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
+	cd-inverted;
+	status = "okay";
+};
+
+&mmc1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins_a>;
+	vmmc-supply = <&reg_aldo1>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	bus-width = <4>;
+	non-removable;
+	status = "okay";
+};
+
+&mmc2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc2_8bit_pins>;
+	vmmc-supply = <&reg_dcdc1>;
+	bus-width = <8>;
+	non-removable;
+	cap-mmc-hw-reset;
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&r_rsb {
+	status = "okay";
+
+	axp22x: pmic@3a3 {
+		compatible = "x-powers,axp223";
+		reg = <0x3a3>;
+		interrupt-parent = <&nmi_intc>;
+		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+		eldoin-supply = <&reg_dcdc1>;
+		x-powers,drive-vbus-en;
+	};
+};
+
+#include "axp223.dtsi"
+
+&ac_power_supply {
+	status = "okay";
+};
+
+&reg_aldo1 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "vcc-io";
+};
+
+&reg_aldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <2500000>;
+	regulator-max-microvolt = <2500000>;
+	regulator-name = "vdd-dll";
+};
+
+&reg_aldo3 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "avcc";
+};
+
+&reg_dc1sw {
+	regulator-name = "vcc-lcd";
+};
+
+&reg_dc5ldo {
+	regulator-always-on;
+	regulator-min-microvolt = <900000>;
+	regulator-max-microvolt = <1400000>;
+	regulator-name = "vdd-cpus";
+};
+
+&reg_dcdc1 {
+	regulator-always-on;
+	regulator-min-microvolt = <3000000>;
+	regulator-max-microvolt = <3000000>;
+	regulator-name = "vcc-3v0";
+};
+
+&reg_dcdc2 {
+	regulator-always-on;
+	regulator-min-microvolt = <900000>;
+	regulator-max-microvolt = <1400000>;
+	regulator-name = "vdd-sys";
+};
+
+&reg_dcdc3 {
+	regulator-always-on;
+	regulator-min-microvolt = <900000>;
+	regulator-max-microvolt = <1400000>;
+	regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc5 {
+	regulator-always-on;
+	regulator-min-microvolt = <1500000>;
+	regulator-max-microvolt = <1500000>;
+	regulator-name = "vcc-dram";
+};
+
+/*
+ * Our WiFi chip needs both DLDO1 and DLDO2 to be powered at the same
+ * time, with the two being in sync. Since this is not really
+ * supported right now, just use the two as always on, and we will fix
+ * it later.
+ */
+&reg_dldo1 {
+	regulator-always-on;
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-wifi0";
+};
+
+&reg_dldo2 {
+	regulator-always-on;
+	regulator-min-microvolt = <3300000>;
+	regulator-max-microvolt = <3300000>;
+	regulator-name = "vcc-wifi1";
+};
+
+&reg_drivevbus {
+	regulator-name = "usb0-vbus";
+	status = "okay";
+};
+
+&reg_rtc_ldo {
+	regulator-name = "vcc-rtc";
+};
+
+&sound {
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart0_pins_b>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins_a>, <&uart1_pins_cts_rts_a>;
+	status = "okay";
+};
+
+&usb_otg {
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usb_power_supply {
+	status = "okay";
+};
+
+&usbphy {
+	usb0_id_det-gpios = <&pio 7 8 GPIO_ACTIVE_HIGH>; /* PH8 */
+	usb0_vbus_power-supply = <&usb_power_supply>;
+	usb0_vbus-supply = <&reg_drivevbus>;
+	usb1_vbus-supply = <&reg_vcc5v0>;
+	status = "okay";
+};
-- 
git-series 0.9.1

[toc] | [prev] | [next] | [standalone]


#1687062 — Re: [PATCH 17/18] arm: dts: sun8i: Add BananaPI M2-Magic DTS

FromChen-Yu Tsai <wens@csie.org>
Date2017-07-14 06:50 +0200
SubjectRe: [PATCH 17/18] arm: dts: sun8i: Add BananaPI M2-Magic DTS
Message-ID<u30I9-6Pb-3@gated-at.bofh.it>
In reply to#1686564
On Thu, Jul 13, 2017 at 10:13 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The Bananapi M2-Magic is a board with an A33, a USB host and USB OTG
> connectors, and 8GB eMMC, an AP6212 WiFi/Bluetooth chip and connectors for
> DSI, CSI and GPIOs.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

Has BPI publicly released the schematics and/or FEX file yet?

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | linux.kernel


csiph-web