xref: /OK3568_Linux_fs/kernel/drivers/video/fbdev/omap2/omapfb/dss/display.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * linux/drivers/video/omap2/dss/display.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2009 Nokia Corporation
6*4882a593Smuzhiyun  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Some code and ideas taken from drivers/video/omap/ driver
9*4882a593Smuzhiyun  * by Imre Deak.
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #define DSS_SUBSYS_NAME "DISPLAY"
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/jiffies.h>
17*4882a593Smuzhiyun #include <linux/platform_device.h>
18*4882a593Smuzhiyun #include <linux/of.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <video/omapfb_dss.h>
21*4882a593Smuzhiyun #include "dss.h"
22*4882a593Smuzhiyun #include "dss_features.h"
23*4882a593Smuzhiyun 
omapdss_default_get_resolution(struct omap_dss_device * dssdev,u16 * xres,u16 * yres)24*4882a593Smuzhiyun void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
25*4882a593Smuzhiyun 			u16 *xres, u16 *yres)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	*xres = dssdev->panel.timings.x_res;
28*4882a593Smuzhiyun 	*yres = dssdev->panel.timings.y_res;
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun EXPORT_SYMBOL(omapdss_default_get_resolution);
31*4882a593Smuzhiyun 
omapdss_default_get_recommended_bpp(struct omap_dss_device * dssdev)32*4882a593Smuzhiyun int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	switch (dssdev->type) {
35*4882a593Smuzhiyun 	case OMAP_DISPLAY_TYPE_DPI:
36*4882a593Smuzhiyun 		if (dssdev->phy.dpi.data_lines == 24)
37*4882a593Smuzhiyun 			return 24;
38*4882a593Smuzhiyun 		else
39*4882a593Smuzhiyun 			return 16;
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	case OMAP_DISPLAY_TYPE_DBI:
42*4882a593Smuzhiyun 		if (dssdev->ctrl.pixel_size == 24)
43*4882a593Smuzhiyun 			return 24;
44*4882a593Smuzhiyun 		else
45*4882a593Smuzhiyun 			return 16;
46*4882a593Smuzhiyun 	case OMAP_DISPLAY_TYPE_DSI:
47*4882a593Smuzhiyun 		if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16)
48*4882a593Smuzhiyun 			return 24;
49*4882a593Smuzhiyun 		else
50*4882a593Smuzhiyun 			return 16;
51*4882a593Smuzhiyun 	case OMAP_DISPLAY_TYPE_VENC:
52*4882a593Smuzhiyun 	case OMAP_DISPLAY_TYPE_SDI:
53*4882a593Smuzhiyun 	case OMAP_DISPLAY_TYPE_HDMI:
54*4882a593Smuzhiyun 	case OMAP_DISPLAY_TYPE_DVI:
55*4882a593Smuzhiyun 		return 24;
56*4882a593Smuzhiyun 	default:
57*4882a593Smuzhiyun 		BUG();
58*4882a593Smuzhiyun 		return 0;
59*4882a593Smuzhiyun 	}
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);
62*4882a593Smuzhiyun 
omapdss_default_get_timings(struct omap_dss_device * dssdev,struct omap_video_timings * timings)63*4882a593Smuzhiyun void omapdss_default_get_timings(struct omap_dss_device *dssdev,
64*4882a593Smuzhiyun 		struct omap_video_timings *timings)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	*timings = dssdev->panel.timings;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun EXPORT_SYMBOL(omapdss_default_get_timings);
69*4882a593Smuzhiyun 
dss_suspend_all_devices(void)70*4882a593Smuzhiyun int dss_suspend_all_devices(void)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	struct omap_dss_device *dssdev = NULL;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	for_each_dss_dev(dssdev) {
75*4882a593Smuzhiyun 		if (!dssdev->driver)
76*4882a593Smuzhiyun 			continue;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 		if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
79*4882a593Smuzhiyun 			dssdev->driver->disable(dssdev);
80*4882a593Smuzhiyun 			dssdev->activate_after_resume = true;
81*4882a593Smuzhiyun 		} else {
82*4882a593Smuzhiyun 			dssdev->activate_after_resume = false;
83*4882a593Smuzhiyun 		}
84*4882a593Smuzhiyun 	}
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	return 0;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
dss_resume_all_devices(void)89*4882a593Smuzhiyun int dss_resume_all_devices(void)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	struct omap_dss_device *dssdev = NULL;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	for_each_dss_dev(dssdev) {
94*4882a593Smuzhiyun 		if (!dssdev->driver)
95*4882a593Smuzhiyun 			continue;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 		if (dssdev->activate_after_resume) {
98*4882a593Smuzhiyun 			dssdev->driver->enable(dssdev);
99*4882a593Smuzhiyun 			dssdev->activate_after_resume = false;
100*4882a593Smuzhiyun 		}
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	return 0;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
dss_disable_all_devices(void)106*4882a593Smuzhiyun void dss_disable_all_devices(void)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	struct omap_dss_device *dssdev = NULL;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	for_each_dss_dev(dssdev) {
111*4882a593Smuzhiyun 		if (!dssdev->driver)
112*4882a593Smuzhiyun 			continue;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 		if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
115*4882a593Smuzhiyun 			dssdev->driver->disable(dssdev);
116*4882a593Smuzhiyun 	}
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun static LIST_HEAD(panel_list);
120*4882a593Smuzhiyun static DEFINE_MUTEX(panel_list_mutex);
121*4882a593Smuzhiyun static int disp_num_counter;
122*4882a593Smuzhiyun 
omapdss_register_display(struct omap_dss_device * dssdev)123*4882a593Smuzhiyun int omapdss_register_display(struct omap_dss_device *dssdev)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	struct omap_dss_driver *drv = dssdev->driver;
126*4882a593Smuzhiyun 	int id;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	/*
129*4882a593Smuzhiyun 	 * Note: this presumes all the displays are either using DT or non-DT,
130*4882a593Smuzhiyun 	 * which normally should be the case. This also presumes that all
131*4882a593Smuzhiyun 	 * displays either have an DT alias, or none has.
132*4882a593Smuzhiyun 	 */
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	if (dssdev->dev->of_node) {
135*4882a593Smuzhiyun 		id = of_alias_get_id(dssdev->dev->of_node, "display");
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 		if (id < 0)
138*4882a593Smuzhiyun 			id = disp_num_counter++;
139*4882a593Smuzhiyun 	} else {
140*4882a593Smuzhiyun 		id = disp_num_counter++;
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	/* Use 'label' property for name, if it exists */
146*4882a593Smuzhiyun 	if (dssdev->dev->of_node)
147*4882a593Smuzhiyun 		of_property_read_string(dssdev->dev->of_node, "label",
148*4882a593Smuzhiyun 			&dssdev->name);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	if (dssdev->name == NULL)
151*4882a593Smuzhiyun 		dssdev->name = dssdev->alias;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	if (drv && drv->get_resolution == NULL)
154*4882a593Smuzhiyun 		drv->get_resolution = omapdss_default_get_resolution;
155*4882a593Smuzhiyun 	if (drv && drv->get_recommended_bpp == NULL)
156*4882a593Smuzhiyun 		drv->get_recommended_bpp = omapdss_default_get_recommended_bpp;
157*4882a593Smuzhiyun 	if (drv && drv->get_timings == NULL)
158*4882a593Smuzhiyun 		drv->get_timings = omapdss_default_get_timings;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	mutex_lock(&panel_list_mutex);
161*4882a593Smuzhiyun 	list_add_tail(&dssdev->panel_list, &panel_list);
162*4882a593Smuzhiyun 	mutex_unlock(&panel_list_mutex);
163*4882a593Smuzhiyun 	return 0;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun EXPORT_SYMBOL(omapdss_register_display);
166*4882a593Smuzhiyun 
omapdss_unregister_display(struct omap_dss_device * dssdev)167*4882a593Smuzhiyun void omapdss_unregister_display(struct omap_dss_device *dssdev)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	mutex_lock(&panel_list_mutex);
170*4882a593Smuzhiyun 	list_del(&dssdev->panel_list);
171*4882a593Smuzhiyun 	mutex_unlock(&panel_list_mutex);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun EXPORT_SYMBOL(omapdss_unregister_display);
174*4882a593Smuzhiyun 
omap_dss_get_device(struct omap_dss_device * dssdev)175*4882a593Smuzhiyun struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	if (!try_module_get(dssdev->owner))
178*4882a593Smuzhiyun 		return NULL;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	if (get_device(dssdev->dev) == NULL) {
181*4882a593Smuzhiyun 		module_put(dssdev->owner);
182*4882a593Smuzhiyun 		return NULL;
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	return dssdev;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun EXPORT_SYMBOL(omap_dss_get_device);
188*4882a593Smuzhiyun 
omap_dss_put_device(struct omap_dss_device * dssdev)189*4882a593Smuzhiyun void omap_dss_put_device(struct omap_dss_device *dssdev)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	put_device(dssdev->dev);
192*4882a593Smuzhiyun 	module_put(dssdev->owner);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun EXPORT_SYMBOL(omap_dss_put_device);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun /*
197*4882a593Smuzhiyun  * ref count of the found device is incremented.
198*4882a593Smuzhiyun  * ref count of from-device is decremented.
199*4882a593Smuzhiyun  */
omap_dss_get_next_device(struct omap_dss_device * from)200*4882a593Smuzhiyun struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	struct list_head *l;
203*4882a593Smuzhiyun 	struct omap_dss_device *dssdev;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	mutex_lock(&panel_list_mutex);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	if (list_empty(&panel_list)) {
208*4882a593Smuzhiyun 		dssdev = NULL;
209*4882a593Smuzhiyun 		goto out;
210*4882a593Smuzhiyun 	}
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	if (from == NULL) {
213*4882a593Smuzhiyun 		dssdev = list_first_entry(&panel_list, struct omap_dss_device,
214*4882a593Smuzhiyun 				panel_list);
215*4882a593Smuzhiyun 		omap_dss_get_device(dssdev);
216*4882a593Smuzhiyun 		goto out;
217*4882a593Smuzhiyun 	}
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	omap_dss_put_device(from);
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	list_for_each(l, &panel_list) {
222*4882a593Smuzhiyun 		dssdev = list_entry(l, struct omap_dss_device, panel_list);
223*4882a593Smuzhiyun 		if (dssdev == from) {
224*4882a593Smuzhiyun 			if (list_is_last(l, &panel_list)) {
225*4882a593Smuzhiyun 				dssdev = NULL;
226*4882a593Smuzhiyun 				goto out;
227*4882a593Smuzhiyun 			}
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 			dssdev = list_entry(l->next, struct omap_dss_device,
230*4882a593Smuzhiyun 					panel_list);
231*4882a593Smuzhiyun 			omap_dss_get_device(dssdev);
232*4882a593Smuzhiyun 			goto out;
233*4882a593Smuzhiyun 		}
234*4882a593Smuzhiyun 	}
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	WARN(1, "'from' dssdev not found\n");
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	dssdev = NULL;
239*4882a593Smuzhiyun out:
240*4882a593Smuzhiyun 	mutex_unlock(&panel_list_mutex);
241*4882a593Smuzhiyun 	return dssdev;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun EXPORT_SYMBOL(omap_dss_get_next_device);
244*4882a593Smuzhiyun 
omap_dss_find_device(void * data,int (* match)(struct omap_dss_device * dssdev,void * data))245*4882a593Smuzhiyun struct omap_dss_device *omap_dss_find_device(void *data,
246*4882a593Smuzhiyun 		int (*match)(struct omap_dss_device *dssdev, void *data))
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	struct omap_dss_device *dssdev = NULL;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
251*4882a593Smuzhiyun 		if (match(dssdev, data))
252*4882a593Smuzhiyun 			return dssdev;
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	return NULL;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun EXPORT_SYMBOL(omap_dss_find_device);
258*4882a593Smuzhiyun 
videomode_to_omap_video_timings(const struct videomode * vm,struct omap_video_timings * ovt)259*4882a593Smuzhiyun void videomode_to_omap_video_timings(const struct videomode *vm,
260*4882a593Smuzhiyun 		struct omap_video_timings *ovt)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	memset(ovt, 0, sizeof(*ovt));
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	ovt->pixelclock = vm->pixelclock;
265*4882a593Smuzhiyun 	ovt->x_res = vm->hactive;
266*4882a593Smuzhiyun 	ovt->hbp = vm->hback_porch;
267*4882a593Smuzhiyun 	ovt->hfp = vm->hfront_porch;
268*4882a593Smuzhiyun 	ovt->hsw = vm->hsync_len;
269*4882a593Smuzhiyun 	ovt->y_res = vm->vactive;
270*4882a593Smuzhiyun 	ovt->vbp = vm->vback_porch;
271*4882a593Smuzhiyun 	ovt->vfp = vm->vfront_porch;
272*4882a593Smuzhiyun 	ovt->vsw = vm->vsync_len;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	ovt->vsync_level = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
275*4882a593Smuzhiyun 		OMAPDSS_SIG_ACTIVE_HIGH :
276*4882a593Smuzhiyun 		OMAPDSS_SIG_ACTIVE_LOW;
277*4882a593Smuzhiyun 	ovt->hsync_level = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
278*4882a593Smuzhiyun 		OMAPDSS_SIG_ACTIVE_HIGH :
279*4882a593Smuzhiyun 		OMAPDSS_SIG_ACTIVE_LOW;
280*4882a593Smuzhiyun 	ovt->de_level = vm->flags & DISPLAY_FLAGS_DE_HIGH ?
281*4882a593Smuzhiyun 		OMAPDSS_SIG_ACTIVE_HIGH :
282*4882a593Smuzhiyun 		OMAPDSS_SIG_ACTIVE_LOW;
283*4882a593Smuzhiyun 	ovt->data_pclk_edge = vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ?
284*4882a593Smuzhiyun 		OMAPDSS_DRIVE_SIG_RISING_EDGE :
285*4882a593Smuzhiyun 		OMAPDSS_DRIVE_SIG_FALLING_EDGE;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	ovt->sync_pclk_edge = ovt->data_pclk_edge;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun EXPORT_SYMBOL(videomode_to_omap_video_timings);
290*4882a593Smuzhiyun 
omap_video_timings_to_videomode(const struct omap_video_timings * ovt,struct videomode * vm)291*4882a593Smuzhiyun void omap_video_timings_to_videomode(const struct omap_video_timings *ovt,
292*4882a593Smuzhiyun 		struct videomode *vm)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	memset(vm, 0, sizeof(*vm));
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	vm->pixelclock = ovt->pixelclock;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	vm->hactive = ovt->x_res;
299*4882a593Smuzhiyun 	vm->hback_porch = ovt->hbp;
300*4882a593Smuzhiyun 	vm->hfront_porch = ovt->hfp;
301*4882a593Smuzhiyun 	vm->hsync_len = ovt->hsw;
302*4882a593Smuzhiyun 	vm->vactive = ovt->y_res;
303*4882a593Smuzhiyun 	vm->vback_porch = ovt->vbp;
304*4882a593Smuzhiyun 	vm->vfront_porch = ovt->vfp;
305*4882a593Smuzhiyun 	vm->vsync_len = ovt->vsw;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	if (ovt->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
308*4882a593Smuzhiyun 		vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
309*4882a593Smuzhiyun 	else
310*4882a593Smuzhiyun 		vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	if (ovt->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
313*4882a593Smuzhiyun 		vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
314*4882a593Smuzhiyun 	else
315*4882a593Smuzhiyun 		vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	if (ovt->de_level == OMAPDSS_SIG_ACTIVE_HIGH)
318*4882a593Smuzhiyun 		vm->flags |= DISPLAY_FLAGS_DE_HIGH;
319*4882a593Smuzhiyun 	else
320*4882a593Smuzhiyun 		vm->flags |= DISPLAY_FLAGS_DE_LOW;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	if (ovt->data_pclk_edge == OMAPDSS_DRIVE_SIG_RISING_EDGE)
323*4882a593Smuzhiyun 		vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
324*4882a593Smuzhiyun 	else
325*4882a593Smuzhiyun 		vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun EXPORT_SYMBOL(omap_video_timings_to_videomode);
328