14bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart/*
26978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart * rcar_du_encoder.c  --  R-Car Display Unit Encoder
34bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart *
436d50464e05f498fa4024270e091b306af5de898Laurent Pinchart * Copyright (C) 2013-2014 Renesas Electronics Corporation
54bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart *
64bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
74bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart *
84bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart * This program is free software; you can redistribute it and/or modify
94bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart * it under the terms of the GNU General Public License as published by
104bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart * the Free Software Foundation; either version 2 of the License, or
114bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart * (at your option) any later version.
124bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart */
134bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
1490374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart#include <linux/export.h>
1590374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart
164bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart#include <drm/drmP.h>
174bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart#include <drm/drm_crtc.h>
184bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart#include <drm/drm_crtc_helper.h>
194bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
204bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart#include "rcar_du_drv.h"
216978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart#include "rcar_du_encoder.h"
224bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart#include "rcar_du_kms.h"
2356c5dd00f8db27a429647b14c8c309bd5d9c1d15Laurent Pinchart#include "rcar_du_lvdscon.h"
2490374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart#include "rcar_du_lvdsenc.h"
256978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart#include "rcar_du_vgacon.h"
264bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
276978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart/* -----------------------------------------------------------------------------
286978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart * Common connector functions
296978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart */
306978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart
316978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchartstruct drm_encoder *
326978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchartrcar_du_connector_best_encoder(struct drm_connector *connector)
334bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart{
346978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart	struct rcar_du_connector *rcon = to_rcar_connector(connector);
356978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart
366978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart	return &rcon->encoder->encoder;
374bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart}
384bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
396978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart/* -----------------------------------------------------------------------------
406978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart * Encoder
416978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart */
426978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart
436978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchartstatic void rcar_du_encoder_dpms(struct drm_encoder *encoder, int mode)
446978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart{
4590374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
4690374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart
4790374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	if (renc->lvds)
4890374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart		rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, mode);
496978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart}
506978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart
516978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchartstatic bool rcar_du_encoder_mode_fixup(struct drm_encoder *encoder,
526978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart				       const struct drm_display_mode *mode,
536978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart				       struct drm_display_mode *adjusted_mode)
544bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart{
5590374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
564bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	const struct drm_display_mode *panel_mode;
574bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	struct drm_device *dev = encoder->dev;
584bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	struct drm_connector *connector;
594bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	bool found = false;
604bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
616978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart	/* DAC encoders have currently no restriction on the mode. */
626978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart	if (encoder->encoder_type == DRM_MODE_ENCODER_DAC)
636978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart		return true;
646978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart
654bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
664bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart		if (connector->encoder == encoder) {
674bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart			found = true;
684bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart			break;
694bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart		}
704bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	}
714bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
724bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	if (!found) {
734bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart		dev_dbg(dev->dev, "mode_fixup: no connector found\n");
744bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart		return false;
754bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	}
764bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
774bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	if (list_empty(&connector->modes)) {
784bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart		dev_dbg(dev->dev, "mode_fixup: empty modes list\n");
794bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart		return false;
804bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	}
814bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
824bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	panel_mode = list_first_entry(&connector->modes,
834bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart				      struct drm_display_mode, head);
844bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
854bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	/* We're not allowed to modify the resolution. */
864bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	if (mode->hdisplay != panel_mode->hdisplay ||
874bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	    mode->vdisplay != panel_mode->vdisplay)
884bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart		return false;
894bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
904bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	/* The flat panel mode is fixed, just copy it to the adjusted mode. */
914bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	drm_mode_copy(adjusted_mode, panel_mode);
924bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
9390374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	/* The internal LVDS encoder has a clock frequency operating range of
9490374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	 * 30MHz to 150MHz. Clamp the clock accordingly.
9590374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	 */
9690374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	if (renc->lvds)
9790374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart		adjusted_mode->clock = clamp(adjusted_mode->clock,
9890374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart					     30000, 150000);
9990374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart
1004bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	return true;
1014bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart}
1024bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
1036978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchartstatic void rcar_du_encoder_mode_prepare(struct drm_encoder *encoder)
1046978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart{
10590374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
10690374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart
10790374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	if (renc->lvds)
10890374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart		rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc,
10990374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart				     DRM_MODE_DPMS_OFF);
1106978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart}
1116978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart
1126978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchartstatic void rcar_du_encoder_mode_commit(struct drm_encoder *encoder)
1136978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart{
11490374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
11590374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart
11690374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	if (renc->lvds)
11790374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart		rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc,
11890374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart				     DRM_MODE_DPMS_ON);
1196978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart}
1206978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart
1216978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchartstatic void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
1226978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart				     struct drm_display_mode *mode,
1236978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart				     struct drm_display_mode *adjusted_mode)
1246978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart{
1256978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart	struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
1266978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart
1276978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart	rcar_du_crtc_route_output(encoder->crtc, renc->output);
1286978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart}
1296978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart
1304bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchartstatic const struct drm_encoder_helper_funcs encoder_helper_funcs = {
1316978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart	.dpms = rcar_du_encoder_dpms,
1326978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart	.mode_fixup = rcar_du_encoder_mode_fixup,
1334bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	.prepare = rcar_du_encoder_mode_prepare,
1344bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	.commit = rcar_du_encoder_mode_commit,
1354bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	.mode_set = rcar_du_encoder_mode_set,
1364bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart};
1374bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
1384bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchartstatic const struct drm_encoder_funcs encoder_funcs = {
1394bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	.destroy = drm_encoder_cleanup,
1404bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart};
1414bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
1426978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchartint rcar_du_encoder_init(struct rcar_du_device *rcdu,
143ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart			 enum rcar_du_encoder_type type,
144ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart			 enum rcar_du_output output,
14596c026911890ceacee238da00a0b140ad634cc43Laurent Pinchart			 const struct rcar_du_encoder_data *data,
14696c026911890ceacee238da00a0b140ad634cc43Laurent Pinchart			 struct device_node *np)
1474bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart{
1484bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	struct rcar_du_encoder *renc;
149ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart	unsigned int encoder_type;
1504bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	int ret;
1514bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
1524bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL);
1534bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	if (renc == NULL)
1544bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart		return -ENOMEM;
1554bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
1564bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	renc->output = output;
1574bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
15890374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	switch (output) {
15990374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	case RCAR_DU_OUTPUT_LVDS0:
16090374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart		renc->lvds = rcdu->lvds[0];
16190374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart		break;
16290374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart
16390374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	case RCAR_DU_OUTPUT_LVDS1:
16490374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart		renc->lvds = rcdu->lvds[1];
16590374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart		break;
16690374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart
16790374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	default:
16890374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart		break;
16990374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart	}
17090374b5c25c9f04895c52a1e7a2468ee8dac525bLaurent Pinchart
171ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart	switch (type) {
172ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart	case RCAR_DU_ENCODER_VGA:
173ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart		encoder_type = DRM_MODE_ENCODER_DAC;
174ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart		break;
175ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart	case RCAR_DU_ENCODER_LVDS:
176ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart		encoder_type = DRM_MODE_ENCODER_LVDS;
177ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart		break;
178ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart	case RCAR_DU_ENCODER_NONE:
179ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart	default:
180ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart		/* No external encoder, use the internal encoder type. */
181ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart		encoder_type = rcdu->info->routes[output].encoder_type;
182ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart		break;
183ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart	}
184ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart
1854bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	ret = drm_encoder_init(rcdu->ddev, &renc->encoder, &encoder_funcs,
186ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart			       encoder_type);
1874bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	if (ret < 0)
1884bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart		return ret;
1894bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
1904bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart	drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs);
1914bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart
192ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart	switch (encoder_type) {
19396c026911890ceacee238da00a0b140ad634cc43Laurent Pinchart	case DRM_MODE_ENCODER_LVDS: {
19496c026911890ceacee238da00a0b140ad634cc43Laurent Pinchart		const struct rcar_du_panel_data *pdata =
19596c026911890ceacee238da00a0b140ad634cc43Laurent Pinchart			data ? &data->connector.lvds.panel : NULL;
19696c026911890ceacee238da00a0b140ad634cc43Laurent Pinchart		return rcar_du_lvds_connector_init(rcdu, renc, pdata, np);
19796c026911890ceacee238da00a0b140ad634cc43Laurent Pinchart	}
1986978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart
199ef67a902e946ad1ef51040cf287a45cc4714e2b5Laurent Pinchart	case DRM_MODE_ENCODER_DAC:
2006978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart		return rcar_du_vga_connector_init(rcdu, renc);
2016978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart
2026978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart	default:
2036978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart		return -EINVAL;
2046978f123776594b251d26dac9bcdf3ce8e9781c8Laurent Pinchart	}
2054bf8e1962f91eed5dbee168d2348983dda0a518fLaurent Pinchart}
206