1 /*
2  * linux/drivers/video/omap2/dss/display.c
3  *
4  * Copyright (C) 2009 Nokia Corporation
5  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6  *
7  * Some code and ideas taken from drivers/video/omap/ driver
8  * by Imre Deak.
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License version 2 as published by
12  * the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17  * more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #define DSS_SUBSYS_NAME "DISPLAY"
24 
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/jiffies.h>
28 #include <linux/platform_device.h>
29 
30 #include <video/omapdss.h>
31 #include "dss.h"
32 #include "dss_features.h"
33 
display_enabled_show(struct device * dev,struct device_attribute * attr,char * buf)34 static ssize_t display_enabled_show(struct device *dev,
35 		struct device_attribute *attr, char *buf)
36 {
37 	struct omap_dss_device *dssdev = to_dss_device(dev);
38 	bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED;
39 
40 	return snprintf(buf, PAGE_SIZE, "%d\n", enabled);
41 }
42 
display_enabled_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)43 static ssize_t display_enabled_store(struct device *dev,
44 		struct device_attribute *attr,
45 		const char *buf, size_t size)
46 {
47 	struct omap_dss_device *dssdev = to_dss_device(dev);
48 	int r;
49 	bool enabled;
50 
51 	r = strtobool(buf, &enabled);
52 	if (r)
53 		return r;
54 
55 	if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
56 		if (enabled) {
57 			r = dssdev->driver->enable(dssdev);
58 			if (r)
59 				return r;
60 		} else {
61 			dssdev->driver->disable(dssdev);
62 		}
63 	}
64 
65 	return size;
66 }
67 
display_tear_show(struct device * dev,struct device_attribute * attr,char * buf)68 static ssize_t display_tear_show(struct device *dev,
69 		struct device_attribute *attr, char *buf)
70 {
71 	struct omap_dss_device *dssdev = to_dss_device(dev);
72 	return snprintf(buf, PAGE_SIZE, "%d\n",
73 			dssdev->driver->get_te ?
74 			dssdev->driver->get_te(dssdev) : 0);
75 }
76 
display_tear_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)77 static ssize_t display_tear_store(struct device *dev,
78 		struct device_attribute *attr, const char *buf, size_t size)
79 {
80 	struct omap_dss_device *dssdev = to_dss_device(dev);
81 	int r;
82 	bool te;
83 
84 	if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
85 		return -ENOENT;
86 
87 	r = strtobool(buf, &te);
88 	if (r)
89 		return r;
90 
91 	r = dssdev->driver->enable_te(dssdev, te);
92 	if (r)
93 		return r;
94 
95 	return size;
96 }
97 
display_timings_show(struct device * dev,struct device_attribute * attr,char * buf)98 static ssize_t display_timings_show(struct device *dev,
99 		struct device_attribute *attr, char *buf)
100 {
101 	struct omap_dss_device *dssdev = to_dss_device(dev);
102 	struct omap_video_timings t;
103 
104 	if (!dssdev->driver->get_timings)
105 		return -ENOENT;
106 
107 	dssdev->driver->get_timings(dssdev, &t);
108 
109 	return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
110 			t.pixel_clock,
111 			t.x_res, t.hfp, t.hbp, t.hsw,
112 			t.y_res, t.vfp, t.vbp, t.vsw);
113 }
114 
display_timings_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)115 static ssize_t display_timings_store(struct device *dev,
116 		struct device_attribute *attr, const char *buf, size_t size)
117 {
118 	struct omap_dss_device *dssdev = to_dss_device(dev);
119 	struct omap_video_timings t;
120 	int r, found;
121 
122 	if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
123 		return -ENOENT;
124 
125 	found = 0;
126 #ifdef CONFIG_OMAP2_DSS_VENC
127 	if (strncmp("pal", buf, 3) == 0) {
128 		t = omap_dss_pal_timings;
129 		found = 1;
130 	} else if (strncmp("ntsc", buf, 4) == 0) {
131 		t = omap_dss_ntsc_timings;
132 		found = 1;
133 	}
134 #endif
135 	if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
136 				&t.pixel_clock,
137 				&t.x_res, &t.hfp, &t.hbp, &t.hsw,
138 				&t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
139 		return -EINVAL;
140 
141 	r = dssdev->driver->check_timings(dssdev, &t);
142 	if (r)
143 		return r;
144 
145 	dssdev->driver->set_timings(dssdev, &t);
146 
147 	return size;
148 }
149 
display_rotate_show(struct device * dev,struct device_attribute * attr,char * buf)150 static ssize_t display_rotate_show(struct device *dev,
151 		struct device_attribute *attr, char *buf)
152 {
153 	struct omap_dss_device *dssdev = to_dss_device(dev);
154 	int rotate;
155 	if (!dssdev->driver->get_rotate)
156 		return -ENOENT;
157 	rotate = dssdev->driver->get_rotate(dssdev);
158 	return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
159 }
160 
display_rotate_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)161 static ssize_t display_rotate_store(struct device *dev,
162 		struct device_attribute *attr, const char *buf, size_t size)
163 {
164 	struct omap_dss_device *dssdev = to_dss_device(dev);
165 	int rot, r;
166 
167 	if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
168 		return -ENOENT;
169 
170 	r = kstrtoint(buf, 0, &rot);
171 	if (r)
172 		return r;
173 
174 	r = dssdev->driver->set_rotate(dssdev, rot);
175 	if (r)
176 		return r;
177 
178 	return size;
179 }
180 
display_mirror_show(struct device * dev,struct device_attribute * attr,char * buf)181 static ssize_t display_mirror_show(struct device *dev,
182 		struct device_attribute *attr, char *buf)
183 {
184 	struct omap_dss_device *dssdev = to_dss_device(dev);
185 	int mirror;
186 	if (!dssdev->driver->get_mirror)
187 		return -ENOENT;
188 	mirror = dssdev->driver->get_mirror(dssdev);
189 	return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
190 }
191 
display_mirror_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)192 static ssize_t display_mirror_store(struct device *dev,
193 		struct device_attribute *attr, const char *buf, size_t size)
194 {
195 	struct omap_dss_device *dssdev = to_dss_device(dev);
196 	int r;
197 	bool mirror;
198 
199 	if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
200 		return -ENOENT;
201 
202 	r = strtobool(buf, &mirror);
203 	if (r)
204 		return r;
205 
206 	r = dssdev->driver->set_mirror(dssdev, mirror);
207 	if (r)
208 		return r;
209 
210 	return size;
211 }
212 
display_wss_show(struct device * dev,struct device_attribute * attr,char * buf)213 static ssize_t display_wss_show(struct device *dev,
214 		struct device_attribute *attr, char *buf)
215 {
216 	struct omap_dss_device *dssdev = to_dss_device(dev);
217 	unsigned int wss;
218 
219 	if (!dssdev->driver->get_wss)
220 		return -ENOENT;
221 
222 	wss = dssdev->driver->get_wss(dssdev);
223 
224 	return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
225 }
226 
display_wss_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)227 static ssize_t display_wss_store(struct device *dev,
228 		struct device_attribute *attr, const char *buf, size_t size)
229 {
230 	struct omap_dss_device *dssdev = to_dss_device(dev);
231 	u32 wss;
232 	int r;
233 
234 	if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
235 		return -ENOENT;
236 
237 	r = kstrtou32(buf, 0, &wss);
238 	if (r)
239 		return r;
240 
241 	if (wss > 0xfffff)
242 		return -EINVAL;
243 
244 	r = dssdev->driver->set_wss(dssdev, wss);
245 	if (r)
246 		return r;
247 
248 	return size;
249 }
250 
251 static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
252 		display_enabled_show, display_enabled_store);
253 static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
254 		display_tear_show, display_tear_store);
255 static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
256 		display_timings_show, display_timings_store);
257 static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
258 		display_rotate_show, display_rotate_store);
259 static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
260 		display_mirror_show, display_mirror_store);
261 static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
262 		display_wss_show, display_wss_store);
263 
264 static struct device_attribute *display_sysfs_attrs[] = {
265 	&dev_attr_enabled,
266 	&dev_attr_tear_elim,
267 	&dev_attr_timings,
268 	&dev_attr_rotate,
269 	&dev_attr_mirror,
270 	&dev_attr_wss,
271 	NULL
272 };
273 
omapdss_default_get_resolution(struct omap_dss_device * dssdev,u16 * xres,u16 * yres)274 void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
275 			u16 *xres, u16 *yres)
276 {
277 	*xres = dssdev->panel.timings.x_res;
278 	*yres = dssdev->panel.timings.y_res;
279 }
280 EXPORT_SYMBOL(omapdss_default_get_resolution);
281 
default_get_overlay_fifo_thresholds(enum omap_plane plane,u32 fifo_size,u32 burst_size,u32 * fifo_low,u32 * fifo_high)282 void default_get_overlay_fifo_thresholds(enum omap_plane plane,
283 		u32 fifo_size, u32 burst_size,
284 		u32 *fifo_low, u32 *fifo_high)
285 {
286 	unsigned buf_unit = dss_feat_get_buffer_size_unit();
287 
288 	*fifo_high = fifo_size - buf_unit;
289 	*fifo_low = fifo_size - burst_size;
290 }
291 
omapdss_default_get_recommended_bpp(struct omap_dss_device * dssdev)292 int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
293 {
294 	switch (dssdev->type) {
295 	case OMAP_DISPLAY_TYPE_DPI:
296 		if (dssdev->phy.dpi.data_lines == 24)
297 			return 24;
298 		else
299 			return 16;
300 
301 	case OMAP_DISPLAY_TYPE_DBI:
302 		if (dssdev->ctrl.pixel_size == 24)
303 			return 24;
304 		else
305 			return 16;
306 	case OMAP_DISPLAY_TYPE_DSI:
307 		if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16)
308 			return 24;
309 		else
310 			return 16;
311 	case OMAP_DISPLAY_TYPE_VENC:
312 	case OMAP_DISPLAY_TYPE_SDI:
313 	case OMAP_DISPLAY_TYPE_HDMI:
314 		return 24;
315 	default:
316 		BUG();
317 	}
318 }
319 EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);
320 
321 /* Checks if replication logic should be used. Only use for active matrix,
322  * when overlay is in RGB12U or RGB16 mode, and LCD interface is
323  * 18bpp or 24bpp */
dss_use_replication(struct omap_dss_device * dssdev,enum omap_color_mode mode)324 bool dss_use_replication(struct omap_dss_device *dssdev,
325 		enum omap_color_mode mode)
326 {
327 	int bpp;
328 
329 	if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
330 		return false;
331 
332 	if (dssdev->type == OMAP_DISPLAY_TYPE_DPI &&
333 			(dssdev->panel.config & OMAP_DSS_LCD_TFT) == 0)
334 		return false;
335 
336 	switch (dssdev->type) {
337 	case OMAP_DISPLAY_TYPE_DPI:
338 		bpp = dssdev->phy.dpi.data_lines;
339 		break;
340 	case OMAP_DISPLAY_TYPE_HDMI:
341 	case OMAP_DISPLAY_TYPE_VENC:
342 	case OMAP_DISPLAY_TYPE_SDI:
343 		bpp = 24;
344 		break;
345 	case OMAP_DISPLAY_TYPE_DBI:
346 		bpp = dssdev->ctrl.pixel_size;
347 		break;
348 	case OMAP_DISPLAY_TYPE_DSI:
349 		bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
350 		break;
351 	default:
352 		BUG();
353 	}
354 
355 	return bpp > 16;
356 }
357 
dss_init_device(struct platform_device * pdev,struct omap_dss_device * dssdev)358 void dss_init_device(struct platform_device *pdev,
359 		struct omap_dss_device *dssdev)
360 {
361 	struct device_attribute *attr;
362 	int i;
363 	int r;
364 
365 	switch (dssdev->type) {
366 #ifdef CONFIG_OMAP2_DSS_DPI
367 	case OMAP_DISPLAY_TYPE_DPI:
368 		r = dpi_init_display(dssdev);
369 		break;
370 #endif
371 #ifdef CONFIG_OMAP2_DSS_RFBI
372 	case OMAP_DISPLAY_TYPE_DBI:
373 		r = rfbi_init_display(dssdev);
374 		break;
375 #endif
376 #ifdef CONFIG_OMAP2_DSS_VENC
377 	case OMAP_DISPLAY_TYPE_VENC:
378 		r = venc_init_display(dssdev);
379 		break;
380 #endif
381 #ifdef CONFIG_OMAP2_DSS_SDI
382 	case OMAP_DISPLAY_TYPE_SDI:
383 		r = sdi_init_display(dssdev);
384 		break;
385 #endif
386 #ifdef CONFIG_OMAP2_DSS_DSI
387 	case OMAP_DISPLAY_TYPE_DSI:
388 		r = dsi_init_display(dssdev);
389 		break;
390 #endif
391 	case OMAP_DISPLAY_TYPE_HDMI:
392 		r = hdmi_init_display(dssdev);
393 		break;
394 	default:
395 		DSSERR("Support for display '%s' not compiled in.\n",
396 				dssdev->name);
397 		return;
398 	}
399 
400 	if (r) {
401 		DSSERR("failed to init display %s\n", dssdev->name);
402 		return;
403 	}
404 
405 	/* create device sysfs files */
406 	i = 0;
407 	while ((attr = display_sysfs_attrs[i++]) != NULL) {
408 		r = device_create_file(&dssdev->dev, attr);
409 		if (r)
410 			DSSERR("failed to create sysfs file\n");
411 	}
412 
413 	/* create display? sysfs links */
414 	r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
415 			dev_name(&dssdev->dev));
416 	if (r)
417 		DSSERR("failed to create sysfs display link\n");
418 }
419 
dss_uninit_device(struct platform_device * pdev,struct omap_dss_device * dssdev)420 void dss_uninit_device(struct platform_device *pdev,
421 		struct omap_dss_device *dssdev)
422 {
423 	struct device_attribute *attr;
424 	int i = 0;
425 
426 	sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev));
427 
428 	while ((attr = display_sysfs_attrs[i++]) != NULL)
429 		device_remove_file(&dssdev->dev, attr);
430 
431 	if (dssdev->manager)
432 		dssdev->manager->unset_device(dssdev->manager);
433 }
434 
dss_suspend_device(struct device * dev,void * data)435 static int dss_suspend_device(struct device *dev, void *data)
436 {
437 	int r;
438 	struct omap_dss_device *dssdev = to_dss_device(dev);
439 
440 	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
441 		dssdev->activate_after_resume = false;
442 		return 0;
443 	}
444 
445 	if (!dssdev->driver->suspend) {
446 		DSSERR("display '%s' doesn't implement suspend\n",
447 				dssdev->name);
448 		return -ENOSYS;
449 	}
450 
451 	r = dssdev->driver->suspend(dssdev);
452 	if (r)
453 		return r;
454 
455 	dssdev->activate_after_resume = true;
456 
457 	return 0;
458 }
459 
dss_suspend_all_devices(void)460 int dss_suspend_all_devices(void)
461 {
462 	int r;
463 	struct bus_type *bus = dss_get_bus();
464 
465 	r = bus_for_each_dev(bus, NULL, NULL, dss_suspend_device);
466 	if (r) {
467 		/* resume all displays that were suspended */
468 		dss_resume_all_devices();
469 		return r;
470 	}
471 
472 	return 0;
473 }
474 
dss_resume_device(struct device * dev,void * data)475 static int dss_resume_device(struct device *dev, void *data)
476 {
477 	int r;
478 	struct omap_dss_device *dssdev = to_dss_device(dev);
479 
480 	if (dssdev->activate_after_resume && dssdev->driver->resume) {
481 		r = dssdev->driver->resume(dssdev);
482 		if (r)
483 			return r;
484 	}
485 
486 	dssdev->activate_after_resume = false;
487 
488 	return 0;
489 }
490 
dss_resume_all_devices(void)491 int dss_resume_all_devices(void)
492 {
493 	struct bus_type *bus = dss_get_bus();
494 
495 	return bus_for_each_dev(bus, NULL, NULL, dss_resume_device);
496 }
497 
dss_disable_device(struct device * dev,void * data)498 static int dss_disable_device(struct device *dev, void *data)
499 {
500 	struct omap_dss_device *dssdev = to_dss_device(dev);
501 
502 	if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
503 		dssdev->driver->disable(dssdev);
504 
505 	return 0;
506 }
507 
dss_disable_all_devices(void)508 void dss_disable_all_devices(void)
509 {
510 	struct bus_type *bus = dss_get_bus();
511 	bus_for_each_dev(bus, NULL, NULL, dss_disable_device);
512 }
513 
514 
omap_dss_get_device(struct omap_dss_device * dssdev)515 void omap_dss_get_device(struct omap_dss_device *dssdev)
516 {
517 	get_device(&dssdev->dev);
518 }
519 EXPORT_SYMBOL(omap_dss_get_device);
520 
omap_dss_put_device(struct omap_dss_device * dssdev)521 void omap_dss_put_device(struct omap_dss_device *dssdev)
522 {
523 	put_device(&dssdev->dev);
524 }
525 EXPORT_SYMBOL(omap_dss_put_device);
526 
527 /* ref count of the found device is incremented. ref count
528  * of from-device is decremented. */
omap_dss_get_next_device(struct omap_dss_device * from)529 struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
530 {
531 	struct device *dev;
532 	struct device *dev_start = NULL;
533 	struct omap_dss_device *dssdev = NULL;
534 
535 	int match(struct device *dev, void *data)
536 	{
537 		return 1;
538 	}
539 
540 	if (from)
541 		dev_start = &from->dev;
542 	dev = bus_find_device(dss_get_bus(), dev_start, NULL, match);
543 	if (dev)
544 		dssdev = to_dss_device(dev);
545 	if (from)
546 		put_device(&from->dev);
547 
548 	return dssdev;
549 }
550 EXPORT_SYMBOL(omap_dss_get_next_device);
551 
omap_dss_find_device(void * data,int (* match)(struct omap_dss_device * dssdev,void * data))552 struct omap_dss_device *omap_dss_find_device(void *data,
553 		int (*match)(struct omap_dss_device *dssdev, void *data))
554 {
555 	struct omap_dss_device *dssdev = NULL;
556 
557 	while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
558 		if (match(dssdev, data))
559 			return dssdev;
560 	}
561 
562 	return NULL;
563 }
564 EXPORT_SYMBOL(omap_dss_find_device);
565 
omap_dss_start_device(struct omap_dss_device * dssdev)566 int omap_dss_start_device(struct omap_dss_device *dssdev)
567 {
568 	if (!dssdev->driver) {
569 		DSSDBG("no driver\n");
570 		return -ENODEV;
571 	}
572 
573 	if (!try_module_get(dssdev->dev.driver->owner)) {
574 		return -ENODEV;
575 	}
576 
577 	return 0;
578 }
579 EXPORT_SYMBOL(omap_dss_start_device);
580 
omap_dss_stop_device(struct omap_dss_device * dssdev)581 void omap_dss_stop_device(struct omap_dss_device *dssdev)
582 {
583 	module_put(dssdev->dev.driver->owner);
584 }
585 EXPORT_SYMBOL(omap_dss_stop_device);
586 
587