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 #include <drm/drm_panel.h>
24 
25 #include "omap_drv.h"
26 
27 /*
28  * encoder funcs
29  */
30 
31 #define to_omap_encoder(x) container_of(x, struct omap_encoder, base)
32 
33 /* The encoder and connector both map to same dssdev.. the encoder
34  * handles the 'active' parts, ie. anything the modifies the state
35  * of the hw, and the connector handles the 'read-only' parts, like
36  * detecting connection and reading edid.
37  */
38 struct omap_encoder {
39 	struct drm_encoder base;
40 	struct omap_dss_device *output;
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_update_videomode_flags(struct videomode *vm,
56 						u32 bus_flags)
57 {
58 	if (!(vm->flags & (DISPLAY_FLAGS_DE_LOW |
59 			   DISPLAY_FLAGS_DE_HIGH))) {
60 		if (bus_flags & DRM_BUS_FLAG_DE_LOW)
61 			vm->flags |= DISPLAY_FLAGS_DE_LOW;
62 		else if (bus_flags & DRM_BUS_FLAG_DE_HIGH)
63 			vm->flags |= DISPLAY_FLAGS_DE_HIGH;
64 	}
65 
66 	if (!(vm->flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |
67 			   DISPLAY_FLAGS_PIXDATA_NEGEDGE))) {
68 		if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
69 			vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
70 		else if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
71 			vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
72 	}
73 
74 	if (!(vm->flags & (DISPLAY_FLAGS_SYNC_POSEDGE |
75 			   DISPLAY_FLAGS_SYNC_NEGEDGE))) {
76 		if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE)
77 			vm->flags |= DISPLAY_FLAGS_SYNC_POSEDGE;
78 		else if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE)
79 			vm->flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
80 	}
81 }
82 
83 static void omap_encoder_hdmi_mode_set(struct drm_connector *connector,
84 				       struct drm_encoder *encoder,
85 				       struct drm_display_mode *adjusted_mode)
86 {
87 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
88 	struct omap_dss_device *dssdev = omap_encoder->output;
89 	bool hdmi_mode;
90 
91 	hdmi_mode = omap_connector_get_hdmi_mode(connector);
92 
93 	if (dssdev->ops->hdmi.set_hdmi_mode)
94 		dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode);
95 
96 	if (hdmi_mode && dssdev->ops->hdmi.set_infoframe) {
97 		struct hdmi_avi_infoframe avi;
98 		int r;
99 
100 		r = drm_hdmi_avi_infoframe_from_display_mode(&avi, connector,
101 							     adjusted_mode);
102 		if (r == 0)
103 			dssdev->ops->hdmi.set_infoframe(dssdev, &avi);
104 	}
105 }
106 
107 static void omap_encoder_mode_set(struct drm_encoder *encoder,
108 				  struct drm_display_mode *mode,
109 				  struct drm_display_mode *adjusted_mode)
110 {
111 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
112 	struct omap_dss_device *output = omap_encoder->output;
113 	struct omap_dss_device *dssdev;
114 	struct drm_device *dev = encoder->dev;
115 	struct drm_connector *connector;
116 	struct drm_bridge *bridge;
117 	struct videomode vm = { 0 };
118 	u32 bus_flags;
119 
120 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
121 		if (connector->encoder == encoder)
122 			break;
123 	}
124 
125 	drm_display_mode_to_videomode(adjusted_mode, &vm);
126 
127 	/*
128 	 * HACK: This fixes the vm flags.
129 	 * struct drm_display_mode does not contain the VSYNC/HSYNC/DE flags and
130 	 * they get lost when converting back and forth between struct
131 	 * drm_display_mode and struct videomode. The hack below goes and
132 	 * fetches the missing flags.
133 	 *
134 	 * A better solution is to use DRM's bus-flags through the whole driver.
135 	 */
136 	for (dssdev = output; dssdev; dssdev = dssdev->next)
137 		omap_encoder_update_videomode_flags(&vm, dssdev->bus_flags);
138 
139 	for (bridge = output->bridge; bridge; bridge = bridge->next) {
140 		if (!bridge->timings)
141 			continue;
142 
143 		bus_flags = bridge->timings->input_bus_flags;
144 		omap_encoder_update_videomode_flags(&vm, bus_flags);
145 	}
146 
147 	bus_flags = connector->display_info.bus_flags;
148 	omap_encoder_update_videomode_flags(&vm, bus_flags);
149 
150 	/* Set timings for all devices in the display pipeline. */
151 	dss_mgr_set_timings(output, &vm);
152 
153 	for (dssdev = output; dssdev; dssdev = dssdev->next) {
154 		if (dssdev->ops->set_timings)
155 			dssdev->ops->set_timings(dssdev, adjusted_mode);
156 	}
157 
158 	/* Set the HDMI mode and HDMI infoframe if applicable. */
159 	if (output->type == OMAP_DISPLAY_TYPE_HDMI)
160 		omap_encoder_hdmi_mode_set(connector, encoder, adjusted_mode);
161 }
162 
163 static void omap_encoder_disable(struct drm_encoder *encoder)
164 {
165 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
166 	struct omap_dss_device *dssdev = omap_encoder->output;
167 	struct drm_device *dev = encoder->dev;
168 
169 	dev_dbg(dev->dev, "disable(%s)\n", dssdev->name);
170 
171 	/* Disable the panel if present. */
172 	if (dssdev->panel) {
173 		drm_panel_disable(dssdev->panel);
174 		drm_panel_unprepare(dssdev->panel);
175 	}
176 
177 	/*
178 	 * Disable the chain of external devices, starting at the one at the
179 	 * internal encoder's output.
180 	 */
181 	omapdss_device_disable(dssdev->next);
182 
183 	/*
184 	 * Disable the internal encoder. This will disable the DSS output. The
185 	 * DSI is treated as an exception as DSI pipelines still use the legacy
186 	 * flow where the pipeline output controls the encoder.
187 	 */
188 	if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) {
189 		dssdev->ops->disable(dssdev);
190 		dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
191 	}
192 
193 	/*
194 	 * Perform the post-disable operations on the chain of external devices
195 	 * to complete the display pipeline disable.
196 	 */
197 	omapdss_device_post_disable(dssdev->next);
198 }
199 
200 static void omap_encoder_enable(struct drm_encoder *encoder)
201 {
202 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
203 	struct omap_dss_device *dssdev = omap_encoder->output;
204 	struct drm_device *dev = encoder->dev;
205 
206 	dev_dbg(dev->dev, "enable(%s)\n", dssdev->name);
207 
208 	/* Prepare the chain of external devices for pipeline enable. */
209 	omapdss_device_pre_enable(dssdev->next);
210 
211 	/*
212 	 * Enable the internal encoder. This will enable the DSS output. The
213 	 * DSI is treated as an exception as DSI pipelines still use the legacy
214 	 * flow where the pipeline output controls the encoder.
215 	 */
216 	if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) {
217 		dssdev->ops->enable(dssdev);
218 		dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
219 	}
220 
221 	/*
222 	 * Enable the chain of external devices, starting at the one at the
223 	 * internal encoder's output.
224 	 */
225 	omapdss_device_enable(dssdev->next);
226 
227 	/* Enable the panel if present. */
228 	if (dssdev->panel) {
229 		drm_panel_prepare(dssdev->panel);
230 		drm_panel_enable(dssdev->panel);
231 	}
232 }
233 
234 static int omap_encoder_atomic_check(struct drm_encoder *encoder,
235 				     struct drm_crtc_state *crtc_state,
236 				     struct drm_connector_state *conn_state)
237 {
238 	struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
239 	enum drm_mode_status status;
240 
241 	status = omap_connector_mode_fixup(omap_encoder->output,
242 					   &crtc_state->mode,
243 					   &crtc_state->adjusted_mode);
244 	if (status != MODE_OK) {
245 		dev_err(encoder->dev->dev, "invalid timings: %d\n", status);
246 		return -EINVAL;
247 	}
248 
249 	return 0;
250 }
251 
252 static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
253 	.mode_set = omap_encoder_mode_set,
254 	.disable = omap_encoder_disable,
255 	.enable = omap_encoder_enable,
256 	.atomic_check = omap_encoder_atomic_check,
257 };
258 
259 /* initialize encoder */
260 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
261 				      struct omap_dss_device *output)
262 {
263 	struct drm_encoder *encoder = NULL;
264 	struct omap_encoder *omap_encoder;
265 
266 	omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL);
267 	if (!omap_encoder)
268 		goto fail;
269 
270 	omap_encoder->output = output;
271 
272 	encoder = &omap_encoder->base;
273 
274 	drm_encoder_init(dev, encoder, &omap_encoder_funcs,
275 			 DRM_MODE_ENCODER_TMDS, NULL);
276 	drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs);
277 
278 	return encoder;
279 
280 fail:
281 	if (encoder)
282 		omap_encoder_destroy(encoder);
283 
284 	return NULL;
285 }
286