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