1 /* 2 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 3 * Author: Rob Clark <rob@ti.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include <linux/list.h> 19 20 #include <drm/drm_crtc.h> 21 #include <drm/drm_modeset_helper_vtables.h> 22 #include <drm/drm_edid.h> 23 24 #include "omap_drv.h" 25 26 /* 27 * encoder funcs 28 */ 29 30 #define to_omap_encoder(x) container_of(x, struct omap_encoder, base) 31 32 /* The encoder and connector both map to same dssdev.. the encoder 33 * handles the 'active' parts, ie. anything the modifies the state 34 * of the hw, and the connector handles the 'read-only' parts, like 35 * detecting connection and reading edid. 36 */ 37 struct omap_encoder { 38 struct drm_encoder base; 39 struct omap_dss_device *output; 40 }; 41 42 static void omap_encoder_destroy(struct drm_encoder *encoder) 43 { 44 struct omap_encoder *omap_encoder = to_omap_encoder(encoder); 45 46 drm_encoder_cleanup(encoder); 47 kfree(omap_encoder); 48 } 49 50 static const struct drm_encoder_funcs omap_encoder_funcs = { 51 .destroy = omap_encoder_destroy, 52 }; 53 54 static void omap_encoder_hdmi_mode_set(struct drm_encoder *encoder, 55 struct drm_display_mode *adjusted_mode) 56 { 57 struct drm_device *dev = encoder->dev; 58 struct omap_encoder *omap_encoder = to_omap_encoder(encoder); 59 struct omap_dss_device *dssdev = omap_encoder->output; 60 struct drm_connector *connector; 61 bool hdmi_mode; 62 63 hdmi_mode = false; 64 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 65 if (connector->encoder == encoder) { 66 hdmi_mode = omap_connector_get_hdmi_mode(connector); 67 break; 68 } 69 } 70 71 if (dssdev->ops->hdmi.set_hdmi_mode) 72 dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode); 73 74 if (hdmi_mode && dssdev->ops->hdmi.set_infoframe) { 75 struct hdmi_avi_infoframe avi; 76 int r; 77 78 r = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector, 79 adjusted_mode); 80 if (r == 0) 81 dssdev->ops->hdmi.set_infoframe(dssdev, &avi); 82 } 83 } 84 85 static void omap_encoder_mode_set(struct drm_encoder *encoder, 86 struct drm_display_mode *mode, 87 struct drm_display_mode *adjusted_mode) 88 { 89 struct omap_encoder *omap_encoder = to_omap_encoder(encoder); 90 struct omap_dss_device *dssdev; 91 struct videomode vm = { 0 }; 92 93 drm_display_mode_to_videomode(adjusted_mode, &vm); 94 95 /* 96 * HACK: This fixes the vm flags. 97 * struct drm_display_mode does not contain the VSYNC/HSYNC/DE flags and 98 * they get lost when converting back and forth between struct 99 * drm_display_mode and struct videomode. The hack below goes and 100 * fetches the missing flags. 101 * 102 * A better solution is to use DRM's bus-flags through the whole driver. 103 */ 104 for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) { 105 unsigned long bus_flags = dssdev->bus_flags; 106 107 if (!(vm.flags & (DISPLAY_FLAGS_DE_LOW | 108 DISPLAY_FLAGS_DE_HIGH))) { 109 if (bus_flags & DRM_BUS_FLAG_DE_LOW) 110 vm.flags |= DISPLAY_FLAGS_DE_LOW; 111 else if (bus_flags & DRM_BUS_FLAG_DE_HIGH) 112 vm.flags |= DISPLAY_FLAGS_DE_HIGH; 113 } 114 115 if (!(vm.flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE | 116 DISPLAY_FLAGS_PIXDATA_NEGEDGE))) { 117 if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE) 118 vm.flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE; 119 else if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) 120 vm.flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE; 121 } 122 123 if (!(vm.flags & (DISPLAY_FLAGS_SYNC_POSEDGE | 124 DISPLAY_FLAGS_SYNC_NEGEDGE))) { 125 if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE) 126 vm.flags |= DISPLAY_FLAGS_SYNC_POSEDGE; 127 else if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE) 128 vm.flags |= DISPLAY_FLAGS_SYNC_NEGEDGE; 129 } 130 } 131 132 /* Set timings for all devices in the display pipeline. */ 133 dss_mgr_set_timings(omap_encoder->output, &vm); 134 135 for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) { 136 if (dssdev->ops->set_timings) 137 dssdev->ops->set_timings(dssdev, adjusted_mode); 138 } 139 140 /* Set the HDMI mode and HDMI infoframe if applicable. */ 141 if (omap_encoder->output->type == OMAP_DISPLAY_TYPE_HDMI) 142 omap_encoder_hdmi_mode_set(encoder, adjusted_mode); 143 } 144 145 static void omap_encoder_disable(struct drm_encoder *encoder) 146 { 147 struct omap_encoder *omap_encoder = to_omap_encoder(encoder); 148 struct omap_dss_device *dssdev = omap_encoder->output; 149 struct drm_device *dev = encoder->dev; 150 151 dev_dbg(dev->dev, "disable(%s)\n", dssdev->name); 152 153 /* 154 * Disable the chain of external devices, starting at the one at the 155 * internal encoder's output. 156 */ 157 omapdss_device_disable(dssdev->next); 158 159 /* 160 * Disable the internal encoder. This will disable the DSS output. The 161 * DSI is treated as an exception as DSI pipelines still use the legacy 162 * flow where the pipeline output controls the encoder. 163 */ 164 if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) { 165 dssdev->ops->disable(dssdev); 166 dssdev->state = OMAP_DSS_DISPLAY_DISABLED; 167 } 168 169 /* 170 * Perform the post-disable operations on the chain of external devices 171 * to complete the display pipeline disable. 172 */ 173 omapdss_device_post_disable(dssdev->next); 174 } 175 176 static void omap_encoder_enable(struct drm_encoder *encoder) 177 { 178 struct omap_encoder *omap_encoder = to_omap_encoder(encoder); 179 struct omap_dss_device *dssdev = omap_encoder->output; 180 struct drm_device *dev = encoder->dev; 181 182 dev_dbg(dev->dev, "enable(%s)\n", dssdev->name); 183 184 /* Prepare the chain of external devices for pipeline enable. */ 185 omapdss_device_pre_enable(dssdev->next); 186 187 /* 188 * Enable the internal encoder. This will enable the DSS output. The 189 * DSI is treated as an exception as DSI pipelines still use the legacy 190 * flow where the pipeline output controls the encoder. 191 */ 192 if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) { 193 dssdev->ops->enable(dssdev); 194 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; 195 } 196 197 /* 198 * Enable the chain of external devices, starting at the one at the 199 * internal encoder's output. 200 */ 201 omapdss_device_enable(dssdev->next); 202 } 203 204 static int omap_encoder_atomic_check(struct drm_encoder *encoder, 205 struct drm_crtc_state *crtc_state, 206 struct drm_connector_state *conn_state) 207 { 208 struct omap_encoder *omap_encoder = to_omap_encoder(encoder); 209 enum drm_mode_status status; 210 211 status = omap_connector_mode_fixup(omap_encoder->output, 212 &crtc_state->mode, 213 &crtc_state->adjusted_mode); 214 if (status != MODE_OK) { 215 dev_err(encoder->dev->dev, "invalid timings: %d\n", status); 216 return -EINVAL; 217 } 218 219 return 0; 220 } 221 222 static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { 223 .mode_set = omap_encoder_mode_set, 224 .disable = omap_encoder_disable, 225 .enable = omap_encoder_enable, 226 .atomic_check = omap_encoder_atomic_check, 227 }; 228 229 /* initialize encoder */ 230 struct drm_encoder *omap_encoder_init(struct drm_device *dev, 231 struct omap_dss_device *output) 232 { 233 struct drm_encoder *encoder = NULL; 234 struct omap_encoder *omap_encoder; 235 236 omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL); 237 if (!omap_encoder) 238 goto fail; 239 240 omap_encoder->output = output; 241 242 encoder = &omap_encoder->base; 243 244 drm_encoder_init(dev, encoder, &omap_encoder_funcs, 245 DRM_MODE_ENCODER_TMDS, NULL); 246 drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs); 247 248 return encoder; 249 250 fail: 251 if (encoder) 252 omap_encoder_destroy(encoder); 253 254 return NULL; 255 } 256