• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
3  * Authors:
4  *	Inki Dae <inki.dae@samsung.com>
5  *	Joonyoung Shim <jy0922.shim@samsung.com>
6  *	Seung-Woo Kim <sw0312.kim@samsung.com>
7  *
8  * This program is free software; you can redistribute  it and/or modify it
9  * under  the terms of  the GNU General  Public License as published by the
10  * Free Software Foundation;  either version 2 of the  License, or (at your
11  * option) any later version.
12  */
13 
14 #include <drm/drmP.h>
15 #include <drm/drm_crtc_helper.h>
16 
17 #include <drm/exynos_drm.h>
18 #include "exynos_drm_drv.h"
19 #include "exynos_drm_encoder.h"
20 
21 #define to_exynos_connector(x)	container_of(x, struct exynos_drm_connector,\
22 				drm_connector)
23 
24 struct exynos_drm_connector {
25 	struct drm_connector	drm_connector;
26 	uint32_t		encoder_id;
27 	struct exynos_drm_manager *manager;
28 	uint32_t		dpms;
29 };
30 
31 /* convert exynos_video_timings to drm_display_mode */
32 static inline void
convert_to_display_mode(struct drm_display_mode * mode,struct exynos_drm_panel_info * panel)33 convert_to_display_mode(struct drm_display_mode *mode,
34 			struct exynos_drm_panel_info *panel)
35 {
36 	struct fb_videomode *timing = &panel->timing;
37 	DRM_DEBUG_KMS("%s\n", __FILE__);
38 
39 	mode->clock = timing->pixclock / 1000;
40 	mode->vrefresh = timing->refresh;
41 
42 	mode->hdisplay = timing->xres;
43 	mode->hsync_start = mode->hdisplay + timing->right_margin;
44 	mode->hsync_end = mode->hsync_start + timing->hsync_len;
45 	mode->htotal = mode->hsync_end + timing->left_margin;
46 
47 	mode->vdisplay = timing->yres;
48 	mode->vsync_start = mode->vdisplay + timing->lower_margin;
49 	mode->vsync_end = mode->vsync_start + timing->vsync_len;
50 	mode->vtotal = mode->vsync_end + timing->upper_margin;
51 	mode->width_mm = panel->width_mm;
52 	mode->height_mm = panel->height_mm;
53 
54 	if (timing->vmode & FB_VMODE_INTERLACED)
55 		mode->flags |= DRM_MODE_FLAG_INTERLACE;
56 
57 	if (timing->vmode & FB_VMODE_DOUBLE)
58 		mode->flags |= DRM_MODE_FLAG_DBLSCAN;
59 }
60 
61 /* convert drm_display_mode to exynos_video_timings */
62 static inline void
convert_to_video_timing(struct fb_videomode * timing,struct drm_display_mode * mode)63 convert_to_video_timing(struct fb_videomode *timing,
64 			struct drm_display_mode *mode)
65 {
66 	DRM_DEBUG_KMS("%s\n", __FILE__);
67 
68 	memset(timing, 0, sizeof(*timing));
69 
70 	timing->pixclock = mode->clock * 1000;
71 	timing->refresh = drm_mode_vrefresh(mode);
72 
73 	timing->xres = mode->hdisplay;
74 	timing->right_margin = mode->hsync_start - mode->hdisplay;
75 	timing->hsync_len = mode->hsync_end - mode->hsync_start;
76 	timing->left_margin = mode->htotal - mode->hsync_end;
77 
78 	timing->yres = mode->vdisplay;
79 	timing->lower_margin = mode->vsync_start - mode->vdisplay;
80 	timing->vsync_len = mode->vsync_end - mode->vsync_start;
81 	timing->upper_margin = mode->vtotal - mode->vsync_end;
82 
83 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
84 		timing->vmode = FB_VMODE_INTERLACED;
85 	else
86 		timing->vmode = FB_VMODE_NONINTERLACED;
87 
88 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
89 		timing->vmode |= FB_VMODE_DOUBLE;
90 }
91 
exynos_drm_connector_get_modes(struct drm_connector * connector)92 static int exynos_drm_connector_get_modes(struct drm_connector *connector)
93 {
94 	struct exynos_drm_connector *exynos_connector =
95 					to_exynos_connector(connector);
96 	struct exynos_drm_manager *manager = exynos_connector->manager;
97 	struct exynos_drm_display_ops *display_ops = manager->display_ops;
98 	struct edid *edid = NULL;
99 	unsigned int count = 0;
100 	int ret;
101 
102 	DRM_DEBUG_KMS("%s\n", __FILE__);
103 
104 	if (!display_ops) {
105 		DRM_DEBUG_KMS("display_ops is null.\n");
106 		return 0;
107 	}
108 
109 	/*
110 	 * if get_edid() exists then get_edid() callback of hdmi side
111 	 * is called to get edid data through i2c interface else
112 	 * get timing from the FIMD driver(display controller).
113 	 *
114 	 * P.S. in case of lcd panel, count is always 1 if success
115 	 * because lcd panel has only one mode.
116 	 */
117 	if (display_ops->get_edid) {
118 		edid = display_ops->get_edid(manager->dev, connector);
119 		if (IS_ERR_OR_NULL(edid)) {
120 			ret = PTR_ERR(edid);
121 			edid = NULL;
122 			DRM_ERROR("Panel operation get_edid failed %d\n", ret);
123 			goto out;
124 		}
125 
126 		count = drm_add_edid_modes(connector, edid);
127 		if (!count) {
128 			DRM_ERROR("Add edid modes failed %d\n", count);
129 			goto out;
130 		}
131 
132 		drm_mode_connector_update_edid_property(connector, edid);
133 	} else {
134 		struct exynos_drm_panel_info *panel;
135 		struct drm_display_mode *mode = drm_mode_create(connector->dev);
136 		if (!mode) {
137 			DRM_ERROR("failed to create a new display mode.\n");
138 			return 0;
139 		}
140 
141 		if (display_ops->get_panel)
142 			panel = display_ops->get_panel(manager->dev);
143 		else {
144 			drm_mode_destroy(connector->dev, mode);
145 			return 0;
146 		}
147 
148 		convert_to_display_mode(mode, panel);
149 		connector->display_info.width_mm = mode->width_mm;
150 		connector->display_info.height_mm = mode->height_mm;
151 
152 		mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
153 		drm_mode_set_name(mode);
154 		drm_mode_probed_add(connector, mode);
155 
156 		count = 1;
157 	}
158 
159 out:
160 	kfree(edid);
161 	return count;
162 }
163 
exynos_drm_connector_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)164 static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
165 					    struct drm_display_mode *mode)
166 {
167 	struct exynos_drm_connector *exynos_connector =
168 					to_exynos_connector(connector);
169 	struct exynos_drm_manager *manager = exynos_connector->manager;
170 	struct exynos_drm_display_ops *display_ops = manager->display_ops;
171 	struct fb_videomode timing;
172 	int ret = MODE_BAD;
173 
174 	DRM_DEBUG_KMS("%s\n", __FILE__);
175 
176 	convert_to_video_timing(&timing, mode);
177 
178 	if (display_ops && display_ops->check_timing)
179 		if (!display_ops->check_timing(manager->dev, (void *)&timing))
180 			ret = MODE_OK;
181 
182 	return ret;
183 }
184 
exynos_drm_best_encoder(struct drm_connector * connector)185 struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
186 {
187 	struct drm_device *dev = connector->dev;
188 	struct exynos_drm_connector *exynos_connector =
189 					to_exynos_connector(connector);
190 	struct drm_mode_object *obj;
191 	struct drm_encoder *encoder;
192 
193 	DRM_DEBUG_KMS("%s\n", __FILE__);
194 
195 	obj = drm_mode_object_find(dev, exynos_connector->encoder_id,
196 				   DRM_MODE_OBJECT_ENCODER);
197 	if (!obj) {
198 		DRM_DEBUG_KMS("Unknown ENCODER ID %d\n",
199 				exynos_connector->encoder_id);
200 		return NULL;
201 	}
202 
203 	encoder = obj_to_encoder(obj);
204 
205 	return encoder;
206 }
207 
208 static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
209 	.get_modes	= exynos_drm_connector_get_modes,
210 	.mode_valid	= exynos_drm_connector_mode_valid,
211 	.best_encoder	= exynos_drm_best_encoder,
212 };
213 
exynos_drm_display_power(struct drm_connector * connector,int mode)214 void exynos_drm_display_power(struct drm_connector *connector, int mode)
215 {
216 	struct drm_encoder *encoder = exynos_drm_best_encoder(connector);
217 	struct exynos_drm_connector *exynos_connector;
218 	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
219 	struct exynos_drm_display_ops *display_ops = manager->display_ops;
220 
221 	exynos_connector = to_exynos_connector(connector);
222 
223 	if (exynos_connector->dpms == mode) {
224 		DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
225 		return;
226 	}
227 
228 	if (display_ops && display_ops->power_on)
229 		display_ops->power_on(manager->dev, mode);
230 
231 	exynos_connector->dpms = mode;
232 }
233 
exynos_drm_connector_dpms(struct drm_connector * connector,int mode)234 static void exynos_drm_connector_dpms(struct drm_connector *connector,
235 					int mode)
236 {
237 	DRM_DEBUG_KMS("%s\n", __FILE__);
238 
239 	/*
240 	 * in case that drm_crtc_helper_set_mode() is called,
241 	 * encoder/crtc->funcs->dpms() will be just returned
242 	 * because they already were DRM_MODE_DPMS_ON so only
243 	 * exynos_drm_display_power() will be called.
244 	 */
245 	drm_helper_connector_dpms(connector, mode);
246 
247 	exynos_drm_display_power(connector, mode);
248 
249 }
250 
exynos_drm_connector_fill_modes(struct drm_connector * connector,unsigned int max_width,unsigned int max_height)251 static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
252 				unsigned int max_width, unsigned int max_height)
253 {
254 	struct exynos_drm_connector *exynos_connector =
255 					to_exynos_connector(connector);
256 	struct exynos_drm_manager *manager = exynos_connector->manager;
257 	struct exynos_drm_manager_ops *ops = manager->ops;
258 	unsigned int width, height;
259 
260 	width = max_width;
261 	height = max_height;
262 
263 	/*
264 	 * if specific driver want to find desired_mode using maxmum
265 	 * resolution then get max width and height from that driver.
266 	 */
267 	if (ops && ops->get_max_resol)
268 		ops->get_max_resol(manager->dev, &width, &height);
269 
270 	return drm_helper_probe_single_connector_modes(connector, width,
271 							height);
272 }
273 
274 /* get detection status of display device. */
275 static enum drm_connector_status
exynos_drm_connector_detect(struct drm_connector * connector,bool force)276 exynos_drm_connector_detect(struct drm_connector *connector, bool force)
277 {
278 	struct exynos_drm_connector *exynos_connector =
279 					to_exynos_connector(connector);
280 	struct exynos_drm_manager *manager = exynos_connector->manager;
281 	struct exynos_drm_display_ops *display_ops =
282 					manager->display_ops;
283 	enum drm_connector_status status = connector_status_disconnected;
284 
285 	DRM_DEBUG_KMS("%s\n", __FILE__);
286 
287 	if (display_ops && display_ops->is_connected) {
288 		if (display_ops->is_connected(manager->dev))
289 			status = connector_status_connected;
290 		else
291 			status = connector_status_disconnected;
292 	}
293 
294 	return status;
295 }
296 
exynos_drm_connector_destroy(struct drm_connector * connector)297 static void exynos_drm_connector_destroy(struct drm_connector *connector)
298 {
299 	struct exynos_drm_connector *exynos_connector =
300 		to_exynos_connector(connector);
301 
302 	DRM_DEBUG_KMS("%s\n", __FILE__);
303 
304 	drm_sysfs_connector_remove(connector);
305 	drm_connector_cleanup(connector);
306 	kfree(exynos_connector);
307 }
308 
309 static struct drm_connector_funcs exynos_connector_funcs = {
310 	.dpms		= exynos_drm_connector_dpms,
311 	.fill_modes	= exynos_drm_connector_fill_modes,
312 	.detect		= exynos_drm_connector_detect,
313 	.destroy	= exynos_drm_connector_destroy,
314 };
315 
exynos_drm_connector_create(struct drm_device * dev,struct drm_encoder * encoder)316 struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
317 						   struct drm_encoder *encoder)
318 {
319 	struct exynos_drm_connector *exynos_connector;
320 	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
321 	struct drm_connector *connector;
322 	int type;
323 	int err;
324 
325 	DRM_DEBUG_KMS("%s\n", __FILE__);
326 
327 	exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL);
328 	if (!exynos_connector) {
329 		DRM_ERROR("failed to allocate connector\n");
330 		return NULL;
331 	}
332 
333 	connector = &exynos_connector->drm_connector;
334 
335 	switch (manager->display_ops->type) {
336 	case EXYNOS_DISPLAY_TYPE_HDMI:
337 		type = DRM_MODE_CONNECTOR_HDMIA;
338 		connector->interlace_allowed = true;
339 		connector->polled = DRM_CONNECTOR_POLL_HPD;
340 		break;
341 	case EXYNOS_DISPLAY_TYPE_VIDI:
342 		type = DRM_MODE_CONNECTOR_VIRTUAL;
343 		connector->polled = DRM_CONNECTOR_POLL_HPD;
344 		break;
345 	default:
346 		type = DRM_MODE_CONNECTOR_Unknown;
347 		break;
348 	}
349 
350 	drm_connector_init(dev, connector, &exynos_connector_funcs, type);
351 	drm_connector_helper_add(connector, &exynos_connector_helper_funcs);
352 
353 	err = drm_sysfs_connector_add(connector);
354 	if (err)
355 		goto err_connector;
356 
357 	exynos_connector->encoder_id = encoder->base.id;
358 	exynos_connector->manager = manager;
359 	exynos_connector->dpms = DRM_MODE_DPMS_OFF;
360 	connector->dpms = DRM_MODE_DPMS_OFF;
361 	connector->encoder = encoder;
362 
363 	err = drm_mode_connector_attach_encoder(connector, encoder);
364 	if (err) {
365 		DRM_ERROR("failed to attach a connector to a encoder\n");
366 		goto err_sysfs;
367 	}
368 
369 	DRM_DEBUG_KMS("connector has been created\n");
370 
371 	return connector;
372 
373 err_sysfs:
374 	drm_sysfs_connector_remove(connector);
375 err_connector:
376 	drm_connector_cleanup(connector);
377 	kfree(exynos_connector);
378 	return NULL;
379 }
380