at v3.13 202 lines 5.2 kB view raw
1/* 2 * rcar_du_encoder.c -- R-Car Display Unit Encoder 3 * 4 * Copyright (C) 2013 Renesas Corporation 5 * 6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 */ 13 14#include <linux/export.h> 15 16#include <drm/drmP.h> 17#include <drm/drm_crtc.h> 18#include <drm/drm_crtc_helper.h> 19 20#include "rcar_du_drv.h" 21#include "rcar_du_encoder.h" 22#include "rcar_du_kms.h" 23#include "rcar_du_lvdscon.h" 24#include "rcar_du_lvdsenc.h" 25#include "rcar_du_vgacon.h" 26 27/* ----------------------------------------------------------------------------- 28 * Common connector functions 29 */ 30 31struct drm_encoder * 32rcar_du_connector_best_encoder(struct drm_connector *connector) 33{ 34 struct rcar_du_connector *rcon = to_rcar_connector(connector); 35 36 return &rcon->encoder->encoder; 37} 38 39/* ----------------------------------------------------------------------------- 40 * Encoder 41 */ 42 43static void rcar_du_encoder_dpms(struct drm_encoder *encoder, int mode) 44{ 45 struct rcar_du_encoder *renc = to_rcar_encoder(encoder); 46 47 if (renc->lvds) 48 rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, mode); 49} 50 51static bool rcar_du_encoder_mode_fixup(struct drm_encoder *encoder, 52 const struct drm_display_mode *mode, 53 struct drm_display_mode *adjusted_mode) 54{ 55 struct rcar_du_encoder *renc = to_rcar_encoder(encoder); 56 const struct drm_display_mode *panel_mode; 57 struct drm_device *dev = encoder->dev; 58 struct drm_connector *connector; 59 bool found = false; 60 61 /* DAC encoders have currently no restriction on the mode. */ 62 if (encoder->encoder_type == DRM_MODE_ENCODER_DAC) 63 return true; 64 65 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 66 if (connector->encoder == encoder) { 67 found = true; 68 break; 69 } 70 } 71 72 if (!found) { 73 dev_dbg(dev->dev, "mode_fixup: no connector found\n"); 74 return false; 75 } 76 77 if (list_empty(&connector->modes)) { 78 dev_dbg(dev->dev, "mode_fixup: empty modes list\n"); 79 return false; 80 } 81 82 panel_mode = list_first_entry(&connector->modes, 83 struct drm_display_mode, head); 84 85 /* We're not allowed to modify the resolution. */ 86 if (mode->hdisplay != panel_mode->hdisplay || 87 mode->vdisplay != panel_mode->vdisplay) 88 return false; 89 90 /* The flat panel mode is fixed, just copy it to the adjusted mode. */ 91 drm_mode_copy(adjusted_mode, panel_mode); 92 93 /* The internal LVDS encoder has a clock frequency operating range of 94 * 30MHz to 150MHz. Clamp the clock accordingly. 95 */ 96 if (renc->lvds) 97 adjusted_mode->clock = clamp(adjusted_mode->clock, 98 30000, 150000); 99 100 return true; 101} 102 103static void rcar_du_encoder_mode_prepare(struct drm_encoder *encoder) 104{ 105 struct rcar_du_encoder *renc = to_rcar_encoder(encoder); 106 107 if (renc->lvds) 108 rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, 109 DRM_MODE_DPMS_OFF); 110} 111 112static void rcar_du_encoder_mode_commit(struct drm_encoder *encoder) 113{ 114 struct rcar_du_encoder *renc = to_rcar_encoder(encoder); 115 116 if (renc->lvds) 117 rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, 118 DRM_MODE_DPMS_ON); 119} 120 121static void rcar_du_encoder_mode_set(struct drm_encoder *encoder, 122 struct drm_display_mode *mode, 123 struct drm_display_mode *adjusted_mode) 124{ 125 struct rcar_du_encoder *renc = to_rcar_encoder(encoder); 126 127 rcar_du_crtc_route_output(encoder->crtc, renc->output); 128} 129 130static const struct drm_encoder_helper_funcs encoder_helper_funcs = { 131 .dpms = rcar_du_encoder_dpms, 132 .mode_fixup = rcar_du_encoder_mode_fixup, 133 .prepare = rcar_du_encoder_mode_prepare, 134 .commit = rcar_du_encoder_mode_commit, 135 .mode_set = rcar_du_encoder_mode_set, 136}; 137 138static const struct drm_encoder_funcs encoder_funcs = { 139 .destroy = drm_encoder_cleanup, 140}; 141 142int rcar_du_encoder_init(struct rcar_du_device *rcdu, 143 enum rcar_du_encoder_type type, 144 enum rcar_du_output output, 145 const struct rcar_du_encoder_data *data) 146{ 147 struct rcar_du_encoder *renc; 148 unsigned int encoder_type; 149 int ret; 150 151 renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL); 152 if (renc == NULL) 153 return -ENOMEM; 154 155 renc->output = output; 156 157 switch (output) { 158 case RCAR_DU_OUTPUT_LVDS0: 159 renc->lvds = rcdu->lvds[0]; 160 break; 161 162 case RCAR_DU_OUTPUT_LVDS1: 163 renc->lvds = rcdu->lvds[1]; 164 break; 165 166 default: 167 break; 168 } 169 170 switch (type) { 171 case RCAR_DU_ENCODER_VGA: 172 encoder_type = DRM_MODE_ENCODER_DAC; 173 break; 174 case RCAR_DU_ENCODER_LVDS: 175 encoder_type = DRM_MODE_ENCODER_LVDS; 176 break; 177 case RCAR_DU_ENCODER_NONE: 178 default: 179 /* No external encoder, use the internal encoder type. */ 180 encoder_type = rcdu->info->routes[output].encoder_type; 181 break; 182 } 183 184 ret = drm_encoder_init(rcdu->ddev, &renc->encoder, &encoder_funcs, 185 encoder_type); 186 if (ret < 0) 187 return ret; 188 189 drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs); 190 191 switch (encoder_type) { 192 case DRM_MODE_ENCODER_LVDS: 193 return rcar_du_lvds_connector_init(rcdu, renc, 194 &data->connector.lvds.panel); 195 196 case DRM_MODE_ENCODER_DAC: 197 return rcar_du_vga_connector_init(rcdu, renc); 198 199 default: 200 return -EINVAL; 201 } 202}