]>
Commit | Line | Data |
---|---|---|
eed07e0e TV |
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> | |
eed07e0e | 28 | #include <linux/platform_device.h> |
7f2bcd06 | 29 | #include <linux/of.h> |
eed07e0e | 30 | |
a0b38cc4 | 31 | #include <video/omapdss.h> |
eed07e0e | 32 | #include "dss.h" |
5ed8cf5b | 33 | #include "dss_features.h" |
eed07e0e | 34 | |
96adcece | 35 | void omapdss_default_get_resolution(struct omap_dss_device *dssdev, |
eed07e0e TV |
36 | u16 *xres, u16 *yres) |
37 | { | |
38 | *xres = dssdev->panel.timings.x_res; | |
39 | *yres = dssdev->panel.timings.y_res; | |
40 | } | |
96adcece | 41 | EXPORT_SYMBOL(omapdss_default_get_resolution); |
eed07e0e | 42 | |
a2699504 | 43 | int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) |
eed07e0e | 44 | { |
eed07e0e TV |
45 | switch (dssdev->type) { |
46 | case OMAP_DISPLAY_TYPE_DPI: | |
47 | if (dssdev->phy.dpi.data_lines == 24) | |
48 | return 24; | |
49 | else | |
50 | return 16; | |
51 | ||
52 | case OMAP_DISPLAY_TYPE_DBI: | |
eed07e0e TV |
53 | if (dssdev->ctrl.pixel_size == 24) |
54 | return 24; | |
55 | else | |
56 | return 16; | |
a3b3cc2b AT |
57 | case OMAP_DISPLAY_TYPE_DSI: |
58 | if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16) | |
59 | return 24; | |
60 | else | |
61 | return 16; | |
eed07e0e TV |
62 | case OMAP_DISPLAY_TYPE_VENC: |
63 | case OMAP_DISPLAY_TYPE_SDI: | |
b119601d | 64 | case OMAP_DISPLAY_TYPE_HDMI: |
bc24b8b6 | 65 | case OMAP_DISPLAY_TYPE_DVI: |
eed07e0e | 66 | return 24; |
eed07e0e TV |
67 | default: |
68 | BUG(); | |
c6eee968 | 69 | return 0; |
eed07e0e TV |
70 | } |
71 | } | |
a2699504 | 72 | EXPORT_SYMBOL(omapdss_default_get_recommended_bpp); |
eed07e0e | 73 | |
4b6430fc GI |
74 | void omapdss_default_get_timings(struct omap_dss_device *dssdev, |
75 | struct omap_video_timings *timings) | |
76 | { | |
77 | *timings = dssdev->panel.timings; | |
78 | } | |
79 | EXPORT_SYMBOL(omapdss_default_get_timings); | |
80 | ||
2e7e3dc7 TV |
81 | static LIST_HEAD(panel_list); |
82 | static DEFINE_MUTEX(panel_list_mutex); | |
83 | static int disp_num_counter; | |
84 | ||
85 | int omapdss_register_display(struct omap_dss_device *dssdev) | |
86 | { | |
87 | struct omap_dss_driver *drv = dssdev->driver; | |
3e22b355 | 88 | int id; |
2e7e3dc7 | 89 | |
3e22b355 TV |
90 | /* |
91 | * Note: this presumes all the displays are either using DT or non-DT, | |
92 | * which normally should be the case. This also presumes that all | |
93 | * displays either have an DT alias, or none has. | |
94 | */ | |
95 | ||
96 | if (dssdev->dev->of_node) { | |
97 | id = of_alias_get_id(dssdev->dev->of_node, "display"); | |
98 | ||
99 | if (id < 0) | |
100 | id = disp_num_counter++; | |
101 | } else { | |
102 | id = disp_num_counter++; | |
103 | } | |
104 | ||
105 | snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id); | |
2e7e3dc7 | 106 | |
7f2bcd06 TV |
107 | /* Use 'label' property for name, if it exists */ |
108 | if (dssdev->dev->of_node) | |
109 | of_property_read_string(dssdev->dev->of_node, "label", | |
110 | &dssdev->name); | |
111 | ||
112 | if (dssdev->name == NULL) | |
113 | dssdev->name = dssdev->alias; | |
2e7e3dc7 TV |
114 | |
115 | if (drv && drv->get_resolution == NULL) | |
116 | drv->get_resolution = omapdss_default_get_resolution; | |
117 | if (drv && drv->get_recommended_bpp == NULL) | |
118 | drv->get_recommended_bpp = omapdss_default_get_recommended_bpp; | |
119 | if (drv && drv->get_timings == NULL) | |
120 | drv->get_timings = omapdss_default_get_timings; | |
121 | ||
122 | mutex_lock(&panel_list_mutex); | |
123 | list_add_tail(&dssdev->panel_list, &panel_list); | |
124 | mutex_unlock(&panel_list_mutex); | |
125 | return 0; | |
126 | } | |
127 | EXPORT_SYMBOL(omapdss_register_display); | |
128 | ||
129 | void omapdss_unregister_display(struct omap_dss_device *dssdev) | |
130 | { | |
131 | mutex_lock(&panel_list_mutex); | |
132 | list_del(&dssdev->panel_list); | |
133 | mutex_unlock(&panel_list_mutex); | |
134 | } | |
135 | EXPORT_SYMBOL(omapdss_unregister_display); | |
eed07e0e | 136 | |
d35317a4 | 137 | struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev) |
eed07e0e | 138 | { |
d35317a4 TV |
139 | if (!try_module_get(dssdev->owner)) |
140 | return NULL; | |
141 | ||
142 | if (get_device(dssdev->dev) == NULL) { | |
143 | module_put(dssdev->owner); | |
144 | return NULL; | |
145 | } | |
146 | ||
147 | return dssdev; | |
eed07e0e TV |
148 | } |
149 | EXPORT_SYMBOL(omap_dss_get_device); | |
150 | ||
151 | void omap_dss_put_device(struct omap_dss_device *dssdev) | |
152 | { | |
ecc8b370 | 153 | put_device(dssdev->dev); |
d35317a4 | 154 | module_put(dssdev->owner); |
eed07e0e TV |
155 | } |
156 | EXPORT_SYMBOL(omap_dss_put_device); | |
157 | ||
67b23ca1 TV |
158 | /* |
159 | * ref count of the found device is incremented. | |
160 | * ref count of from-device is decremented. | |
161 | */ | |
eed07e0e TV |
162 | struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from) |
163 | { | |
67b23ca1 TV |
164 | struct list_head *l; |
165 | struct omap_dss_device *dssdev; | |
166 | ||
167 | mutex_lock(&panel_list_mutex); | |
eed07e0e | 168 | |
67b23ca1 TV |
169 | if (list_empty(&panel_list)) { |
170 | dssdev = NULL; | |
171 | goto out; | |
eed07e0e TV |
172 | } |
173 | ||
67b23ca1 TV |
174 | if (from == NULL) { |
175 | dssdev = list_first_entry(&panel_list, struct omap_dss_device, | |
176 | panel_list); | |
177 | omap_dss_get_device(dssdev); | |
178 | goto out; | |
179 | } | |
180 | ||
181 | omap_dss_put_device(from); | |
182 | ||
183 | list_for_each(l, &panel_list) { | |
184 | dssdev = list_entry(l, struct omap_dss_device, panel_list); | |
185 | if (dssdev == from) { | |
186 | if (list_is_last(l, &panel_list)) { | |
187 | dssdev = NULL; | |
188 | goto out; | |
189 | } | |
190 | ||
191 | dssdev = list_entry(l->next, struct omap_dss_device, | |
192 | panel_list); | |
193 | omap_dss_get_device(dssdev); | |
194 | goto out; | |
195 | } | |
196 | } | |
eed07e0e | 197 | |
67b23ca1 TV |
198 | WARN(1, "'from' dssdev not found\n"); |
199 | ||
200 | dssdev = NULL; | |
201 | out: | |
202 | mutex_unlock(&panel_list_mutex); | |
eed07e0e TV |
203 | return dssdev; |
204 | } | |
205 | EXPORT_SYMBOL(omap_dss_get_next_device); | |
206 | ||
207 | struct omap_dss_device *omap_dss_find_device(void *data, | |
208 | int (*match)(struct omap_dss_device *dssdev, void *data)) | |
209 | { | |
210 | struct omap_dss_device *dssdev = NULL; | |
211 | ||
212 | while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) { | |
213 | if (match(dssdev, data)) | |
214 | return dssdev; | |
215 | } | |
216 | ||
217 | return NULL; | |
218 | } | |
219 | EXPORT_SYMBOL(omap_dss_find_device); | |
220 | ||
6fcd485b TV |
221 | void videomode_to_omap_video_timings(const struct videomode *vm, |
222 | struct omap_video_timings *ovt) | |
223 | { | |
224 | memset(ovt, 0, sizeof(*ovt)); | |
225 | ||
d8d78941 | 226 | ovt->pixelclock = vm->pixelclock; |
6fcd485b TV |
227 | ovt->x_res = vm->hactive; |
228 | ovt->hbp = vm->hback_porch; | |
229 | ovt->hfp = vm->hfront_porch; | |
230 | ovt->hsw = vm->hsync_len; | |
231 | ovt->y_res = vm->vactive; | |
232 | ovt->vbp = vm->vback_porch; | |
233 | ovt->vfp = vm->vfront_porch; | |
234 | ovt->vsw = vm->vsync_len; | |
235 | ||
236 | ovt->vsync_level = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ? | |
237 | OMAPDSS_SIG_ACTIVE_HIGH : | |
238 | OMAPDSS_SIG_ACTIVE_LOW; | |
239 | ovt->hsync_level = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ? | |
240 | OMAPDSS_SIG_ACTIVE_HIGH : | |
241 | OMAPDSS_SIG_ACTIVE_LOW; | |
242 | ovt->de_level = vm->flags & DISPLAY_FLAGS_DE_HIGH ? | |
243 | OMAPDSS_SIG_ACTIVE_HIGH : | |
9b842a47 | 244 | OMAPDSS_SIG_ACTIVE_LOW; |
6fcd485b TV |
245 | ovt->data_pclk_edge = vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ? |
246 | OMAPDSS_DRIVE_SIG_RISING_EDGE : | |
247 | OMAPDSS_DRIVE_SIG_FALLING_EDGE; | |
248 | ||
386f167c | 249 | ovt->sync_pclk_edge = ovt->data_pclk_edge; |
6fcd485b TV |
250 | } |
251 | EXPORT_SYMBOL(videomode_to_omap_video_timings); | |
252 | ||
253 | void omap_video_timings_to_videomode(const struct omap_video_timings *ovt, | |
254 | struct videomode *vm) | |
255 | { | |
256 | memset(vm, 0, sizeof(*vm)); | |
257 | ||
d8d78941 | 258 | vm->pixelclock = ovt->pixelclock; |
6fcd485b TV |
259 | |
260 | vm->hactive = ovt->x_res; | |
261 | vm->hback_porch = ovt->hbp; | |
262 | vm->hfront_porch = ovt->hfp; | |
263 | vm->hsync_len = ovt->hsw; | |
264 | vm->vactive = ovt->y_res; | |
265 | vm->vback_porch = ovt->vbp; | |
266 | vm->vfront_porch = ovt->vfp; | |
267 | vm->vsync_len = ovt->vsw; | |
268 | ||
269 | if (ovt->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH) | |
270 | vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH; | |
271 | else | |
272 | vm->flags |= DISPLAY_FLAGS_HSYNC_LOW; | |
273 | ||
274 | if (ovt->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH) | |
275 | vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH; | |
276 | else | |
277 | vm->flags |= DISPLAY_FLAGS_VSYNC_LOW; | |
278 | ||
279 | if (ovt->de_level == OMAPDSS_SIG_ACTIVE_HIGH) | |
280 | vm->flags |= DISPLAY_FLAGS_DE_HIGH; | |
281 | else | |
282 | vm->flags |= DISPLAY_FLAGS_DE_LOW; | |
283 | ||
284 | if (ovt->data_pclk_edge == OMAPDSS_DRIVE_SIG_RISING_EDGE) | |
285 | vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE; | |
286 | else | |
287 | vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE; | |
288 | } | |
289 | EXPORT_SYMBOL(omap_video_timings_to_videomode); |