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