Merge branch 'drm/next/du' of git://linuxtv.org/pinchartl/fbdev into drm-next
authorDave Airlie <airlied@redhat.com>
Wed, 21 Jan 2015 00:16:24 +0000 (10:16 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 21 Jan 2015 00:16:24 +0000 (10:16 +1000)
* 'drm/next/du' of git://linuxtv.org/pinchartl/fbdev:
  drm: rcar-du: Implement support for interlaced modes
  drm: rcar-du: Clamp DPMS states to on and off
  drm: rcar-du: Enable hotplug detection on HDMI connector
  drm: rcar-du: Output HSYNC instead of CSYNC
  drm: rcar-du: Add support for external pixel clock
  drm: rcar-du: Refactor DEFR8 feature
  drm: rcar-du: Remove LVDS and HDMI encoders chaining restriction
  drm: rcar-du: Configure pitch for chroma plane of multiplanar formats
  drm: rcar-du: Don't fail probe in case of partial encoder init error
  drm: adv7511: Remove interlaced mode check

14 files changed:
Documentation/devicetree/bindings/video/renesas,du.txt
drivers/gpu/drm/i2c/adv7511.c
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
drivers/gpu/drm/rcar-du/rcar_du_crtc.h
drivers/gpu/drm/rcar-du/rcar_du_drv.c
drivers/gpu/drm/rcar-du/rcar_du_drv.h
drivers/gpu/drm/rcar-du/rcar_du_encoder.c
drivers/gpu/drm/rcar-du/rcar_du_group.c
drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
drivers/gpu/drm/rcar-du/rcar_du_kms.c
drivers/gpu/drm/rcar-du/rcar_du_plane.c
drivers/gpu/drm/rcar-du/rcar_du_regs.h
drivers/gpu/drm/rcar-du/rcar_du_vgacon.c

index 5102830f276017135a05289e5c92bd87ae6e9d21..c902323928f700a356d7e8fd118cde2e680e2c94 100644 (file)
@@ -26,6 +26,10 @@ Required Properties:
       per LVDS encoder. The functional clocks must be named "du.x" with "x"
       being the channel numerical index. The LVDS clocks must be named
       "lvds.x" with "x" being the LVDS encoder numerical index.
+    - In addition to the functional and encoder clocks, all DU versions also
+      support externally supplied pixel clocks. Those clocks are optional.
+      When supplied they must be named "dclkin.x" with "x" being the input
+      clock numerical index.
 
 Required nodes:
 
index faf1c0c5ab2eb9300b9acef0a337bfd7bc8a0d64..fa140e04d5fa72f18237054c2b10f23f77355d83 100644 (file)
@@ -644,9 +644,6 @@ static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
        if (mode->clock > 165000)
                return MODE_CLOCK_HIGH;
 
-       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-               return MODE_NO_INTERLACE;
-
        return MODE_OK;
 }
 
index 23cc910951f430a279b6b01ae88e5f03d7de3e74..25c7a998fc2cf075fe1ecb6c8fe603f439abab7f 100644 (file)
@@ -74,39 +74,77 @@ static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
        if (ret < 0)
                return ret;
 
+       ret = clk_prepare_enable(rcrtc->extclock);
+       if (ret < 0)
+               goto error_clock;
+
        ret = rcar_du_group_get(rcrtc->group);
        if (ret < 0)
-               clk_disable_unprepare(rcrtc->clock);
+               goto error_group;
+
+       return 0;
 
+error_group:
+       clk_disable_unprepare(rcrtc->extclock);
+error_clock:
+       clk_disable_unprepare(rcrtc->clock);
        return ret;
 }
 
 static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
 {
        rcar_du_group_put(rcrtc->group);
+
+       clk_disable_unprepare(rcrtc->extclock);
        clk_disable_unprepare(rcrtc->clock);
 }
 
 static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
 {
        const struct drm_display_mode *mode = &rcrtc->crtc.mode;
+       unsigned long mode_clock = mode->clock * 1000;
        unsigned long clk;
        u32 value;
+       u32 escr;
        u32 div;
 
-       /* Dot clock */
+       /* Compute the clock divisor and select the internal or external dot
+        * clock based on the requested frequency.
+        */
        clk = clk_get_rate(rcrtc->clock);
-       div = DIV_ROUND_CLOSEST(clk, mode->clock * 1000);
+       div = DIV_ROUND_CLOSEST(clk, mode_clock);
        div = clamp(div, 1U, 64U) - 1;
+       escr = div | ESCR_DCLKSEL_CLKS;
+
+       if (rcrtc->extclock) {
+               unsigned long extclk;
+               unsigned long extrate;
+               unsigned long rate;
+               u32 extdiv;
+
+               extclk = clk_get_rate(rcrtc->extclock);
+               extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
+               extdiv = clamp(extdiv, 1U, 64U) - 1;
+
+               rate = clk / (div + 1);
+               extrate = extclk / (extdiv + 1);
+
+               if (abs((long)extrate - (long)mode_clock) <
+                   abs((long)rate - (long)mode_clock)) {
+                       dev_dbg(rcrtc->group->dev->dev,
+                               "crtc%u: using external clock\n", rcrtc->index);
+                       escr = extdiv | ESCR_DCLKSEL_DCLKIN;
+               }
+       }
 
        rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR,
-                           ESCR_DCLKSEL_CLKS | div);
+                           escr);
        rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
 
        /* Signal polarities */
        value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL)
              | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL)
-             | DSMR_DIPM_DE;
+             | DSMR_DIPM_DE | DSMR_CSPM;
        rcar_du_crtc_write(rcrtc, DSMR, value);
 
        /* Display timings */
@@ -117,12 +155,15 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
                                        mode->hsync_start - 1);
        rcar_du_crtc_write(rcrtc, HCR,  mode->htotal - 1);
 
-       rcar_du_crtc_write(rcrtc, VDSR, mode->vtotal - mode->vsync_end - 2);
-       rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end +
-                                       mode->vdisplay - 2);
-       rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end +
-                                       mode->vsync_start - 1);
-       rcar_du_crtc_write(rcrtc, VCR,  mode->vtotal - 1);
+       rcar_du_crtc_write(rcrtc, VDSR, mode->crtc_vtotal -
+                                       mode->crtc_vsync_end - 2);
+       rcar_du_crtc_write(rcrtc, VDER, mode->crtc_vtotal -
+                                       mode->crtc_vsync_end +
+                                       mode->crtc_vdisplay - 2);
+       rcar_du_crtc_write(rcrtc, VSPR, mode->crtc_vtotal -
+                                       mode->crtc_vsync_end +
+                                       mode->crtc_vsync_start - 1);
+       rcar_du_crtc_write(rcrtc, VCR,  mode->crtc_vtotal - 1);
 
        rcar_du_crtc_write(rcrtc, DESR,  mode->htotal - mode->hsync_start);
        rcar_du_crtc_write(rcrtc, DEWR,  mode->hdisplay);
@@ -139,9 +180,10 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
         */
        rcrtc->outputs |= BIT(output);
 
-       /* Store RGB routing to DPAD0 for R8A7790. */
-       if (rcar_du_has(rcdu, RCAR_DU_FEATURE_DEFR8) &&
-           output == RCAR_DU_OUTPUT_DPAD0)
+       /* Store RGB routing to DPAD0, the hardware will be configured when
+        * starting the CRTC.
+        */
+       if (output == RCAR_DU_OUTPUT_DPAD0)
                rcdu->dpad0_source = rcrtc->index;
 }
 
@@ -217,6 +259,7 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
 static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
 {
        struct drm_crtc *crtc = &rcrtc->crtc;
+       bool interlaced;
        unsigned int i;
 
        if (rcrtc->started)
@@ -252,7 +295,10 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
         * sync mode (with the HSYNC and VSYNC signals configured as outputs and
         * actively driven).
         */
-       rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_MASTER);
+       interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
+       rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
+                            (interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
+                            DSYSR_TVM_MASTER);
 
        rcar_du_group_start_stop(rcrtc->group, true);
 
@@ -308,6 +354,9 @@ static void rcar_du_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
        struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
 
+       if (mode != DRM_MODE_DPMS_ON)
+               mode = DRM_MODE_DPMS_OFF;
+
        if (rcrtc->dpms == mode)
                return;
 
@@ -486,7 +535,7 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
        status = rcar_du_crtc_read(rcrtc, DSSR);
        rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
 
-       if (status & DSSR_VBK) {
+       if (status & DSSR_FRM) {
                drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index);
                rcar_du_crtc_finish_page_flip(rcrtc);
                ret = IRQ_HANDLED;
@@ -542,12 +591,13 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
        struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index];
        struct drm_crtc *crtc = &rcrtc->crtc;
        unsigned int irqflags;
-       char clk_name[5];
+       struct clk *clk;
+       char clk_name[9];
        char *name;
        int irq;
        int ret;
 
-       /* Get the CRTC clock. */
+       /* Get the CRTC clock and the optional external clock. */
        if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ_CLOCK)) {
                sprintf(clk_name, "du.%u", index);
                name = clk_name;
@@ -561,6 +611,15 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
                return PTR_ERR(rcrtc->clock);
        }
 
+       sprintf(clk_name, "dclkin.%u", index);
+       clk = devm_clk_get(rcdu->dev, clk_name);
+       if (!IS_ERR(clk)) {
+               rcrtc->extclock = clk;
+       } else if (PTR_ERR(rcrtc->clock) == -EPROBE_DEFER) {
+               dev_info(rcdu->dev, "can't get external clock %u\n", index);
+               return -EPROBE_DEFER;
+       }
+
        rcrtc->group = rgrp;
        rcrtc->mmio_offset = mmio_offsets[index];
        rcrtc->index = index;
index 984e6083699fe380a1d6b1e9d9c4c249ee6d4167..d2f89f7d2e5e3e6c6001c63a49ff032ece9aeded 100644 (file)
@@ -26,6 +26,7 @@ struct rcar_du_crtc {
        struct drm_crtc crtc;
 
        struct clk *clock;
+       struct clk *extclock;
        unsigned int mmio_offset;
        unsigned int index;
        bool started;
index 7bfa09cf18d59a3d7a526b77cf897d168b384326..e0d74f821416cdf31ed7e738b8726395276891b6 100644 (file)
@@ -56,7 +56,8 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = {
 };
 
 static const struct rcar_du_device_info rcar_du_r8a7790_info = {
-       .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8,
+       .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
+                 | RCAR_DU_FEATURE_EXT_CTRL_REGS,
        .quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES,
        .num_crtcs = 3,
        .routes = {
@@ -83,7 +84,8 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = {
 };
 
 static const struct rcar_du_device_info rcar_du_r8a7791_info = {
-       .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8,
+       .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
+                 | RCAR_DU_FEATURE_EXT_CTRL_REGS,
        .num_crtcs = 2,
        .routes = {
                /* R8A7791 has one RGB output, one LVDS output and one
index 0a724669f02d461351617c5044b4e7e89f7262da..c5b9ea6a7eaab38d370014b643298064ba9a32ab 100644 (file)
@@ -27,7 +27,7 @@ struct rcar_du_device;
 struct rcar_du_lvdsenc;
 
 #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0)        /* Per-CRTC IRQ and clock */
-#define RCAR_DU_FEATURE_DEFR8          (1 << 1)        /* Has DEFR8 register */
+#define RCAR_DU_FEATURE_EXT_CTRL_REGS  (1 << 1)        /* Has extended control registers */
 
 #define RCAR_DU_QUIRK_ALIGN_128B       (1 << 0)        /* Align pitches to 128 bytes */
 #define RCAR_DU_QUIRK_LVDS_LANES       (1 << 1)        /* LVDS lanes 1 and 3 inverted */
index 34a122a3966419e406cb958ce8a6b194f9fdae1f..279167f783f67857ee3b37cd491419626933399d 100644 (file)
@@ -46,6 +46,9 @@ static void rcar_du_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
        struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
 
+       if (mode != DRM_MODE_DPMS_ON)
+               mode = DRM_MODE_DPMS_OFF;
+
        if (renc->lvds)
                rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, mode);
 }
@@ -190,35 +193,42 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
        }
 
        if (type == RCAR_DU_ENCODER_HDMI) {
-               if (renc->lvds) {
-                       dev_err(rcdu->dev,
-                               "Chaining LVDS and HDMI encoders not supported\n");
-                       return -EINVAL;
-               }
-
                ret = rcar_du_hdmienc_init(rcdu, renc, enc_node);
                if (ret < 0)
-                       return ret;
+                       goto done;
        } else {
                ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
                                       encoder_type);
                if (ret < 0)
-                       return ret;
+                       goto done;
 
                drm_encoder_helper_add(encoder, &encoder_helper_funcs);
        }
 
        switch (encoder_type) {
        case DRM_MODE_ENCODER_LVDS:
-               return rcar_du_lvds_connector_init(rcdu, renc, con_node);
+               ret = rcar_du_lvds_connector_init(rcdu, renc, con_node);
+               break;
 
        case DRM_MODE_ENCODER_DAC:
-               return rcar_du_vga_connector_init(rcdu, renc);
+               ret = rcar_du_vga_connector_init(rcdu, renc);
+               break;
 
        case DRM_MODE_ENCODER_TMDS:
-               return rcar_du_hdmi_connector_init(rcdu, renc);
+               ret = rcar_du_hdmi_connector_init(rcdu, renc);
+               break;
 
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               break;
        }
+
+done:
+       if (ret < 0) {
+               if (encoder->name)
+                       encoder->funcs->destroy(encoder);
+               devm_kfree(rcdu->dev, renc);
+       }
+
+       return ret;
 }
index 4e7614b145db550d1364723e76dd27ffd36b404f..1bdc0ee0c2483c936b8fffd31948c42fe74e8455 100644 (file)
@@ -48,9 +48,6 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp)
 {
        u32 defr8 = DEFR8_CODE | DEFR8_DEFE8;
 
-       if (!rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_DEFR8))
-               return;
-
        /* The DEFR8 register for the first group also controls RGB output
         * routing to DPAD0
         */
@@ -69,7 +66,20 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
        rcar_du_group_write(rgrp, DEFR4, DEFR4_CODE);
        rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5);
 
-       rcar_du_group_setup_defr8(rgrp);
+       if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) {
+               rcar_du_group_setup_defr8(rgrp);
+
+               /* Configure input dot clock routing. We currently hardcode the
+                * configuration to routing DOTCLKINn to DUn.
+                */
+               rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE |
+                                   DIDSR_LCDS_DCLKIN(2) |
+                                   DIDSR_LCDS_DCLKIN(1) |
+                                   DIDSR_LCDS_DCLKIN(0) |
+                                   DIDSR_PDCS_CLK(2, 0) |
+                                   DIDSR_PDCS_CLK(1, 0) |
+                                   DIDSR_PDCS_CLK(0, 0));
+       }
 
        /* Use DS1PR and DS2PR to configure planes priorities and connects the
         * superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
@@ -149,6 +159,9 @@ static int rcar_du_set_dpad0_routing(struct rcar_du_device *rcdu)
 {
        int ret;
 
+       if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_EXT_CTRL_REGS))
+               return 0;
+
        /* RGB output routing to DPAD0 is configured in the DEFR8 register of
         * the first group. As this function can be called with the DU0 and DU1
         * CRTCs disabled, we need to enable the first group clock before
index 4d7d4dd46d2603c6cc3d4f06958edac30d34a2a4..ca94b029ac80ca664c0a53631328eaf90e971754 100644 (file)
@@ -95,6 +95,8 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
        connector = &rcon->connector;
        connector->display_info.width_mm = 0;
        connector->display_info.height_mm = 0;
+       connector->interlace_allowed = true;
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
 
        ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
                                 DRM_MODE_CONNECTOR_HDMIA);
index 359bc999a9c8444ff41d43ee2c8af3cc36308509..221f0a17fd6a62bbde33950e8529ce371aff9323 100644 (file)
@@ -21,6 +21,7 @@
 #include "rcar_du_drv.h"
 #include "rcar_du_encoder.h"
 #include "rcar_du_hdmienc.h"
+#include "rcar_du_lvdsenc.h"
 
 struct rcar_du_hdmienc {
        struct rcar_du_encoder *renc;
@@ -36,12 +37,21 @@ static void rcar_du_hdmienc_dpms(struct drm_encoder *encoder, int mode)
        struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
        struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
 
+       if (mode != DRM_MODE_DPMS_ON)
+               mode = DRM_MODE_DPMS_OFF;
+
        if (hdmienc->dpms == mode)
                return;
 
+       if (mode == DRM_MODE_DPMS_ON && hdmienc->renc->lvds)
+               rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode);
+
        if (sfuncs->dpms)
                sfuncs->dpms(encoder, mode);
 
+       if (mode != DRM_MODE_DPMS_ON && hdmienc->renc->lvds)
+               rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode);
+
        hdmienc->dpms = mode;
 }
 
@@ -49,8 +59,16 @@ static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder *encoder,
                                       const struct drm_display_mode *mode,
                                       struct drm_display_mode *adjusted_mode)
 {
+       struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
        struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
 
+       /* The internal LVDS encoder has a clock frequency operating range of
+        * 30MHz to 150MHz. Clamp the clock accordingly.
+        */
+       if (hdmienc->renc->lvds)
+               adjusted_mode->clock = clamp(adjusted_mode->clock,
+                                            30000, 150000);
+
        if (sfuncs->mode_fixup == NULL)
                return true;
 
index 0c5ee616b5a3aabd12234ee7f208dc277a99d73f..cc9136e8ee9cd2f73c65850215fad60a584358ee 100644 (file)
@@ -346,8 +346,14 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
                /* Process the output pipeline. */
                ret = rcar_du_encoders_init_one(rcdu, output, &ep);
                if (ret < 0) {
-                       of_node_put(ep_node);
-                       return ret;
+                       if (ret == -EPROBE_DEFER) {
+                               of_node_put(ep_node);
+                               return ret;
+                       }
+
+                       dev_info(rcdu->dev,
+                                "encoder initialization failed, skipping\n");
+                       continue;
                }
 
                num_encoders += ret;
@@ -413,6 +419,11 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
        if (ret < 0)
                return ret;
 
+       if (ret == 0) {
+               dev_err(rcdu->dev, "error: no encoder could be initialized\n");
+               return -EINVAL;
+       }
+
        num_encoders = ret;
 
        /* Set the possible CRTCs and possible clones. There's always at least
index 72a7cb47bd9f8a2e18d846185e9b7a0ee77dcefb..50f2f2b20d39fce3d8465611196a6ee6f36e803d 100644 (file)
@@ -104,14 +104,22 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
 {
        struct rcar_du_group *rgrp = plane->group;
        unsigned int index = plane->hwindex;
+       bool interlaced;
        u32 mwr;
 
-       /* Memory pitch (expressed in pixels) */
+       interlaced = plane->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
+
+       /* Memory pitch (expressed in pixels). Must be doubled for interlaced
+        * operation with 32bpp formats.
+        */
        if (plane->format->planes == 2)
                mwr = plane->pitch;
        else
                mwr = plane->pitch * 8 / plane->format->bpp;
 
+       if (interlaced && plane->format->bpp == 32)
+               mwr *= 2;
+
        rcar_du_plane_write(rgrp, index, PnMWR, mwr);
 
        /* The Y position is expressed in raster line units and must be doubled
@@ -119,17 +127,23 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
         * doubling the Y position is found in the R8A7779 datasheet, but the
         * rule seems to apply there as well.
         *
+        * Despite not being documented, doubling seem not to be needed when
+        * operating in interlaced mode.
+        *
         * Similarly, for the second plane, NV12 and NV21 formats seem to
-        * require a halved Y position value.
+        * require a halved Y position value, in both progressive and interlaced
+        * modes.
         */
        rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x);
        rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y *
-                           (plane->format->bpp == 32 ? 2 : 1));
+                           (!interlaced && plane->format->bpp == 32 ? 2 : 1));
        rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[0]);
 
        if (plane->format->planes == 2) {
                index = (index + 1) % 8;
 
+               rcar_du_plane_write(rgrp, index, PnMWR, plane->pitch);
+
                rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x);
                rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y *
                                    (plane->format->bpp == 16 ? 2 : 1) / 2);
index 73f7347f740bd1f94707990a8d9115fcf57fc518..70fcbc471ebdc81e45542ca9262376e6caf3ba5b 100644 (file)
@@ -34,6 +34,7 @@
 #define DSYSR_SCM_INT_NONE     (0 << 4)
 #define DSYSR_SCM_INT_SYNC     (2 << 4)
 #define DSYSR_SCM_INT_VIDEO    (3 << 4)
+#define DSYSR_SCM_MASK         (3 << 4)
 
 #define DSMR                   0x00004
 #define DSMR_VSPM              (1 << 28)
 #define DIDSR_LCDS_LVDS0(n)    (2 << (8 + (n) * 2))
 #define DIDSR_LCDS_LVDS1(n)    (3 << (8 + (n) * 2))
 #define DIDSR_LCDS_MASK(n)     (3 << (8 + (n) * 2))
-#define DIDSR_PCDS_CLK(n, clk) (clk << ((n) * 2))
-#define DIDSR_PCDS_MASK(n)     (3 << ((n) * 2))
+#define DIDSR_PDCS_CLK(n, clk) (clk << ((n) * 2))
+#define DIDSR_PDCS_MASK(n)     (3 << ((n) * 2))
 
 /* -----------------------------------------------------------------------------
  * Display Timing Generation Registers
index 752747a5e920e847ac689aa78555da1c12716b9e..9d4879921cc7a92e574ba15f47c95370e9a469b9 100644 (file)
@@ -64,6 +64,7 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
        connector = &rcon->connector;
        connector->display_info.width_mm = 0;
        connector->display_info.height_mm = 0;
+       connector->interlace_allowed = true;
 
        ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
                                 DRM_MODE_CONNECTOR_VGA);