All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] Add TV Encoder support for ZTE DRM driver
@ 2017-01-19 16:24 Shawn Guo
  2017-01-19 16:24 ` [PATCH 1/5] drm: zte: add interlace mode support Shawn Guo
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Shawn Guo @ 2017-01-19 16:24 UTC (permalink / raw)
  To: dri-devel
  Cc: Mark Rutland, devicetree, Daniel Vetter, Baoyou Xie, Rob Herring,
	Jun Nie

From: Shawn Guo <shawn.guo@linaro.org>

The series updates zx_vou driver a bit as the preparation of adding
TVENC output device, and then adds the device driver.

Shawn Guo (5):
  drm: zte: add interlace mode support
  drm: zte: move struct vou_inf into zx_vou driver
  drm: zte: add function to configure vou_ctrl dividers
  dt: add bindings for ZTE tvenc device
  drm: zte: add tvenc driver support

 .../devicetree/bindings/display/zte,vou.txt        |  15 +
 drivers/gpu/drm/zte/Makefile                       |   1 +
 drivers/gpu/drm/zte/zx_drm_drv.c                   |   1 +
 drivers/gpu/drm/zte/zx_drm_drv.h                   |   1 +
 drivers/gpu/drm/zte/zx_hdmi.c                      |  12 +-
 drivers/gpu/drm/zte/zx_tvenc.c                     | 416 +++++++++++++++++++++
 drivers/gpu/drm/zte/zx_tvenc_regs.h                |  31 ++
 drivers/gpu/drm/zte/zx_vou.c                       | 168 ++++++++-
 drivers/gpu/drm/zte/zx_vou.h                       |  32 +-
 drivers/gpu/drm/zte/zx_vou_regs.h                  |  31 ++
 10 files changed, 682 insertions(+), 26 deletions(-)
 create mode 100644 drivers/gpu/drm/zte/zx_tvenc.c
 create mode 100644 drivers/gpu/drm/zte/zx_tvenc_regs.h

-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/5] drm: zte: add interlace mode support
  2017-01-19 16:24 [PATCH 0/5] Add TV Encoder support for ZTE DRM driver Shawn Guo
@ 2017-01-19 16:24 ` Shawn Guo
       [not found]   ` <1484843100-16284-2-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
  2017-01-19 16:24 ` [PATCH 2/5] drm: zte: move struct vou_inf into zx_vou driver Shawn Guo
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Shawn Guo @ 2017-01-19 16:24 UTC (permalink / raw)
  To: dri-devel
  Cc: Mark Rutland, devicetree, Daniel Vetter, Baoyou Xie, Rob Herring,
	Jun Nie

From: Shawn Guo <shawn.guo@linaro.org>

It adds interlace mode support in VOU TIMING_CTRL and channel control
block, so that VOU driver gets ready to support output device in
interlace mode like TV Encoder.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/gpu/drm/zte/zx_vou.c      | 53 +++++++++++++++++++++++++++++++++++++--
 drivers/gpu/drm/zte/zx_vou_regs.h | 15 +++++++++++
 2 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
index 3056b41df518..8c4f0e2885f3 100644
--- a/drivers/gpu/drm/zte/zx_vou.c
+++ b/drivers/gpu/drm/zte/zx_vou.c
@@ -40,6 +40,7 @@ struct zx_crtc_regs {
 	u32 fir_active;
 	u32 fir_htiming;
 	u32 fir_vtiming;
+	u32 sec_vtiming;
 	u32 timing_shift;
 	u32 timing_pi_shift;
 };
@@ -48,6 +49,7 @@ struct zx_crtc_regs {
 	.fir_active = FIR_MAIN_ACTIVE,
 	.fir_htiming = FIR_MAIN_H_TIMING,
 	.fir_vtiming = FIR_MAIN_V_TIMING,
+	.sec_vtiming = SEC_MAIN_V_TIMING,
 	.timing_shift = TIMING_MAIN_SHIFT,
 	.timing_pi_shift = TIMING_MAIN_PI_SHIFT,
 };
@@ -56,6 +58,7 @@ struct zx_crtc_regs {
 	.fir_active = FIR_AUX_ACTIVE,
 	.fir_htiming = FIR_AUX_H_TIMING,
 	.fir_vtiming = FIR_AUX_V_TIMING,
+	.sec_vtiming = SEC_AUX_V_TIMING,
 	.timing_shift = TIMING_AUX_SHIFT,
 	.timing_pi_shift = TIMING_AUX_PI_SHIFT,
 };
@@ -65,6 +68,10 @@ struct zx_crtc_bits {
 	u32 polarity_shift;
 	u32 int_frame_mask;
 	u32 tc_enable;
+	u32 sec_vactive_shift;
+	u32 sec_vactive_mask;
+	u32 interlace_select;
+	u32 pi_enable;
 };
 
 static const struct zx_crtc_bits main_crtc_bits = {
@@ -72,6 +79,10 @@ struct zx_crtc_bits {
 	.polarity_shift = MAIN_POL_SHIFT,
 	.int_frame_mask = TIMING_INT_MAIN_FRAME,
 	.tc_enable = MAIN_TC_EN,
+	.sec_vactive_shift = SEC_VACT_MAIN_SHIFT,
+	.sec_vactive_mask = SEC_VACT_MAIN_MASK,
+	.interlace_select = MAIN_INTERLACE_SEL,
+	.pi_enable = MAIN_PI_EN,
 };
 
 static const struct zx_crtc_bits aux_crtc_bits = {
@@ -79,6 +90,10 @@ struct zx_crtc_bits {
 	.polarity_shift = AUX_POL_SHIFT,
 	.int_frame_mask = TIMING_INT_AUX_FRAME,
 	.tc_enable = AUX_TC_EN,
+	.sec_vactive_shift = SEC_VACT_AUX_SHIFT,
+	.sec_vactive_mask = SEC_VACT_AUX_MASK,
+	.interlace_select = AUX_INTERLACE_SEL,
+	.pi_enable = AUX_PI_EN,
 };
 
 struct zx_crtc {
@@ -196,19 +211,26 @@ static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
 static void zx_crtc_enable(struct drm_crtc *crtc)
 {
 	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
 	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
 	struct zx_vou_hw *vou = zcrtc->vou;
 	const struct zx_crtc_regs *regs = zcrtc->regs;
 	const struct zx_crtc_bits *bits = zcrtc->bits;
 	struct videomode vm;
+	u32 vactive;
 	u32 pol = 0;
 	u32 val;
+	u32 mask;
 	int ret;
 
 	drm_display_mode_to_videomode(mode, &vm);
 
 	/* Set up timing parameters */
-	val = V_ACTIVE(vm.vactive - 1);
+	vactive = vm.vactive;
+	if (interlaced)
+		vactive /= 2;
+
+	val = V_ACTIVE(vactive - 1);
 	val |= H_ACTIVE(vm.hactive - 1);
 	zx_writel(vou->timing + regs->fir_active, val);
 
@@ -222,6 +244,22 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
 	val |= FRONT_PORCH(vm.vfront_porch - 1);
 	zx_writel(vou->timing + regs->fir_vtiming, val);
 
+	if (interlaced) {
+		u32 shift = bits->sec_vactive_shift;
+		u32 mask = bits->sec_vactive_mask;
+
+		val = zx_readl(vou->timing + SEC_V_ACTIVE);
+		val &= ~mask;
+		val |= ((vactive - 1) << shift) & mask;
+		zx_writel(vou->timing + SEC_V_ACTIVE, val);
+
+		val = SYNC_WIDE(vm.vsync_len - 1);
+		/* sec_vbp = fir_vbp + 1 */
+		val |= BACK_PORCH(vm.vback_porch);
+		val |= FRONT_PORCH(vm.vfront_porch - 1);
+		zx_writel(vou->timing + regs->sec_vtiming, val);
+	}
+
 	/* Set up polarities */
 	if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW)
 		pol |= 1 << POL_VSYNC_SHIFT;
@@ -232,9 +270,16 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
 		       pol << bits->polarity_shift);
 
 	/* Setup SHIFT register by following what ZTE BSP does */
-	zx_writel(vou->timing + regs->timing_shift, H_SHIFT_VAL);
+	val = H_SHIFT_VAL;
+	if (interlaced)
+		val |= V_SHIFT_VAL << 16;
+	zx_writel(vou->timing + regs->timing_shift, val);
 	zx_writel(vou->timing + regs->timing_pi_shift, H_PI_SHIFT_VAL);
 
+	/* Progressive or interlace scan select */
+	mask = bits->interlace_select | bits->pi_enable;
+	zx_writel_mask(vou->timing + SCAN_CTRL, mask, interlaced ? mask : 0);
+
 	/* Enable TIMING_CTRL */
 	zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable,
 		       bits->tc_enable);
@@ -245,6 +290,10 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
 	zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_H_MASK,
 		       vm.vactive << CHN_SCREEN_H_SHIFT);
 
+	/* Configure channel interlace buffer control */
+	zx_writel_mask(zcrtc->chnreg + CHN_INTERLACE_BUF_CTRL, CHN_INTERLACE_EN,
+		       interlaced ? CHN_INTERLACE_EN : 0);
+
 	/* Update channel */
 	vou_chn_set_update(zcrtc);
 
diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h
index 193c1ce01fe7..e6ed844e068a 100644
--- a/drivers/gpu/drm/zte/zx_vou_regs.h
+++ b/drivers/gpu/drm/zte/zx_vou_regs.h
@@ -75,6 +75,8 @@
 #define CHN_SCREEN_H_SHIFT		5
 #define CHN_SCREEN_H_MASK		(0x1fff << CHN_SCREEN_H_SHIFT)
 #define CHN_UPDATE			0x08
+#define CHN_INTERLACE_BUF_CTRL		0x24
+#define CHN_INTERLACE_EN		BIT(2)
 
 /* TIMING_CTRL registers */
 #define TIMING_TC_ENABLE		0x04
@@ -117,6 +119,19 @@
 #define TIMING_MAIN_SHIFT		0x2c
 #define TIMING_AUX_SHIFT		0x30
 #define H_SHIFT_VAL			0x0048
+#define V_SHIFT_VAL			0x0001
+#define SCAN_CTRL			0x34
+#define AUX_PI_EN			BIT(19)
+#define MAIN_PI_EN			BIT(18)
+#define AUX_INTERLACE_SEL		BIT(1)
+#define MAIN_INTERLACE_SEL		BIT(0)
+#define SEC_V_ACTIVE			0x38
+#define SEC_VACT_MAIN_SHIFT		0
+#define SEC_VACT_MAIN_MASK		(0xffff << SEC_VACT_MAIN_SHIFT)
+#define SEC_VACT_AUX_SHIFT		16
+#define SEC_VACT_AUX_MASK		(0xffff << SEC_VACT_AUX_SHIFT)
+#define SEC_MAIN_V_TIMING		0x3c
+#define SEC_AUX_V_TIMING		0x40
 #define TIMING_MAIN_PI_SHIFT		0x68
 #define TIMING_AUX_PI_SHIFT		0x6c
 #define H_PI_SHIFT_VAL			0x000f
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 2/5] drm: zte: move struct vou_inf into zx_vou driver
  2017-01-19 16:24 [PATCH 0/5] Add TV Encoder support for ZTE DRM driver Shawn Guo
  2017-01-19 16:24 ` [PATCH 1/5] drm: zte: add interlace mode support Shawn Guo
@ 2017-01-19 16:24 ` Shawn Guo
       [not found]   ` <1484843100-16284-3-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
  2017-01-19 16:24 ` [PATCH 3/5] drm: zte: add function to configure vou_ctrl dividers Shawn Guo
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Shawn Guo @ 2017-01-19 16:24 UTC (permalink / raw)
  To: dri-devel
  Cc: Mark Rutland, devicetree, Daniel Vetter, Baoyou Xie, Rob Herring,
	Jun Nie

From: Shawn Guo <shawn.guo@linaro.org>

Although data in struct vou_inf is defined per output device, it doesn't
belong to the device itself but VOU control module.  All these data can
just be defined in VOU driver, and output device driver only needs to
invoke VOU driver function with device ID to enable/disable specific
output device.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/gpu/drm/zte/zx_hdmi.c | 12 ++----------
 drivers/gpu/drm/zte/zx_vou.c  | 31 ++++++++++++++++++++++++-------
 drivers/gpu/drm/zte/zx_vou.h  | 11 ++---------
 3 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c
index 6bf6c364811e..2f1e278ab50e 100644
--- a/drivers/gpu/drm/zte/zx_hdmi.c
+++ b/drivers/gpu/drm/zte/zx_hdmi.c
@@ -53,13 +53,6 @@ struct zx_hdmi {
 
 #define to_zx_hdmi(x) container_of(x, struct zx_hdmi, x)
 
-static const struct vou_inf vou_inf_hdmi = {
-	.id = VOU_HDMI,
-	.data_sel = VOU_YUV444,
-	.clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
-	.clocks_sel_bits = BIT(13) | BIT(2),
-};
-
 static inline u8 hdmi_readb(struct zx_hdmi *hdmi, u16 offset)
 {
 	return readl_relaxed(hdmi->mmio + offset * 4);
@@ -238,14 +231,14 @@ static void zx_hdmi_encoder_enable(struct drm_encoder *encoder)
 
 	zx_hdmi_hw_enable(hdmi);
 
-	vou_inf_enable(hdmi->inf, encoder->crtc);
+	vou_inf_enable(VOU_HDMI, encoder->crtc);
 }
 
 static void zx_hdmi_encoder_disable(struct drm_encoder *encoder)
 {
 	struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
 
-	vou_inf_disable(hdmi->inf, encoder->crtc);
+	vou_inf_disable(VOU_HDMI, encoder->crtc);
 
 	zx_hdmi_hw_disable(hdmi);
 
@@ -523,7 +516,6 @@ static int zx_hdmi_bind(struct device *dev, struct device *master, void *data)
 
 	hdmi->dev = dev;
 	hdmi->drm = drm;
-	hdmi->inf = &vou_inf_hdmi;
 
 	dev_set_drvdata(dev, hdmi);
 
diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
index 8c4f0e2885f3..c48704b4425a 100644
--- a/drivers/gpu/drm/zte/zx_vou.c
+++ b/drivers/gpu/drm/zte/zx_vou.c
@@ -158,6 +158,21 @@ struct zx_vou_hw {
 	struct zx_crtc *aux_crtc;
 };
 
+struct vou_inf {
+	enum vou_inf_id id;
+	enum vou_inf_data_sel data_sel;
+	u32 clocks_en_bits;
+	u32 clocks_sel_bits;
+};
+
+static struct vou_inf vou_infs[] = {
+	[VOU_HDMI] = {
+		.data_sel = VOU_YUV444,
+		.clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
+		.clocks_sel_bits = BIT(13) | BIT(2),
+	},
+};
+
 static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc)
 {
 	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
@@ -165,20 +180,21 @@ static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc)
 	return zcrtc->vou;
 }
 
-void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc)
+void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc)
 {
 	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
 	struct zx_vou_hw *vou = zcrtc->vou;
+	struct vou_inf *inf = &vou_infs[id];
 	bool is_main = zcrtc->chn_type == VOU_CHN_MAIN;
-	u32 data_sel_shift = inf->id << 1;
+	u32 data_sel_shift = id << 1;
 
 	/* Select data format */
 	zx_writel_mask(vou->vouctl + VOU_INF_DATA_SEL, 0x3 << data_sel_shift,
 		       inf->data_sel << data_sel_shift);
 
 	/* Select channel */
-	zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << inf->id,
-		       zcrtc->chn_type << inf->id);
+	zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << id,
+		       zcrtc->chn_type << id);
 
 	/* Select interface clocks */
 	zx_writel_mask(vou->vouctl + VOU_CLK_SEL, inf->clocks_sel_bits,
@@ -189,15 +205,16 @@ void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc)
 		       inf->clocks_en_bits);
 
 	/* Enable the device */
-	zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 1 << inf->id);
+	zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 1 << id);
 }
 
-void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc)
+void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc)
 {
 	struct zx_vou_hw *vou = crtc_to_vou(crtc);
+	struct vou_inf *inf = &vou_infs[id];
 
 	/* Disable the device */
-	zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 0);
+	zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 0);
 
 	/* Disable interface clocks */
 	zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 0);
diff --git a/drivers/gpu/drm/zte/zx_vou.h b/drivers/gpu/drm/zte/zx_vou.h
index 4b4339be641b..a41a0ad49857 100644
--- a/drivers/gpu/drm/zte/zx_vou.h
+++ b/drivers/gpu/drm/zte/zx_vou.h
@@ -30,15 +30,8 @@ enum vou_inf_data_sel {
 	VOU_RGB_666	= 3,
 };
 
-struct vou_inf {
-	enum vou_inf_id id;
-	enum vou_inf_data_sel data_sel;
-	u32 clocks_en_bits;
-	u32 clocks_sel_bits;
-};
-
-void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc);
-void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc);
+void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc);
+void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc);
 
 int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe);
 void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe);
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 3/5] drm: zte: add function to configure vou_ctrl dividers
  2017-01-19 16:24 [PATCH 0/5] Add TV Encoder support for ZTE DRM driver Shawn Guo
  2017-01-19 16:24 ` [PATCH 1/5] drm: zte: add interlace mode support Shawn Guo
  2017-01-19 16:24 ` [PATCH 2/5] drm: zte: move struct vou_inf into zx_vou driver Shawn Guo
@ 2017-01-19 16:24 ` Shawn Guo
  2017-01-23 15:47   ` Sean Paul
  2017-01-19 16:24 ` [PATCH 4/5] dt: add bindings for ZTE tvenc device Shawn Guo
  2017-01-19 16:25 ` [PATCH 5/5] drm: zte: add tvenc driver support Shawn Guo
  4 siblings, 1 reply; 15+ messages in thread
From: Shawn Guo @ 2017-01-19 16:24 UTC (permalink / raw)
  To: dri-devel
  Cc: Mark Rutland, devicetree, Daniel Vetter, Baoyou Xie, Rob Herring,
	Jun Nie

From: Shawn Guo <shawn.guo@linaro.org>

The clock control module (CRM) cannot always provide desired frequency
for all VOU output devices.  That's why VOU integrates a few dividers
to further divide the clocks from CRM.  Let's add an interface for
configuring these dividers.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/gpu/drm/zte/zx_vou.c      | 79 +++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/zte/zx_vou.h      | 25 +++++++++++++
 drivers/gpu/drm/zte/zx_vou_regs.h | 16 ++++++++
 3 files changed, 120 insertions(+)

diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
index c48704b4425a..98f0f51f9748 100644
--- a/drivers/gpu/drm/zte/zx_vou.c
+++ b/drivers/gpu/drm/zte/zx_vou.c
@@ -72,6 +72,13 @@ struct zx_crtc_bits {
 	u32 sec_vactive_mask;
 	u32 interlace_select;
 	u32 pi_enable;
+	u32 div_vga_shift;
+	u32 div_pic_shift;
+	u32 div_tvenc_shift;
+	u32 div_hdmi_pnx_shift;
+	u32 div_hdmi_shift;
+	u32 div_inf_shift;
+	u32 div_layer_shift;
 };
 
 static const struct zx_crtc_bits main_crtc_bits = {
@@ -83,6 +90,13 @@ struct zx_crtc_bits {
 	.sec_vactive_mask = SEC_VACT_MAIN_MASK,
 	.interlace_select = MAIN_INTERLACE_SEL,
 	.pi_enable = MAIN_PI_EN,
+	.div_vga_shift = VGA_MAIN_DIV_SHIFT,
+	.div_pic_shift = PIC_MAIN_DIV_SHIFT,
+	.div_tvenc_shift = TVENC_MAIN_DIV_SHIFT,
+	.div_hdmi_pnx_shift = HDMI_MAIN_PNX_DIV_SHIFT,
+	.div_hdmi_shift = HDMI_MAIN_DIV_SHIFT,
+	.div_inf_shift = INF_MAIN_DIV_SHIFT,
+	.div_layer_shift = LAYER_MAIN_DIV_SHIFT,
 };
 
 static const struct zx_crtc_bits aux_crtc_bits = {
@@ -94,6 +108,13 @@ struct zx_crtc_bits {
 	.sec_vactive_mask = SEC_VACT_AUX_MASK,
 	.interlace_select = AUX_INTERLACE_SEL,
 	.pi_enable = AUX_PI_EN,
+	.div_vga_shift = VGA_AUX_DIV_SHIFT,
+	.div_pic_shift = PIC_AUX_DIV_SHIFT,
+	.div_tvenc_shift = TVENC_AUX_DIV_SHIFT,
+	.div_hdmi_pnx_shift = HDMI_AUX_PNX_DIV_SHIFT,
+	.div_hdmi_shift = HDMI_AUX_DIV_SHIFT,
+	.div_inf_shift = INF_AUX_DIV_SHIFT,
+	.div_layer_shift = LAYER_AUX_DIV_SHIFT,
 };
 
 struct zx_crtc {
@@ -220,6 +241,64 @@ void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc)
 	zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 0);
 }
 
+void zx_vou_config_dividers(struct drm_crtc *crtc,
+			    struct vou_div_config *configs, int num)
+{
+	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
+	struct zx_vou_hw *vou = zcrtc->vou;
+	const struct zx_crtc_bits *bits = zcrtc->bits;
+	int i;
+
+	/* Clear update flag bit */
+	zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE, 0);
+
+	for (i = 0; i < num; i++) {
+		struct vou_div_config *cfg = configs + i;
+		u32 reg, shift;
+
+		switch (cfg->id) {
+		case VOU_DIV_VGA:
+			reg = VOU_CLK_SEL;
+			shift = bits->div_vga_shift;
+			break;
+		case VOU_DIV_PIC:
+			reg = VOU_CLK_SEL;
+			shift = bits->div_pic_shift;
+			break;
+		case VOU_DIV_TVENC:
+			reg = VOU_DIV_PARA;
+			shift = bits->div_tvenc_shift;
+			break;
+		case VOU_DIV_HDMI_PNX:
+			reg = VOU_DIV_PARA;
+			shift = bits->div_hdmi_pnx_shift;
+			break;
+		case VOU_DIV_HDMI:
+			reg = VOU_DIV_PARA;
+			shift = bits->div_hdmi_shift;
+			break;
+		case VOU_DIV_INF:
+			reg = VOU_DIV_PARA;
+			shift = bits->div_inf_shift;
+			break;
+		case VOU_DIV_LAYER:
+			reg = VOU_DIV_PARA;
+			shift = bits->div_layer_shift;
+			break;
+		default:
+			continue;
+		}
+
+		/* Each divider occupies 3 bits */
+		zx_writel_mask(vou->vouctl + reg, 0x7 << shift,
+			       cfg->val << shift);
+	}
+
+	/* Set update flag bit to get dividers effected */
+	zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE,
+		       DIV_PARA_UPDATE);
+}
+
 static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
 {
 	zx_writel(zcrtc->chnreg + CHN_UPDATE, 1);
diff --git a/drivers/gpu/drm/zte/zx_vou.h b/drivers/gpu/drm/zte/zx_vou.h
index a41a0ad49857..0dae4faefac4 100644
--- a/drivers/gpu/drm/zte/zx_vou.h
+++ b/drivers/gpu/drm/zte/zx_vou.h
@@ -33,6 +33,31 @@ enum vou_inf_data_sel {
 void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc);
 void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc);
 
+enum vou_div_id {
+	VOU_DIV_VGA,
+	VOU_DIV_PIC,
+	VOU_DIV_TVENC,
+	VOU_DIV_HDMI_PNX,
+	VOU_DIV_HDMI,
+	VOU_DIV_INF,
+	VOU_DIV_LAYER,
+};
+
+enum vou_div_val {
+	VOU_DIV_1 = 0,
+	VOU_DIV_2 = 1,
+	VOU_DIV_4 = 3,
+	VOU_DIV_8 = 7,
+};
+
+struct vou_div_config {
+	enum vou_div_id id;
+	enum vou_div_val val;
+};
+
+void zx_vou_config_dividers(struct drm_crtc *crtc,
+			    struct vou_div_config *configs, int num);
+
 int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe);
 void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe);
 
diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h
index e6ed844e068a..552772137cf0 100644
--- a/drivers/gpu/drm/zte/zx_vou_regs.h
+++ b/drivers/gpu/drm/zte/zx_vou_regs.h
@@ -176,11 +176,27 @@
 #define VOU_INF_DATA_SEL		0x08
 #define VOU_SOFT_RST			0x14
 #define VOU_CLK_SEL			0x18
+#define VGA_AUX_DIV_SHIFT		29
+#define VGA_MAIN_DIV_SHIFT		26
+#define PIC_MAIN_DIV_SHIFT		23
+#define PIC_AUX_DIV_SHIFT		20
 #define VOU_CLK_VL2_SEL			BIT(8)
 #define VOU_CLK_VL1_SEL			BIT(7)
 #define VOU_CLK_VL0_SEL			BIT(6)
 #define VOU_CLK_GL1_SEL			BIT(5)
 #define VOU_CLK_GL0_SEL			BIT(4)
+#define VOU_DIV_PARA			0x1c
+#define DIV_PARA_UPDATE			BIT(31)
+#define TVENC_AUX_DIV_SHIFT		28
+#define HDMI_AUX_PNX_DIV_SHIFT		25
+#define HDMI_MAIN_PNX_DIV_SHIFT		22
+#define HDMI_AUX_DIV_SHIFT		19
+#define HDMI_MAIN_DIV_SHIFT		16
+#define TVENC_MAIN_DIV_SHIFT		13
+#define INF_AUX_DIV_SHIFT		9
+#define INF_MAIN_DIV_SHIFT		6
+#define LAYER_AUX_DIV_SHIFT		3
+#define LAYER_MAIN_DIV_SHIFT		0
 #define VOU_CLK_REQEN			0x20
 #define VOU_CLK_EN			0x24
 
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 4/5] dt: add bindings for ZTE tvenc device
  2017-01-19 16:24 [PATCH 0/5] Add TV Encoder support for ZTE DRM driver Shawn Guo
                   ` (2 preceding siblings ...)
  2017-01-19 16:24 ` [PATCH 3/5] drm: zte: add function to configure vou_ctrl dividers Shawn Guo
@ 2017-01-19 16:24 ` Shawn Guo
  2017-01-19 17:11   ` Lucas Stach
       [not found]   ` <1484843100-16284-5-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
  2017-01-19 16:25 ` [PATCH 5/5] drm: zte: add tvenc driver support Shawn Guo
  4 siblings, 2 replies; 15+ messages in thread
From: Shawn Guo @ 2017-01-19 16:24 UTC (permalink / raw)
  To: dri-devel
  Cc: Mark Rutland, devicetree, Daniel Vetter, Baoyou Xie, Rob Herring,
	Jun Nie

From: Shawn Guo <shawn.guo@linaro.org>

It adds bindings doc for ZTE VOU TV Encoder device.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 Documentation/devicetree/bindings/display/zte,vou.txt | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/zte,vou.txt b/Documentation/devicetree/bindings/display/zte,vou.txt
index 740e5bd2e4f7..9c356284232b 100644
--- a/Documentation/devicetree/bindings/display/zte,vou.txt
+++ b/Documentation/devicetree/bindings/display/zte,vou.txt
@@ -49,6 +49,15 @@ Required properties:
 	"osc_clk"
 	"xclk"
 
+* TV Encoder output device
+
+Required properties:
+ - compatible: should be "zte,zx296718-tvenc"
+ - reg: Physical base address and length of the TVENC device IO region
+ - zte,tvenc-power-control: the phandle to SYSCTRL block followed by two
+   integer cells.  The first cell is the offset of SYSCTRL register used
+   to control TV Encoder DAC power, and the second cell is the bit mask.
+
 Example:
 
 vou: vou@1440000 {
@@ -81,4 +90,10 @@ vou: vou@1440000 {
 			 <&topcrm HDMI_XCLK>;
 		clock-names = "osc_cec", "osc_clk", "xclk";
 	};
+
+	tvenc: tvenc@2000 {
+		compatible = "zte,zx296718-tvenc";
+		reg = <0x2000 0x1000>;
+		zte,tvenc-power-control = <&sysctrl 0x170 0x10>;
+	};
 };
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 5/5] drm: zte: add tvenc driver support
  2017-01-19 16:24 [PATCH 0/5] Add TV Encoder support for ZTE DRM driver Shawn Guo
                   ` (3 preceding siblings ...)
  2017-01-19 16:24 ` [PATCH 4/5] dt: add bindings for ZTE tvenc device Shawn Guo
@ 2017-01-19 16:25 ` Shawn Guo
  2017-01-23 16:10   ` Sean Paul
  4 siblings, 1 reply; 15+ messages in thread
From: Shawn Guo @ 2017-01-19 16:25 UTC (permalink / raw)
  To: dri-devel
  Cc: Mark Rutland, devicetree, Daniel Vetter, Baoyou Xie, Rob Herring,
	Jun Nie

From: Shawn Guo <shawn.guo@linaro.org>

It adds the TV Encoder driver to support video output in PAL and NTSC
format.  The driver uses syscon/regmap interface to configure register
bit sitting in SYSCTRL module for DAC power control.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/gpu/drm/zte/Makefile        |   1 +
 drivers/gpu/drm/zte/zx_drm_drv.c    |   1 +
 drivers/gpu/drm/zte/zx_drm_drv.h    |   1 +
 drivers/gpu/drm/zte/zx_tvenc.c      | 416 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/zte/zx_tvenc_regs.h |  31 +++
 drivers/gpu/drm/zte/zx_vou.c        |   5 +
 6 files changed, 455 insertions(+)
 create mode 100644 drivers/gpu/drm/zte/zx_tvenc.c
 create mode 100644 drivers/gpu/drm/zte/zx_tvenc_regs.h

diff --git a/drivers/gpu/drm/zte/Makefile b/drivers/gpu/drm/zte/Makefile
index 699180bfd57c..01352b56c418 100644
--- a/drivers/gpu/drm/zte/Makefile
+++ b/drivers/gpu/drm/zte/Makefile
@@ -2,6 +2,7 @@ zxdrm-y := \
 	zx_drm_drv.o \
 	zx_hdmi.o \
 	zx_plane.o \
+	zx_tvenc.o \
 	zx_vou.o
 
 obj-$(CONFIG_DRM_ZTE) += zxdrm.o
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c
index 3e76f72c92ff..13081fed902d 100644
--- a/drivers/gpu/drm/zte/zx_drm_drv.c
+++ b/drivers/gpu/drm/zte/zx_drm_drv.c
@@ -247,6 +247,7 @@ static int zx_drm_remove(struct platform_device *pdev)
 static struct platform_driver *drivers[] = {
 	&zx_crtc_driver,
 	&zx_hdmi_driver,
+	&zx_tvenc_driver,
 	&zx_drm_platform_driver,
 };
 
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.h b/drivers/gpu/drm/zte/zx_drm_drv.h
index e65cd18a6cba..5ca035b079c7 100644
--- a/drivers/gpu/drm/zte/zx_drm_drv.h
+++ b/drivers/gpu/drm/zte/zx_drm_drv.h
@@ -13,6 +13,7 @@
 
 extern struct platform_driver zx_crtc_driver;
 extern struct platform_driver zx_hdmi_driver;
+extern struct platform_driver zx_tvenc_driver;
 
 static inline u32 zx_readl(void __iomem *reg)
 {
diff --git a/drivers/gpu/drm/zte/zx_tvenc.c b/drivers/gpu/drm/zte/zx_tvenc.c
new file mode 100644
index 000000000000..5a6cff1ff8a8
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_tvenc.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright 2017 Linaro Ltd.
+ * Copyright 2017 ZTE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drmP.h>
+
+#include "zx_drm_drv.h"
+#include "zx_tvenc_regs.h"
+#include "zx_vou.h"
+
+struct zx_tvenc_pwrctrl {
+	struct regmap *regmap;
+	u32 reg;
+	u32 mask;
+};
+
+struct zx_tvenc {
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+	struct device *dev;
+	void __iomem *mmio;
+	const struct vou_inf *inf;
+	struct zx_tvenc_pwrctrl pwrctrl;
+};
+
+#define to_zx_tvenc(x) container_of(x, struct zx_tvenc, x)
+
+struct zx_tvenc_mode {
+	char *name;
+	u32 hdisplay;
+	u32 vdisplay;
+	u32 hfp;
+	u32 hbp;
+	u32 hsw;
+	u32 vfp;
+	u32 vbp;
+	u32 vsw;
+	u32 video_info;
+	u32 video_res;
+	u32 field1_param;
+	u32 field2_param;
+	u32 burst_line_odd1;
+	u32 burst_line_even1;
+	u32 burst_line_odd2;
+	u32 burst_line_even2;
+	u32 line_timing_param;
+	u32 weight_value;
+	u32 blank_black_level;
+	u32 burst_level;
+	u32 control_param;
+	u32 sub_carrier_phase1;
+	u32 phase_line_incr_cvbs;
+};
+
+static const struct zx_tvenc_mode tvenc_modes[] = {
+	{
+		.name = "PAL",
+		.hdisplay = 720,
+		.vdisplay = 576,
+		.hfp = 12,
+		.hbp = 130,
+		.hsw = 2,
+		.vfp = 2,
+		.vbp = 20,
+		.vsw = 2,
+		.video_info = 0x00040040,
+		.video_res = 0x05a9c760,
+		.field1_param = 0x0004d416,
+		.field2_param = 0x0009b94f,
+		.burst_line_odd1 = 0x0004d406,
+		.burst_line_even1 = 0x0009b53e,
+		.burst_line_odd2 = 0x0004d805,
+		.burst_line_even2 = 0x0009b93f,
+		.line_timing_param = 0x06a96fdf,
+		.weight_value = 0x00c188a0,
+		.blank_black_level = 0x0000fcfc,
+		.burst_level = 0x00001595,
+		.control_param = 0x00000001,
+		.sub_carrier_phase1 = 0x1504c566,
+		.phase_line_incr_cvbs = 0xc068db8c,
+	}, {
+		.name = "NTSC",
+		.hdisplay = 720,
+		.vdisplay = 480,
+		.hfp = 16,
+		.hbp = 120,
+		.hsw = 2,
+		.vfp = 3,
+		.vbp = 17,
+		.vsw = 2,
+		.video_info = 0x00040080,
+		.video_res = 0x05a8375a,
+		.field1_param = 0x00041817,
+		.field2_param = 0x0008351e,
+		.burst_line_odd1 = 0x00041006,
+		.burst_line_even1 = 0x0008290d,
+		.burst_line_odd2 = 0x00000000,
+		.burst_line_even2 = 0x00000000,
+		.line_timing_param = 0x06a8ef9e,
+		.weight_value = 0x00b68197,
+		.blank_black_level = 0x0000f0f0,
+		.burst_level = 0x0000009c,
+		.control_param = 0x00000001,
+		.sub_carrier_phase1 = 0x10f83e10,
+		.phase_line_incr_cvbs = 0x80000000,
+	},
+};
+
+static const struct zx_tvenc_mode *
+zx_tvenc_find_zmode(struct drm_display_mode *mode)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tvenc_modes); i++) {
+		const struct zx_tvenc_mode *zmode = &tvenc_modes[i];
+
+		if (!strcmp(mode->name, zmode->name))
+			return zmode;
+	}
+
+	return NULL;
+}
+
+static void zx_tvenc_encoder_mode_set(struct drm_encoder *encoder,
+				      struct drm_display_mode *mode,
+				      struct drm_display_mode *adj_mode)
+{
+	struct zx_tvenc *tvenc = to_zx_tvenc(encoder);
+	const struct zx_tvenc_mode *zmode;
+	struct vou_div_config configs[] = {
+		{ VOU_DIV_INF,   VOU_DIV_4 },
+		{ VOU_DIV_TVENC, VOU_DIV_1 },
+		{ VOU_DIV_LAYER, VOU_DIV_2 },
+	};
+
+	zx_vou_config_dividers(encoder->crtc, configs, ARRAY_SIZE(configs));
+
+	zmode = zx_tvenc_find_zmode(mode);
+	if (!zmode) {
+		DRM_DEV_ERROR(tvenc->dev, "failed to find zmode\n");
+		return;
+	}
+
+	zx_writel(tvenc->mmio + VENC_VIDEO_INFO, zmode->video_info);
+	zx_writel(tvenc->mmio + VENC_VIDEO_RES, zmode->video_res);
+	zx_writel(tvenc->mmio + VENC_FIELD1_PARAM, zmode->field1_param);
+	zx_writel(tvenc->mmio + VENC_FIELD2_PARAM, zmode->field2_param);
+	zx_writel(tvenc->mmio + VENC_LINE_O_1, zmode->burst_line_odd1);
+	zx_writel(tvenc->mmio + VENC_LINE_E_1, zmode->burst_line_even1);
+	zx_writel(tvenc->mmio + VENC_LINE_O_2, zmode->burst_line_odd2);
+	zx_writel(tvenc->mmio + VENC_LINE_E_2, zmode->burst_line_even2);
+	zx_writel(tvenc->mmio + VENC_LINE_TIMING_PARAM,
+		  zmode->line_timing_param);
+	zx_writel(tvenc->mmio + VENC_WEIGHT_VALUE, zmode->weight_value);
+	zx_writel(tvenc->mmio + VENC_BLANK_BLACK_LEVEL,
+		  zmode->blank_black_level);
+	zx_writel(tvenc->mmio + VENC_BURST_LEVEL, zmode->burst_level);
+	zx_writel(tvenc->mmio + VENC_CONTROL_PARAM, zmode->control_param);
+	zx_writel(tvenc->mmio + VENC_SUB_CARRIER_PHASE1,
+		  zmode->sub_carrier_phase1);
+	zx_writel(tvenc->mmio + VENC_PHASE_LINE_INCR_CVBS,
+		  zmode->phase_line_incr_cvbs);
+}
+
+static void zx_tvenc_encoder_enable(struct drm_encoder *encoder)
+{
+	struct zx_tvenc *tvenc = to_zx_tvenc(encoder);
+	struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl;
+
+	/* Set bit to power up TVENC DAC */
+	regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask,
+			   pwrctrl->mask);
+
+	vou_inf_enable(VOU_TV_ENC, encoder->crtc);
+
+	zx_writel(tvenc->mmio + VENC_ENABLE, 1);
+}
+
+static void zx_tvenc_encoder_disable(struct drm_encoder *encoder)
+{
+	struct zx_tvenc *tvenc = to_zx_tvenc(encoder);
+	struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl;
+
+	zx_writel(tvenc->mmio + VENC_ENABLE, 0);
+
+	vou_inf_disable(VOU_TV_ENC, encoder->crtc);
+
+	/* Clear bit to power down TVENC DAC */
+	regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask, 0);
+}
+
+static const struct drm_encoder_helper_funcs zx_tvenc_encoder_helper_funcs = {
+	.enable	= zx_tvenc_encoder_enable,
+	.disable = zx_tvenc_encoder_disable,
+	.mode_set = zx_tvenc_encoder_mode_set,
+};
+
+static const struct drm_encoder_funcs zx_tvenc_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static void zx_tvenc_mode_to_drm_mode(const struct zx_tvenc_mode *zmode,
+				      struct drm_display_mode *mode)
+{
+	strcpy(mode->name, zmode->name);
+
+	mode->type = DRM_MODE_TYPE_DRIVER;
+	mode->flags = DRM_MODE_FLAG_INTERLACE;
+	mode->flags |= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC;
+
+	/*
+	 * The CRM cannot directly provide such a low rate, and we have to
+	 * ask a multiflied rate from CRM and use the divider in VOU to get
+	 * the disired one.
+	 */
+	mode->clock = 13500 * 4;
+
+	mode->hdisplay = zmode->hdisplay;
+	mode->hsync_start = mode->hdisplay + zmode->hfp;
+	mode->hsync_end = mode->hsync_start + zmode->hsw;
+	mode->htotal = mode->hsync_end + zmode->hbp;
+
+	mode->vdisplay = zmode->vdisplay;
+	mode->vsync_start = mode->vdisplay + zmode->vfp;
+	mode->vsync_end = mode->vsync_start + zmode->vsw;
+	mode->vtotal = mode->vsync_end + zmode->vbp;
+}
+
+static int zx_tvenc_connector_get_modes(struct drm_connector *connector)
+{
+	struct zx_tvenc *tvenc = to_zx_tvenc(connector);
+	struct device *dev = tvenc->dev;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tvenc_modes); i++) {
+		struct drm_display_mode *mode;
+		const struct zx_tvenc_mode *zmode = &tvenc_modes[i];
+
+		mode = drm_mode_create(connector->dev);
+		if (!mode) {
+			DRM_DEV_ERROR(dev, "failed to create drm mode\n");
+			return 0;
+		}
+
+		zx_tvenc_mode_to_drm_mode(zmode, mode);
+		drm_mode_probed_add(connector, mode);
+	}
+
+	return i;
+}
+
+static enum drm_mode_status
+zx_tvenc_connector_mode_valid(struct drm_connector *connector,
+			      struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static struct drm_connector_helper_funcs zx_tvenc_connector_helper_funcs = {
+	.get_modes = zx_tvenc_connector_get_modes,
+	.mode_valid = zx_tvenc_connector_mode_valid,
+};
+
+static const struct drm_connector_funcs zx_tvenc_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int zx_tvenc_register(struct drm_device *drm, struct zx_tvenc *tvenc)
+{
+	struct drm_encoder *encoder = &tvenc->encoder;
+	struct drm_connector *connector = &tvenc->connector;
+
+	/*
+	 * The tvenc is designed to use aux channel, as there is a deflicker
+	 * block for the channel.
+	 */
+	encoder->possible_crtcs = BIT(1);
+
+	drm_encoder_init(drm, encoder, &zx_tvenc_encoder_funcs,
+			 DRM_MODE_ENCODER_TVDAC, NULL);
+	drm_encoder_helper_add(encoder, &zx_tvenc_encoder_helper_funcs);
+
+	connector->interlace_allowed = true;
+
+	drm_connector_init(drm, connector, &zx_tvenc_connector_funcs,
+			   DRM_MODE_CONNECTOR_Composite);
+	drm_connector_helper_add(connector, &zx_tvenc_connector_helper_funcs);
+
+	drm_mode_connector_attach_encoder(connector, encoder);
+
+	return 0;
+}
+
+static int zx_tvenc_pwrctrl_init(struct zx_tvenc *tvenc)
+{
+	struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl;
+	struct device *dev = tvenc->dev;
+	struct of_phandle_args out_args;
+	struct regmap *regmap;
+	int ret;
+
+	ret = of_parse_phandle_with_fixed_args(dev->of_node,
+				"zte,tvenc-power-control", 2, 0, &out_args);
+	if (ret)
+		return ret;
+
+	regmap = syscon_node_to_regmap(out_args.np);
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		goto out;
+	}
+
+	pwrctrl->regmap = regmap;
+	pwrctrl->reg = out_args.args[0];
+	pwrctrl->mask = out_args.args[1];
+
+out:
+	of_node_put(out_args.np);
+	return ret;
+}
+
+static int zx_tvenc_bind(struct device *dev, struct device *master, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm = data;
+	struct resource *res;
+	struct zx_tvenc *tvenc;
+	int ret;
+
+	tvenc = devm_kzalloc(dev, sizeof(*tvenc), GFP_KERNEL);
+	if (!tvenc)
+		return -ENOMEM;
+
+	tvenc->dev = dev;
+	dev_set_drvdata(dev, tvenc);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	tvenc->mmio = devm_ioremap_resource(dev, res);
+	if (IS_ERR(tvenc->mmio)) {
+		ret = PTR_ERR(tvenc->mmio);
+		DRM_DEV_ERROR(dev, "failed to remap tvenc region: %d\n", ret);
+		return ret;
+	}
+
+	ret = zx_tvenc_pwrctrl_init(tvenc);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "failed to init power control: %d\n", ret);
+		return ret;
+	}
+
+	ret = zx_tvenc_register(drm, tvenc);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "failed to register tvenc: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void zx_tvenc_unbind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct zx_tvenc *tvenc = dev_get_drvdata(dev);
+
+	tvenc->connector.funcs->destroy(&tvenc->connector);
+	tvenc->encoder.funcs->destroy(&tvenc->encoder);
+}
+
+static const struct component_ops zx_tvenc_component_ops = {
+	.bind = zx_tvenc_bind,
+	.unbind = zx_tvenc_unbind,
+};
+
+static int zx_tvenc_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &zx_tvenc_component_ops);
+}
+
+static int zx_tvenc_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &zx_tvenc_component_ops);
+	return 0;
+}
+
+static const struct of_device_id zx_tvenc_of_match[] = {
+	{ .compatible = "zte,zx296718-tvenc", },
+	{ /* end */ },
+};
+MODULE_DEVICE_TABLE(of, zx_tvenc_of_match);
+
+struct platform_driver zx_tvenc_driver = {
+	.probe = zx_tvenc_probe,
+	.remove = zx_tvenc_remove,
+	.driver	= {
+		.name = "zx-tvenc",
+		.of_match_table	= zx_tvenc_of_match,
+	},
+};
diff --git a/drivers/gpu/drm/zte/zx_tvenc_regs.h b/drivers/gpu/drm/zte/zx_tvenc_regs.h
new file mode 100644
index 000000000000..bd91f5dcc1f3
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_tvenc_regs.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 Linaro Ltd.
+ * Copyright 2017 ZTE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ZX_TVENC_REGS_H__
+#define __ZX_TVENC_REGS_H__
+
+#define VENC_VIDEO_INFO			0x04
+#define VENC_VIDEO_RES			0x08
+#define VENC_FIELD1_PARAM		0x10
+#define VENC_FIELD2_PARAM		0x14
+#define VENC_LINE_O_1			0x18
+#define VENC_LINE_E_1			0x1c
+#define VENC_LINE_O_2			0x20
+#define VENC_LINE_E_2			0x24
+#define VENC_LINE_TIMING_PARAM		0x28
+#define VENC_WEIGHT_VALUE		0x2c
+#define VENC_BLANK_BLACK_LEVEL		0x30
+#define VENC_BURST_LEVEL		0x34
+#define VENC_CONTROL_PARAM		0x3c
+#define VENC_SUB_CARRIER_PHASE1		0x40
+#define VENC_PHASE_LINE_INCR_CVBS	0x48
+#define VENC_ENABLE			0xa8
+
+#endif /* __ZX_TVENC_REGS_H__ */
diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
index 98f0f51f9748..61d4ff709d83 100644
--- a/drivers/gpu/drm/zte/zx_vou.c
+++ b/drivers/gpu/drm/zte/zx_vou.c
@@ -192,6 +192,11 @@ struct vou_inf {
 		.clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
 		.clocks_sel_bits = BIT(13) | BIT(2),
 	},
+	[VOU_TV_ENC] = {
+		.data_sel = VOU_YUV444,
+		.clocks_en_bits = BIT(15),
+		.clocks_sel_bits = BIT(11) | BIT(0),
+	},
 };
 
 static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc)
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] dt: add bindings for ZTE tvenc device
  2017-01-19 16:24 ` [PATCH 4/5] dt: add bindings for ZTE tvenc device Shawn Guo
@ 2017-01-19 17:11   ` Lucas Stach
  2017-01-23  1:33     ` Shawn Guo
       [not found]   ` <1484843100-16284-5-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
  1 sibling, 1 reply; 15+ messages in thread
From: Lucas Stach @ 2017-01-19 17:11 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Mark Rutland, devicetree, Daniel Vetter, Baoyou Xie, dri-devel,
	Rob Herring, Jun Nie

Am Freitag, den 20.01.2017, 00:24 +0800 schrieb Shawn Guo:
> From: Shawn Guo <shawn.guo@linaro.org>
> 
> It adds bindings doc for ZTE VOU TV Encoder device.
> 
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
>  Documentation/devicetree/bindings/display/zte,vou.txt | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/display/zte,vou.txt b/Documentation/devicetree/bindings/display/zte,vou.txt
> index 740e5bd2e4f7..9c356284232b 100644
> --- a/Documentation/devicetree/bindings/display/zte,vou.txt
> +++ b/Documentation/devicetree/bindings/display/zte,vou.txt
> @@ -49,6 +49,15 @@ Required properties:
>  	"osc_clk"
>  	"xclk"
>  
> +* TV Encoder output device
> +
> +Required properties:
> + - compatible: should be "zte,zx296718-tvenc"
> + - reg: Physical base address and length of the TVENC device IO region
> + - zte,tvenc-power-control: the phandle to SYSCTRL block followed by two
> +   integer cells.  The first cell is the offset of SYSCTRL register used
> +   to control TV Encoder DAC power, and the second cell is the bit mask.

I don't know much about this platform, but shouldn't this be handled
with a proper power domain driver, rather than bashing bits directly?

Regards,
Lucas

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] dt: add bindings for ZTE tvenc device
  2017-01-19 17:11   ` Lucas Stach
@ 2017-01-23  1:33     ` Shawn Guo
  0 siblings, 0 replies; 15+ messages in thread
From: Shawn Guo @ 2017-01-23  1:33 UTC (permalink / raw)
  To: Lucas Stach
  Cc: Mark Rutland, devicetree, Daniel Vetter, Baoyou Xie, dri-devel,
	Rob Herring, Jun Nie

On Thu, Jan 19, 2017 at 06:11:17PM +0100, Lucas Stach wrote:
> Am Freitag, den 20.01.2017, 00:24 +0800 schrieb Shawn Guo:
> > From: Shawn Guo <shawn.guo@linaro.org>
> > 
> > It adds bindings doc for ZTE VOU TV Encoder device.
> > 
> > Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> > ---
> >  Documentation/devicetree/bindings/display/zte,vou.txt | 15 +++++++++++++++
> >  1 file changed, 15 insertions(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/display/zte,vou.txt b/Documentation/devicetree/bindings/display/zte,vou.txt
> > index 740e5bd2e4f7..9c356284232b 100644
> > --- a/Documentation/devicetree/bindings/display/zte,vou.txt
> > +++ b/Documentation/devicetree/bindings/display/zte,vou.txt
> > @@ -49,6 +49,15 @@ Required properties:
> >  	"osc_clk"
> >  	"xclk"
> >  
> > +* TV Encoder output device
> > +
> > +Required properties:
> > + - compatible: should be "zte,zx296718-tvenc"
> > + - reg: Physical base address and length of the TVENC device IO region
> > + - zte,tvenc-power-control: the phandle to SYSCTRL block followed by two
> > +   integer cells.  The first cell is the offset of SYSCTRL register used
> > +   to control TV Encoder DAC power, and the second cell is the bit mask.
> 
> I don't know much about this platform, but shouldn't this be handled
> with a proper power domain driver, rather than bashing bits directly?

There is a power domain controller (PCU) on ZTE platform which controls
power for a list of hardware blocks [1].  TVENC DAC is not on the list.
Rather than PCU, it's controlled by SYSCTRL block which contains various
control bits for various aspects of the system.

Shawn

[1] https://git.kernel.org/cgit/linux/kernel/git/shawnguo/linux.git/commit/?h=zte/pm-domains&id=eea1d99b900fe19dce3042dac555c270221be147
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 4/5] dt: add bindings for ZTE tvenc device
       [not found]   ` <1484843100-16284-5-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
@ 2017-01-23 14:46     ` Rob Herring
  0 siblings, 0 replies; 15+ messages in thread
From: Rob Herring @ 2017-01-23 14:46 UTC (permalink / raw)
  To: Shawn Guo
  Cc: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Daniel Vetter, Sean Paul,
	David Airlie, Mark Rutland, Baoyou Xie, Jun Nie, Shawn Guo

On Fri, Jan 20, 2017 at 12:24:59AM +0800, Shawn Guo wrote:
> From: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> 
> It adds bindings doc for ZTE VOU TV Encoder device.
> 
> Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
>  Documentation/devicetree/bindings/display/zte,vou.txt | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)

Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/5] drm: zte: add interlace mode support
       [not found]   ` <1484843100-16284-2-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
@ 2017-01-23 15:19     ` Sean Paul
       [not found]       ` <20170123151901.GA19505-6JpoNmjd1+aEBhuJAZrboHoUN1GumTyQ7j82oEJ37pA@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Sean Paul @ 2017-01-23 15:19 UTC (permalink / raw)
  To: Shawn Guo
  Cc: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Daniel Vetter, Baoyou Xie,
	Rob Herring, Jun Nie

On Fri, Jan 20, 2017 at 12:24:56AM +0800, Shawn Guo wrote:
> From: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> 
> It adds interlace mode support in VOU TIMING_CTRL and channel control
> block, so that VOU driver gets ready to support output device in
> interlace mode like TV Encoder.
> 
> Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
>  drivers/gpu/drm/zte/zx_vou.c      | 53 +++++++++++++++++++++++++++++++++++++--
>  drivers/gpu/drm/zte/zx_vou_regs.h | 15 +++++++++++
>  2 files changed, 66 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
> index 3056b41df518..8c4f0e2885f3 100644
> --- a/drivers/gpu/drm/zte/zx_vou.c
> +++ b/drivers/gpu/drm/zte/zx_vou.c

<snip>

> @@ -196,19 +211,26 @@ static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
>  static void zx_crtc_enable(struct drm_crtc *crtc)
>  {
>  	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> +	bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
>  	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
>  	struct zx_vou_hw *vou = zcrtc->vou;
>  	const struct zx_crtc_regs *regs = zcrtc->regs;
>  	const struct zx_crtc_bits *bits = zcrtc->bits;
>  	struct videomode vm;
> +	u32 vactive;
>  	u32 pol = 0;
>  	u32 val;
> +	u32 mask;
>  	int ret;
>  
>  	drm_display_mode_to_videomode(mode, &vm);
>  
>  	/* Set up timing parameters */
> -	val = V_ACTIVE(vm.vactive - 1);
> +	vactive = vm.vactive;
> +	if (interlaced)
> +		vactive /= 2;
> +
> +	val = V_ACTIVE(vactive - 1);

Instead of introducing a new var, I think you can get away with:

if (interlaced)
        val = V_ACTIVE(vm.vactive / 2);
else
        val = V_ACTIVE(vm.vactive - 1);


>  	val |= H_ACTIVE(vm.hactive - 1);
>  	zx_writel(vou->timing + regs->fir_active, val);
>  
> @@ -222,6 +244,22 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
>  	val |= FRONT_PORCH(vm.vfront_porch - 1);
>  	zx_writel(vou->timing + regs->fir_vtiming, val);
>  
> +	if (interlaced) {
> +		u32 shift = bits->sec_vactive_shift;
> +		u32 mask = bits->sec_vactive_mask;

mask is already defined at the function scope

> +
> +		val = zx_readl(vou->timing + SEC_V_ACTIVE);
> +		val &= ~mask;
> +		val |= ((vactive - 1) << shift) & mask;
> +		zx_writel(vou->timing + SEC_V_ACTIVE, val);
> +
> +		val = SYNC_WIDE(vm.vsync_len - 1);
> +		/* sec_vbp = fir_vbp + 1 */

Looks like leftover kruft here.

> +		val |= BACK_PORCH(vm.vback_porch);
> +		val |= FRONT_PORCH(vm.vfront_porch - 1);
> +		zx_writel(vou->timing + regs->sec_vtiming, val);
> +	}
> +
>  	/* Set up polarities */
>  	if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW)
>  		pol |= 1 << POL_VSYNC_SHIFT;
> @@ -232,9 +270,16 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
>  		       pol << bits->polarity_shift);
>  
>  	/* Setup SHIFT register by following what ZTE BSP does */
> -	zx_writel(vou->timing + regs->timing_shift, H_SHIFT_VAL);
> +	val = H_SHIFT_VAL;
> +	if (interlaced)
> +		val |= V_SHIFT_VAL << 16;
> +	zx_writel(vou->timing + regs->timing_shift, val);
>  	zx_writel(vou->timing + regs->timing_pi_shift, H_PI_SHIFT_VAL);
>  
> +	/* Progressive or interlace scan select */
> +	mask = bits->interlace_select | bits->pi_enable;
> +	zx_writel_mask(vou->timing + SCAN_CTRL, mask, interlaced ? mask : 0);
> +
>  	/* Enable TIMING_CTRL */
>  	zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable,
>  		       bits->tc_enable);
> @@ -245,6 +290,10 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
>  	zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_H_MASK,
>  		       vm.vactive << CHN_SCREEN_H_SHIFT);
>  
> +	/* Configure channel interlace buffer control */
> +	zx_writel_mask(zcrtc->chnreg + CHN_INTERLACE_BUF_CTRL, CHN_INTERLACE_EN,
> +		       interlaced ? CHN_INTERLACE_EN : 0);
> +
>  	/* Update channel */
>  	vou_chn_set_update(zcrtc);
>  
> diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h
> index 193c1ce01fe7..e6ed844e068a 100644
> --- a/drivers/gpu/drm/zte/zx_vou_regs.h
> +++ b/drivers/gpu/drm/zte/zx_vou_regs.h
> @@ -75,6 +75,8 @@
>  #define CHN_SCREEN_H_SHIFT		5
>  #define CHN_SCREEN_H_MASK		(0x1fff << CHN_SCREEN_H_SHIFT)
>  #define CHN_UPDATE			0x08
> +#define CHN_INTERLACE_BUF_CTRL		0x24

Maybe it's my email reader, but it seems like there's an alignment issue here.

> +#define CHN_INTERLACE_EN		BIT(2)
>  
>  /* TIMING_CTRL registers */
>  #define TIMING_TC_ENABLE		0x04
> @@ -117,6 +119,19 @@
>  #define TIMING_MAIN_SHIFT		0x2c
>  #define TIMING_AUX_SHIFT		0x30
>  #define H_SHIFT_VAL			0x0048
> +#define V_SHIFT_VAL			0x0001
> +#define SCAN_CTRL			0x34
> +#define AUX_PI_EN			BIT(19)
> +#define MAIN_PI_EN			BIT(18)
> +#define AUX_INTERLACE_SEL		BIT(1)
> +#define MAIN_INTERLACE_SEL		BIT(0)
> +#define SEC_V_ACTIVE			0x38
> +#define SEC_VACT_MAIN_SHIFT		0
> +#define SEC_VACT_MAIN_MASK		(0xffff << SEC_VACT_MAIN_SHIFT)
> +#define SEC_VACT_AUX_SHIFT		16
> +#define SEC_VACT_AUX_MASK		(0xffff << SEC_VACT_AUX_SHIFT)
> +#define SEC_MAIN_V_TIMING		0x3c
> +#define SEC_AUX_V_TIMING		0x40
>  #define TIMING_MAIN_PI_SHIFT		0x68
>  #define TIMING_AUX_PI_SHIFT		0x6c
>  #define H_PI_SHIFT_VAL			0x000f
> -- 
> 1.9.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/5] drm: zte: move struct vou_inf into zx_vou driver
       [not found]   ` <1484843100-16284-3-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
@ 2017-01-23 15:30     ` Sean Paul
  0 siblings, 0 replies; 15+ messages in thread
From: Sean Paul @ 2017-01-23 15:30 UTC (permalink / raw)
  To: Shawn Guo
  Cc: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Daniel Vetter, Baoyou Xie,
	Rob Herring, Jun Nie

On Fri, Jan 20, 2017 at 12:24:57AM +0800, Shawn Guo wrote:
> From: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> 
> Although data in struct vou_inf is defined per output device, it doesn't
> belong to the device itself but VOU control module.  All these data can
> just be defined in VOU driver, and output device driver only needs to
> invoke VOU driver function with device ID to enable/disable specific
> output device.
> 

Reviewed-by: Sean Paul <seanpaul-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>

> Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
>  drivers/gpu/drm/zte/zx_hdmi.c | 12 ++----------
>  drivers/gpu/drm/zte/zx_vou.c  | 31 ++++++++++++++++++++++++-------
>  drivers/gpu/drm/zte/zx_vou.h  | 11 ++---------
>  3 files changed, 28 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c
> index 6bf6c364811e..2f1e278ab50e 100644
> --- a/drivers/gpu/drm/zte/zx_hdmi.c
> +++ b/drivers/gpu/drm/zte/zx_hdmi.c
> @@ -53,13 +53,6 @@ struct zx_hdmi {
>  
>  #define to_zx_hdmi(x) container_of(x, struct zx_hdmi, x)
>  
> -static const struct vou_inf vou_inf_hdmi = {
> -	.id = VOU_HDMI,
> -	.data_sel = VOU_YUV444,
> -	.clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
> -	.clocks_sel_bits = BIT(13) | BIT(2),
> -};
> -
>  static inline u8 hdmi_readb(struct zx_hdmi *hdmi, u16 offset)
>  {
>  	return readl_relaxed(hdmi->mmio + offset * 4);
> @@ -238,14 +231,14 @@ static void zx_hdmi_encoder_enable(struct drm_encoder *encoder)
>  
>  	zx_hdmi_hw_enable(hdmi);
>  
> -	vou_inf_enable(hdmi->inf, encoder->crtc);
> +	vou_inf_enable(VOU_HDMI, encoder->crtc);
>  }
>  
>  static void zx_hdmi_encoder_disable(struct drm_encoder *encoder)
>  {
>  	struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
>  
> -	vou_inf_disable(hdmi->inf, encoder->crtc);
> +	vou_inf_disable(VOU_HDMI, encoder->crtc);
>  
>  	zx_hdmi_hw_disable(hdmi);
>  
> @@ -523,7 +516,6 @@ static int zx_hdmi_bind(struct device *dev, struct device *master, void *data)
>  
>  	hdmi->dev = dev;
>  	hdmi->drm = drm;
> -	hdmi->inf = &vou_inf_hdmi;
>  
>  	dev_set_drvdata(dev, hdmi);
>  
> diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
> index 8c4f0e2885f3..c48704b4425a 100644
> --- a/drivers/gpu/drm/zte/zx_vou.c
> +++ b/drivers/gpu/drm/zte/zx_vou.c
> @@ -158,6 +158,21 @@ struct zx_vou_hw {
>  	struct zx_crtc *aux_crtc;
>  };
>  
> +struct vou_inf {
> +	enum vou_inf_id id;
> +	enum vou_inf_data_sel data_sel;
> +	u32 clocks_en_bits;
> +	u32 clocks_sel_bits;
> +};
> +
> +static struct vou_inf vou_infs[] = {
> +	[VOU_HDMI] = {
> +		.data_sel = VOU_YUV444,
> +		.clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
> +		.clocks_sel_bits = BIT(13) | BIT(2),
> +	},
> +};
> +
>  static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc)
>  {
>  	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
> @@ -165,20 +180,21 @@ static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc)
>  	return zcrtc->vou;
>  }
>  
> -void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc)
> +void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc)
>  {
>  	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
>  	struct zx_vou_hw *vou = zcrtc->vou;
> +	struct vou_inf *inf = &vou_infs[id];
>  	bool is_main = zcrtc->chn_type == VOU_CHN_MAIN;
> -	u32 data_sel_shift = inf->id << 1;
> +	u32 data_sel_shift = id << 1;
>  
>  	/* Select data format */
>  	zx_writel_mask(vou->vouctl + VOU_INF_DATA_SEL, 0x3 << data_sel_shift,
>  		       inf->data_sel << data_sel_shift);
>  
>  	/* Select channel */
> -	zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << inf->id,
> -		       zcrtc->chn_type << inf->id);
> +	zx_writel_mask(vou->vouctl + VOU_INF_CH_SEL, 0x1 << id,
> +		       zcrtc->chn_type << id);
>  
>  	/* Select interface clocks */
>  	zx_writel_mask(vou->vouctl + VOU_CLK_SEL, inf->clocks_sel_bits,
> @@ -189,15 +205,16 @@ void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc)
>  		       inf->clocks_en_bits);
>  
>  	/* Enable the device */
> -	zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 1 << inf->id);
> +	zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 1 << id);
>  }
>  
> -void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc)
> +void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc)
>  {
>  	struct zx_vou_hw *vou = crtc_to_vou(crtc);
> +	struct vou_inf *inf = &vou_infs[id];
>  
>  	/* Disable the device */
> -	zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << inf->id, 0);
> +	zx_writel_mask(vou->vouctl + VOU_INF_EN, 1 << id, 0);
>  
>  	/* Disable interface clocks */
>  	zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 0);
> diff --git a/drivers/gpu/drm/zte/zx_vou.h b/drivers/gpu/drm/zte/zx_vou.h
> index 4b4339be641b..a41a0ad49857 100644
> --- a/drivers/gpu/drm/zte/zx_vou.h
> +++ b/drivers/gpu/drm/zte/zx_vou.h
> @@ -30,15 +30,8 @@ enum vou_inf_data_sel {
>  	VOU_RGB_666	= 3,
>  };
>  
> -struct vou_inf {
> -	enum vou_inf_id id;
> -	enum vou_inf_data_sel data_sel;
> -	u32 clocks_en_bits;
> -	u32 clocks_sel_bits;
> -};
> -
> -void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc);
> -void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc);
> +void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc);
> +void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc);
>  
>  int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe);
>  void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe);
> -- 
> 1.9.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Sean Paul, Software Engineer, Google / Chromium OS
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 3/5] drm: zte: add function to configure vou_ctrl dividers
  2017-01-19 16:24 ` [PATCH 3/5] drm: zte: add function to configure vou_ctrl dividers Shawn Guo
@ 2017-01-23 15:47   ` Sean Paul
  0 siblings, 0 replies; 15+ messages in thread
From: Sean Paul @ 2017-01-23 15:47 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Mark Rutland, devicetree, Daniel Vetter, Baoyou Xie, dri-devel,
	Rob Herring, Jun Nie

On Fri, Jan 20, 2017 at 12:24:58AM +0800, Shawn Guo wrote:
> From: Shawn Guo <shawn.guo@linaro.org>
> 
> The clock control module (CRM) cannot always provide desired frequency
> for all VOU output devices.  That's why VOU integrates a few dividers
> to further divide the clocks from CRM.  Let's add an interface for
> configuring these dividers.
> 

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
>  drivers/gpu/drm/zte/zx_vou.c      | 79 +++++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/zte/zx_vou.h      | 25 +++++++++++++
>  drivers/gpu/drm/zte/zx_vou_regs.h | 16 ++++++++
>  3 files changed, 120 insertions(+)
> 
> diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
> index c48704b4425a..98f0f51f9748 100644
> --- a/drivers/gpu/drm/zte/zx_vou.c
> +++ b/drivers/gpu/drm/zte/zx_vou.c
> @@ -72,6 +72,13 @@ struct zx_crtc_bits {
>  	u32 sec_vactive_mask;
>  	u32 interlace_select;
>  	u32 pi_enable;
> +	u32 div_vga_shift;
> +	u32 div_pic_shift;
> +	u32 div_tvenc_shift;
> +	u32 div_hdmi_pnx_shift;
> +	u32 div_hdmi_shift;
> +	u32 div_inf_shift;
> +	u32 div_layer_shift;
>  };
>  
>  static const struct zx_crtc_bits main_crtc_bits = {
> @@ -83,6 +90,13 @@ struct zx_crtc_bits {
>  	.sec_vactive_mask = SEC_VACT_MAIN_MASK,
>  	.interlace_select = MAIN_INTERLACE_SEL,
>  	.pi_enable = MAIN_PI_EN,
> +	.div_vga_shift = VGA_MAIN_DIV_SHIFT,
> +	.div_pic_shift = PIC_MAIN_DIV_SHIFT,
> +	.div_tvenc_shift = TVENC_MAIN_DIV_SHIFT,
> +	.div_hdmi_pnx_shift = HDMI_MAIN_PNX_DIV_SHIFT,
> +	.div_hdmi_shift = HDMI_MAIN_DIV_SHIFT,
> +	.div_inf_shift = INF_MAIN_DIV_SHIFT,
> +	.div_layer_shift = LAYER_MAIN_DIV_SHIFT,
>  };
>  
>  static const struct zx_crtc_bits aux_crtc_bits = {
> @@ -94,6 +108,13 @@ struct zx_crtc_bits {
>  	.sec_vactive_mask = SEC_VACT_AUX_MASK,
>  	.interlace_select = AUX_INTERLACE_SEL,
>  	.pi_enable = AUX_PI_EN,
> +	.div_vga_shift = VGA_AUX_DIV_SHIFT,
> +	.div_pic_shift = PIC_AUX_DIV_SHIFT,
> +	.div_tvenc_shift = TVENC_AUX_DIV_SHIFT,
> +	.div_hdmi_pnx_shift = HDMI_AUX_PNX_DIV_SHIFT,
> +	.div_hdmi_shift = HDMI_AUX_DIV_SHIFT,
> +	.div_inf_shift = INF_AUX_DIV_SHIFT,
> +	.div_layer_shift = LAYER_AUX_DIV_SHIFT,
>  };
>  
>  struct zx_crtc {
> @@ -220,6 +241,64 @@ void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc)
>  	zx_writel_mask(vou->vouctl + VOU_CLK_EN, inf->clocks_en_bits, 0);
>  }
>  
> +void zx_vou_config_dividers(struct drm_crtc *crtc,
> +			    struct vou_div_config *configs, int num)
> +{
> +	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
> +	struct zx_vou_hw *vou = zcrtc->vou;
> +	const struct zx_crtc_bits *bits = zcrtc->bits;
> +	int i;
> +
> +	/* Clear update flag bit */
> +	zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE, 0);
> +
> +	for (i = 0; i < num; i++) {
> +		struct vou_div_config *cfg = configs + i;
> +		u32 reg, shift;
> +
> +		switch (cfg->id) {
> +		case VOU_DIV_VGA:
> +			reg = VOU_CLK_SEL;
> +			shift = bits->div_vga_shift;
> +			break;
> +		case VOU_DIV_PIC:
> +			reg = VOU_CLK_SEL;
> +			shift = bits->div_pic_shift;
> +			break;
> +		case VOU_DIV_TVENC:
> +			reg = VOU_DIV_PARA;
> +			shift = bits->div_tvenc_shift;
> +			break;
> +		case VOU_DIV_HDMI_PNX:
> +			reg = VOU_DIV_PARA;
> +			shift = bits->div_hdmi_pnx_shift;
> +			break;
> +		case VOU_DIV_HDMI:
> +			reg = VOU_DIV_PARA;
> +			shift = bits->div_hdmi_shift;
> +			break;
> +		case VOU_DIV_INF:
> +			reg = VOU_DIV_PARA;
> +			shift = bits->div_inf_shift;
> +			break;
> +		case VOU_DIV_LAYER:
> +			reg = VOU_DIV_PARA;
> +			shift = bits->div_layer_shift;
> +			break;
> +		default:
> +			continue;
> +		}
> +
> +		/* Each divider occupies 3 bits */
> +		zx_writel_mask(vou->vouctl + reg, 0x7 << shift,
> +			       cfg->val << shift);
> +	}
> +
> +	/* Set update flag bit to get dividers effected */
> +	zx_writel_mask(vou->vouctl + VOU_DIV_PARA, DIV_PARA_UPDATE,
> +		       DIV_PARA_UPDATE);
> +}
> +
>  static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
>  {
>  	zx_writel(zcrtc->chnreg + CHN_UPDATE, 1);
> diff --git a/drivers/gpu/drm/zte/zx_vou.h b/drivers/gpu/drm/zte/zx_vou.h
> index a41a0ad49857..0dae4faefac4 100644
> --- a/drivers/gpu/drm/zte/zx_vou.h
> +++ b/drivers/gpu/drm/zte/zx_vou.h
> @@ -33,6 +33,31 @@ enum vou_inf_data_sel {
>  void vou_inf_enable(enum vou_inf_id id, struct drm_crtc *crtc);
>  void vou_inf_disable(enum vou_inf_id id, struct drm_crtc *crtc);
>  
> +enum vou_div_id {
> +	VOU_DIV_VGA,
> +	VOU_DIV_PIC,
> +	VOU_DIV_TVENC,
> +	VOU_DIV_HDMI_PNX,
> +	VOU_DIV_HDMI,
> +	VOU_DIV_INF,
> +	VOU_DIV_LAYER,
> +};
> +
> +enum vou_div_val {
> +	VOU_DIV_1 = 0,
> +	VOU_DIV_2 = 1,
> +	VOU_DIV_4 = 3,
> +	VOU_DIV_8 = 7,
> +};
> +
> +struct vou_div_config {
> +	enum vou_div_id id;
> +	enum vou_div_val val;
> +};
> +
> +void zx_vou_config_dividers(struct drm_crtc *crtc,
> +			    struct vou_div_config *configs, int num);
> +
>  int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe);
>  void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe);
>  
> diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h
> index e6ed844e068a..552772137cf0 100644
> --- a/drivers/gpu/drm/zte/zx_vou_regs.h
> +++ b/drivers/gpu/drm/zte/zx_vou_regs.h
> @@ -176,11 +176,27 @@
>  #define VOU_INF_DATA_SEL		0x08
>  #define VOU_SOFT_RST			0x14
>  #define VOU_CLK_SEL			0x18
> +#define VGA_AUX_DIV_SHIFT		29
> +#define VGA_MAIN_DIV_SHIFT		26
> +#define PIC_MAIN_DIV_SHIFT		23
> +#define PIC_AUX_DIV_SHIFT		20
>  #define VOU_CLK_VL2_SEL			BIT(8)
>  #define VOU_CLK_VL1_SEL			BIT(7)
>  #define VOU_CLK_VL0_SEL			BIT(6)
>  #define VOU_CLK_GL1_SEL			BIT(5)
>  #define VOU_CLK_GL0_SEL			BIT(4)
> +#define VOU_DIV_PARA			0x1c
> +#define DIV_PARA_UPDATE			BIT(31)
> +#define TVENC_AUX_DIV_SHIFT		28
> +#define HDMI_AUX_PNX_DIV_SHIFT		25
> +#define HDMI_MAIN_PNX_DIV_SHIFT		22
> +#define HDMI_AUX_DIV_SHIFT		19
> +#define HDMI_MAIN_DIV_SHIFT		16
> +#define TVENC_MAIN_DIV_SHIFT		13
> +#define INF_AUX_DIV_SHIFT		9
> +#define INF_MAIN_DIV_SHIFT		6
> +#define LAYER_AUX_DIV_SHIFT		3
> +#define LAYER_MAIN_DIV_SHIFT		0
>  #define VOU_CLK_REQEN			0x20
>  #define VOU_CLK_EN			0x24
>  
> -- 
> 1.9.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Sean Paul, Software Engineer, Google / Chromium OS
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 5/5] drm: zte: add tvenc driver support
  2017-01-19 16:25 ` [PATCH 5/5] drm: zte: add tvenc driver support Shawn Guo
@ 2017-01-23 16:10   ` Sean Paul
       [not found]     ` <20170123161034.GE19505-6JpoNmjd1+aEBhuJAZrboHoUN1GumTyQ7j82oEJ37pA@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Sean Paul @ 2017-01-23 16:10 UTC (permalink / raw)
  To: Shawn Guo
  Cc: Mark Rutland, devicetree, Daniel Vetter, Baoyou Xie, dri-devel,
	Rob Herring, Jun Nie

On Fri, Jan 20, 2017 at 12:25:00AM +0800, Shawn Guo wrote:
> From: Shawn Guo <shawn.guo@linaro.org>
> 
> It adds the TV Encoder driver to support video output in PAL and NTSC
> format.  The driver uses syscon/regmap interface to configure register
> bit sitting in SYSCTRL module for DAC power control.
> 
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
>  drivers/gpu/drm/zte/Makefile        |   1 +
>  drivers/gpu/drm/zte/zx_drm_drv.c    |   1 +
>  drivers/gpu/drm/zte/zx_drm_drv.h    |   1 +
>  drivers/gpu/drm/zte/zx_tvenc.c      | 416 ++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/zte/zx_tvenc_regs.h |  31 +++
>  drivers/gpu/drm/zte/zx_vou.c        |   5 +
>  6 files changed, 455 insertions(+)
>  create mode 100644 drivers/gpu/drm/zte/zx_tvenc.c
>  create mode 100644 drivers/gpu/drm/zte/zx_tvenc_regs.h
> 
> diff --git a/drivers/gpu/drm/zte/Makefile b/drivers/gpu/drm/zte/Makefile
> index 699180bfd57c..01352b56c418 100644
> --- a/drivers/gpu/drm/zte/Makefile
> +++ b/drivers/gpu/drm/zte/Makefile
> @@ -2,6 +2,7 @@ zxdrm-y := \
>  	zx_drm_drv.o \
>  	zx_hdmi.o \
>  	zx_plane.o \
> +	zx_tvenc.o \
>  	zx_vou.o
>  
>  obj-$(CONFIG_DRM_ZTE) += zxdrm.o
> diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c
> index 3e76f72c92ff..13081fed902d 100644
> --- a/drivers/gpu/drm/zte/zx_drm_drv.c
> +++ b/drivers/gpu/drm/zte/zx_drm_drv.c
> @@ -247,6 +247,7 @@ static int zx_drm_remove(struct platform_device *pdev)
>  static struct platform_driver *drivers[] = {
>  	&zx_crtc_driver,
>  	&zx_hdmi_driver,
> +	&zx_tvenc_driver,
>  	&zx_drm_platform_driver,
>  };
>  
> diff --git a/drivers/gpu/drm/zte/zx_drm_drv.h b/drivers/gpu/drm/zte/zx_drm_drv.h
> index e65cd18a6cba..5ca035b079c7 100644
> --- a/drivers/gpu/drm/zte/zx_drm_drv.h
> +++ b/drivers/gpu/drm/zte/zx_drm_drv.h
> @@ -13,6 +13,7 @@
>  
>  extern struct platform_driver zx_crtc_driver;
>  extern struct platform_driver zx_hdmi_driver;
> +extern struct platform_driver zx_tvenc_driver;
>  
>  static inline u32 zx_readl(void __iomem *reg)
>  {
> diff --git a/drivers/gpu/drm/zte/zx_tvenc.c b/drivers/gpu/drm/zte/zx_tvenc.c
> new file mode 100644
> index 000000000000..5a6cff1ff8a8
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_tvenc.c
> @@ -0,0 +1,416 @@
> +/*
> + * Copyright 2017 Linaro Ltd.
> + * Copyright 2017 ZTE Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/regmap.h>
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drmP.h>
> +
> +#include "zx_drm_drv.h"
> +#include "zx_tvenc_regs.h"
> +#include "zx_vou.h"
> +
> +struct zx_tvenc_pwrctrl {
> +	struct regmap *regmap;
> +	u32 reg;
> +	u32 mask;
> +};
> +
> +struct zx_tvenc {
> +	struct drm_connector connector;
> +	struct drm_encoder encoder;
> +	struct device *dev;
> +	void __iomem *mmio;
> +	const struct vou_inf *inf;
> +	struct zx_tvenc_pwrctrl pwrctrl;
> +};
> +
> +#define to_zx_tvenc(x) container_of(x, struct zx_tvenc, x)
> +
> +struct zx_tvenc_mode {
> +	char *name;
> +	u32 hdisplay;
> +	u32 vdisplay;
> +	u32 hfp;
> +	u32 hbp;
> +	u32 hsw;
> +	u32 vfp;
> +	u32 vbp;
> +	u32 vsw;

Let's not duplicate these fields and do conversions. I think you should embed a
drm_display_mode struct here instead and just return it in get_modes. Check out
panel_desc in drivers/gpu/drm/panel/panel-simple.c, I think you can do something
similar here.

> +	u32 video_info;
> +	u32 video_res;
> +	u32 field1_param;
> +	u32 field2_param;
> +	u32 burst_line_odd1;
> +	u32 burst_line_even1;
> +	u32 burst_line_odd2;
> +	u32 burst_line_even2;
> +	u32 line_timing_param;
> +	u32 weight_value;
> +	u32 blank_black_level;
> +	u32 burst_level;
> +	u32 control_param;
> +	u32 sub_carrier_phase1;
> +	u32 phase_line_incr_cvbs;
> +};
> +
> +static const struct zx_tvenc_mode tvenc_modes[] = {
> +	{
> +		.name = "PAL",
> +		.hdisplay = 720,
> +		.vdisplay = 576,
> +		.hfp = 12,
> +		.hbp = 130,
> +		.hsw = 2,
> +		.vfp = 2,
> +		.vbp = 20,
> +		.vsw = 2,
> +		.video_info = 0x00040040,
> +		.video_res = 0x05a9c760,
> +		.field1_param = 0x0004d416,
> +		.field2_param = 0x0009b94f,
> +		.burst_line_odd1 = 0x0004d406,
> +		.burst_line_even1 = 0x0009b53e,
> +		.burst_line_odd2 = 0x0004d805,
> +		.burst_line_even2 = 0x0009b93f,
> +		.line_timing_param = 0x06a96fdf,
> +		.weight_value = 0x00c188a0,
> +		.blank_black_level = 0x0000fcfc,
> +		.burst_level = 0x00001595,
> +		.control_param = 0x00000001,
> +		.sub_carrier_phase1 = 0x1504c566,
> +		.phase_line_incr_cvbs = 0xc068db8c,

I don't suppose you can derive these magic values from the mode?

> +	}, {
> +		.name = "NTSC",
> +		.hdisplay = 720,
> +		.vdisplay = 480,
> +		.hfp = 16,
> +		.hbp = 120,
> +		.hsw = 2,
> +		.vfp = 3,
> +		.vbp = 17,
> +		.vsw = 2,
> +		.video_info = 0x00040080,
> +		.video_res = 0x05a8375a,
> +		.field1_param = 0x00041817,
> +		.field2_param = 0x0008351e,
> +		.burst_line_odd1 = 0x00041006,
> +		.burst_line_even1 = 0x0008290d,
> +		.burst_line_odd2 = 0x00000000,
> +		.burst_line_even2 = 0x00000000,
> +		.line_timing_param = 0x06a8ef9e,
> +		.weight_value = 0x00b68197,
> +		.blank_black_level = 0x0000f0f0,
> +		.burst_level = 0x0000009c,
> +		.control_param = 0x00000001,
> +		.sub_carrier_phase1 = 0x10f83e10,
> +		.phase_line_incr_cvbs = 0x80000000,
> +	},
> +};
> +
> +static const struct zx_tvenc_mode *
> +zx_tvenc_find_zmode(struct drm_display_mode *mode)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(tvenc_modes); i++) {
> +		const struct zx_tvenc_mode *zmode = &tvenc_modes[i];
> +
> +		if (!strcmp(mode->name, zmode->name))

drm_mode_equal() is your friend

> +			return zmode;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void zx_tvenc_encoder_mode_set(struct drm_encoder *encoder,
> +				      struct drm_display_mode *mode,
> +				      struct drm_display_mode *adj_mode)
> +{
> +	struct zx_tvenc *tvenc = to_zx_tvenc(encoder);
> +	const struct zx_tvenc_mode *zmode;
> +	struct vou_div_config configs[] = {
> +		{ VOU_DIV_INF,   VOU_DIV_4 },
> +		{ VOU_DIV_TVENC, VOU_DIV_1 },
> +		{ VOU_DIV_LAYER, VOU_DIV_2 },
> +	};
> +
> +	zx_vou_config_dividers(encoder->crtc, configs, ARRAY_SIZE(configs));
> +
> +	zmode = zx_tvenc_find_zmode(mode);
> +	if (!zmode) {
> +		DRM_DEV_ERROR(tvenc->dev, "failed to find zmode\n");
> +		return;
> +	}
> +
> +	zx_writel(tvenc->mmio + VENC_VIDEO_INFO, zmode->video_info);
> +	zx_writel(tvenc->mmio + VENC_VIDEO_RES, zmode->video_res);
> +	zx_writel(tvenc->mmio + VENC_FIELD1_PARAM, zmode->field1_param);
> +	zx_writel(tvenc->mmio + VENC_FIELD2_PARAM, zmode->field2_param);
> +	zx_writel(tvenc->mmio + VENC_LINE_O_1, zmode->burst_line_odd1);
> +	zx_writel(tvenc->mmio + VENC_LINE_E_1, zmode->burst_line_even1);
> +	zx_writel(tvenc->mmio + VENC_LINE_O_2, zmode->burst_line_odd2);
> +	zx_writel(tvenc->mmio + VENC_LINE_E_2, zmode->burst_line_even2);
> +	zx_writel(tvenc->mmio + VENC_LINE_TIMING_PARAM,
> +		  zmode->line_timing_param);
> +	zx_writel(tvenc->mmio + VENC_WEIGHT_VALUE, zmode->weight_value);
> +	zx_writel(tvenc->mmio + VENC_BLANK_BLACK_LEVEL,
> +		  zmode->blank_black_level);
> +	zx_writel(tvenc->mmio + VENC_BURST_LEVEL, zmode->burst_level);
> +	zx_writel(tvenc->mmio + VENC_CONTROL_PARAM, zmode->control_param);
> +	zx_writel(tvenc->mmio + VENC_SUB_CARRIER_PHASE1,
> +		  zmode->sub_carrier_phase1);
> +	zx_writel(tvenc->mmio + VENC_PHASE_LINE_INCR_CVBS,
> +		  zmode->phase_line_incr_cvbs);
> +}
> +
> +static void zx_tvenc_encoder_enable(struct drm_encoder *encoder)
> +{
> +	struct zx_tvenc *tvenc = to_zx_tvenc(encoder);
> +	struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl;
> +
> +	/* Set bit to power up TVENC DAC */
> +	regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask,
> +			   pwrctrl->mask);
> +
> +	vou_inf_enable(VOU_TV_ENC, encoder->crtc);
> +
> +	zx_writel(tvenc->mmio + VENC_ENABLE, 1);
> +}
> +
> +static void zx_tvenc_encoder_disable(struct drm_encoder *encoder)
> +{
> +	struct zx_tvenc *tvenc = to_zx_tvenc(encoder);
> +	struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl;
> +
> +	zx_writel(tvenc->mmio + VENC_ENABLE, 0);
> +
> +	vou_inf_disable(VOU_TV_ENC, encoder->crtc);
> +
> +	/* Clear bit to power down TVENC DAC */
> +	regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask, 0);
> +}
> +
> +static const struct drm_encoder_helper_funcs zx_tvenc_encoder_helper_funcs = {
> +	.enable	= zx_tvenc_encoder_enable,
> +	.disable = zx_tvenc_encoder_disable,
> +	.mode_set = zx_tvenc_encoder_mode_set,
> +};
> +
> +static const struct drm_encoder_funcs zx_tvenc_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
> +static void zx_tvenc_mode_to_drm_mode(const struct zx_tvenc_mode *zmode,
> +				      struct drm_display_mode *mode)
> +{
> +	strcpy(mode->name, zmode->name);

Consider drm_mode_set_name() instead of rolling your own names

> +
> +	mode->type = DRM_MODE_TYPE_DRIVER;
> +	mode->flags = DRM_MODE_FLAG_INTERLACE;
> +	mode->flags |= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC;
> +
> +	/*
> +	 * The CRM cannot directly provide such a low rate, and we have to
> +	 * ask a multiflied rate from CRM and use the divider in VOU to get

s/multified/multiplied/

> +	 * the disired one.

s/disired/desired/

> +	 */
> +	mode->clock = 13500 * 4;

I don't think this should be hardcoded at runtime, stick it in the modes above

> +
> +	mode->hdisplay = zmode->hdisplay;
> +	mode->hsync_start = mode->hdisplay + zmode->hfp;
> +	mode->hsync_end = mode->hsync_start + zmode->hsw;
> +	mode->htotal = mode->hsync_end + zmode->hbp;
> +
> +	mode->vdisplay = zmode->vdisplay;
> +	mode->vsync_start = mode->vdisplay + zmode->vfp;
> +	mode->vsync_end = mode->vsync_start + zmode->vsw;
> +	mode->vtotal = mode->vsync_end + zmode->vbp;
> +}
> +
> +static int zx_tvenc_connector_get_modes(struct drm_connector *connector)
> +{
> +	struct zx_tvenc *tvenc = to_zx_tvenc(connector);
> +	struct device *dev = tvenc->dev;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(tvenc_modes); i++) {
> +		struct drm_display_mode *mode;
> +		const struct zx_tvenc_mode *zmode = &tvenc_modes[i];
> +
> +		mode = drm_mode_create(connector->dev);
> +		if (!mode) {
> +			DRM_DEV_ERROR(dev, "failed to create drm mode\n");
> +			return 0;
> +		}
> +
> +		zx_tvenc_mode_to_drm_mode(zmode, mode);
> +		drm_mode_probed_add(connector, mode);
> +	}
> +
> +	return i;
> +}
> +
> +static enum drm_mode_status
> +zx_tvenc_connector_mode_valid(struct drm_connector *connector,
> +			      struct drm_display_mode *mode)
> +{

You probably want to do a sanity check to ensure the mode is in your list above
(and not user-submitted).

> +	return MODE_OK;
> +}
> +
> +static struct drm_connector_helper_funcs zx_tvenc_connector_helper_funcs = {
> +	.get_modes = zx_tvenc_connector_get_modes,
> +	.mode_valid = zx_tvenc_connector_mode_valid,
> +};
> +
> +static const struct drm_connector_funcs zx_tvenc_connector_funcs = {
> +	.dpms = drm_atomic_helper_connector_dpms,
> +	.fill_modes = drm_helper_probe_single_connector_modes,
> +	.destroy = drm_connector_cleanup,
> +	.reset = drm_atomic_helper_connector_reset,
> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static int zx_tvenc_register(struct drm_device *drm, struct zx_tvenc *tvenc)
> +{
> +	struct drm_encoder *encoder = &tvenc->encoder;
> +	struct drm_connector *connector = &tvenc->connector;
> +
> +	/*
> +	 * The tvenc is designed to use aux channel, as there is a deflicker
> +	 * block for the channel.
> +	 */
> +	encoder->possible_crtcs = BIT(1);
> +
> +	drm_encoder_init(drm, encoder, &zx_tvenc_encoder_funcs,
> +			 DRM_MODE_ENCODER_TVDAC, NULL);
> +	drm_encoder_helper_add(encoder, &zx_tvenc_encoder_helper_funcs);
> +
> +	connector->interlace_allowed = true;
> +
> +	drm_connector_init(drm, connector, &zx_tvenc_connector_funcs,
> +			   DRM_MODE_CONNECTOR_Composite);
> +	drm_connector_helper_add(connector, &zx_tvenc_connector_helper_funcs);
> +
> +	drm_mode_connector_attach_encoder(connector, encoder);
> +
> +	return 0;
> +}
> +
> +static int zx_tvenc_pwrctrl_init(struct zx_tvenc *tvenc)
> +{
> +	struct zx_tvenc_pwrctrl *pwrctrl = &tvenc->pwrctrl;
> +	struct device *dev = tvenc->dev;
> +	struct of_phandle_args out_args;
> +	struct regmap *regmap;
> +	int ret;
> +
> +	ret = of_parse_phandle_with_fixed_args(dev->of_node,
> +				"zte,tvenc-power-control", 2, 0, &out_args);
> +	if (ret)
> +		return ret;
> +
> +	regmap = syscon_node_to_regmap(out_args.np);
> +	if (IS_ERR(regmap)) {
> +		ret = PTR_ERR(regmap);
> +		goto out;
> +	}
> +
> +	pwrctrl->regmap = regmap;
> +	pwrctrl->reg = out_args.args[0];
> +	pwrctrl->mask = out_args.args[1];
> +
> +out:
> +	of_node_put(out_args.np);
> +	return ret;
> +}
> +
> +static int zx_tvenc_bind(struct device *dev, struct device *master, void *data)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct drm_device *drm = data;
> +	struct resource *res;
> +	struct zx_tvenc *tvenc;
> +	int ret;
> +
> +	tvenc = devm_kzalloc(dev, sizeof(*tvenc), GFP_KERNEL);
> +	if (!tvenc)
> +		return -ENOMEM;
> +
> +	tvenc->dev = dev;
> +	dev_set_drvdata(dev, tvenc);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	tvenc->mmio = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(tvenc->mmio)) {
> +		ret = PTR_ERR(tvenc->mmio);
> +		DRM_DEV_ERROR(dev, "failed to remap tvenc region: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = zx_tvenc_pwrctrl_init(tvenc);
> +	if (ret) {
> +		DRM_DEV_ERROR(dev, "failed to init power control: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = zx_tvenc_register(drm, tvenc);
> +	if (ret) {
> +		DRM_DEV_ERROR(dev, "failed to register tvenc: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void zx_tvenc_unbind(struct device *dev, struct device *master,
> +			    void *data)
> +{
> +	struct zx_tvenc *tvenc = dev_get_drvdata(dev);
> +
> +	tvenc->connector.funcs->destroy(&tvenc->connector);
> +	tvenc->encoder.funcs->destroy(&tvenc->encoder);

I think drm_mode_config_cleanup() should take care of calling these

> +}
> +
> +static const struct component_ops zx_tvenc_component_ops = {
> +	.bind = zx_tvenc_bind,
> +	.unbind = zx_tvenc_unbind,
> +};
> +
> +static int zx_tvenc_probe(struct platform_device *pdev)
> +{
> +	return component_add(&pdev->dev, &zx_tvenc_component_ops);
> +}
> +
> +static int zx_tvenc_remove(struct platform_device *pdev)
> +{
> +	component_del(&pdev->dev, &zx_tvenc_component_ops);
> +	return 0;
> +}
> +
> +static const struct of_device_id zx_tvenc_of_match[] = {
> +	{ .compatible = "zte,zx296718-tvenc", },
> +	{ /* end */ },
> +};
> +MODULE_DEVICE_TABLE(of, zx_tvenc_of_match);
> +
> +struct platform_driver zx_tvenc_driver = {
> +	.probe = zx_tvenc_probe,
> +	.remove = zx_tvenc_remove,
> +	.driver	= {
> +		.name = "zx-tvenc",
> +		.of_match_table	= zx_tvenc_of_match,
> +	},
> +};
> diff --git a/drivers/gpu/drm/zte/zx_tvenc_regs.h b/drivers/gpu/drm/zte/zx_tvenc_regs.h
> new file mode 100644
> index 000000000000..bd91f5dcc1f3
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_tvenc_regs.h
> @@ -0,0 +1,31 @@
> +/*
> + * Copyright 2017 Linaro Ltd.
> + * Copyright 2017 ZTE Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef __ZX_TVENC_REGS_H__
> +#define __ZX_TVENC_REGS_H__
> +
> +#define VENC_VIDEO_INFO			0x04
> +#define VENC_VIDEO_RES			0x08
> +#define VENC_FIELD1_PARAM		0x10
> +#define VENC_FIELD2_PARAM		0x14
> +#define VENC_LINE_O_1			0x18
> +#define VENC_LINE_E_1			0x1c
> +#define VENC_LINE_O_2			0x20
> +#define VENC_LINE_E_2			0x24
> +#define VENC_LINE_TIMING_PARAM		0x28
> +#define VENC_WEIGHT_VALUE		0x2c
> +#define VENC_BLANK_BLACK_LEVEL		0x30
> +#define VENC_BURST_LEVEL		0x34
> +#define VENC_CONTROL_PARAM		0x3c
> +#define VENC_SUB_CARRIER_PHASE1		0x40
> +#define VENC_PHASE_LINE_INCR_CVBS	0x48
> +#define VENC_ENABLE			0xa8
> +
> +#endif /* __ZX_TVENC_REGS_H__ */
> diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
> index 98f0f51f9748..61d4ff709d83 100644
> --- a/drivers/gpu/drm/zte/zx_vou.c
> +++ b/drivers/gpu/drm/zte/zx_vou.c
> @@ -192,6 +192,11 @@ struct vou_inf {
>  		.clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
>  		.clocks_sel_bits = BIT(13) | BIT(2),
>  	},
> +	[VOU_TV_ENC] = {
> +		.data_sel = VOU_YUV444,
> +		.clocks_en_bits = BIT(15),
> +		.clocks_sel_bits = BIT(11) | BIT(0),
> +	},
>  };
>  
>  static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc)
> -- 
> 1.9.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Sean Paul, Software Engineer, Google / Chromium OS
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/5] drm: zte: add interlace mode support
       [not found]       ` <20170123151901.GA19505-6JpoNmjd1+aEBhuJAZrboHoUN1GumTyQ7j82oEJ37pA@public.gmane.org>
@ 2017-01-26  3:14         ` Shawn Guo
  0 siblings, 0 replies; 15+ messages in thread
From: Shawn Guo @ 2017-01-26  3:14 UTC (permalink / raw)
  To: Sean Paul
  Cc: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW, Mark Rutland,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Daniel Vetter, Baoyou Xie,
	Rob Herring, Jun Nie

Hi Sean,

Thanks for reviewing the patches.

On Mon, Jan 23, 2017 at 10:19:01AM -0500, Sean Paul wrote:
> On Fri, Jan 20, 2017 at 12:24:56AM +0800, Shawn Guo wrote:
> > From: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> > 
> > It adds interlace mode support in VOU TIMING_CTRL and channel control
> > block, so that VOU driver gets ready to support output device in
> > interlace mode like TV Encoder.
> > 
> > Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> > ---
> >  drivers/gpu/drm/zte/zx_vou.c      | 53 +++++++++++++++++++++++++++++++++++++--
> >  drivers/gpu/drm/zte/zx_vou_regs.h | 15 +++++++++++
> >  2 files changed, 66 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/zte/zx_vou.c b/drivers/gpu/drm/zte/zx_vou.c
> > index 3056b41df518..8c4f0e2885f3 100644
> > --- a/drivers/gpu/drm/zte/zx_vou.c
> > +++ b/drivers/gpu/drm/zte/zx_vou.c
> 
> <snip>
> 
> > @@ -196,19 +211,26 @@ static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
> >  static void zx_crtc_enable(struct drm_crtc *crtc)
> >  {
> >  	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> > +	bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
> >  	struct zx_crtc *zcrtc = to_zx_crtc(crtc);
> >  	struct zx_vou_hw *vou = zcrtc->vou;
> >  	const struct zx_crtc_regs *regs = zcrtc->regs;
> >  	const struct zx_crtc_bits *bits = zcrtc->bits;
> >  	struct videomode vm;
> > +	u32 vactive;
> >  	u32 pol = 0;
> >  	u32 val;
> > +	u32 mask;
> >  	int ret;
> >  
> >  	drm_display_mode_to_videomode(mode, &vm);
> >  
> >  	/* Set up timing parameters */
> > -	val = V_ACTIVE(vm.vactive - 1);
> > +	vactive = vm.vactive;
> > +	if (interlaced)
> > +		vactive /= 2;
> > +
> > +	val = V_ACTIVE(vactive - 1);
> 
> Instead of introducing a new var, I think you can get away with:
> 
> if (interlaced)
>         val = V_ACTIVE(vm.vactive / 2);
> else
>         val = V_ACTIVE(vm.vactive - 1);

The variable is used by SEC_V_ACTIVE register setup below as well.  But
yeah, I admit this additional variable makes the code even harder for
readers.  I will kill it by having interlaced case check where
necessary.

> 
> 
> >  	val |= H_ACTIVE(vm.hactive - 1);
> >  	zx_writel(vou->timing + regs->fir_active, val);
> >  
> > @@ -222,6 +244,22 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
> >  	val |= FRONT_PORCH(vm.vfront_porch - 1);
> >  	zx_writel(vou->timing + regs->fir_vtiming, val);
> >  
> > +	if (interlaced) {
> > +		u32 shift = bits->sec_vactive_shift;
> > +		u32 mask = bits->sec_vactive_mask;
> 
> mask is already defined at the function scope

Right.  I will rename the one in function scope to avoid the confusion.

> 
> > +
> > +		val = zx_readl(vou->timing + SEC_V_ACTIVE);
> > +		val &= ~mask;
> > +		val |= ((vactive - 1) << shift) & mask;
> > +		zx_writel(vou->timing + SEC_V_ACTIVE, val);
> > +
> > +		val = SYNC_WIDE(vm.vsync_len - 1);
> > +		/* sec_vbp = fir_vbp + 1 */
> 
> Looks like leftover kruft here.

It's actually a comment which seems to be only understandable by
myself :)  I will write up some proper text for it.

> 
> > +		val |= BACK_PORCH(vm.vback_porch);
> > +		val |= FRONT_PORCH(vm.vfront_porch - 1);
> > +		zx_writel(vou->timing + regs->sec_vtiming, val);
> > +	}
> > +
> >  	/* Set up polarities */
> >  	if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW)
> >  		pol |= 1 << POL_VSYNC_SHIFT;
> > @@ -232,9 +270,16 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
> >  		       pol << bits->polarity_shift);
> >  
> >  	/* Setup SHIFT register by following what ZTE BSP does */
> > -	zx_writel(vou->timing + regs->timing_shift, H_SHIFT_VAL);
> > +	val = H_SHIFT_VAL;
> > +	if (interlaced)
> > +		val |= V_SHIFT_VAL << 16;
> > +	zx_writel(vou->timing + regs->timing_shift, val);
> >  	zx_writel(vou->timing + regs->timing_pi_shift, H_PI_SHIFT_VAL);
> >  
> > +	/* Progressive or interlace scan select */
> > +	mask = bits->interlace_select | bits->pi_enable;
> > +	zx_writel_mask(vou->timing + SCAN_CTRL, mask, interlaced ? mask : 0);
> > +
> >  	/* Enable TIMING_CTRL */
> >  	zx_writel_mask(vou->timing + TIMING_TC_ENABLE, bits->tc_enable,
> >  		       bits->tc_enable);
> > @@ -245,6 +290,10 @@ static void zx_crtc_enable(struct drm_crtc *crtc)
> >  	zx_writel_mask(zcrtc->chnreg + CHN_CTRL1, CHN_SCREEN_H_MASK,
> >  		       vm.vactive << CHN_SCREEN_H_SHIFT);
> >  
> > +	/* Configure channel interlace buffer control */
> > +	zx_writel_mask(zcrtc->chnreg + CHN_INTERLACE_BUF_CTRL, CHN_INTERLACE_EN,
> > +		       interlaced ? CHN_INTERLACE_EN : 0);
> > +
> >  	/* Update channel */
> >  	vou_chn_set_update(zcrtc);
> >  
> > diff --git a/drivers/gpu/drm/zte/zx_vou_regs.h b/drivers/gpu/drm/zte/zx_vou_regs.h
> > index 193c1ce01fe7..e6ed844e068a 100644
> > --- a/drivers/gpu/drm/zte/zx_vou_regs.h
> > +++ b/drivers/gpu/drm/zte/zx_vou_regs.h
> > @@ -75,6 +75,8 @@
> >  #define CHN_SCREEN_H_SHIFT		5
> >  #define CHN_SCREEN_H_MASK		(0x1fff << CHN_SCREEN_H_SHIFT)
> >  #define CHN_UPDATE			0x08
> > +#define CHN_INTERLACE_BUF_CTRL		0x24
> 
> Maybe it's my email reader, but it seems like there's an alignment issue here.

It's indeed your email reader.

Shawn

> 
> > +#define CHN_INTERLACE_EN		BIT(2)
> >  
> >  /* TIMING_CTRL registers */
> >  #define TIMING_TC_ENABLE		0x04
> > @@ -117,6 +119,19 @@
> >  #define TIMING_MAIN_SHIFT		0x2c
> >  #define TIMING_AUX_SHIFT		0x30
> >  #define H_SHIFT_VAL			0x0048
> > +#define V_SHIFT_VAL			0x0001
> > +#define SCAN_CTRL			0x34
> > +#define AUX_PI_EN			BIT(19)
> > +#define MAIN_PI_EN			BIT(18)
> > +#define AUX_INTERLACE_SEL		BIT(1)
> > +#define MAIN_INTERLACE_SEL		BIT(0)
> > +#define SEC_V_ACTIVE			0x38
> > +#define SEC_VACT_MAIN_SHIFT		0
> > +#define SEC_VACT_MAIN_MASK		(0xffff << SEC_VACT_MAIN_SHIFT)
> > +#define SEC_VACT_AUX_SHIFT		16
> > +#define SEC_VACT_AUX_MASK		(0xffff << SEC_VACT_AUX_SHIFT)
> > +#define SEC_MAIN_V_TIMING		0x3c
> > +#define SEC_AUX_V_TIMING		0x40
> >  #define TIMING_MAIN_PI_SHIFT		0x68
> >  #define TIMING_AUX_PI_SHIFT		0x6c
> >  #define H_PI_SHIFT_VAL			0x000f
> > -- 
> > 1.9.1
> > 
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 5/5] drm: zte: add tvenc driver support
       [not found]     ` <20170123161034.GE19505-6JpoNmjd1+aEBhuJAZrboHoUN1GumTyQ7j82oEJ37pA@public.gmane.org>
@ 2017-01-26 15:06       ` Shawn Guo
  0 siblings, 0 replies; 15+ messages in thread
From: Shawn Guo @ 2017-01-26 15:06 UTC (permalink / raw)
  To: Sean Paul
  Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA, Daniel Vetter,
	Baoyou Xie, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	Rob Herring, Jun Nie

On Mon, Jan 23, 2017 at 11:10:34AM -0500, Sean Paul wrote:
> > +static const struct zx_tvenc_mode tvenc_modes[] = {
> > +	{
> > +		.name = "PAL",
> > +		.hdisplay = 720,
> > +		.vdisplay = 576,
> > +		.hfp = 12,
> > +		.hbp = 130,
> > +		.hsw = 2,
> > +		.vfp = 2,
> > +		.vbp = 20,
> > +		.vsw = 2,
> > +		.video_info = 0x00040040,
> > +		.video_res = 0x05a9c760,
> > +		.field1_param = 0x0004d416,
> > +		.field2_param = 0x0009b94f,
> > +		.burst_line_odd1 = 0x0004d406,
> > +		.burst_line_even1 = 0x0009b53e,
> > +		.burst_line_odd2 = 0x0004d805,
> > +		.burst_line_even2 = 0x0009b93f,
> > +		.line_timing_param = 0x06a96fdf,
> > +		.weight_value = 0x00c188a0,
> > +		.blank_black_level = 0x0000fcfc,
> > +		.burst_level = 0x00001595,
> > +		.control_param = 0x00000001,
> > +		.sub_carrier_phase1 = 0x1504c566,
> > +		.phase_line_incr_cvbs = 0xc068db8c,
> 
> I don't suppose you can derive these magic values from the mode?

No, we have no way to derive these register values from the mode
parameters.  The registers contain a lot of hardware specific
configurations which need to be set up differently per PAL or NTSC.

All other comments will be addressed in v2.  Thanks for the review
effort.

Shawn
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2017-01-26 15:06 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-19 16:24 [PATCH 0/5] Add TV Encoder support for ZTE DRM driver Shawn Guo
2017-01-19 16:24 ` [PATCH 1/5] drm: zte: add interlace mode support Shawn Guo
     [not found]   ` <1484843100-16284-2-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2017-01-23 15:19     ` Sean Paul
     [not found]       ` <20170123151901.GA19505-6JpoNmjd1+aEBhuJAZrboHoUN1GumTyQ7j82oEJ37pA@public.gmane.org>
2017-01-26  3:14         ` Shawn Guo
2017-01-19 16:24 ` [PATCH 2/5] drm: zte: move struct vou_inf into zx_vou driver Shawn Guo
     [not found]   ` <1484843100-16284-3-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2017-01-23 15:30     ` Sean Paul
2017-01-19 16:24 ` [PATCH 3/5] drm: zte: add function to configure vou_ctrl dividers Shawn Guo
2017-01-23 15:47   ` Sean Paul
2017-01-19 16:24 ` [PATCH 4/5] dt: add bindings for ZTE tvenc device Shawn Guo
2017-01-19 17:11   ` Lucas Stach
2017-01-23  1:33     ` Shawn Guo
     [not found]   ` <1484843100-16284-5-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2017-01-23 14:46     ` Rob Herring
2017-01-19 16:25 ` [PATCH 5/5] drm: zte: add tvenc driver support Shawn Guo
2017-01-23 16:10   ` Sean Paul
     [not found]     ` <20170123161034.GE19505-6JpoNmjd1+aEBhuJAZrboHoUN1GumTyQ7j82oEJ37pA@public.gmane.org>
2017-01-26 15:06       ` Shawn Guo

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.