All of lore.kernel.org
 help / color / mirror / Atom feed
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
To: dri-devel@lists.freedesktop.org
Cc: linux-sh@vger.kernel.org
Subject: [PATCH 22/22] drm: rcar-du: lvds: Add R-Car Gen3 support
Date: Sun, 13 Sep 2015 22:51:09 +0000	[thread overview]
Message-ID: <1442184669-30990-23-git-send-email-laurent.pinchart+renesas@ideasonboard.com> (raw)
In-Reply-To: <1442184669-30990-1-git-send-email-laurent.pinchart+renesas@ideasonboard.com>

From: Koji Matsuoka <koji.matsuoka.xm@renesas.com>

The LVDS encoder differs slightly in Gen3 SoCs in its PLL configuration.
Add support for the Gen3 LVDS PLL parameters and startup procedure.

Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/gpu/drm/rcar-du/Kconfig           |   4 +-
 drivers/gpu/drm/rcar-du/rcar_du_drv.c     |  10 ++-
 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c | 133 ++++++++++++++++++++++--------
 drivers/gpu/drm/rcar-du/rcar_lvds_regs.h  |  24 ++++--
 4 files changed, 123 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index 6c3e49e9e290..971ab014eee5 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -21,10 +21,8 @@ config DRM_RCAR_HDMI
 config DRM_RCAR_LVDS
 	bool "R-Car DU LVDS Encoder Support"
 	depends on DRM_RCAR_DU
-	depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST
 	help
-	  Enable support for the R-Car Display Unit embedded LVDS encoders
-	  (currently only on R8A7790 and R8A7791).
+	  Enable support for the R-Car Display Unit embedded LVDS encoders.
 
 config DRM_RCAR_VSP
 	bool "R-Car DU VSP Compositor Support"
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 4909db60971a..87eedb7fee28 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -140,15 +140,21 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = {
 		  | RCAR_DU_FEATURE_VSP1_SOURCE,
 	.num_crtcs = 4,
 	.routes = {
-		/* R8A7795 has one RGB output, and two HDMI and one LVDS
-		 * (currently unsupported) outputs
+		/* R8A7795 has one RGB output, one LVDS output and two
+		 * (currently unsupported) HDMI outputs.
 		 */
 		[RCAR_DU_OUTPUT_DPAD0] = {
 			.possible_crtcs = BIT(3),
 			.encoder_type = DRM_MODE_ENCODER_NONE,
 			.port = 0,
 		},
+		[RCAR_DU_OUTPUT_LVDS0] = {
+			.possible_crtcs = BIT(0),
+			.encoder_type = DRM_MODE_ENCODER_LVDS,
+			.port = 3,
+		},
 	},
+	.num_lvds = 1,
 };
 
 static const struct of_device_id rcar_du_of_table[] = {
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
index 02acebadf7d6..ef3a50321ecc 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
@@ -38,22 +38,13 @@ static void rcar_lvds_write(struct rcar_du_lvdsenc *lvds, u32 reg, u32 data)
 	iowrite32(data, lvds->mmio + reg);
 }
 
-static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
-				 struct rcar_du_crtc *rcrtc)
+static void rcar_du_lvdsenc_start_gen2(struct rcar_du_lvdsenc *lvds,
+				       struct rcar_du_crtc *rcrtc)
 {
 	const struct drm_display_mode *mode = &rcrtc->crtc.mode;
 	unsigned int freq = mode->clock;
 	u32 lvdcr0;
-	u32 lvdhcr;
 	u32 pllcr;
-	int ret;
-
-	if (lvds->enabled)
-		return 0;
-
-	ret = clk_prepare_enable(lvds->clock);
-	if (ret < 0)
-		return ret;
 
 	/* PLL clock configuration */
 	if (freq < 39000)
@@ -67,26 +58,6 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
 
 	rcar_lvds_write(lvds, LVDPLLCR, pllcr);
 
-	/* Hardcode the channels and control signals routing for now.
-	 *
-	 * HSYNC -> CTRL0
-	 * VSYNC -> CTRL1
-	 * DISP  -> CTRL2
-	 * 0     -> CTRL3
-	 */
-	rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
-			LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
-			LVDCTRCR_CTR0SEL_HSYNC);
-
-	if (rcar_du_needs(lvds->dev, RCAR_DU_QUIRK_LVDS_LANES))
-		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3)
-		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1);
-	else
-		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1)
-		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3);
-
-	rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
-
 	/* Select the input, hardcode mode 0, enable LVDS operation and turn
 	 * bias circuitry on.
 	 */
@@ -96,8 +67,10 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
 	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
 
 	/* Turn all the channels on. */
-	rcar_lvds_write(lvds, LVDCR1, LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) |
-			LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY);
+	rcar_lvds_write(lvds, LVDCR1,
+			LVDCR1_CHSTBY_GEN2(3) | LVDCR1_CHSTBY_GEN2(2) |
+			LVDCR1_CHSTBY_GEN2(1) | LVDCR1_CHSTBY_GEN2(0) |
+			LVDCR1_CLKSTBY_GEN2);
 
 	/* Turn the PLL on, wait for the startup delay, and turn the output
 	 * on.
@@ -109,8 +82,90 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
 
 	lvdcr0 |= LVDCR0_LVRES;
 	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+}
+
+static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds,
+				       struct rcar_du_crtc *rcrtc)
+{
+	const struct drm_display_mode *mode = &rcrtc->crtc.mode;
+	unsigned int freq = mode->clock;
+	u32 lvdcr0;
+	u32 pllcr;
+
+	/* PLL clock configuration */
+	if (freq < 42000)
+		pllcr = LVDPLLCR_PLLDIVCNT_42M;
+	else if (freq < 85000)
+		pllcr = LVDPLLCR_PLLDIVCNT_85M;
+	else if (freq < 128000)
+		pllcr = LVDPLLCR_PLLDIVCNT_128M;
+	else
+		pllcr = LVDPLLCR_PLLDIVCNT_148M;
+
+	rcar_lvds_write(lvds, LVDPLLCR, pllcr);
+
+	/* Turn the PLL on, set it to LVDS normal mode, wait for the startup
+	 * delay and turn the output on.
+	 */
+	lvdcr0 = LVDCR0_PLLON;
+	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+
+	lvdcr0 |= LVDCR0_PWD;
+	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+
+	usleep_range(100, 150);
+
+	lvdcr0 |= LVDCR0_LVRES;
+	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+
+	/* Turn all the channels on. */
+	rcar_lvds_write(lvds, LVDCR1,
+			LVDCR1_CHSTBY_GEN3(3) | LVDCR1_CHSTBY_GEN3(2) |
+			LVDCR1_CHSTBY_GEN3(1) | LVDCR1_CHSTBY_GEN3(0) |
+			LVDCR1_CLKSTBY_GEN3);
+}
+
+static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
+				 struct rcar_du_crtc *rcrtc)
+{
+	u32 lvdhcr;
+	int ret;
+
+	if (lvds->enabled)
+		return 0;
+
+	ret = clk_prepare_enable(lvds->clock);
+	if (ret < 0)
+		return ret;
+
+	/* Hardcode the channels and control signals routing for now.
+	 *
+	 * HSYNC -> CTRL0
+	 * VSYNC -> CTRL1
+	 * DISP  -> CTRL2
+	 * 0     -> CTRL3
+	 */
+	rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
+			LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
+			LVDCTRCR_CTR0SEL_HSYNC);
+
+	if (rcar_du_needs(lvds->dev, RCAR_DU_QUIRK_LVDS_LANES))
+		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3)
+		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1);
+	else
+		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1)
+		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3);
+
+	rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
+
+	/* Perform generation-specific initialization. */
+	if (lvds->dev->info->gen < 3)
+		rcar_du_lvdsenc_start_gen2(lvds, rcrtc);
+	else
+		rcar_du_lvdsenc_start_gen3(lvds, rcrtc);
 
 	lvds->enabled = true;
+
 	return 0;
 }
 
@@ -143,10 +198,16 @@ int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds, struct drm_crtc *crtc,
 void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds,
 				  struct drm_display_mode *mode)
 {
-	/* The internal LVDS encoder has a clock frequency operating range of
-	 * 30MHz to 150MHz. Clamp the clock accordingly.
+	struct rcar_du_device *rcdu = lvds->dev;
+
+	/* The internal LVDS encoder has a restricted clock frequency operating
+	 * range (30MHz to 150MHz on Gen2, 25.175MHz to 148.5MHz on Gen3). Clamp
+	 * the clock accordingly.
 	 */
-	mode->clock = clamp(mode->clock, 30000, 150000);
+	if (rcdu->info->gen < 3)
+		mode->clock = clamp(mode->clock, 30000, 150000);
+	else
+		mode->clock = clamp(mode->clock, 25175, 148500);
 }
 
 static int rcar_du_lvdsenc_get_resources(struct rcar_du_lvdsenc *lvds,
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
index b1eafd097a79..d7d294ba2dbe 100644
--- a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
@@ -1,7 +1,7 @@
 /*
  * rcar_lvds_regs.h  --  R-Car LVDS Interface Registers Definitions
  *
- * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013-2015 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -15,28 +15,38 @@
 
 #define LVDCR0				0x0000
 #define LVDCR0_DUSEL			(1 << 15)
-#define LVDCR0_DMD			(1 << 12)
+#define LVDCR0_DMD			(1 << 12)		/* Gen2 only */
 #define LVDCR0_LVMD_MASK		(0xf << 8)
 #define LVDCR0_LVMD_SHIFT		8
 #define LVDCR0_PLLON			(1 << 4)
-#define LVDCR0_BEN			(1 << 2)
-#define LVDCR0_LVEN			(1 << 1)
+#define LVDCR0_PWD			(1 << 2)		/* Gen3 only */
+#define LVDCR0_BEN			(1 << 2)		/* Gen2 only */
+#define LVDCR0_LVEN			(1 << 1)		/* Gen2 only */
 #define LVDCR0_LVRES			(1 << 0)
 
 #define LVDCR1				0x0004
-#define LVDCR1_CKSEL			(1 << 15)
-#define LVDCR1_CHSTBY(n)		(3 << (2 + (n) * 2))
-#define LVDCR1_CLKSTBY			(3 << 0)
+#define LVDCR1_CKSEL			(1 << 15)		/* Gen2 only */
+#define LVDCR1_CHSTBY_GEN2(n)		(3 << (2 + (n) * 2))	/* Gen2 only */
+#define LVDCR1_CHSTBY_GEN3(n)		(1 << (2 + (n) * 2))	/* Gen3 only */
+#define LVDCR1_CLKSTBY_GEN2		(3 << 0)		/* Gen2 only */
+#define LVDCR1_CLKSTBY_GEN3		(1 << 0)		/* Gen3 only */
 
 #define LVDPLLCR			0x0008
 #define LVDPLLCR_CEEN			(1 << 14)
 #define LVDPLLCR_FBEN			(1 << 13)
 #define LVDPLLCR_COSEL			(1 << 12)
+/* Gen2 */
 #define LVDPLLCR_PLLDLYCNT_150M		(0x1bf << 0)
 #define LVDPLLCR_PLLDLYCNT_121M		(0x22c << 0)
 #define LVDPLLCR_PLLDLYCNT_60M		(0x77b << 0)
 #define LVDPLLCR_PLLDLYCNT_38M		(0x69a << 0)
 #define LVDPLLCR_PLLDLYCNT_MASK		(0x7ff << 0)
+/* Gen3 */
+#define LVDPLLCR_PLLDIVCNT_42M		(0x014cb << 0)
+#define LVDPLLCR_PLLDIVCNT_85M		(0x00a45 << 0)
+#define LVDPLLCR_PLLDIVCNT_128M		(0x006c3 << 0)
+#define LVDPLLCR_PLLDIVCNT_148M		(0x046c1 << 0)
+#define LVDPLLCR_PLLDIVCNT_MASK		(0x7ffff << 0)
 
 #define LVDCTRCR			0x000c
 #define LVDCTRCR_CTR3SEL_ZERO		(0 << 12)
-- 
2.4.6


WARNING: multiple messages have this Message-ID (diff)
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
To: dri-devel@lists.freedesktop.org
Cc: linux-sh@vger.kernel.org
Subject: [PATCH 22/22] drm: rcar-du: lvds: Add R-Car Gen3 support
Date: Mon, 14 Sep 2015 01:51:09 +0300	[thread overview]
Message-ID: <1442184669-30990-23-git-send-email-laurent.pinchart+renesas@ideasonboard.com> (raw)
In-Reply-To: <1442184669-30990-1-git-send-email-laurent.pinchart+renesas@ideasonboard.com>

From: Koji Matsuoka <koji.matsuoka.xm@renesas.com>

The LVDS encoder differs slightly in Gen3 SoCs in its PLL configuration.
Add support for the Gen3 LVDS PLL parameters and startup procedure.

Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
 drivers/gpu/drm/rcar-du/Kconfig           |   4 +-
 drivers/gpu/drm/rcar-du/rcar_du_drv.c     |  10 ++-
 drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c | 133 ++++++++++++++++++++++--------
 drivers/gpu/drm/rcar-du/rcar_lvds_regs.h  |  24 ++++--
 4 files changed, 123 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index 6c3e49e9e290..971ab014eee5 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -21,10 +21,8 @@ config DRM_RCAR_HDMI
 config DRM_RCAR_LVDS
 	bool "R-Car DU LVDS Encoder Support"
 	depends on DRM_RCAR_DU
-	depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST
 	help
-	  Enable support for the R-Car Display Unit embedded LVDS encoders
-	  (currently only on R8A7790 and R8A7791).
+	  Enable support for the R-Car Display Unit embedded LVDS encoders.
 
 config DRM_RCAR_VSP
 	bool "R-Car DU VSP Compositor Support"
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 4909db60971a..87eedb7fee28 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -140,15 +140,21 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = {
 		  | RCAR_DU_FEATURE_VSP1_SOURCE,
 	.num_crtcs = 4,
 	.routes = {
-		/* R8A7795 has one RGB output, and two HDMI and one LVDS
-		 * (currently unsupported) outputs
+		/* R8A7795 has one RGB output, one LVDS output and two
+		 * (currently unsupported) HDMI outputs.
 		 */
 		[RCAR_DU_OUTPUT_DPAD0] = {
 			.possible_crtcs = BIT(3),
 			.encoder_type = DRM_MODE_ENCODER_NONE,
 			.port = 0,
 		},
+		[RCAR_DU_OUTPUT_LVDS0] = {
+			.possible_crtcs = BIT(0),
+			.encoder_type = DRM_MODE_ENCODER_LVDS,
+			.port = 3,
+		},
 	},
+	.num_lvds = 1,
 };
 
 static const struct of_device_id rcar_du_of_table[] = {
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
index 02acebadf7d6..ef3a50321ecc 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
@@ -38,22 +38,13 @@ static void rcar_lvds_write(struct rcar_du_lvdsenc *lvds, u32 reg, u32 data)
 	iowrite32(data, lvds->mmio + reg);
 }
 
-static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
-				 struct rcar_du_crtc *rcrtc)
+static void rcar_du_lvdsenc_start_gen2(struct rcar_du_lvdsenc *lvds,
+				       struct rcar_du_crtc *rcrtc)
 {
 	const struct drm_display_mode *mode = &rcrtc->crtc.mode;
 	unsigned int freq = mode->clock;
 	u32 lvdcr0;
-	u32 lvdhcr;
 	u32 pllcr;
-	int ret;
-
-	if (lvds->enabled)
-		return 0;
-
-	ret = clk_prepare_enable(lvds->clock);
-	if (ret < 0)
-		return ret;
 
 	/* PLL clock configuration */
 	if (freq < 39000)
@@ -67,26 +58,6 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
 
 	rcar_lvds_write(lvds, LVDPLLCR, pllcr);
 
-	/* Hardcode the channels and control signals routing for now.
-	 *
-	 * HSYNC -> CTRL0
-	 * VSYNC -> CTRL1
-	 * DISP  -> CTRL2
-	 * 0     -> CTRL3
-	 */
-	rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
-			LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
-			LVDCTRCR_CTR0SEL_HSYNC);
-
-	if (rcar_du_needs(lvds->dev, RCAR_DU_QUIRK_LVDS_LANES))
-		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3)
-		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1);
-	else
-		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1)
-		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3);
-
-	rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
-
 	/* Select the input, hardcode mode 0, enable LVDS operation and turn
 	 * bias circuitry on.
 	 */
@@ -96,8 +67,10 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
 	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
 
 	/* Turn all the channels on. */
-	rcar_lvds_write(lvds, LVDCR1, LVDCR1_CHSTBY(3) | LVDCR1_CHSTBY(2) |
-			LVDCR1_CHSTBY(1) | LVDCR1_CHSTBY(0) | LVDCR1_CLKSTBY);
+	rcar_lvds_write(lvds, LVDCR1,
+			LVDCR1_CHSTBY_GEN2(3) | LVDCR1_CHSTBY_GEN2(2) |
+			LVDCR1_CHSTBY_GEN2(1) | LVDCR1_CHSTBY_GEN2(0) |
+			LVDCR1_CLKSTBY_GEN2);
 
 	/* Turn the PLL on, wait for the startup delay, and turn the output
 	 * on.
@@ -109,8 +82,90 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
 
 	lvdcr0 |= LVDCR0_LVRES;
 	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+}
+
+static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds,
+				       struct rcar_du_crtc *rcrtc)
+{
+	const struct drm_display_mode *mode = &rcrtc->crtc.mode;
+	unsigned int freq = mode->clock;
+	u32 lvdcr0;
+	u32 pllcr;
+
+	/* PLL clock configuration */
+	if (freq < 42000)
+		pllcr = LVDPLLCR_PLLDIVCNT_42M;
+	else if (freq < 85000)
+		pllcr = LVDPLLCR_PLLDIVCNT_85M;
+	else if (freq < 128000)
+		pllcr = LVDPLLCR_PLLDIVCNT_128M;
+	else
+		pllcr = LVDPLLCR_PLLDIVCNT_148M;
+
+	rcar_lvds_write(lvds, LVDPLLCR, pllcr);
+
+	/* Turn the PLL on, set it to LVDS normal mode, wait for the startup
+	 * delay and turn the output on.
+	 */
+	lvdcr0 = LVDCR0_PLLON;
+	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+
+	lvdcr0 |= LVDCR0_PWD;
+	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+
+	usleep_range(100, 150);
+
+	lvdcr0 |= LVDCR0_LVRES;
+	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
+
+	/* Turn all the channels on. */
+	rcar_lvds_write(lvds, LVDCR1,
+			LVDCR1_CHSTBY_GEN3(3) | LVDCR1_CHSTBY_GEN3(2) |
+			LVDCR1_CHSTBY_GEN3(1) | LVDCR1_CHSTBY_GEN3(0) |
+			LVDCR1_CLKSTBY_GEN3);
+}
+
+static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
+				 struct rcar_du_crtc *rcrtc)
+{
+	u32 lvdhcr;
+	int ret;
+
+	if (lvds->enabled)
+		return 0;
+
+	ret = clk_prepare_enable(lvds->clock);
+	if (ret < 0)
+		return ret;
+
+	/* Hardcode the channels and control signals routing for now.
+	 *
+	 * HSYNC -> CTRL0
+	 * VSYNC -> CTRL1
+	 * DISP  -> CTRL2
+	 * 0     -> CTRL3
+	 */
+	rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
+			LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
+			LVDCTRCR_CTR0SEL_HSYNC);
+
+	if (rcar_du_needs(lvds->dev, RCAR_DU_QUIRK_LVDS_LANES))
+		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3)
+		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1);
+	else
+		lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1)
+		       | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3);
+
+	rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
+
+	/* Perform generation-specific initialization. */
+	if (lvds->dev->info->gen < 3)
+		rcar_du_lvdsenc_start_gen2(lvds, rcrtc);
+	else
+		rcar_du_lvdsenc_start_gen3(lvds, rcrtc);
 
 	lvds->enabled = true;
+
 	return 0;
 }
 
@@ -143,10 +198,16 @@ int rcar_du_lvdsenc_enable(struct rcar_du_lvdsenc *lvds, struct drm_crtc *crtc,
 void rcar_du_lvdsenc_atomic_check(struct rcar_du_lvdsenc *lvds,
 				  struct drm_display_mode *mode)
 {
-	/* The internal LVDS encoder has a clock frequency operating range of
-	 * 30MHz to 150MHz. Clamp the clock accordingly.
+	struct rcar_du_device *rcdu = lvds->dev;
+
+	/* The internal LVDS encoder has a restricted clock frequency operating
+	 * range (30MHz to 150MHz on Gen2, 25.175MHz to 148.5MHz on Gen3). Clamp
+	 * the clock accordingly.
 	 */
-	mode->clock = clamp(mode->clock, 30000, 150000);
+	if (rcdu->info->gen < 3)
+		mode->clock = clamp(mode->clock, 30000, 150000);
+	else
+		mode->clock = clamp(mode->clock, 25175, 148500);
 }
 
 static int rcar_du_lvdsenc_get_resources(struct rcar_du_lvdsenc *lvds,
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
index b1eafd097a79..d7d294ba2dbe 100644
--- a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
@@ -1,7 +1,7 @@
 /*
  * rcar_lvds_regs.h  --  R-Car LVDS Interface Registers Definitions
  *
- * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013-2015 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -15,28 +15,38 @@
 
 #define LVDCR0				0x0000
 #define LVDCR0_DUSEL			(1 << 15)
-#define LVDCR0_DMD			(1 << 12)
+#define LVDCR0_DMD			(1 << 12)		/* Gen2 only */
 #define LVDCR0_LVMD_MASK		(0xf << 8)
 #define LVDCR0_LVMD_SHIFT		8
 #define LVDCR0_PLLON			(1 << 4)
-#define LVDCR0_BEN			(1 << 2)
-#define LVDCR0_LVEN			(1 << 1)
+#define LVDCR0_PWD			(1 << 2)		/* Gen3 only */
+#define LVDCR0_BEN			(1 << 2)		/* Gen2 only */
+#define LVDCR0_LVEN			(1 << 1)		/* Gen2 only */
 #define LVDCR0_LVRES			(1 << 0)
 
 #define LVDCR1				0x0004
-#define LVDCR1_CKSEL			(1 << 15)
-#define LVDCR1_CHSTBY(n)		(3 << (2 + (n) * 2))
-#define LVDCR1_CLKSTBY			(3 << 0)
+#define LVDCR1_CKSEL			(1 << 15)		/* Gen2 only */
+#define LVDCR1_CHSTBY_GEN2(n)		(3 << (2 + (n) * 2))	/* Gen2 only */
+#define LVDCR1_CHSTBY_GEN3(n)		(1 << (2 + (n) * 2))	/* Gen3 only */
+#define LVDCR1_CLKSTBY_GEN2		(3 << 0)		/* Gen2 only */
+#define LVDCR1_CLKSTBY_GEN3		(1 << 0)		/* Gen3 only */
 
 #define LVDPLLCR			0x0008
 #define LVDPLLCR_CEEN			(1 << 14)
 #define LVDPLLCR_FBEN			(1 << 13)
 #define LVDPLLCR_COSEL			(1 << 12)
+/* Gen2 */
 #define LVDPLLCR_PLLDLYCNT_150M		(0x1bf << 0)
 #define LVDPLLCR_PLLDLYCNT_121M		(0x22c << 0)
 #define LVDPLLCR_PLLDLYCNT_60M		(0x77b << 0)
 #define LVDPLLCR_PLLDLYCNT_38M		(0x69a << 0)
 #define LVDPLLCR_PLLDLYCNT_MASK		(0x7ff << 0)
+/* Gen3 */
+#define LVDPLLCR_PLLDIVCNT_42M		(0x014cb << 0)
+#define LVDPLLCR_PLLDIVCNT_85M		(0x00a45 << 0)
+#define LVDPLLCR_PLLDIVCNT_128M		(0x006c3 << 0)
+#define LVDPLLCR_PLLDIVCNT_148M		(0x046c1 << 0)
+#define LVDPLLCR_PLLDIVCNT_MASK		(0x7ffff << 0)
 
 #define LVDCTRCR			0x000c
 #define LVDCTRCR_CTR3SEL_ZERO		(0 << 12)
-- 
2.4.6


  parent reply	other threads:[~2015-09-13 22:51 UTC|newest]

Thread overview: 58+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-13 22:50 [PATCH 00/22] R-Car DU: Add Gen3 support Laurent Pinchart
2015-09-13 22:50 ` Laurent Pinchart
2015-09-13 22:50 ` [PATCH 01/22] drm: rcar-du: Don't update planes on disabled CRTCs Laurent Pinchart
2015-09-13 22:50   ` Laurent Pinchart
2015-09-13 22:50 ` [PATCH 02/22] drm: rcar-du: Add support for the R8A7793 DU Laurent Pinchart
2015-09-13 22:50   ` Laurent Pinchart
2015-09-13 22:50 ` [PATCH 03/22] drm: rcar-du: Add support for the R8A7794 DU Laurent Pinchart
2015-09-13 22:50   ` Laurent Pinchart
2015-09-13 22:50 ` [PATCH 04/22] drm: rcar-du: Compute plane DDCR4 register value directly Laurent Pinchart
2015-09-13 22:50   ` Laurent Pinchart
2015-09-13 22:50 ` [PATCH 05/22] drm: rcar-du: Refactor plane setup Laurent Pinchart
2015-09-13 22:50   ` Laurent Pinchart
2015-09-13 22:50 ` [PATCH 06/22] drm: rcar-du: Add VSP1 support to the planes allocator Laurent Pinchart
2015-09-13 22:50   ` Laurent Pinchart
2015-09-13 22:50 ` [PATCH 07/22] drm: rcar-du: Add VSP1 compositor support Laurent Pinchart
2015-09-13 22:50   ` Laurent Pinchart
2015-09-13 22:50 ` [PATCH 08/22] drm: rcar-du: Restart the DU group when a plane source changes Laurent Pinchart
2015-09-13 22:50   ` Laurent Pinchart
2015-09-14  7:22   ` Daniel Vetter
2015-09-14  7:22     ` Daniel Vetter
2015-12-17  7:11     ` Laurent Pinchart
2015-12-17  7:11       ` Laurent Pinchart
2015-12-17  9:41       ` Daniel Vetter
2015-12-17  9:41         ` Daniel Vetter
2015-12-27  9:00         ` Laurent Pinchart
2015-12-27  9:00           ` Laurent Pinchart
2015-09-13 22:50 ` [PATCH 09/22] drm: rcar-du: Move plane allocator to rcar_du_plane.c Laurent Pinchart
2015-09-13 22:50   ` Laurent Pinchart
2015-09-13 22:50 ` [PATCH 10/22] drm: rcar-du: Expose the VSP1 compositor through KMS planes Laurent Pinchart
2015-09-13 22:50   ` Laurent Pinchart
2015-09-13 22:50 ` [PATCH 11/22] drm: rcar-du: Use the VSP atomic update API Laurent Pinchart
2015-09-13 22:50   ` Laurent Pinchart
2015-09-13 22:50 ` [PATCH 12/22] drm: rcar-du: Fix compile warning on 64-bit platforms Laurent Pinchart
2015-09-13 22:50   ` Laurent Pinchart
2015-09-13 22:51 ` [PATCH 13/22] drm: rcar-du: Enable compilation on ARM64 Laurent Pinchart
2015-09-13 22:51   ` Laurent Pinchart
2015-09-13 22:51 ` [PATCH 14/22] drm: rcar-du: Drop LVDS double dependency on OF Laurent Pinchart
2015-09-13 22:51   ` Laurent Pinchart
2015-09-13 22:51 ` [PATCH 15/22] drm: rcar-du: Support up to 4 CRTCs Laurent Pinchart
2015-09-13 22:51   ` Laurent Pinchart
2015-09-13 22:51 ` [PATCH 16/22] drm: rcar-du: Output the DISP signal on the DISP pin Laurent Pinchart
2015-09-13 22:51   ` Laurent Pinchart
2015-09-13 22:51 ` [PATCH 17/22] drm: rcar-du: Output the DISP signal on the ODDF pin Laurent Pinchart
2015-09-13 22:51   ` Laurent Pinchart
2015-09-13 22:51 ` [PATCH 18/22] drm: rcar-du: Add R8A7795 device support Laurent Pinchart
2015-09-13 22:51   ` Laurent Pinchart
2015-09-13 22:51 ` [PATCH 19/22] drm: rcar-du: lvds: Avoid duplication of clock clamp code Laurent Pinchart
2015-09-13 22:51   ` Laurent Pinchart
2015-09-13 22:51 ` [PATCH 20/22] drm: rcar-du: lvds: Fix PLL frequency-related configuration Laurent Pinchart
2015-09-13 22:51   ` Laurent Pinchart
2015-09-13 22:51 ` [PATCH 21/22] drm: rcar-du: lvds: Rename PLLEN bit to PLLON Laurent Pinchart
2015-09-13 22:51   ` Laurent Pinchart
2015-09-13 22:51 ` Laurent Pinchart [this message]
2015-09-13 22:51   ` [PATCH 22/22] drm: rcar-du: lvds: Add R-Car Gen3 support Laurent Pinchart
2015-09-14  7:52 ` [PATCH 00/22] R-Car DU: Add " Geert Uytterhoeven
2015-09-14  7:52   ` Geert Uytterhoeven
2015-09-14  8:07   ` Geert Uytterhoeven
2015-09-14  8:07     ` Geert Uytterhoeven

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=1442184669-30990-23-git-send-email-laurent.pinchart+renesas@ideasonboard.com \
    --to=laurent.pinchart+renesas@ideasonboard.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-sh@vger.kernel.org \
    /path/to/YOUR_REPLY

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

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