linux/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
Laurent Pinchart c6a27fa41f drm: rcar-du: Convert LVDS encoder code to bridge driver
The LVDS encoders used to be described in DT as part of the DU. They now
have their own DT node, linked to the DU using the OF graph bindings.
This allows moving internal LVDS encoder support to a separate driver
modelled as a DRM bridge. Backward compatibility is retained as legacy
DT is patched live to move to the new bindings.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
2018-03-07 18:06:49 +02:00

99 lines
2.4 KiB
C

/*
* rcar_du_encoder.c -- R-Car Display Unit Encoder
*
* Copyright (C) 2013-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 <linux/export.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_panel.h>
#include "rcar_du_drv.h"
#include "rcar_du_encoder.h"
#include "rcar_du_kms.h"
/* -----------------------------------------------------------------------------
* Encoder
*/
static void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
rcar_du_crtc_route_output(crtc_state->crtc, renc->output);
}
static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
.atomic_mode_set = rcar_du_encoder_mode_set,
};
static const struct drm_encoder_funcs encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
int rcar_du_encoder_init(struct rcar_du_device *rcdu,
enum rcar_du_output output,
struct device_node *enc_node,
struct device_node *con_node)
{
struct rcar_du_encoder *renc;
struct drm_encoder *encoder;
struct drm_bridge *bridge = NULL;
int ret;
renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL);
if (renc == NULL)
return -ENOMEM;
renc->output = output;
encoder = rcar_encoder_to_drm_encoder(renc);
dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n",
enc_node, output);
/* Locate the DRM bridge from the encoder DT node. */
bridge = of_drm_find_bridge(enc_node);
if (!bridge) {
ret = -EPROBE_DEFER;
goto done;
}
ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
DRM_MODE_ENCODER_NONE, NULL);
if (ret < 0)
goto done;
drm_encoder_helper_add(encoder, &encoder_helper_funcs);
/*
* Attach the bridge to the encoder. The bridge will create the
* connector.
*/
ret = drm_bridge_attach(encoder, bridge, NULL);
if (ret) {
drm_encoder_cleanup(encoder);
return ret;
}
done:
if (ret < 0) {
if (encoder->name)
encoder->funcs->destroy(encoder);
devm_kfree(rcdu->dev, renc);
}
return ret;
}