Skip to content

Commit

Permalink
drm: rcar-du: Add HDMI encoder and connector support
Browse files Browse the repository at this point in the history
SoCs that integrate the DU have no internal HDMI encoder, support
external encoders only.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
  • Loading branch information
Laurent Pinchart committed Nov 26, 2014
1 parent 69746b4 commit 637e619
Show file tree
Hide file tree
Showing 9 changed files with 375 additions and 7 deletions.
11 changes: 9 additions & 2 deletions drivers/gpu/drm/rcar-du/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,17 @@ config DRM_RCAR_DU
Choose this option if you have an R-Car chipset.
If M is selected the module will be called rcar-du-drm.

config DRM_RCAR_HDMI
bool "R-Car DU HDMI Encoder Support"
depends on DRM_RCAR_DU
depends on OF
help
Enable support for external HDMI encoders.

config DRM_RCAR_LVDS
bool "R-Car DU LVDS Encoder Support"
depends on DRM_RCAR_DU
depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST
help
Enable support the R-Car Display Unit embedded LVDS encoders
(currently only on R8A7790).
Enable support for the R-Car Display Unit embedded LVDS encoders
(currently only on R8A7790 and R8A7791).
2 changes: 2 additions & 0 deletions drivers/gpu/drm/rcar-du/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ rcar-du-drm-y := rcar_du_crtc.o \
rcar_du_plane.o \
rcar_du_vgacon.o

rcar-du-drm-$(CONFIG_DRM_RCAR_HDMI) += rcar_du_hdmicon.o \
rcar_du_hdmienc.o
rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_lvdsenc.o

obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o
30 changes: 25 additions & 5 deletions drivers/gpu/drm/rcar-du/rcar_du_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -177,19 +179,34 @@ 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. */
encoder_type = rcdu->info->routes[output].encoder_type;
break;
}

ret = drm_encoder_init(rcdu->ddev, 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(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:
Expand All @@ -198,6 +215,9 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
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;
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/rcar-du/rcar_du_encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,21 @@
#include <drm/drm_encoder_slave.h>

struct rcar_du_device;
struct rcar_du_hdmienc;
struct rcar_du_lvdsenc;

enum rcar_du_encoder_type {
RCAR_DU_ENCODER_UNUSED = 0,
RCAR_DU_ENCODER_NONE,
RCAR_DU_ENCODER_VGA,
RCAR_DU_ENCODER_LVDS,
RCAR_DU_ENCODER_HDMI,
};

struct rcar_du_encoder {
struct drm_encoder_slave slave;
enum rcar_du_output output;
struct rcar_du_hdmienc *hdmi;
struct rcar_du_lvdsenc *lvds;
};

Expand Down
118 changes: 118 additions & 0 deletions drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* R-Car Display Unit HDMI Connector
*
* Copyright (C) 2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/

#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder_slave.h>

#include "rcar_du_drv.h"
#include "rcar_du_encoder.h"
#include "rcar_du_hdmicon.h"
#include "rcar_du_kms.h"

#define to_slave_funcs(e) (to_rcar_encoder(e)->slave.slave_funcs)

static int rcar_du_hdmi_connector_get_modes(struct drm_connector *connector)
{
struct drm_encoder *encoder = connector->encoder;
struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);

if (sfuncs->get_modes == NULL)
return 0;

return sfuncs->get_modes(encoder, connector);
}

static int rcar_du_hdmi_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct drm_encoder *encoder = connector->encoder;
struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);

if (sfuncs->mode_valid == NULL)
return MODE_OK;

return sfuncs->mode_valid(encoder, mode);
}

static const struct drm_connector_helper_funcs connector_helper_funcs = {
.get_modes = rcar_du_hdmi_connector_get_modes,
.mode_valid = rcar_du_hdmi_connector_mode_valid,
.best_encoder = rcar_du_connector_best_encoder,
};

static void rcar_du_hdmi_connector_destroy(struct drm_connector *connector)
{
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
}

static enum drm_connector_status
rcar_du_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
struct drm_encoder *encoder = connector->encoder;
struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);

if (sfuncs->detect == NULL)
return connector_status_unknown;

return sfuncs->detect(encoder, connector);
}

static const struct drm_connector_funcs connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = rcar_du_hdmi_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = rcar_du_hdmi_connector_destroy,
};

int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
struct rcar_du_encoder *renc)
{
struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);
struct rcar_du_connector *rcon;
struct drm_connector *connector;
int ret;

rcon = devm_kzalloc(rcdu->dev, sizeof(*rcon), GFP_KERNEL);
if (rcon == NULL)
return -ENOMEM;

connector = &rcon->connector;
connector->display_info.width_mm = 0;
connector->display_info.height_mm = 0;

ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
if (ret < 0)
return ret;

drm_connector_helper_add(connector, &connector_helper_funcs);
ret = drm_connector_register(connector);
if (ret < 0)
return ret;

drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
drm_object_property_set_value(&connector->base,
rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);

ret = drm_mode_connector_attach_encoder(connector, encoder);
if (ret < 0)
return ret;

connector->encoder = encoder;
rcon->encoder = renc;

return 0;
}
31 changes: 31 additions & 0 deletions drivers/gpu/drm/rcar-du/rcar_du_hdmicon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* R-Car Display Unit HDMI Connector
*
* Copyright (C) 2014 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/

#ifndef __RCAR_DU_HDMICON_H__
#define __RCAR_DU_HDMICON_H__

struct rcar_du_device;
struct rcar_du_encoder;

#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI)
int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
struct rcar_du_encoder *renc);
#else
static inline int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
struct rcar_du_encoder *renc)
{
return -ENOSYS;
}
#endif

#endif /* __RCAR_DU_HDMICON_H__ */
Loading

0 comments on commit 637e619

Please sign in to comment.