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_crtc_helper.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 *dssdev; 40 }; 41 42 struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder) 43 { 44 struct omap_encoder *omap_encoder = to_omap_encoder(encoder); 45 46 return omap_encoder->dssdev; 47 } 48 49 static void omap_encoder_destroy(struct drm_encoder *encoder) 50 { 51 struct omap_encoder *omap_encoder = to_omap_encoder(encoder); 52 53 drm_encoder_cleanup(encoder); 54 kfree(omap_encoder); 55 } 56 57 static const struct drm_encoder_funcs omap_encoder_funcs = { 58 .destroy = omap_encoder_destroy, 59 }; 60 61 static void omap_encoder_mode_set(struct drm_encoder *encoder, 62 struct drm_display_mode *mode, 63 struct drm_display_mode *adjusted_mode) 64 { 65 struct drm_device *dev = encoder->dev; 66 struct omap_encoder *omap_encoder = to_omap_encoder(encoder); 67 struct omap_dss_device *dssdev = omap_encoder->dssdev; 68 struct drm_connector *connector; 69 bool hdmi_mode; 70 int r; 71 72 hdmi_mode = false; 73 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 74 if (connector->encoder == encoder) { 75 hdmi_mode = omap_connector_get_hdmi_mode(connector); 76 break; 77 } 78 } 79 80 if (dssdev->driver->set_hdmi_mode) 81 dssdev->driver->set_hdmi_mode(dssdev, hdmi_mode); 82 83 if (hdmi_mode && dssdev->driver->set_hdmi_infoframe) { 84 struct hdmi_avi_infoframe avi; 85 86 r = drm_hdmi_avi_infoframe_from_display_mode(&avi, adjusted_mode, 87 false); 88 if (r == 0) 89 dssdev->driver->set_hdmi_infoframe(dssdev, &avi); 90 } 91 } 92 93 static void omap_encoder_disable(struct drm_encoder *encoder) 94 { 95 struct omap_encoder *omap_encoder = to_omap_encoder(encoder); 96 struct omap_dss_device *dssdev = omap_encoder->dssdev; 97 struct omap_dss_driver *dssdrv = dssdev->driver; 98 99 dssdrv->disable(dssdev); 100 } 101 102 static int omap_encoder_update(struct drm_encoder *encoder, 103 enum omap_channel channel, 104 struct videomode *vm) 105 { 106 struct drm_device *dev = encoder->dev; 107 struct omap_encoder *omap_encoder = to_omap_encoder(encoder); 108 struct omap_dss_device *dssdev = omap_encoder->dssdev; 109 struct omap_dss_driver *dssdrv = dssdev->driver; 110 int ret; 111 112 if (dssdrv->check_timings) { 113 ret = dssdrv->check_timings(dssdev, vm); 114 } else { 115 struct videomode t = {0}; 116 117 dssdrv->get_timings(dssdev, &t); 118 119 if (memcmp(vm, &t, sizeof(*vm))) 120 ret = -EINVAL; 121 else 122 ret = 0; 123 } 124 125 if (ret) { 126 dev_err(dev->dev, "could not set timings: %d\n", ret); 127 return ret; 128 } 129 130 if (dssdrv->set_timings) 131 dssdrv->set_timings(dssdev, vm); 132 133 return 0; 134 } 135 136 static void omap_encoder_enable(struct drm_encoder *encoder) 137 { 138 struct omap_encoder *omap_encoder = to_omap_encoder(encoder); 139 struct omap_dss_device *dssdev = omap_encoder->dssdev; 140 struct omap_dss_driver *dssdrv = dssdev->driver; 141 int r; 142 143 omap_encoder_update(encoder, omap_crtc_channel(encoder->crtc), 144 omap_crtc_timings(encoder->crtc)); 145 146 r = dssdrv->enable(dssdev); 147 if (r) 148 dev_err(encoder->dev->dev, 149 "Failed to enable display '%s': %d\n", 150 dssdev->name, r); 151 } 152 153 static int omap_encoder_atomic_check(struct drm_encoder *encoder, 154 struct drm_crtc_state *crtc_state, 155 struct drm_connector_state *conn_state) 156 { 157 return 0; 158 } 159 160 static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { 161 .mode_set = omap_encoder_mode_set, 162 .disable = omap_encoder_disable, 163 .enable = omap_encoder_enable, 164 .atomic_check = omap_encoder_atomic_check, 165 }; 166 167 /* initialize encoder */ 168 struct drm_encoder *omap_encoder_init(struct drm_device *dev, 169 struct omap_dss_device *dssdev) 170 { 171 struct drm_encoder *encoder = NULL; 172 struct omap_encoder *omap_encoder; 173 174 omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL); 175 if (!omap_encoder) 176 goto fail; 177 178 omap_encoder->dssdev = dssdev; 179 180 encoder = &omap_encoder->base; 181 182 drm_encoder_init(dev, encoder, &omap_encoder_funcs, 183 DRM_MODE_ENCODER_TMDS, NULL); 184 drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs); 185 186 return encoder; 187 188 fail: 189 if (encoder) 190 omap_encoder_destroy(encoder); 191 192 return NULL; 193 } 194