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