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 *output;
40 	struct omap_dss_device *display;
41 };
42 
43 static void omap_encoder_destroy(struct drm_encoder *encoder)
44 {
45 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
46 
47 	drm_encoder_cleanup(encoder);
48 	kfree(omap_encoder);
49 }
50 
51 static const struct drm_encoder_funcs omap_encoder_funcs = {
52 	.destroy = omap_encoder_destroy,
53 };
54 
55 static void omap_encoder_mode_set(struct drm_encoder *encoder,
56 				  struct drm_display_mode *mode,
57 				  struct drm_display_mode *adjusted_mode)
58 {
59 	struct drm_device *dev = encoder->dev;
60 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
61 	struct drm_connector *connector;
62 	struct omap_dss_device *dssdev;
63 	struct videomode vm = { 0 };
64 	bool hdmi_mode;
65 	int r;
66 
67 	drm_display_mode_to_videomode(adjusted_mode, &vm);
68 
69 	/*
70 	 * HACK: This fixes the vm flags.
71 	 * struct drm_display_mode does not contain the VSYNC/HSYNC/DE flags and
72 	 * they get lost when converting back and forth between struct
73 	 * drm_display_mode and struct videomode. The hack below goes and
74 	 * fetches the missing flags.
75 	 *
76 	 * A better solution is to use DRM's bus-flags through the whole driver.
77 	 */
78 	for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
79 		unsigned long bus_flags = dssdev->bus_flags;
80 
81 		if (!(vm.flags & (DISPLAY_FLAGS_DE_LOW |
82 				  DISPLAY_FLAGS_DE_HIGH))) {
83 			if (bus_flags & DRM_BUS_FLAG_DE_LOW)
84 				vm.flags |= DISPLAY_FLAGS_DE_LOW;
85 			else if (bus_flags & DRM_BUS_FLAG_DE_HIGH)
86 				vm.flags |= DISPLAY_FLAGS_DE_HIGH;
87 		}
88 
89 		if (!(vm.flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |
90 				  DISPLAY_FLAGS_PIXDATA_NEGEDGE))) {
91 			if (bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
92 				vm.flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
93 			else if (bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
94 				vm.flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
95 		}
96 
97 		if (!(vm.flags & (DISPLAY_FLAGS_SYNC_POSEDGE |
98 				  DISPLAY_FLAGS_SYNC_NEGEDGE))) {
99 			if (bus_flags & DRM_BUS_FLAG_SYNC_POSEDGE)
100 				vm.flags |= DISPLAY_FLAGS_SYNC_POSEDGE;
101 			else if (bus_flags & DRM_BUS_FLAG_SYNC_NEGEDGE)
102 				vm.flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
103 		}
104 	}
105 
106 	/* Set timings for all devices in the display pipeline. */
107 	dss_mgr_set_timings(omap_encoder->output, &vm);
108 
109 	for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
110 		if (dssdev->ops->set_timings)
111 			dssdev->ops->set_timings(dssdev, &vm);
112 	}
113 
114 	/* Set the HDMI mode and HDMI infoframe if applicable. */
115 	hdmi_mode = false;
116 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
117 		if (connector->encoder == encoder) {
118 			hdmi_mode = omap_connector_get_hdmi_mode(connector);
119 			break;
120 		}
121 	}
122 
123 	dssdev = omap_encoder->output;
124 
125 	if (dssdev->ops->hdmi.set_hdmi_mode)
126 		dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode);
127 
128 	if (hdmi_mode && dssdev->ops->hdmi.set_infoframe) {
129 		struct hdmi_avi_infoframe avi;
130 
131 		r = drm_hdmi_avi_infoframe_from_display_mode(&avi, adjusted_mode,
132 							     false);
133 		if (r == 0)
134 			dssdev->ops->hdmi.set_infoframe(dssdev, &avi);
135 	}
136 }
137 
138 static void omap_encoder_disable(struct drm_encoder *encoder)
139 {
140 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
141 	struct omap_dss_device *dssdev = omap_encoder->display;
142 
143 	dssdev->ops->disable(dssdev);
144 }
145 
146 static void omap_encoder_enable(struct drm_encoder *encoder)
147 {
148 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
149 	struct omap_dss_device *dssdev = omap_encoder->display;
150 	int r;
151 
152 	r = dssdev->ops->enable(dssdev);
153 	if (r)
154 		dev_err(encoder->dev->dev,
155 			"Failed to enable display '%s': %d\n",
156 			dssdev->name, r);
157 }
158 
159 static int omap_encoder_atomic_check(struct drm_encoder *encoder,
160 				     struct drm_crtc_state *crtc_state,
161 				     struct drm_connector_state *conn_state)
162 {
163 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
164 	enum omap_channel channel = omap_encoder->output->dispc_channel;
165 	struct drm_device *dev = encoder->dev;
166 	struct omap_drm_private *priv = dev->dev_private;
167 	struct omap_dss_device *dssdev;
168 	struct videomode vm = { 0 };
169 	int ret;
170 
171 	drm_display_mode_to_videomode(&crtc_state->mode, &vm);
172 
173 	ret = priv->dispc_ops->mgr_check_timings(priv->dispc, channel, &vm);
174 	if (ret)
175 		goto done;
176 
177 	for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
178 		if (!dssdev->ops->check_timings)
179 			continue;
180 
181 		ret = dssdev->ops->check_timings(dssdev, &vm);
182 		if (ret)
183 			goto done;
184 	}
185 
186 	drm_display_mode_from_videomode(&vm, &crtc_state->adjusted_mode);
187 
188 done:
189 	if (ret)
190 		dev_err(dev->dev, "invalid timings: %d\n", ret);
191 
192 	return ret;
193 }
194 
195 static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
196 	.mode_set = omap_encoder_mode_set,
197 	.disable = omap_encoder_disable,
198 	.enable = omap_encoder_enable,
199 	.atomic_check = omap_encoder_atomic_check,
200 };
201 
202 /* initialize encoder */
203 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
204 				      struct omap_dss_device *output,
205 				      struct omap_dss_device *display)
206 {
207 	struct drm_encoder *encoder = NULL;
208 	struct omap_encoder *omap_encoder;
209 
210 	omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL);
211 	if (!omap_encoder)
212 		goto fail;
213 
214 	omap_encoder->output = output;
215 	omap_encoder->display = display;
216 
217 	encoder = &omap_encoder->base;
218 
219 	drm_encoder_init(dev, encoder, &omap_encoder_funcs,
220 			 DRM_MODE_ENCODER_TMDS, NULL);
221 	drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs);
222 
223 	return encoder;
224 
225 fail:
226 	if (encoder)
227 		omap_encoder_destroy(encoder);
228 
229 	return NULL;
230 }
231