[PATCH 4/6] imx-drm: ipuv3-crtc: Implement mode_fixup

2014-12-15 Thread slongerb...@gmail.com
From: Steve Longerbeam 

Ask the IPU display interface, via ipu_di_adjust_videomode(), to
adjust a video mode to meet any DI restrictions. The function takes
a subsystem independent videomode, so the drm_display_mode must be
converted to videomode first, and then the adjusted mode converted
back to a drm_display_mode.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/drm/imx/ipuv3-crtc.c |   12 
 1 file changed, 12 insertions(+)

diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index 11e84a2..fb16026 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -242,6 +242,18 @@ static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc,
  const struct drm_display_mode *mode,
  struct drm_display_mode *adjusted_mode)
 {
+   struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+   struct videomode vm;
+   int ret;
+
+   videomode_from_drm_display_mode(adjusted_mode, &vm);
+
+   ret = ipu_di_adjust_videomode(ipu_crtc->di, &vm);
+   if (ret)
+   return false;
+
+   drm_display_mode_from_videomode(&vm, adjusted_mode);
+
return true;
 }

-- 
1.7.9.5



[PATCH 0/6] imx-drm: ipuv3-crtc: Implement mode_fixup

2014-12-15 Thread slongerb...@gmail.com
From: Steve Longerbeam 

This patchset implements ->mode_fixup() in the imx ipuv3-crtc driver,
using a new support function ipu_di_adjust_videomode(). This new
function needs to be subsystem independent, so it accepts a video
mode as a 'struct videomode'. Hence ipu-crtc ->mode_fixup() needs
another support function to convert a drm_display_mode to a videomode
before passing the mode to ipu_di_adjust_videomode() for fixup.

Also some related code cleanup: 'struct ipu_di_signal_cfg' should
use 'struct videomode' for mode timings.

Jiada Wang (1):
  gpu: ipu-di: Add ipu_di_adjust_videomode()

Steve Longerbeam (5):
  gpu: ipu-di: remove some non-functional code
  drm_modes: add videomode_from_drm_display_mode
  imx-drm: ipuv3-crtc: Implement mode_fixup
  imx-drm: encoder mode_set must use adjusted mode
  gpu: ipu-v3: Use videomode in struct ipu_di_signal_cfg

 drivers/gpu/drm/drm_modes.c|   40 +++
 drivers/gpu/drm/imx/imx-hdmi.c |4 +-
 drivers/gpu/drm/imx/imx-ldb.c  |4 +-
 drivers/gpu/drm/imx/imx-tve.c  |4 +-
 drivers/gpu/drm/imx/ipuv3-crtc.c   |   39 +-
 drivers/gpu/drm/imx/parallel-display.c |4 +-
 drivers/gpu/ipu-v3/ipu-di.c|  124 
 include/drm/drm_modes.h|2 +
 include/video/imx-ipu-v3.h |   21 ++
 9 files changed, 150 insertions(+), 92 deletions(-)

-- 
1.7.9.5



[PATCH 1/6] gpu: ipu-di: Add ipu_di_adjust_videomode()

2014-12-15 Thread slongerb...@gmail.com
From: Jiada Wang 

On some monitors, high resolution modes are not working, exhibiting
pixel column truncation problems (for example, 1280x1024 displays as
1280x1022).

The function ipu_di_adjust_videomode() aims to fix these issues by
adjusting a passed videomode to IPU restrictions. The function can
be called from the drm_crtc_helper_funcs->mode_fixup() methods.

Signed-off-by: Jiada Wang 
Signed-off-by: Deepak Das 
Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-di.c |   29 +
 include/video/imx-ipu-v3.h  |2 ++
 2 files changed, 31 insertions(+)

diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c
index c490ba4..46f9570 100644
--- a/drivers/gpu/ipu-v3/ipu-di.c
+++ b/drivers/gpu/ipu-v3/ipu-di.c
@@ -511,6 +511,35 @@ static void ipu_di_config_clock(struct ipu_di *di,
clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
 }

+/*
+ * This function is called to adjust a video mode to IPU restrictions.
+ * It is meant to be called from drm crtc mode_fixup() methods.
+ */
+int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
+{
+   u32 diff;
+
+   if (mode->vfront_porch >= 2)
+   return 0;
+
+   diff = 2 - mode->vfront_porch;
+
+   if (mode->vback_porch >= diff) {
+   mode->vfront_porch = 2;
+   mode->vback_porch -= diff;
+   } else if (mode->vsync_len > diff) {
+   mode->vfront_porch = 2;
+   mode->vsync_len = mode->vsync_len - diff;
+   } else {
+   dev_warn(di->ipu->dev, "failed to adjust videomode\n");
+   return -EINVAL;
+   }
+
+   dev_warn(di->ipu->dev, "videomode adapted for IPU restrictions\n");
+   return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
+
 int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 {
u32 reg;
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index c74bf4a..d333d54 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -17,6 +17,7 @@
 #include 
 #include 
 #include 
+#include 

 struct ipu_soc;

@@ -236,6 +237,7 @@ void ipu_di_put(struct ipu_di *);
 int ipu_di_disable(struct ipu_di *);
 int ipu_di_enable(struct ipu_di *);
 int ipu_di_get_num(struct ipu_di *);
+int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode);
 int ipu_di_init_sync_panel(struct ipu_di *, struct ipu_di_signal_cfg *sig);

 /*
-- 
1.7.9.5



[PATCH 2/6] gpu: ipu-di: remove some non-functional code

2014-12-15 Thread slongerb...@gmail.com
From: Steve Longerbeam 

h_total and v_total were calculated in ipu_di_init_sync_panel()
but never actually used. Remove.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/ipu-v3/ipu-di.c |6 --
 1 file changed, 6 deletions(-)

diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c
index 46f9570..41df8d7 100644
--- a/drivers/gpu/ipu-v3/ipu-di.c
+++ b/drivers/gpu/ipu-v3/ipu-di.c
@@ -545,7 +545,6 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct 
ipu_di_signal_cfg *sig)
u32 reg;
u32 di_gen, vsync_cnt;
u32 div;
-   u32 h_total, v_total;

dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
di->id, sig->width, sig->height);
@@ -553,11 +552,6 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct 
ipu_di_signal_cfg *sig)
if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
return -EINVAL;

-   h_total = sig->width + sig->h_sync_width + sig->h_start_width +
-   sig->h_end_width;
-   v_total = sig->height + sig->v_sync_width + sig->v_start_width +
-   sig->v_end_width;
-
dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
clk_get_rate(di->clk_ipu),
clk_get_rate(di->clk_di),
-- 
1.7.9.5



[PATCH 3/6] drm_modes: add videomode_from_drm_display_mode

2014-12-15 Thread slongerb...@gmail.com
From: Steve Longerbeam 

Add conversion from drm_display_mode to videomode.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/drm/drm_modes.c |   40 
 include/drm/drm_modes.h |2 ++
 2 files changed, 42 insertions(+)

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 6d8b941..583a391 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -615,6 +615,46 @@ void drm_display_mode_from_videomode(const struct 
videomode *vm,
 }
 EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);

+/**
+ * videomode_from_drm_display_mode - fill in @vm using @dmode,
+ * @dmode: drm_display_mode structure to use as source
+ * @vm: videomode structure to use as destination
+ *
+ * Fills out @vm using the display mode specified in @dmode.
+ */
+void videomode_from_drm_display_mode(const struct drm_display_mode *dmode,
+struct videomode *vm)
+{
+   vm->hactive = dmode->hdisplay;
+   vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
+   vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
+   vm->hback_porch = dmode->htotal - dmode->hsync_end;
+
+   vm->vactive = dmode->vdisplay;
+   vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
+   vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
+   vm->vback_porch = dmode->vtotal - dmode->vsync_end;
+
+   vm->pixelclock = dmode->clock * 1000;
+
+   vm->flags = 0;
+   if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
+   vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
+   else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
+   vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
+   if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
+   vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
+   else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
+   vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
+   if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
+   vm->flags |= DISPLAY_FLAGS_INTERLACED;
+   if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
+   vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
+   if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
+   vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
+}
+EXPORT_SYMBOL_GPL(videomode_from_drm_display_mode);
+
 #ifdef CONFIG_OF
 /**
  * of_get_drm_display_mode - get a drm_display_mode from devicetree
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
index 91d0582..60c0144 100644
--- a/include/drm/drm_modes.h
+++ b/include/drm/drm_modes.h
@@ -197,6 +197,8 @@ struct drm_display_mode *drm_gtf_mode_complex(struct 
drm_device *dev,
  int GTF_K, int GTF_2J);
 void drm_display_mode_from_videomode(const struct videomode *vm,
 struct drm_display_mode *dmode);
+void videomode_from_drm_display_mode(const struct drm_display_mode *dmode,
+struct videomode *vm);
 int of_get_drm_display_mode(struct device_node *np,
struct drm_display_mode *dmode,
int index);
-- 
1.7.9.5



[PATCH 5/6] imx-drm: encoder mode_set must use adjusted mode

2014-12-15 Thread slongerb...@gmail.com
From: Steve Longerbeam 

The encoder ->mode_set() methods need to use the hw adjusted mode,
not the original mode.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/drm/imx/imx-hdmi.c |4 ++--
 drivers/gpu/drm/imx/imx-ldb.c  |4 ++--
 drivers/gpu/drm/imx/imx-tve.c  |4 ++--
 drivers/gpu/drm/imx/parallel-display.c |4 ++--
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/imx/imx-hdmi.c b/drivers/gpu/drm/imx/imx-hdmi.c
index aaec6b2..32116cc 100644
--- a/drivers/gpu/drm/imx/imx-hdmi.c
+++ b/drivers/gpu/drm/imx/imx-hdmi.c
@@ -1417,8 +1417,8 @@ static struct drm_encoder 
*imx_hdmi_connector_best_encoder(struct drm_connector
 }

 static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
-   struct drm_display_mode *mode,
-   struct drm_display_mode *adjusted_mode)
+   struct drm_display_mode *orig_mode,
+   struct drm_display_mode *mode)
 {
struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);

diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index 4662e00..a88c0e1 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -246,8 +246,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder 
*encoder)
 }

 static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
-struct drm_display_mode *mode,
-struct drm_display_mode *adjusted_mode)
+struct drm_display_mode *orig_mode,
+struct drm_display_mode *mode)
 {
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
struct imx_ldb *ldb = imx_ldb_ch->ldb;
diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c
index 42c651b..9709bf9a 100644
--- a/drivers/gpu/drm/imx/imx-tve.c
+++ b/drivers/gpu/drm/imx/imx-tve.c
@@ -312,8 +312,8 @@ static void imx_tve_encoder_prepare(struct drm_encoder 
*encoder)
 }

 static void imx_tve_encoder_mode_set(struct drm_encoder *encoder,
-struct drm_display_mode *mode,
-struct drm_display_mode *adjusted_mode)
+struct drm_display_mode *orig_mode,
+struct drm_display_mode *mode)
 {
struct imx_tve *tve = enc_to_tve(encoder);
unsigned long rounded_rate;
diff --git a/drivers/gpu/drm/imx/parallel-display.c 
b/drivers/gpu/drm/imx/parallel-display.c
index 015a454..d0842a4 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -131,8 +131,8 @@ static void imx_pd_encoder_commit(struct drm_encoder 
*encoder)
 }

 static void imx_pd_encoder_mode_set(struct drm_encoder *encoder,
-struct drm_display_mode *mode,
-struct drm_display_mode *adjusted_mode)
+struct drm_display_mode *orig_mode,
+struct drm_display_mode *mode)
 {
 }

-- 
1.7.9.5



[PATCH 6/6] gpu: ipu-v3: Use videomode in struct ipu_di_signal_cfg

2014-12-15 Thread slongerb...@gmail.com
From: Steve Longerbeam 

This patch changes struct ipu_di_signal_cfg to use struct videomode
to define video timings and flags.

Signed-off-by: Steve Longerbeam 
---
 drivers/gpu/drm/imx/ipuv3-crtc.c |   27 +++-
 drivers/gpu/ipu-v3/ipu-di.c  |   89 --
 include/video/imx-ipu-v3.h   |   19 ++--
 3 files changed, 57 insertions(+), 78 deletions(-)

diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index fb16026..0a50129 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -158,35 +158,20 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,

out_pixel_fmt = ipu_crtc->interface_pix_fmt;

-   if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-   sig_cfg.interlaced = 1;
-   if (mode->flags & DRM_MODE_FLAG_PHSYNC)
-   sig_cfg.Hsync_pol = 1;
-   if (mode->flags & DRM_MODE_FLAG_PVSYNC)
-   sig_cfg.Vsync_pol = 1;
-
sig_cfg.enable_pol = 1;
sig_cfg.clk_pol = 0;
-   sig_cfg.width = mode->hdisplay;
-   sig_cfg.height = mode->vdisplay;
sig_cfg.pixel_fmt = out_pixel_fmt;
-   sig_cfg.h_start_width = mode->htotal - mode->hsync_end;
-   sig_cfg.h_sync_width = mode->hsync_end - mode->hsync_start;
-   sig_cfg.h_end_width = mode->hsync_start - mode->hdisplay;
-
-   sig_cfg.v_start_width = mode->vtotal - mode->vsync_end;
-   sig_cfg.v_sync_width = mode->vsync_end - mode->vsync_start;
-   sig_cfg.v_end_width = mode->vsync_start - mode->vdisplay;
-   sig_cfg.pixelclock = mode->clock * 1000;
sig_cfg.clkflags = ipu_crtc->di_clkflags;
-
sig_cfg.v_to_h_sync = 0;
-
sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin;
sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin;

-   ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced,
-   out_pixel_fmt, mode->hdisplay);
+   videomode_from_drm_display_mode(mode, &sig_cfg.mode);
+
+   ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di,
+  (mode->flags & DRM_MODE_FLAG_INTERLACE) ?
+  true : false,
+  out_pixel_fmt, mode->hdisplay);
if (ret) {
dev_err(ipu_crtc->dev,
"initializing display controller failed with 
%d\n",
diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c
index 41df8d7..d95fbd0 100644
--- a/drivers/gpu/ipu-v3/ipu-di.c
+++ b/drivers/gpu/ipu-v3/ipu-di.c
@@ -207,10 +207,10 @@ static void ipu_di_sync_config(struct ipu_di *di, struct 
di_sync_config *config,
 static void ipu_di_sync_config_interlaced(struct ipu_di *di,
struct ipu_di_signal_cfg *sig)
 {
-   u32 h_total = sig->width + sig->h_sync_width +
-   sig->h_start_width + sig->h_end_width;
-   u32 v_total = sig->height + sig->v_sync_width +
-   sig->v_start_width + sig->v_end_width;
+   u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
+   sig->mode.hback_porch + sig->mode.hfront_porch;
+   u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
+   sig->mode.vback_porch + sig->mode.vfront_porch;
u32 reg;
struct di_sync_config cfg[] = {
{
@@ -229,13 +229,13 @@ static void ipu_di_sync_config_interlaced(struct ipu_di 
*di,
}, {
.run_count = v_total / 2 - 1,
.run_src = DI_SYNC_HSYNC,
-   .offset_count = sig->v_start_width,
+   .offset_count = sig->mode.vback_porch,
.offset_src = DI_SYNC_HSYNC,
.repeat_count = 2,
.cnt_clr_src = DI_SYNC_VSYNC,
}, {
.run_src = DI_SYNC_HSYNC,
-   .repeat_count = sig->height / 2,
+   .repeat_count = sig->mode.vactive / 2,
.cnt_clr_src = 4,
}, {
.run_count = v_total - 1,
@@ -249,9 +249,9 @@ static void ipu_di_sync_config_interlaced(struct ipu_di *di,
.cnt_clr_src = DI_SYNC_VSYNC,
}, {
.run_src = DI_SYNC_CLK,
-   .offset_count = sig->h_start_width,
+   .offset_count = sig->mode.hback_porch,
.offset_src = DI_SYNC_CLK,
-   .repeat_count = sig->width,
+   .repeat_count = sig->mode.hactive,
.cnt_clr_src = 5,
}, {
.run_count = v_total - 1,
@@ -277,10 +277,10 @@ static void ipu_di_sync_config_interlaced(struct ipu_di 
*di,
 static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
struct ipu_di_signal_cfg *sig, int div)
 {
-   u32 h_total = sig->width + sig->h_sync_width + sig->h_start_widt