drm: rcar-du: Add HDMI encoder and connector support
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / gpu / drm / rcar-du / rcar_du_encoder.c
index 3daa7a1..34a122a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * rcar_du_encoder.c  --  R-Car Display Unit Encoder
  *
- * Copyright (C) 2013 Renesas Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
  *
  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  *
@@ -19,6 +19,8 @@
 
 #include "rcar_du_drv.h"
 #include "rcar_du_encoder.h"
+#include "rcar_du_hdmicon.h"
+#include "rcar_du_hdmienc.h"
 #include "rcar_du_kms.h"
 #include "rcar_du_lvdscon.h"
 #include "rcar_du_lvdsenc.h"
@@ -33,7 +35,7 @@ rcar_du_connector_best_encoder(struct drm_connector *connector)
 {
        struct rcar_du_connector *rcon = to_rcar_connector(connector);
 
-       return &rcon->encoder->encoder;
+       return rcar_encoder_to_drm_encoder(rcon->encoder);
 }
 
 /* -----------------------------------------------------------------------------
@@ -142,9 +144,11 @@ static const struct drm_encoder_funcs encoder_funcs = {
 int rcar_du_encoder_init(struct rcar_du_device *rcdu,
                         enum rcar_du_encoder_type type,
                         enum rcar_du_output output,
-                        const struct rcar_du_encoder_data *data)
+                        struct device_node *enc_node,
+                        struct device_node *con_node)
 {
        struct rcar_du_encoder *renc;
+       struct drm_encoder *encoder;
        unsigned int encoder_type;
        int ret;
 
@@ -153,6 +157,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
                return -ENOMEM;
 
        renc->output = output;
+       encoder = rcar_encoder_to_drm_encoder(renc);
 
        switch (output) {
        case RCAR_DU_OUTPUT_LVDS0:
@@ -174,6 +179,9 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
        case RCAR_DU_ENCODER_LVDS:
                encoder_type = DRM_MODE_ENCODER_LVDS;
                break;
+       case RCAR_DU_ENCODER_HDMI:
+               encoder_type = DRM_MODE_ENCODER_TMDS;
+               break;
        case RCAR_DU_ENCODER_NONE:
        default:
                /* No external encoder, use the internal encoder type. */
@@ -181,21 +189,35 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
                break;
        }
 
-       ret = drm_encoder_init(rcdu->ddev, &renc->encoder, &encoder_funcs,
-                              encoder_type);
-       if (ret < 0)
-               return ret;
+       if (type == RCAR_DU_ENCODER_HDMI) {
+               if (renc->lvds) {
+                       dev_err(rcdu->dev,
+                               "Chaining LVDS and HDMI encoders not supported\n");
+                       return -EINVAL;
+               }
 
-       drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs);
+               ret = rcar_du_hdmienc_init(rcdu, renc, enc_node);
+               if (ret < 0)
+                       return ret;
+       } else {
+               ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
+                                      encoder_type);
+               if (ret < 0)
+                       return ret;
+
+               drm_encoder_helper_add(encoder, &encoder_helper_funcs);
+       }
 
        switch (encoder_type) {
        case DRM_MODE_ENCODER_LVDS:
-               return rcar_du_lvds_connector_init(rcdu, renc,
-                                                  &data->connector.lvds.panel);
+               return rcar_du_lvds_connector_init(rcdu, renc, con_node);
 
        case DRM_MODE_ENCODER_DAC:
                return rcar_du_vga_connector_init(rcdu, renc);
 
+       case DRM_MODE_ENCODER_TMDS:
+               return rcar_du_hdmi_connector_init(rcdu, renc);
+
        default:
                return -EINVAL;
        }