staging: drm/imx: Add support for VGA via TVE on i.MX53
authorPhilipp Zabel <p.zabel@pengutronix.de>
Mon, 8 Apr 2013 16:04:35 +0000 (18:04 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 9 Apr 2013 23:16:16 +0000 (16:16 -0700)
This adds display interface timings for the Television Encoder
connected to IPU DI1 on i.MX53 and adds some configuration
glue code to select which IPU signal generators / pins are to
be used for HSYNC/VSYNC signals.

The default configuration is pin2/pin3 for hsync/vsync. The
VGA connector on i.MX53-QSB uses pin7/pin8, and the analog
part of the DVI-I connector on MBa53 connects to pin4/pin6.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/imx-drm/imx-drm-core.c
drivers/staging/imx-drm/imx-drm.h
drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
drivers/staging/imx-drm/ipu-v3/ipu-di.c
drivers/staging/imx-drm/ipuv3-crtc.c

index cec19f1..6455305 100644 (file)
@@ -112,8 +112,8 @@ static struct imx_drm_crtc *imx_drm_crtc_by_num(struct imx_drm_device *imxdrm,
        return NULL;
 }
 
-int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
-               u32 interface_pix_fmt)
+int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+               u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
 {
        struct imx_drm_device *imxdrm = crtc->dev->dev_private;
        struct imx_drm_crtc *imx_crtc;
@@ -134,9 +134,18 @@ found:
        helper = &imx_crtc->imx_drm_helper_funcs;
        if (helper->set_interface_pix_fmt)
                return helper->set_interface_pix_fmt(crtc,
-                               encoder_type, interface_pix_fmt);
+                               encoder_type, interface_pix_fmt,
+                               hsync_pin, vsync_pin);
        return 0;
 }
+EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format_pins);
+
+int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
+               u32 interface_pix_fmt)
+{
+       return imx_drm_crtc_panel_format_pins(crtc, encoder_type,
+                                             interface_pix_fmt, 0, 0);
+}
 EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
 
 int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
index a24508f..f2aac91 100644 (file)
@@ -18,7 +18,7 @@ struct imx_drm_crtc_helper_funcs {
        int (*enable_vblank)(struct drm_crtc *crtc);
        void (*disable_vblank)(struct drm_crtc *crtc);
        int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type,
-                       u32 pix_fmt);
+                       u32 pix_fmt, int hsync_pin, int vsync_pin);
        const struct drm_crtc_helper_funcs *crtc_helper_funcs;
        const struct drm_crtc_funcs *crtc_funcs;
 };
@@ -54,6 +54,8 @@ struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
 
 struct drm_device *imx_drm_device_get(void);
 void imx_drm_device_put(void);
+int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+               u32 interface_pix_fmt, int hsync_pin, int vsync_pin);
 int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
                u32 interface_pix_fmt);
 void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
index 66572d5..74c022e 100644 (file)
@@ -54,6 +54,9 @@ struct ipu_di_signal_cfg {
 #define IPU_DI_CLKMODE_SYNC    (1 << 0)
 #define IPU_DI_CLKMODE_EXT     (1 << 1)
        unsigned long clkflags;
+
+       u8 hsync_pin;
+       u8 vsync_pin;
 };
 
 enum ipu_color_space {
index 26534b7..19d777e 100644 (file)
@@ -440,7 +440,7 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
                        .repeat_count = sig->height,
                        .cnt_clr_src = DI_SYNC_VSYNC,
                } , {
-                       /* 5: DE, referenced by DC */
+                       /* 5: Pixel Active, referenced by DC */
                        .run_src = DI_SYNC_CLK,
                        .offset_count = sig->h_sync_width + sig->h_start_width,
                        .offset_src = DI_SYNC_CLK,
@@ -454,13 +454,78 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
                        /* unused */
                } , {
                        /* unused */
+               },
+       };
+       /* can't use #7 and #8 for line active and pixel active counters */
+       struct di_sync_config cfg_vga[] = {
+               {
+                       /* 1: INT_HSYNC */
+                       .run_count = h_total - 1,
+                       .run_src = DI_SYNC_CLK,
+               } , {
+                       /* 2: VSYNC */
+                       .run_count = v_total - 1,
+                       .run_src = DI_SYNC_INT_HSYNC,
+               } , {
+                       /* 3: Line Active */
+                       .run_src = DI_SYNC_INT_HSYNC,
+                       .offset_count = sig->v_sync_width + sig->v_start_width,
+                       .offset_src = DI_SYNC_INT_HSYNC,
+                       .repeat_count = sig->height,
+                       .cnt_clr_src = 3 /* VSYNC */,
+               } , {
+                       /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
+                       .run_count = h_total - 1,
+                       .run_src = DI_SYNC_CLK,
+                       .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
+                       .offset_src = DI_SYNC_CLK,
+                       .cnt_polarity_gen_en = 1,
+                       .cnt_polarity_trigger_src = DI_SYNC_CLK,
+                       .cnt_down = sig->h_sync_width * 2,
+               } , {
+                       /* 5: Pixel Active signal to DC */
+                       .run_src = DI_SYNC_CLK,
+                       .offset_count = sig->h_sync_width + sig->h_start_width,
+                       .offset_src = DI_SYNC_CLK,
+                       .repeat_count = sig->width,
+                       .cnt_clr_src = 4, /* Line Active */
+               } , {
+                       /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
+                       .run_count = v_total - 1,
+                       .run_src = DI_SYNC_INT_HSYNC,
+                       .offset_count = 1, /* magic value from Freescale TVE driver */
+                       .offset_src = DI_SYNC_INT_HSYNC,
+                       .cnt_polarity_gen_en = 1,
+                       .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+                       .cnt_down = sig->v_sync_width * 2,
+               } , {
+                       /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
+                       .run_count = h_total - 1,
+                       .run_src = DI_SYNC_CLK,
+                       .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
+                       .offset_src = DI_SYNC_CLK,
+                       .cnt_polarity_gen_en = 1,
+                       .cnt_polarity_trigger_src = DI_SYNC_CLK,
+                       .cnt_down = sig->h_sync_width * 2,
+               } , {
+                       /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
+                       .run_count = v_total - 1,
+                       .run_src = DI_SYNC_INT_HSYNC,
+                       .offset_count = 1, /* magic value from Freescale TVE driver */
+                       .offset_src = DI_SYNC_INT_HSYNC,
+                       .cnt_polarity_gen_en = 1,
+                       .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+                       .cnt_down = sig->v_sync_width * 2,
                } , {
                        /* unused */
                },
        };
 
        ipu_di_write(di, v_total - 1, DI_SCR_CONF);
-       ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
+       if (sig->hsync_pin == 2 && sig->vsync_pin == 3)
+               ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
+       else
+               ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
 }
 
 int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
@@ -537,11 +602,25 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
                ipu_di_sync_config_noninterlaced(di, sig, div);
 
                vsync_cnt = 3;
-
-               if (sig->Hsync_pol)
-                       di_gen |= DI_GEN_POLARITY_2;
-               if (sig->Vsync_pol)
-                       di_gen |= DI_GEN_POLARITY_3;
+               if (di->id == 1)
+                       vsync_cnt = 6;
+
+               if (sig->Hsync_pol) {
+                       if (sig->hsync_pin == 2)
+                               di_gen |= DI_GEN_POLARITY_2;
+                       else if (sig->hsync_pin == 4)
+                               di_gen |= DI_GEN_POLARITY_4;
+                       else if (sig->hsync_pin == 7)
+                               di_gen |= DI_GEN_POLARITY_7;
+               }
+               if (sig->Vsync_pol) {
+                       if (sig->hsync_pin == 3)
+                               di_gen |= DI_GEN_POLARITY_3;
+                       else if (sig->hsync_pin == 6)
+                               di_gen |= DI_GEN_POLARITY_6;
+                       else if (sig->hsync_pin == 8)
+                               di_gen |= DI_GEN_POLARITY_8;
+               }
        }
 
        if (!sig->clk_pol)
index 620e571..ea61c86 100644 (file)
@@ -60,6 +60,8 @@ struct ipu_crtc {
        int                     irq;
        u32                     interface_pix_fmt;
        unsigned long           di_clkflags;
+       int                     di_hsync_pin;
+       int                     di_vsync_pin;
 };
 
 #define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base)
@@ -255,6 +257,9 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
 
        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;
+
        if (ipu_crtc->dp) {
                ret = ipu_dp_setup_channel(ipu_crtc->dp, IPUV3_COLORSPACE_RGB,
                                IPUV3_COLORSPACE_RGB);
@@ -406,11 +411,13 @@ static void ipu_disable_vblank(struct drm_crtc *crtc)
 }
 
 static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
-               u32 pixfmt)
+               u32 pixfmt, int hsync_pin, int vsync_pin)
 {
        struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
 
        ipu_crtc->interface_pix_fmt = pixfmt;
+       ipu_crtc->di_hsync_pin = hsync_pin;
+       ipu_crtc->di_vsync_pin = vsync_pin;
 
        switch (encoder_type) {
        case DRM_MODE_ENCODER_DAC: