Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef67a902 authored by Laurent Pinchart's avatar Laurent Pinchart
Browse files

drm/rcar-du: Rework output routing support



Split the output routing specification between SoC-internal data,
specified in the rcar_du_device_info structure, and board data, passed
through platform data.

The DU has 5 possible outputs (DPAD0/1, LVDS0/1, TCON). SoC-internal
output routing data specify which output are valid, which CRTCs can be
connected to the valid outputs, and the type of in-SoC encoder for the
output.

Platform data then specifies external encoders and the output they are
connected to.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
parent 38b62fb3
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -129,14 +129,16 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
	rcar_du_crtc_write(rcrtc, DEWR,  mode->hdisplay);
}

void rcar_du_crtc_route_output(struct drm_crtc *crtc, unsigned int output)
void rcar_du_crtc_route_output(struct drm_crtc *crtc,
			       enum rcar_du_output output)
{
	struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
	struct rcar_du_device *rcdu = rcrtc->group->dev;

	/* Store the route from the CRTC output to the DU output. The DU will be
	 * configured when starting the CRTC.
	 */
	rcrtc->outputs |= 1 << output;
	rcrtc->outputs |= BIT(output);
}

void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
+3 −1
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#define __RCAR_DU_CRTC_H__

#include <linux/mutex.h>
#include <linux/platform_data/rcar-du.h>

#include <drm/drmP.h>
#include <drm/drm_crtc.h>
@@ -45,7 +46,8 @@ void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc);
void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc);

void rcar_du_crtc_route_output(struct drm_crtc *crtc, unsigned int output);
void rcar_du_crtc_route_output(struct drm_crtc *crtc,
			       enum rcar_du_output output);
void rcar_du_crtc_update_planes(struct drm_crtc *crtc);

#endif /* __RCAR_DU_CRTC_H__ */
+30 −0
Original line number Diff line number Diff line
@@ -219,12 +219,42 @@ static int rcar_du_remove(struct platform_device *pdev)
static const struct rcar_du_device_info rcar_du_r8a7779_info = {
	.features = 0,
	.num_crtcs = 2,
	.routes = {
		/* R8A7779 has two RGB outputs and one (currently unsupported)
		 * TCON output.
		 */
		[RCAR_DU_OUTPUT_DPAD0] = {
			.possible_crtcs = BIT(0),
			.encoder_type = DRM_MODE_ENCODER_NONE,
		},
		[RCAR_DU_OUTPUT_DPAD1] = {
			.possible_crtcs = BIT(1) | BIT(0),
			.encoder_type = DRM_MODE_ENCODER_NONE,
		},
	},
};

static const struct rcar_du_device_info rcar_du_r8a7790_info = {
	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_ALIGN_128B
		  | RCAR_DU_FEATURE_DEFR8,
	.num_crtcs = 3,
	.routes = {
		/* R8A7790 has one RGB output, two LVDS outputs and one
		 * (currently unsupported) TCON output.
		 */
		[RCAR_DU_OUTPUT_DPAD0] = {
			.possible_crtcs = BIT(2) | BIT(1) | BIT(0),
			.encoder_type = DRM_MODE_ENCODER_NONE,
		},
		[RCAR_DU_OUTPUT_LVDS0] = {
			.possible_crtcs = BIT(0),
			.encoder_type = DRM_MODE_ENCODER_LVDS,
		},
		[RCAR_DU_OUTPUT_LVDS1] = {
			.possible_crtcs = BIT(2) | BIT(1),
			.encoder_type = DRM_MODE_ENCODER_LVDS,
		},
	},
};

static const struct platform_device_id rcar_du_id_table[] = {
+16 −0
Original line number Diff line number Diff line
@@ -29,14 +29,30 @@ struct rcar_du_device;
#define RCAR_DU_FEATURE_ALIGN_128B	(1 << 1)	/* Align pitches to 128 bytes */
#define RCAR_DU_FEATURE_DEFR8		(1 << 2)	/* Has DEFR8 register */

/*
 * struct rcar_du_output_routing - Output routing specification
 * @possible_crtcs: bitmask of possible CRTCs for the output
 * @encoder_type: DRM type of the internal encoder associated with the output
 *
 * The DU has 5 possible outputs (DPAD0/1, LVDS0/1, TCON). Output routing data
 * specify the valid SoC outputs, which CRTCs can drive the output, and the type
 * of in-SoC encoder for the output.
 */
struct rcar_du_output_routing {
	unsigned int possible_crtcs;
	unsigned int encoder_type;
};

/*
 * struct rcar_du_device_info - DU model-specific information
 * @features: device features (RCAR_DU_FEATURE_*)
 * @num_crtcs: total number of CRTCs
 * @routes: array of CRTC to output routes, indexed by output (RCAR_DU_OUTPUT_*)
 */
struct rcar_du_device_info {
	unsigned int features;
	unsigned int num_crtcs;
	struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX];
};

struct rcar_du_device {
+21 −5
Original line number Diff line number Diff line
@@ -115,10 +115,12 @@ static const struct drm_encoder_funcs encoder_funcs = {
};

int rcar_du_encoder_init(struct rcar_du_device *rcdu,
			 enum rcar_du_encoder_type type, unsigned int output,
			 enum rcar_du_encoder_type type,
			 enum rcar_du_output output,
			 const struct rcar_du_encoder_data *data)
{
	struct rcar_du_encoder *renc;
	unsigned int encoder_type;
	int ret;

	renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL);
@@ -127,19 +129,33 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,

	renc->output = output;

	switch (type) {
	case RCAR_DU_ENCODER_VGA:
		encoder_type = DRM_MODE_ENCODER_DAC;
		break;
	case RCAR_DU_ENCODER_LVDS:
		encoder_type = DRM_MODE_ENCODER_LVDS;
		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, &renc->encoder, &encoder_funcs,
			       type);
			       encoder_type);
	if (ret < 0)
		return ret;

	drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs);

	switch (type) {
	case RCAR_DU_ENCODER_LVDS:
	switch (encoder_type) {
	case DRM_MODE_ENCODER_LVDS:
		return rcar_du_lvds_connector_init(rcdu, renc,
						   &data->connector.lvds.panel);

	case RCAR_DU_ENCODER_VGA:
	case DRM_MODE_ENCODER_DAC:
		return rcar_du_vga_connector_init(rcdu, renc);

	default:
Loading