diff options
Diffstat (limited to 'drivers/video/omap2/dss')
-rw-r--r-- | drivers/video/omap2/dss/Makefile | 3 | ||||
-rw-r--r-- | drivers/video/omap2/dss/apply.c | 1324 | ||||
-rw-r--r-- | drivers/video/omap2/dss/core.c | 2 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dispc.c | 407 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dispc.h | 11 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dispc_coefs.c | 326 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dpi.c | 7 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 612 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss.h | 74 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss_features.c | 11 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss_features.h | 1 | ||||
-rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 59 | ||||
-rw-r--r-- | drivers/video/omap2/dss/manager.c | 1221 | ||||
-rw-r--r-- | drivers/video/omap2/dss/overlay.c | 435 | ||||
-rw-r--r-- | drivers/video/omap2/dss/rfbi.c | 1 | ||||
-rw-r--r-- | drivers/video/omap2/dss/sdi.c | 8 | ||||
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi.h | 10 | ||||
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | 37 | ||||
-rw-r--r-- | drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h | 3 | ||||
-rw-r--r-- | drivers/video/omap2/dss/venc.c | 28 |
20 files changed, 2588 insertions, 1992 deletions
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index bd34ac5b2026..5c450b0f94d0 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o | 1 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o |
2 | omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o | 2 | omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ |
3 | manager.o overlay.o apply.o | ||
3 | omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o | 4 | omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o |
4 | omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o | 5 | omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o |
5 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o | 6 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o |
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c new file mode 100644 index 000000000000..052dc874cd3d --- /dev/null +++ b/drivers/video/omap2/dss/apply.c | |||
@@ -0,0 +1,1324 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Texas Instruments | ||
3 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #define DSS_SUBSYS_NAME "APPLY" | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/jiffies.h> | ||
24 | |||
25 | #include <video/omapdss.h> | ||
26 | |||
27 | #include "dss.h" | ||
28 | #include "dss_features.h" | ||
29 | |||
30 | /* | ||
31 | * We have 4 levels of cache for the dispc settings. First two are in SW and | ||
32 | * the latter two in HW. | ||
33 | * | ||
34 | * set_info() | ||
35 | * v | ||
36 | * +--------------------+ | ||
37 | * | user_info | | ||
38 | * +--------------------+ | ||
39 | * v | ||
40 | * apply() | ||
41 | * v | ||
42 | * +--------------------+ | ||
43 | * | info | | ||
44 | * +--------------------+ | ||
45 | * v | ||
46 | * write_regs() | ||
47 | * v | ||
48 | * +--------------------+ | ||
49 | * | shadow registers | | ||
50 | * +--------------------+ | ||
51 | * v | ||
52 | * VFP or lcd/digit_enable | ||
53 | * v | ||
54 | * +--------------------+ | ||
55 | * | registers | | ||
56 | * +--------------------+ | ||
57 | */ | ||
58 | |||
59 | struct ovl_priv_data { | ||
60 | |||
61 | bool user_info_dirty; | ||
62 | struct omap_overlay_info user_info; | ||
63 | |||
64 | bool info_dirty; | ||
65 | struct omap_overlay_info info; | ||
66 | |||
67 | bool shadow_info_dirty; | ||
68 | |||
69 | bool extra_info_dirty; | ||
70 | bool shadow_extra_info_dirty; | ||
71 | |||
72 | bool enabled; | ||
73 | enum omap_channel channel; | ||
74 | u32 fifo_low, fifo_high; | ||
75 | |||
76 | /* | ||
77 | * True if overlay is to be enabled. Used to check and calculate configs | ||
78 | * for the overlay before it is enabled in the HW. | ||
79 | */ | ||
80 | bool enabling; | ||
81 | }; | ||
82 | |||
83 | struct mgr_priv_data { | ||
84 | |||
85 | bool user_info_dirty; | ||
86 | struct omap_overlay_manager_info user_info; | ||
87 | |||
88 | bool info_dirty; | ||
89 | struct omap_overlay_manager_info info; | ||
90 | |||
91 | bool shadow_info_dirty; | ||
92 | |||
93 | /* If true, GO bit is up and shadow registers cannot be written. | ||
94 | * Never true for manual update displays */ | ||
95 | bool busy; | ||
96 | |||
97 | /* If true, dispc output is enabled */ | ||
98 | bool updating; | ||
99 | |||
100 | /* If true, a display is enabled using this manager */ | ||
101 | bool enabled; | ||
102 | }; | ||
103 | |||
104 | static struct { | ||
105 | struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; | ||
106 | struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; | ||
107 | |||
108 | bool irq_enabled; | ||
109 | } dss_data; | ||
110 | |||
111 | /* protects dss_data */ | ||
112 | static spinlock_t data_lock; | ||
113 | /* lock for blocking functions */ | ||
114 | static DEFINE_MUTEX(apply_lock); | ||
115 | static DECLARE_COMPLETION(extra_updated_completion); | ||
116 | |||
117 | static void dss_register_vsync_isr(void); | ||
118 | |||
119 | static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl) | ||
120 | { | ||
121 | return &dss_data.ovl_priv_data_array[ovl->id]; | ||
122 | } | ||
123 | |||
124 | static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr) | ||
125 | { | ||
126 | return &dss_data.mgr_priv_data_array[mgr->id]; | ||
127 | } | ||
128 | |||
129 | void dss_apply_init(void) | ||
130 | { | ||
131 | const int num_ovls = dss_feat_get_num_ovls(); | ||
132 | int i; | ||
133 | |||
134 | spin_lock_init(&data_lock); | ||
135 | |||
136 | for (i = 0; i < num_ovls; ++i) { | ||
137 | struct ovl_priv_data *op; | ||
138 | |||
139 | op = &dss_data.ovl_priv_data_array[i]; | ||
140 | |||
141 | op->info.global_alpha = 255; | ||
142 | |||
143 | switch (i) { | ||
144 | case 0: | ||
145 | op->info.zorder = 0; | ||
146 | break; | ||
147 | case 1: | ||
148 | op->info.zorder = | ||
149 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0; | ||
150 | break; | ||
151 | case 2: | ||
152 | op->info.zorder = | ||
153 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0; | ||
154 | break; | ||
155 | case 3: | ||
156 | op->info.zorder = | ||
157 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0; | ||
158 | break; | ||
159 | } | ||
160 | |||
161 | op->user_info = op->info; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | static bool ovl_manual_update(struct omap_overlay *ovl) | ||
166 | { | ||
167 | return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | ||
168 | } | ||
169 | |||
170 | static bool mgr_manual_update(struct omap_overlay_manager *mgr) | ||
171 | { | ||
172 | return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | ||
173 | } | ||
174 | |||
175 | static int dss_check_settings_low(struct omap_overlay_manager *mgr, | ||
176 | struct omap_dss_device *dssdev, bool applying) | ||
177 | { | ||
178 | struct omap_overlay_info *oi; | ||
179 | struct omap_overlay_manager_info *mi; | ||
180 | struct omap_overlay *ovl; | ||
181 | struct omap_overlay_info *ois[MAX_DSS_OVERLAYS]; | ||
182 | struct ovl_priv_data *op; | ||
183 | struct mgr_priv_data *mp; | ||
184 | |||
185 | mp = get_mgr_priv(mgr); | ||
186 | |||
187 | if (applying && mp->user_info_dirty) | ||
188 | mi = &mp->user_info; | ||
189 | else | ||
190 | mi = &mp->info; | ||
191 | |||
192 | /* collect the infos to be tested into the array */ | ||
193 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
194 | op = get_ovl_priv(ovl); | ||
195 | |||
196 | if (!op->enabled && !op->enabling) | ||
197 | oi = NULL; | ||
198 | else if (applying && op->user_info_dirty) | ||
199 | oi = &op->user_info; | ||
200 | else | ||
201 | oi = &op->info; | ||
202 | |||
203 | ois[ovl->id] = oi; | ||
204 | } | ||
205 | |||
206 | return dss_mgr_check(mgr, dssdev, mi, ois); | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * check manager and overlay settings using overlay_info from data->info | ||
211 | */ | ||
212 | static int dss_check_settings(struct omap_overlay_manager *mgr, | ||
213 | struct omap_dss_device *dssdev) | ||
214 | { | ||
215 | return dss_check_settings_low(mgr, dssdev, false); | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * check manager and overlay settings using overlay_info from ovl->info if | ||
220 | * dirty and from data->info otherwise | ||
221 | */ | ||
222 | static int dss_check_settings_apply(struct omap_overlay_manager *mgr, | ||
223 | struct omap_dss_device *dssdev) | ||
224 | { | ||
225 | return dss_check_settings_low(mgr, dssdev, true); | ||
226 | } | ||
227 | |||
228 | static bool need_isr(void) | ||
229 | { | ||
230 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
231 | int i; | ||
232 | |||
233 | for (i = 0; i < num_mgrs; ++i) { | ||
234 | struct omap_overlay_manager *mgr; | ||
235 | struct mgr_priv_data *mp; | ||
236 | struct omap_overlay *ovl; | ||
237 | |||
238 | mgr = omap_dss_get_overlay_manager(i); | ||
239 | mp = get_mgr_priv(mgr); | ||
240 | |||
241 | if (!mp->enabled) | ||
242 | continue; | ||
243 | |||
244 | if (mgr_manual_update(mgr)) { | ||
245 | /* to catch FRAMEDONE */ | ||
246 | if (mp->updating) | ||
247 | return true; | ||
248 | } else { | ||
249 | /* to catch GO bit going down */ | ||
250 | if (mp->busy) | ||
251 | return true; | ||
252 | |||
253 | /* to write new values to registers */ | ||
254 | if (mp->info_dirty) | ||
255 | return true; | ||
256 | |||
257 | /* to set GO bit */ | ||
258 | if (mp->shadow_info_dirty) | ||
259 | return true; | ||
260 | |||
261 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
262 | struct ovl_priv_data *op; | ||
263 | |||
264 | op = get_ovl_priv(ovl); | ||
265 | |||
266 | /* | ||
267 | * NOTE: we check extra_info flags even for | ||
268 | * disabled overlays, as extra_infos need to be | ||
269 | * always written. | ||
270 | */ | ||
271 | |||
272 | /* to write new values to registers */ | ||
273 | if (op->extra_info_dirty) | ||
274 | return true; | ||
275 | |||
276 | /* to set GO bit */ | ||
277 | if (op->shadow_extra_info_dirty) | ||
278 | return true; | ||
279 | |||
280 | if (!op->enabled) | ||
281 | continue; | ||
282 | |||
283 | /* to write new values to registers */ | ||
284 | if (op->info_dirty) | ||
285 | return true; | ||
286 | |||
287 | /* to set GO bit */ | ||
288 | if (op->shadow_info_dirty) | ||
289 | return true; | ||
290 | } | ||
291 | } | ||
292 | } | ||
293 | |||
294 | return false; | ||
295 | } | ||
296 | |||
297 | static bool need_go(struct omap_overlay_manager *mgr) | ||
298 | { | ||
299 | struct omap_overlay *ovl; | ||
300 | struct mgr_priv_data *mp; | ||
301 | struct ovl_priv_data *op; | ||
302 | |||
303 | mp = get_mgr_priv(mgr); | ||
304 | |||
305 | if (mp->shadow_info_dirty) | ||
306 | return true; | ||
307 | |||
308 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
309 | op = get_ovl_priv(ovl); | ||
310 | if (op->shadow_info_dirty || op->shadow_extra_info_dirty) | ||
311 | return true; | ||
312 | } | ||
313 | |||
314 | return false; | ||
315 | } | ||
316 | |||
317 | /* returns true if an extra_info field is currently being updated */ | ||
318 | static bool extra_info_update_ongoing(void) | ||
319 | { | ||
320 | const int num_ovls = omap_dss_get_num_overlays(); | ||
321 | struct ovl_priv_data *op; | ||
322 | struct omap_overlay *ovl; | ||
323 | struct mgr_priv_data *mp; | ||
324 | int i; | ||
325 | |||
326 | for (i = 0; i < num_ovls; ++i) { | ||
327 | ovl = omap_dss_get_overlay(i); | ||
328 | op = get_ovl_priv(ovl); | ||
329 | |||
330 | if (!ovl->manager) | ||
331 | continue; | ||
332 | |||
333 | mp = get_mgr_priv(ovl->manager); | ||
334 | |||
335 | if (!mp->enabled) | ||
336 | continue; | ||
337 | |||
338 | if (!mp->updating) | ||
339 | continue; | ||
340 | |||
341 | if (op->extra_info_dirty || op->shadow_extra_info_dirty) | ||
342 | return true; | ||
343 | } | ||
344 | |||
345 | return false; | ||
346 | } | ||
347 | |||
348 | /* wait until no extra_info updates are pending */ | ||
349 | static void wait_pending_extra_info_updates(void) | ||
350 | { | ||
351 | bool updating; | ||
352 | unsigned long flags; | ||
353 | unsigned long t; | ||
354 | |||
355 | spin_lock_irqsave(&data_lock, flags); | ||
356 | |||
357 | updating = extra_info_update_ongoing(); | ||
358 | |||
359 | if (!updating) { | ||
360 | spin_unlock_irqrestore(&data_lock, flags); | ||
361 | return; | ||
362 | } | ||
363 | |||
364 | init_completion(&extra_updated_completion); | ||
365 | |||
366 | spin_unlock_irqrestore(&data_lock, flags); | ||
367 | |||
368 | t = msecs_to_jiffies(500); | ||
369 | wait_for_completion_timeout(&extra_updated_completion, t); | ||
370 | |||
371 | updating = extra_info_update_ongoing(); | ||
372 | |||
373 | WARN_ON(updating); | ||
374 | } | ||
375 | |||
376 | int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | ||
377 | { | ||
378 | unsigned long timeout = msecs_to_jiffies(500); | ||
379 | struct mgr_priv_data *mp; | ||
380 | u32 irq; | ||
381 | int r; | ||
382 | int i; | ||
383 | struct omap_dss_device *dssdev = mgr->device; | ||
384 | |||
385 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
386 | return 0; | ||
387 | |||
388 | if (mgr_manual_update(mgr)) | ||
389 | return 0; | ||
390 | |||
391 | irq = dispc_mgr_get_vsync_irq(mgr->id); | ||
392 | |||
393 | mp = get_mgr_priv(mgr); | ||
394 | i = 0; | ||
395 | while (1) { | ||
396 | unsigned long flags; | ||
397 | bool shadow_dirty, dirty; | ||
398 | |||
399 | spin_lock_irqsave(&data_lock, flags); | ||
400 | dirty = mp->info_dirty; | ||
401 | shadow_dirty = mp->shadow_info_dirty; | ||
402 | spin_unlock_irqrestore(&data_lock, flags); | ||
403 | |||
404 | if (!dirty && !shadow_dirty) { | ||
405 | r = 0; | ||
406 | break; | ||
407 | } | ||
408 | |||
409 | /* 4 iterations is the worst case: | ||
410 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | ||
411 | * 2 - first VSYNC, dirty = true | ||
412 | * 3 - dirty = false, shadow_dirty = true | ||
413 | * 4 - shadow_dirty = false */ | ||
414 | if (i++ == 3) { | ||
415 | DSSERR("mgr(%d)->wait_for_go() not finishing\n", | ||
416 | mgr->id); | ||
417 | r = 0; | ||
418 | break; | ||
419 | } | ||
420 | |||
421 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
422 | if (r == -ERESTARTSYS) | ||
423 | break; | ||
424 | |||
425 | if (r) { | ||
426 | DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); | ||
427 | break; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | return r; | ||
432 | } | ||
433 | |||
434 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) | ||
435 | { | ||
436 | unsigned long timeout = msecs_to_jiffies(500); | ||
437 | struct ovl_priv_data *op; | ||
438 | struct omap_dss_device *dssdev; | ||
439 | u32 irq; | ||
440 | int r; | ||
441 | int i; | ||
442 | |||
443 | if (!ovl->manager) | ||
444 | return 0; | ||
445 | |||
446 | dssdev = ovl->manager->device; | ||
447 | |||
448 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
449 | return 0; | ||
450 | |||
451 | if (ovl_manual_update(ovl)) | ||
452 | return 0; | ||
453 | |||
454 | irq = dispc_mgr_get_vsync_irq(ovl->manager->id); | ||
455 | |||
456 | op = get_ovl_priv(ovl); | ||
457 | i = 0; | ||
458 | while (1) { | ||
459 | unsigned long flags; | ||
460 | bool shadow_dirty, dirty; | ||
461 | |||
462 | spin_lock_irqsave(&data_lock, flags); | ||
463 | dirty = op->info_dirty; | ||
464 | shadow_dirty = op->shadow_info_dirty; | ||
465 | spin_unlock_irqrestore(&data_lock, flags); | ||
466 | |||
467 | if (!dirty && !shadow_dirty) { | ||
468 | r = 0; | ||
469 | break; | ||
470 | } | ||
471 | |||
472 | /* 4 iterations is the worst case: | ||
473 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | ||
474 | * 2 - first VSYNC, dirty = true | ||
475 | * 3 - dirty = false, shadow_dirty = true | ||
476 | * 4 - shadow_dirty = false */ | ||
477 | if (i++ == 3) { | ||
478 | DSSERR("ovl(%d)->wait_for_go() not finishing\n", | ||
479 | ovl->id); | ||
480 | r = 0; | ||
481 | break; | ||
482 | } | ||
483 | |||
484 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
485 | if (r == -ERESTARTSYS) | ||
486 | break; | ||
487 | |||
488 | if (r) { | ||
489 | DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); | ||
490 | break; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | return r; | ||
495 | } | ||
496 | |||
497 | static void dss_ovl_write_regs(struct omap_overlay *ovl) | ||
498 | { | ||
499 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
500 | struct omap_overlay_info *oi; | ||
501 | bool ilace, replication; | ||
502 | struct mgr_priv_data *mp; | ||
503 | int r; | ||
504 | |||
505 | DSSDBGF("%d", ovl->id); | ||
506 | |||
507 | if (!op->enabled || !op->info_dirty) | ||
508 | return; | ||
509 | |||
510 | oi = &op->info; | ||
511 | |||
512 | replication = dss_use_replication(ovl->manager->device, oi->color_mode); | ||
513 | |||
514 | ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC; | ||
515 | |||
516 | r = dispc_ovl_setup(ovl->id, oi, ilace, replication); | ||
517 | if (r) { | ||
518 | /* | ||
519 | * We can't do much here, as this function can be called from | ||
520 | * vsync interrupt. | ||
521 | */ | ||
522 | DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id); | ||
523 | |||
524 | /* This will leave fifo configurations in a nonoptimal state */ | ||
525 | op->enabled = false; | ||
526 | dispc_ovl_enable(ovl->id, false); | ||
527 | return; | ||
528 | } | ||
529 | |||
530 | mp = get_mgr_priv(ovl->manager); | ||
531 | |||
532 | op->info_dirty = false; | ||
533 | if (mp->updating) | ||
534 | op->shadow_info_dirty = true; | ||
535 | } | ||
536 | |||
537 | static void dss_ovl_write_regs_extra(struct omap_overlay *ovl) | ||
538 | { | ||
539 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
540 | struct mgr_priv_data *mp; | ||
541 | |||
542 | DSSDBGF("%d", ovl->id); | ||
543 | |||
544 | if (!op->extra_info_dirty) | ||
545 | return; | ||
546 | |||
547 | /* note: write also when op->enabled == false, so that the ovl gets | ||
548 | * disabled */ | ||
549 | |||
550 | dispc_ovl_enable(ovl->id, op->enabled); | ||
551 | dispc_ovl_set_channel_out(ovl->id, op->channel); | ||
552 | dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high); | ||
553 | |||
554 | mp = get_mgr_priv(ovl->manager); | ||
555 | |||
556 | op->extra_info_dirty = false; | ||
557 | if (mp->updating) | ||
558 | op->shadow_extra_info_dirty = true; | ||
559 | } | ||
560 | |||
561 | static void dss_mgr_write_regs(struct omap_overlay_manager *mgr) | ||
562 | { | ||
563 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
564 | struct omap_overlay *ovl; | ||
565 | |||
566 | DSSDBGF("%d", mgr->id); | ||
567 | |||
568 | if (!mp->enabled) | ||
569 | return; | ||
570 | |||
571 | WARN_ON(mp->busy); | ||
572 | |||
573 | /* Commit overlay settings */ | ||
574 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
575 | dss_ovl_write_regs(ovl); | ||
576 | dss_ovl_write_regs_extra(ovl); | ||
577 | } | ||
578 | |||
579 | if (mp->info_dirty) { | ||
580 | dispc_mgr_setup(mgr->id, &mp->info); | ||
581 | |||
582 | mp->info_dirty = false; | ||
583 | if (mp->updating) | ||
584 | mp->shadow_info_dirty = true; | ||
585 | } | ||
586 | } | ||
587 | |||
588 | static void dss_write_regs(void) | ||
589 | { | ||
590 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | ||
591 | int i; | ||
592 | |||
593 | for (i = 0; i < num_mgrs; ++i) { | ||
594 | struct omap_overlay_manager *mgr; | ||
595 | struct mgr_priv_data *mp; | ||
596 | int r; | ||
597 | |||
598 | mgr = omap_dss_get_overlay_manager(i); | ||
599 | mp = get_mgr_priv(mgr); | ||
600 | |||
601 | if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) | ||
602 | continue; | ||
603 | |||
604 | r = dss_check_settings(mgr, mgr->device); | ||
605 | if (r) { | ||
606 | DSSERR("cannot write registers for manager %s: " | ||
607 | "illegal configuration\n", mgr->name); | ||
608 | continue; | ||
609 | } | ||
610 | |||
611 | dss_mgr_write_regs(mgr); | ||
612 | } | ||
613 | } | ||
614 | |||
615 | static void dss_set_go_bits(void) | ||
616 | { | ||
617 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | ||
618 | int i; | ||
619 | |||
620 | for (i = 0; i < num_mgrs; ++i) { | ||
621 | struct omap_overlay_manager *mgr; | ||
622 | struct mgr_priv_data *mp; | ||
623 | |||
624 | mgr = omap_dss_get_overlay_manager(i); | ||
625 | mp = get_mgr_priv(mgr); | ||
626 | |||
627 | if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) | ||
628 | continue; | ||
629 | |||
630 | if (!need_go(mgr)) | ||
631 | continue; | ||
632 | |||
633 | mp->busy = true; | ||
634 | |||
635 | if (!dss_data.irq_enabled && need_isr()) | ||
636 | dss_register_vsync_isr(); | ||
637 | |||
638 | dispc_mgr_go(mgr->id); | ||
639 | } | ||
640 | |||
641 | } | ||
642 | |||
643 | void dss_mgr_start_update(struct omap_overlay_manager *mgr) | ||
644 | { | ||
645 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
646 | unsigned long flags; | ||
647 | int r; | ||
648 | |||
649 | spin_lock_irqsave(&data_lock, flags); | ||
650 | |||
651 | WARN_ON(mp->updating); | ||
652 | |||
653 | r = dss_check_settings(mgr, mgr->device); | ||
654 | if (r) { | ||
655 | DSSERR("cannot start manual update: illegal configuration\n"); | ||
656 | spin_unlock_irqrestore(&data_lock, flags); | ||
657 | return; | ||
658 | } | ||
659 | |||
660 | dss_mgr_write_regs(mgr); | ||
661 | |||
662 | mp->updating = true; | ||
663 | |||
664 | if (!dss_data.irq_enabled && need_isr()) | ||
665 | dss_register_vsync_isr(); | ||
666 | |||
667 | dispc_mgr_enable(mgr->id, true); | ||
668 | |||
669 | spin_unlock_irqrestore(&data_lock, flags); | ||
670 | } | ||
671 | |||
672 | static void dss_apply_irq_handler(void *data, u32 mask); | ||
673 | |||
674 | static void dss_register_vsync_isr(void) | ||
675 | { | ||
676 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
677 | u32 mask; | ||
678 | int r, i; | ||
679 | |||
680 | mask = 0; | ||
681 | for (i = 0; i < num_mgrs; ++i) | ||
682 | mask |= dispc_mgr_get_vsync_irq(i); | ||
683 | |||
684 | for (i = 0; i < num_mgrs; ++i) | ||
685 | mask |= dispc_mgr_get_framedone_irq(i); | ||
686 | |||
687 | r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); | ||
688 | WARN_ON(r); | ||
689 | |||
690 | dss_data.irq_enabled = true; | ||
691 | } | ||
692 | |||
693 | static void dss_unregister_vsync_isr(void) | ||
694 | { | ||
695 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
696 | u32 mask; | ||
697 | int r, i; | ||
698 | |||
699 | mask = 0; | ||
700 | for (i = 0; i < num_mgrs; ++i) | ||
701 | mask |= dispc_mgr_get_vsync_irq(i); | ||
702 | |||
703 | for (i = 0; i < num_mgrs; ++i) | ||
704 | mask |= dispc_mgr_get_framedone_irq(i); | ||
705 | |||
706 | r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask); | ||
707 | WARN_ON(r); | ||
708 | |||
709 | dss_data.irq_enabled = false; | ||
710 | } | ||
711 | |||
712 | static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) | ||
713 | { | ||
714 | struct omap_overlay *ovl; | ||
715 | struct mgr_priv_data *mp; | ||
716 | struct ovl_priv_data *op; | ||
717 | |||
718 | mp = get_mgr_priv(mgr); | ||
719 | mp->shadow_info_dirty = false; | ||
720 | |||
721 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
722 | op = get_ovl_priv(ovl); | ||
723 | op->shadow_info_dirty = false; | ||
724 | op->shadow_extra_info_dirty = false; | ||
725 | } | ||
726 | } | ||
727 | |||
728 | static void dss_apply_irq_handler(void *data, u32 mask) | ||
729 | { | ||
730 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
731 | int i; | ||
732 | bool extra_updating; | ||
733 | |||
734 | spin_lock(&data_lock); | ||
735 | |||
736 | /* clear busy, updating flags, shadow_dirty flags */ | ||
737 | for (i = 0; i < num_mgrs; i++) { | ||
738 | struct omap_overlay_manager *mgr; | ||
739 | struct mgr_priv_data *mp; | ||
740 | bool was_updating; | ||
741 | |||
742 | mgr = omap_dss_get_overlay_manager(i); | ||
743 | mp = get_mgr_priv(mgr); | ||
744 | |||
745 | if (!mp->enabled) | ||
746 | continue; | ||
747 | |||
748 | was_updating = mp->updating; | ||
749 | mp->updating = dispc_mgr_is_enabled(i); | ||
750 | |||
751 | if (!mgr_manual_update(mgr)) { | ||
752 | bool was_busy = mp->busy; | ||
753 | mp->busy = dispc_mgr_go_busy(i); | ||
754 | |||
755 | if (was_busy && !mp->busy) | ||
756 | mgr_clear_shadow_dirty(mgr); | ||
757 | } else { | ||
758 | if (was_updating && !mp->updating) | ||
759 | mgr_clear_shadow_dirty(mgr); | ||
760 | } | ||
761 | } | ||
762 | |||
763 | dss_write_regs(); | ||
764 | dss_set_go_bits(); | ||
765 | |||
766 | extra_updating = extra_info_update_ongoing(); | ||
767 | if (!extra_updating) | ||
768 | complete_all(&extra_updated_completion); | ||
769 | |||
770 | if (!need_isr()) | ||
771 | dss_unregister_vsync_isr(); | ||
772 | |||
773 | spin_unlock(&data_lock); | ||
774 | } | ||
775 | |||
776 | static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl) | ||
777 | { | ||
778 | struct ovl_priv_data *op; | ||
779 | |||
780 | op = get_ovl_priv(ovl); | ||
781 | |||
782 | if (!op->user_info_dirty) | ||
783 | return; | ||
784 | |||
785 | op->user_info_dirty = false; | ||
786 | op->info_dirty = true; | ||
787 | op->info = op->user_info; | ||
788 | } | ||
789 | |||
790 | static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr) | ||
791 | { | ||
792 | struct mgr_priv_data *mp; | ||
793 | |||
794 | mp = get_mgr_priv(mgr); | ||
795 | |||
796 | if (!mp->user_info_dirty) | ||
797 | return; | ||
798 | |||
799 | mp->user_info_dirty = false; | ||
800 | mp->info_dirty = true; | ||
801 | mp->info = mp->user_info; | ||
802 | } | ||
803 | |||
804 | int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) | ||
805 | { | ||
806 | unsigned long flags; | ||
807 | struct omap_overlay *ovl; | ||
808 | int r; | ||
809 | |||
810 | DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); | ||
811 | |||
812 | spin_lock_irqsave(&data_lock, flags); | ||
813 | |||
814 | r = dss_check_settings_apply(mgr, mgr->device); | ||
815 | if (r) { | ||
816 | spin_unlock_irqrestore(&data_lock, flags); | ||
817 | DSSERR("failed to apply settings: illegal configuration.\n"); | ||
818 | return r; | ||
819 | } | ||
820 | |||
821 | /* Configure overlays */ | ||
822 | list_for_each_entry(ovl, &mgr->overlays, list) | ||
823 | omap_dss_mgr_apply_ovl(ovl); | ||
824 | |||
825 | /* Configure manager */ | ||
826 | omap_dss_mgr_apply_mgr(mgr); | ||
827 | |||
828 | dss_write_regs(); | ||
829 | dss_set_go_bits(); | ||
830 | |||
831 | spin_unlock_irqrestore(&data_lock, flags); | ||
832 | |||
833 | return 0; | ||
834 | } | ||
835 | |||
836 | static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable) | ||
837 | { | ||
838 | struct ovl_priv_data *op; | ||
839 | |||
840 | op = get_ovl_priv(ovl); | ||
841 | |||
842 | if (op->enabled == enable) | ||
843 | return; | ||
844 | |||
845 | op->enabled = enable; | ||
846 | op->extra_info_dirty = true; | ||
847 | } | ||
848 | |||
849 | static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl, | ||
850 | u32 fifo_low, u32 fifo_high) | ||
851 | { | ||
852 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
853 | |||
854 | if (op->fifo_low == fifo_low && op->fifo_high == fifo_high) | ||
855 | return; | ||
856 | |||
857 | op->fifo_low = fifo_low; | ||
858 | op->fifo_high = fifo_high; | ||
859 | op->extra_info_dirty = true; | ||
860 | } | ||
861 | |||
862 | static void dss_ovl_setup_fifo(struct omap_overlay *ovl) | ||
863 | { | ||
864 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
865 | struct omap_dss_device *dssdev; | ||
866 | u32 size, burst_size; | ||
867 | u32 fifo_low, fifo_high; | ||
868 | |||
869 | if (!op->enabled && !op->enabling) | ||
870 | return; | ||
871 | |||
872 | dssdev = ovl->manager->device; | ||
873 | |||
874 | size = dispc_ovl_get_fifo_size(ovl->id); | ||
875 | |||
876 | burst_size = dispc_ovl_get_burst_size(ovl->id); | ||
877 | |||
878 | switch (dssdev->type) { | ||
879 | case OMAP_DISPLAY_TYPE_DPI: | ||
880 | case OMAP_DISPLAY_TYPE_DBI: | ||
881 | case OMAP_DISPLAY_TYPE_SDI: | ||
882 | case OMAP_DISPLAY_TYPE_VENC: | ||
883 | case OMAP_DISPLAY_TYPE_HDMI: | ||
884 | default_get_overlay_fifo_thresholds(ovl->id, size, | ||
885 | burst_size, &fifo_low, &fifo_high); | ||
886 | break; | ||
887 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
888 | case OMAP_DISPLAY_TYPE_DSI: | ||
889 | dsi_get_overlay_fifo_thresholds(ovl->id, size, | ||
890 | burst_size, &fifo_low, &fifo_high); | ||
891 | break; | ||
892 | #endif | ||
893 | default: | ||
894 | BUG(); | ||
895 | } | ||
896 | |||
897 | dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); | ||
898 | } | ||
899 | |||
900 | static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr) | ||
901 | { | ||
902 | struct omap_overlay *ovl; | ||
903 | struct mgr_priv_data *mp; | ||
904 | |||
905 | mp = get_mgr_priv(mgr); | ||
906 | |||
907 | if (!mp->enabled) | ||
908 | return; | ||
909 | |||
910 | list_for_each_entry(ovl, &mgr->overlays, list) | ||
911 | dss_ovl_setup_fifo(ovl); | ||
912 | } | ||
913 | |||
914 | static void dss_setup_fifos(void) | ||
915 | { | ||
916 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | ||
917 | struct omap_overlay_manager *mgr; | ||
918 | int i; | ||
919 | |||
920 | for (i = 0; i < num_mgrs; ++i) { | ||
921 | mgr = omap_dss_get_overlay_manager(i); | ||
922 | dss_mgr_setup_fifos(mgr); | ||
923 | } | ||
924 | } | ||
925 | |||
926 | int dss_mgr_enable(struct omap_overlay_manager *mgr) | ||
927 | { | ||
928 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
929 | unsigned long flags; | ||
930 | int r; | ||
931 | |||
932 | mutex_lock(&apply_lock); | ||
933 | |||
934 | if (mp->enabled) | ||
935 | goto out; | ||
936 | |||
937 | spin_lock_irqsave(&data_lock, flags); | ||
938 | |||
939 | mp->enabled = true; | ||
940 | |||
941 | r = dss_check_settings(mgr, mgr->device); | ||
942 | if (r) { | ||
943 | DSSERR("failed to enable manager %d: check_settings failed\n", | ||
944 | mgr->id); | ||
945 | goto err; | ||
946 | } | ||
947 | |||
948 | dss_setup_fifos(); | ||
949 | |||
950 | dss_write_regs(); | ||
951 | dss_set_go_bits(); | ||
952 | |||
953 | if (!mgr_manual_update(mgr)) | ||
954 | mp->updating = true; | ||
955 | |||
956 | spin_unlock_irqrestore(&data_lock, flags); | ||
957 | |||
958 | if (!mgr_manual_update(mgr)) | ||
959 | dispc_mgr_enable(mgr->id, true); | ||
960 | |||
961 | out: | ||
962 | mutex_unlock(&apply_lock); | ||
963 | |||
964 | return 0; | ||
965 | |||
966 | err: | ||
967 | mp->enabled = false; | ||
968 | spin_unlock_irqrestore(&data_lock, flags); | ||
969 | mutex_unlock(&apply_lock); | ||
970 | return r; | ||
971 | } | ||
972 | |||
973 | void dss_mgr_disable(struct omap_overlay_manager *mgr) | ||
974 | { | ||
975 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
976 | unsigned long flags; | ||
977 | |||
978 | mutex_lock(&apply_lock); | ||
979 | |||
980 | if (!mp->enabled) | ||
981 | goto out; | ||
982 | |||
983 | if (!mgr_manual_update(mgr)) | ||
984 | dispc_mgr_enable(mgr->id, false); | ||
985 | |||
986 | spin_lock_irqsave(&data_lock, flags); | ||
987 | |||
988 | mp->updating = false; | ||
989 | mp->enabled = false; | ||
990 | |||
991 | spin_unlock_irqrestore(&data_lock, flags); | ||
992 | |||
993 | out: | ||
994 | mutex_unlock(&apply_lock); | ||
995 | } | ||
996 | |||
997 | int dss_mgr_set_info(struct omap_overlay_manager *mgr, | ||
998 | struct omap_overlay_manager_info *info) | ||
999 | { | ||
1000 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1001 | unsigned long flags; | ||
1002 | int r; | ||
1003 | |||
1004 | r = dss_mgr_simple_check(mgr, info); | ||
1005 | if (r) | ||
1006 | return r; | ||
1007 | |||
1008 | spin_lock_irqsave(&data_lock, flags); | ||
1009 | |||
1010 | mp->user_info = *info; | ||
1011 | mp->user_info_dirty = true; | ||
1012 | |||
1013 | spin_unlock_irqrestore(&data_lock, flags); | ||
1014 | |||
1015 | return 0; | ||
1016 | } | ||
1017 | |||
1018 | void dss_mgr_get_info(struct omap_overlay_manager *mgr, | ||
1019 | struct omap_overlay_manager_info *info) | ||
1020 | { | ||
1021 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1022 | unsigned long flags; | ||
1023 | |||
1024 | spin_lock_irqsave(&data_lock, flags); | ||
1025 | |||
1026 | *info = mp->user_info; | ||
1027 | |||
1028 | spin_unlock_irqrestore(&data_lock, flags); | ||
1029 | } | ||
1030 | |||
1031 | int dss_mgr_set_device(struct omap_overlay_manager *mgr, | ||
1032 | struct omap_dss_device *dssdev) | ||
1033 | { | ||
1034 | int r; | ||
1035 | |||
1036 | mutex_lock(&apply_lock); | ||
1037 | |||
1038 | if (dssdev->manager) { | ||
1039 | DSSERR("display '%s' already has a manager '%s'\n", | ||
1040 | dssdev->name, dssdev->manager->name); | ||
1041 | r = -EINVAL; | ||
1042 | goto err; | ||
1043 | } | ||
1044 | |||
1045 | if ((mgr->supported_displays & dssdev->type) == 0) { | ||
1046 | DSSERR("display '%s' does not support manager '%s'\n", | ||
1047 | dssdev->name, mgr->name); | ||
1048 | r = -EINVAL; | ||
1049 | goto err; | ||
1050 | } | ||
1051 | |||
1052 | dssdev->manager = mgr; | ||
1053 | mgr->device = dssdev; | ||
1054 | |||
1055 | mutex_unlock(&apply_lock); | ||
1056 | |||
1057 | return 0; | ||
1058 | err: | ||
1059 | mutex_unlock(&apply_lock); | ||
1060 | return r; | ||
1061 | } | ||
1062 | |||
1063 | int dss_mgr_unset_device(struct omap_overlay_manager *mgr) | ||
1064 | { | ||
1065 | int r; | ||
1066 | |||
1067 | mutex_lock(&apply_lock); | ||
1068 | |||
1069 | if (!mgr->device) { | ||
1070 | DSSERR("failed to unset display, display not set.\n"); | ||
1071 | r = -EINVAL; | ||
1072 | goto err; | ||
1073 | } | ||
1074 | |||
1075 | /* | ||
1076 | * Don't allow currently enabled displays to have the overlay manager | ||
1077 | * pulled out from underneath them | ||
1078 | */ | ||
1079 | if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) { | ||
1080 | r = -EINVAL; | ||
1081 | goto err; | ||
1082 | } | ||
1083 | |||
1084 | mgr->device->manager = NULL; | ||
1085 | mgr->device = NULL; | ||
1086 | |||
1087 | mutex_unlock(&apply_lock); | ||
1088 | |||
1089 | return 0; | ||
1090 | err: | ||
1091 | mutex_unlock(&apply_lock); | ||
1092 | return r; | ||
1093 | } | ||
1094 | |||
1095 | |||
1096 | int dss_ovl_set_info(struct omap_overlay *ovl, | ||
1097 | struct omap_overlay_info *info) | ||
1098 | { | ||
1099 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1100 | unsigned long flags; | ||
1101 | int r; | ||
1102 | |||
1103 | r = dss_ovl_simple_check(ovl, info); | ||
1104 | if (r) | ||
1105 | return r; | ||
1106 | |||
1107 | spin_lock_irqsave(&data_lock, flags); | ||
1108 | |||
1109 | op->user_info = *info; | ||
1110 | op->user_info_dirty = true; | ||
1111 | |||
1112 | spin_unlock_irqrestore(&data_lock, flags); | ||
1113 | |||
1114 | return 0; | ||
1115 | } | ||
1116 | |||
1117 | void dss_ovl_get_info(struct omap_overlay *ovl, | ||
1118 | struct omap_overlay_info *info) | ||
1119 | { | ||
1120 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1121 | unsigned long flags; | ||
1122 | |||
1123 | spin_lock_irqsave(&data_lock, flags); | ||
1124 | |||
1125 | *info = op->user_info; | ||
1126 | |||
1127 | spin_unlock_irqrestore(&data_lock, flags); | ||
1128 | } | ||
1129 | |||
1130 | int dss_ovl_set_manager(struct omap_overlay *ovl, | ||
1131 | struct omap_overlay_manager *mgr) | ||
1132 | { | ||
1133 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1134 | unsigned long flags; | ||
1135 | int r; | ||
1136 | |||
1137 | if (!mgr) | ||
1138 | return -EINVAL; | ||
1139 | |||
1140 | mutex_lock(&apply_lock); | ||
1141 | |||
1142 | if (ovl->manager) { | ||
1143 | DSSERR("overlay '%s' already has a manager '%s'\n", | ||
1144 | ovl->name, ovl->manager->name); | ||
1145 | r = -EINVAL; | ||
1146 | goto err; | ||
1147 | } | ||
1148 | |||
1149 | spin_lock_irqsave(&data_lock, flags); | ||
1150 | |||
1151 | if (op->enabled) { | ||
1152 | spin_unlock_irqrestore(&data_lock, flags); | ||
1153 | DSSERR("overlay has to be disabled to change the manager\n"); | ||
1154 | r = -EINVAL; | ||
1155 | goto err; | ||
1156 | } | ||
1157 | |||
1158 | op->channel = mgr->id; | ||
1159 | op->extra_info_dirty = true; | ||
1160 | |||
1161 | ovl->manager = mgr; | ||
1162 | list_add_tail(&ovl->list, &mgr->overlays); | ||
1163 | |||
1164 | spin_unlock_irqrestore(&data_lock, flags); | ||
1165 | |||
1166 | /* XXX: When there is an overlay on a DSI manual update display, and | ||
1167 | * the overlay is first disabled, then moved to tv, and enabled, we | ||
1168 | * seem to get SYNC_LOST_DIGIT error. | ||
1169 | * | ||
1170 | * Waiting doesn't seem to help, but updating the manual update display | ||
1171 | * after disabling the overlay seems to fix this. This hints that the | ||
1172 | * overlay is perhaps somehow tied to the LCD output until the output | ||
1173 | * is updated. | ||
1174 | * | ||
1175 | * Userspace workaround for this is to update the LCD after disabling | ||
1176 | * the overlay, but before moving the overlay to TV. | ||
1177 | */ | ||
1178 | |||
1179 | mutex_unlock(&apply_lock); | ||
1180 | |||
1181 | return 0; | ||
1182 | err: | ||
1183 | mutex_unlock(&apply_lock); | ||
1184 | return r; | ||
1185 | } | ||
1186 | |||
1187 | int dss_ovl_unset_manager(struct omap_overlay *ovl) | ||
1188 | { | ||
1189 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1190 | unsigned long flags; | ||
1191 | int r; | ||
1192 | |||
1193 | mutex_lock(&apply_lock); | ||
1194 | |||
1195 | if (!ovl->manager) { | ||
1196 | DSSERR("failed to detach overlay: manager not set\n"); | ||
1197 | r = -EINVAL; | ||
1198 | goto err; | ||
1199 | } | ||
1200 | |||
1201 | spin_lock_irqsave(&data_lock, flags); | ||
1202 | |||
1203 | if (op->enabled) { | ||
1204 | spin_unlock_irqrestore(&data_lock, flags); | ||
1205 | DSSERR("overlay has to be disabled to unset the manager\n"); | ||
1206 | r = -EINVAL; | ||
1207 | goto err; | ||
1208 | } | ||
1209 | |||
1210 | op->channel = -1; | ||
1211 | |||
1212 | ovl->manager = NULL; | ||
1213 | list_del(&ovl->list); | ||
1214 | |||
1215 | spin_unlock_irqrestore(&data_lock, flags); | ||
1216 | |||
1217 | mutex_unlock(&apply_lock); | ||
1218 | |||
1219 | return 0; | ||
1220 | err: | ||
1221 | mutex_unlock(&apply_lock); | ||
1222 | return r; | ||
1223 | } | ||
1224 | |||
1225 | bool dss_ovl_is_enabled(struct omap_overlay *ovl) | ||
1226 | { | ||
1227 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1228 | unsigned long flags; | ||
1229 | bool e; | ||
1230 | |||
1231 | spin_lock_irqsave(&data_lock, flags); | ||
1232 | |||
1233 | e = op->enabled; | ||
1234 | |||
1235 | spin_unlock_irqrestore(&data_lock, flags); | ||
1236 | |||
1237 | return e; | ||
1238 | } | ||
1239 | |||
1240 | int dss_ovl_enable(struct omap_overlay *ovl) | ||
1241 | { | ||
1242 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1243 | unsigned long flags; | ||
1244 | int r; | ||
1245 | |||
1246 | mutex_lock(&apply_lock); | ||
1247 | |||
1248 | if (op->enabled) { | ||
1249 | r = 0; | ||
1250 | goto err1; | ||
1251 | } | ||
1252 | |||
1253 | if (ovl->manager == NULL || ovl->manager->device == NULL) { | ||
1254 | r = -EINVAL; | ||
1255 | goto err1; | ||
1256 | } | ||
1257 | |||
1258 | spin_lock_irqsave(&data_lock, flags); | ||
1259 | |||
1260 | op->enabling = true; | ||
1261 | |||
1262 | r = dss_check_settings(ovl->manager, ovl->manager->device); | ||
1263 | if (r) { | ||
1264 | DSSERR("failed to enable overlay %d: check_settings failed\n", | ||
1265 | ovl->id); | ||
1266 | goto err2; | ||
1267 | } | ||
1268 | |||
1269 | dss_setup_fifos(); | ||
1270 | |||
1271 | op->enabling = false; | ||
1272 | dss_apply_ovl_enable(ovl, true); | ||
1273 | |||
1274 | dss_write_regs(); | ||
1275 | dss_set_go_bits(); | ||
1276 | |||
1277 | spin_unlock_irqrestore(&data_lock, flags); | ||
1278 | |||
1279 | mutex_unlock(&apply_lock); | ||
1280 | |||
1281 | return 0; | ||
1282 | err2: | ||
1283 | op->enabling = false; | ||
1284 | spin_unlock_irqrestore(&data_lock, flags); | ||
1285 | err1: | ||
1286 | mutex_unlock(&apply_lock); | ||
1287 | return r; | ||
1288 | } | ||
1289 | |||
1290 | int dss_ovl_disable(struct omap_overlay *ovl) | ||
1291 | { | ||
1292 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1293 | unsigned long flags; | ||
1294 | int r; | ||
1295 | |||
1296 | mutex_lock(&apply_lock); | ||
1297 | |||
1298 | if (!op->enabled) { | ||
1299 | r = 0; | ||
1300 | goto err; | ||
1301 | } | ||
1302 | |||
1303 | if (ovl->manager == NULL || ovl->manager->device == NULL) { | ||
1304 | r = -EINVAL; | ||
1305 | goto err; | ||
1306 | } | ||
1307 | |||
1308 | spin_lock_irqsave(&data_lock, flags); | ||
1309 | |||
1310 | dss_apply_ovl_enable(ovl, false); | ||
1311 | dss_write_regs(); | ||
1312 | dss_set_go_bits(); | ||
1313 | |||
1314 | spin_unlock_irqrestore(&data_lock, flags); | ||
1315 | |||
1316 | mutex_unlock(&apply_lock); | ||
1317 | |||
1318 | return 0; | ||
1319 | |||
1320 | err: | ||
1321 | mutex_unlock(&apply_lock); | ||
1322 | return r; | ||
1323 | } | ||
1324 | |||
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index da7b18576549..8613f86fb56d 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c | |||
@@ -178,6 +178,8 @@ static int omap_dss_probe(struct platform_device *pdev) | |||
178 | 178 | ||
179 | dss_features_init(); | 179 | dss_features_init(); |
180 | 180 | ||
181 | dss_apply_init(); | ||
182 | |||
181 | dss_init_overlay_managers(pdev); | 183 | dss_init_overlay_managers(pdev); |
182 | dss_init_overlays(pdev); | 184 | dss_init_overlays(pdev); |
183 | 185 | ||
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 5c81533eacaa..a5ec7f37c185 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
@@ -64,22 +64,6 @@ struct omap_dispc_isr_data { | |||
64 | u32 mask; | 64 | u32 mask; |
65 | }; | 65 | }; |
66 | 66 | ||
67 | struct dispc_h_coef { | ||
68 | s8 hc4; | ||
69 | s8 hc3; | ||
70 | u8 hc2; | ||
71 | s8 hc1; | ||
72 | s8 hc0; | ||
73 | }; | ||
74 | |||
75 | struct dispc_v_coef { | ||
76 | s8 vc22; | ||
77 | s8 vc2; | ||
78 | u8 vc1; | ||
79 | s8 vc0; | ||
80 | s8 vc00; | ||
81 | }; | ||
82 | |||
83 | enum omap_burst_size { | 67 | enum omap_burst_size { |
84 | BURST_SIZE_X2 = 0, | 68 | BURST_SIZE_X2 = 0, |
85 | BURST_SIZE_X4 = 1, | 69 | BURST_SIZE_X4 = 1, |
@@ -438,6 +422,34 @@ static struct omap_dss_device *dispc_mgr_get_device(enum omap_channel channel) | |||
438 | return mgr ? mgr->device : NULL; | 422 | return mgr ? mgr->device : NULL; |
439 | } | 423 | } |
440 | 424 | ||
425 | u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) | ||
426 | { | ||
427 | switch (channel) { | ||
428 | case OMAP_DSS_CHANNEL_LCD: | ||
429 | return DISPC_IRQ_VSYNC; | ||
430 | case OMAP_DSS_CHANNEL_LCD2: | ||
431 | return DISPC_IRQ_VSYNC2; | ||
432 | case OMAP_DSS_CHANNEL_DIGIT: | ||
433 | return DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; | ||
434 | default: | ||
435 | BUG(); | ||
436 | } | ||
437 | } | ||
438 | |||
439 | u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) | ||
440 | { | ||
441 | switch (channel) { | ||
442 | case OMAP_DSS_CHANNEL_LCD: | ||
443 | return DISPC_IRQ_FRAMEDONE; | ||
444 | case OMAP_DSS_CHANNEL_LCD2: | ||
445 | return DISPC_IRQ_FRAMEDONE2; | ||
446 | case OMAP_DSS_CHANNEL_DIGIT: | ||
447 | return 0; | ||
448 | default: | ||
449 | BUG(); | ||
450 | } | ||
451 | } | ||
452 | |||
441 | bool dispc_mgr_go_busy(enum omap_channel channel) | 453 | bool dispc_mgr_go_busy(enum omap_channel channel) |
442 | { | 454 | { |
443 | int bit; | 455 | int bit; |
@@ -533,105 +545,27 @@ static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value) | |||
533 | dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); | 545 | dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); |
534 | } | 546 | } |
535 | 547 | ||
536 | static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup, | 548 | static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc, |
537 | int vscaleup, int five_taps, | 549 | int fir_vinc, int five_taps, |
538 | enum omap_color_component color_comp) | 550 | enum omap_color_component color_comp) |
539 | { | 551 | { |
540 | /* Coefficients for horizontal up-sampling */ | 552 | const struct dispc_coef *h_coef, *v_coef; |
541 | static const struct dispc_h_coef coef_hup[8] = { | ||
542 | { 0, 0, 128, 0, 0 }, | ||
543 | { -1, 13, 124, -8, 0 }, | ||
544 | { -2, 30, 112, -11, -1 }, | ||
545 | { -5, 51, 95, -11, -2 }, | ||
546 | { 0, -9, 73, 73, -9 }, | ||
547 | { -2, -11, 95, 51, -5 }, | ||
548 | { -1, -11, 112, 30, -2 }, | ||
549 | { 0, -8, 124, 13, -1 }, | ||
550 | }; | ||
551 | |||
552 | /* Coefficients for vertical up-sampling */ | ||
553 | static const struct dispc_v_coef coef_vup_3tap[8] = { | ||
554 | { 0, 0, 128, 0, 0 }, | ||
555 | { 0, 3, 123, 2, 0 }, | ||
556 | { 0, 12, 111, 5, 0 }, | ||
557 | { 0, 32, 89, 7, 0 }, | ||
558 | { 0, 0, 64, 64, 0 }, | ||
559 | { 0, 7, 89, 32, 0 }, | ||
560 | { 0, 5, 111, 12, 0 }, | ||
561 | { 0, 2, 123, 3, 0 }, | ||
562 | }; | ||
563 | |||
564 | static const struct dispc_v_coef coef_vup_5tap[8] = { | ||
565 | { 0, 0, 128, 0, 0 }, | ||
566 | { -1, 13, 124, -8, 0 }, | ||
567 | { -2, 30, 112, -11, -1 }, | ||
568 | { -5, 51, 95, -11, -2 }, | ||
569 | { 0, -9, 73, 73, -9 }, | ||
570 | { -2, -11, 95, 51, -5 }, | ||
571 | { -1, -11, 112, 30, -2 }, | ||
572 | { 0, -8, 124, 13, -1 }, | ||
573 | }; | ||
574 | |||
575 | /* Coefficients for horizontal down-sampling */ | ||
576 | static const struct dispc_h_coef coef_hdown[8] = { | ||
577 | { 0, 36, 56, 36, 0 }, | ||
578 | { 4, 40, 55, 31, -2 }, | ||
579 | { 8, 44, 54, 27, -5 }, | ||
580 | { 12, 48, 53, 22, -7 }, | ||
581 | { -9, 17, 52, 51, 17 }, | ||
582 | { -7, 22, 53, 48, 12 }, | ||
583 | { -5, 27, 54, 44, 8 }, | ||
584 | { -2, 31, 55, 40, 4 }, | ||
585 | }; | ||
586 | |||
587 | /* Coefficients for vertical down-sampling */ | ||
588 | static const struct dispc_v_coef coef_vdown_3tap[8] = { | ||
589 | { 0, 36, 56, 36, 0 }, | ||
590 | { 0, 40, 57, 31, 0 }, | ||
591 | { 0, 45, 56, 27, 0 }, | ||
592 | { 0, 50, 55, 23, 0 }, | ||
593 | { 0, 18, 55, 55, 0 }, | ||
594 | { 0, 23, 55, 50, 0 }, | ||
595 | { 0, 27, 56, 45, 0 }, | ||
596 | { 0, 31, 57, 40, 0 }, | ||
597 | }; | ||
598 | |||
599 | static const struct dispc_v_coef coef_vdown_5tap[8] = { | ||
600 | { 0, 36, 56, 36, 0 }, | ||
601 | { 4, 40, 55, 31, -2 }, | ||
602 | { 8, 44, 54, 27, -5 }, | ||
603 | { 12, 48, 53, 22, -7 }, | ||
604 | { -9, 17, 52, 51, 17 }, | ||
605 | { -7, 22, 53, 48, 12 }, | ||
606 | { -5, 27, 54, 44, 8 }, | ||
607 | { -2, 31, 55, 40, 4 }, | ||
608 | }; | ||
609 | |||
610 | const struct dispc_h_coef *h_coef; | ||
611 | const struct dispc_v_coef *v_coef; | ||
612 | int i; | 553 | int i; |
613 | 554 | ||
614 | if (hscaleup) | 555 | h_coef = dispc_ovl_get_scale_coef(fir_hinc, true); |
615 | h_coef = coef_hup; | 556 | v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps); |
616 | else | ||
617 | h_coef = coef_hdown; | ||
618 | |||
619 | if (vscaleup) | ||
620 | v_coef = five_taps ? coef_vup_5tap : coef_vup_3tap; | ||
621 | else | ||
622 | v_coef = five_taps ? coef_vdown_5tap : coef_vdown_3tap; | ||
623 | 557 | ||
624 | for (i = 0; i < 8; i++) { | 558 | for (i = 0; i < 8; i++) { |
625 | u32 h, hv; | 559 | u32 h, hv; |
626 | 560 | ||
627 | h = FLD_VAL(h_coef[i].hc0, 7, 0) | 561 | h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0) |
628 | | FLD_VAL(h_coef[i].hc1, 15, 8) | 562 | | FLD_VAL(h_coef[i].hc1_vc0, 15, 8) |
629 | | FLD_VAL(h_coef[i].hc2, 23, 16) | 563 | | FLD_VAL(h_coef[i].hc2_vc1, 23, 16) |
630 | | FLD_VAL(h_coef[i].hc3, 31, 24); | 564 | | FLD_VAL(h_coef[i].hc3_vc2, 31, 24); |
631 | hv = FLD_VAL(h_coef[i].hc4, 7, 0) | 565 | hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0) |
632 | | FLD_VAL(v_coef[i].vc0, 15, 8) | 566 | | FLD_VAL(v_coef[i].hc1_vc0, 15, 8) |
633 | | FLD_VAL(v_coef[i].vc1, 23, 16) | 567 | | FLD_VAL(v_coef[i].hc2_vc1, 23, 16) |
634 | | FLD_VAL(v_coef[i].vc2, 31, 24); | 568 | | FLD_VAL(v_coef[i].hc3_vc2, 31, 24); |
635 | 569 | ||
636 | if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { | 570 | if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { |
637 | dispc_ovl_write_firh_reg(plane, i, h); | 571 | dispc_ovl_write_firh_reg(plane, i, h); |
@@ -646,8 +580,8 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup, | |||
646 | if (five_taps) { | 580 | if (five_taps) { |
647 | for (i = 0; i < 8; i++) { | 581 | for (i = 0; i < 8; i++) { |
648 | u32 v; | 582 | u32 v; |
649 | v = FLD_VAL(v_coef[i].vc00, 7, 0) | 583 | v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0) |
650 | | FLD_VAL(v_coef[i].vc22, 15, 8); | 584 | | FLD_VAL(v_coef[i].hc4_vc22, 15, 8); |
651 | if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) | 585 | if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) |
652 | dispc_ovl_write_firv_reg(plane, i, v); | 586 | dispc_ovl_write_firv_reg(plane, i, v); |
653 | else | 587 | else |
@@ -875,8 +809,7 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane, | |||
875 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); | 809 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); |
876 | } | 810 | } |
877 | 811 | ||
878 | static void dispc_ovl_set_channel_out(enum omap_plane plane, | 812 | void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) |
879 | enum omap_channel channel) | ||
880 | { | 813 | { |
881 | int shift; | 814 | int shift; |
882 | u32 val; | 815 | u32 val; |
@@ -923,6 +856,39 @@ static void dispc_ovl_set_channel_out(enum omap_plane plane, | |||
923 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); | 856 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); |
924 | } | 857 | } |
925 | 858 | ||
859 | static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) | ||
860 | { | ||
861 | int shift; | ||
862 | u32 val; | ||
863 | enum omap_channel channel; | ||
864 | |||
865 | switch (plane) { | ||
866 | case OMAP_DSS_GFX: | ||
867 | shift = 8; | ||
868 | break; | ||
869 | case OMAP_DSS_VIDEO1: | ||
870 | case OMAP_DSS_VIDEO2: | ||
871 | case OMAP_DSS_VIDEO3: | ||
872 | shift = 16; | ||
873 | break; | ||
874 | default: | ||
875 | BUG(); | ||
876 | } | ||
877 | |||
878 | val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); | ||
879 | |||
880 | if (dss_has_feature(FEAT_MGR_LCD2)) { | ||
881 | if (FLD_GET(val, 31, 30) == 0) | ||
882 | channel = FLD_GET(val, shift, shift); | ||
883 | else | ||
884 | channel = OMAP_DSS_CHANNEL_LCD2; | ||
885 | } else { | ||
886 | channel = FLD_GET(val, shift, shift); | ||
887 | } | ||
888 | |||
889 | return channel; | ||
890 | } | ||
891 | |||
926 | static void dispc_ovl_set_burst_size(enum omap_plane plane, | 892 | static void dispc_ovl_set_burst_size(enum omap_plane plane, |
927 | enum omap_burst_size burst_size) | 893 | enum omap_burst_size burst_size) |
928 | { | 894 | { |
@@ -964,7 +930,7 @@ void dispc_enable_gamma_table(bool enable) | |||
964 | REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); | 930 | REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); |
965 | } | 931 | } |
966 | 932 | ||
967 | void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) | 933 | static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) |
968 | { | 934 | { |
969 | u16 reg; | 935 | u16 reg; |
970 | 936 | ||
@@ -978,7 +944,7 @@ void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) | |||
978 | REG_FLD_MOD(reg, enable, 15, 15); | 944 | REG_FLD_MOD(reg, enable, 15, 15); |
979 | } | 945 | } |
980 | 946 | ||
981 | void dispc_mgr_set_cpr_coef(enum omap_channel channel, | 947 | static void dispc_mgr_set_cpr_coef(enum omap_channel channel, |
982 | struct omap_dss_cpr_coefs *coefs) | 948 | struct omap_dss_cpr_coefs *coefs) |
983 | { | 949 | { |
984 | u32 coef_r, coef_g, coef_b; | 950 | u32 coef_r, coef_g, coef_b; |
@@ -1057,8 +1023,7 @@ u32 dispc_ovl_get_fifo_size(enum omap_plane plane) | |||
1057 | return dispc.fifo_size[plane]; | 1023 | return dispc.fifo_size[plane]; |
1058 | } | 1024 | } |
1059 | 1025 | ||
1060 | static void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, | 1026 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) |
1061 | u32 high) | ||
1062 | { | 1027 | { |
1063 | u8 hi_start, hi_end, lo_start, lo_end; | 1028 | u8 hi_start, hi_end, lo_start, lo_end; |
1064 | u32 unit; | 1029 | u32 unit; |
@@ -1169,17 +1134,12 @@ static void dispc_ovl_set_scale_param(enum omap_plane plane, | |||
1169 | enum omap_color_component color_comp) | 1134 | enum omap_color_component color_comp) |
1170 | { | 1135 | { |
1171 | int fir_hinc, fir_vinc; | 1136 | int fir_hinc, fir_vinc; |
1172 | int hscaleup, vscaleup; | ||
1173 | |||
1174 | hscaleup = orig_width <= out_width; | ||
1175 | vscaleup = orig_height <= out_height; | ||
1176 | |||
1177 | dispc_ovl_set_scale_coef(plane, hscaleup, vscaleup, five_taps, | ||
1178 | color_comp); | ||
1179 | 1137 | ||
1180 | fir_hinc = 1024 * orig_width / out_width; | 1138 | fir_hinc = 1024 * orig_width / out_width; |
1181 | fir_vinc = 1024 * orig_height / out_height; | 1139 | fir_vinc = 1024 * orig_height / out_height; |
1182 | 1140 | ||
1141 | dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps, | ||
1142 | color_comp); | ||
1183 | dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); | 1143 | dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); |
1184 | } | 1144 | } |
1185 | 1145 | ||
@@ -1654,6 +1614,9 @@ static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width, | |||
1654 | u32 fclk = 0; | 1614 | u32 fclk = 0; |
1655 | u64 tmp, pclk = dispc_mgr_pclk_rate(channel); | 1615 | u64 tmp, pclk = dispc_mgr_pclk_rate(channel); |
1656 | 1616 | ||
1617 | if (height <= out_height && width <= out_width) | ||
1618 | return (unsigned long) pclk; | ||
1619 | |||
1657 | if (height > out_height) { | 1620 | if (height > out_height) { |
1658 | struct omap_dss_device *dssdev = dispc_mgr_get_device(channel); | 1621 | struct omap_dss_device *dssdev = dispc_mgr_get_device(channel); |
1659 | unsigned int ppl = dssdev->panel.timings.x_res; | 1622 | unsigned int ppl = dssdev->panel.timings.x_res; |
@@ -1708,7 +1671,16 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, | |||
1708 | else | 1671 | else |
1709 | vf = 1; | 1672 | vf = 1; |
1710 | 1673 | ||
1711 | return dispc_mgr_pclk_rate(channel) * vf * hf; | 1674 | if (cpu_is_omap24xx()) { |
1675 | if (vf > 1 && hf > 1) | ||
1676 | return dispc_mgr_pclk_rate(channel) * 4; | ||
1677 | else | ||
1678 | return dispc_mgr_pclk_rate(channel) * 2; | ||
1679 | } else if (cpu_is_omap34xx()) { | ||
1680 | return dispc_mgr_pclk_rate(channel) * vf * hf; | ||
1681 | } else { | ||
1682 | return dispc_mgr_pclk_rate(channel) * hf; | ||
1683 | } | ||
1712 | } | 1684 | } |
1713 | 1685 | ||
1714 | static int dispc_ovl_calc_scaling(enum omap_plane plane, | 1686 | static int dispc_ovl_calc_scaling(enum omap_plane plane, |
@@ -1718,6 +1690,8 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
1718 | { | 1690 | { |
1719 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | 1691 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); |
1720 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); | 1692 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); |
1693 | const int maxsinglelinewidth = | ||
1694 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | ||
1721 | unsigned long fclk = 0; | 1695 | unsigned long fclk = 0; |
1722 | 1696 | ||
1723 | if (width == out_width && height == out_height) | 1697 | if (width == out_width && height == out_height) |
@@ -1734,28 +1708,40 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
1734 | out_height > height * 8) | 1708 | out_height > height * 8) |
1735 | return -EINVAL; | 1709 | return -EINVAL; |
1736 | 1710 | ||
1737 | /* Must use 5-tap filter? */ | 1711 | if (cpu_is_omap24xx()) { |
1738 | *five_taps = height > out_height * 2; | 1712 | if (width > maxsinglelinewidth) |
1739 | 1713 | DSSERR("Cannot scale max input width exceeded"); | |
1740 | if (!*five_taps) { | 1714 | *five_taps = false; |
1715 | fclk = calc_fclk(channel, width, height, out_width, | ||
1716 | out_height); | ||
1717 | } else if (cpu_is_omap34xx()) { | ||
1718 | if (width > (maxsinglelinewidth * 2)) { | ||
1719 | DSSERR("Cannot setup scaling"); | ||
1720 | DSSERR("width exceeds maximum width possible"); | ||
1721 | return -EINVAL; | ||
1722 | } | ||
1723 | fclk = calc_fclk_five_taps(channel, width, height, out_width, | ||
1724 | out_height, color_mode); | ||
1725 | if (width > maxsinglelinewidth) { | ||
1726 | if (height > out_height && height < out_height * 2) | ||
1727 | *five_taps = false; | ||
1728 | else { | ||
1729 | DSSERR("cannot setup scaling with five taps"); | ||
1730 | return -EINVAL; | ||
1731 | } | ||
1732 | } | ||
1733 | if (!*five_taps) | ||
1734 | fclk = calc_fclk(channel, width, height, out_width, | ||
1735 | out_height); | ||
1736 | } else { | ||
1737 | if (width > maxsinglelinewidth) { | ||
1738 | DSSERR("Cannot scale width exceeds max line width"); | ||
1739 | return -EINVAL; | ||
1740 | } | ||
1741 | fclk = calc_fclk(channel, width, height, out_width, | 1741 | fclk = calc_fclk(channel, width, height, out_width, |
1742 | out_height); | 1742 | out_height); |
1743 | |||
1744 | /* Try 5-tap filter if 3-tap fclk is too high */ | ||
1745 | if (cpu_is_omap34xx() && height > out_height && | ||
1746 | fclk > dispc_fclk_rate()) | ||
1747 | *five_taps = true; | ||
1748 | } | ||
1749 | |||
1750 | if (width > (2048 >> *five_taps)) { | ||
1751 | DSSERR("failed to set up scaling, fclk too low\n"); | ||
1752 | return -EINVAL; | ||
1753 | } | 1743 | } |
1754 | 1744 | ||
1755 | if (*five_taps) | ||
1756 | fclk = calc_fclk_five_taps(channel, width, height, | ||
1757 | out_width, out_height, color_mode); | ||
1758 | |||
1759 | DSSDBG("required fclk rate = %lu Hz\n", fclk); | 1745 | DSSDBG("required fclk rate = %lu Hz\n", fclk); |
1760 | DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); | 1746 | DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); |
1761 | 1747 | ||
@@ -1771,11 +1757,10 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
1771 | } | 1757 | } |
1772 | 1758 | ||
1773 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | 1759 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, |
1774 | bool ilace, enum omap_channel channel, bool replication, | 1760 | bool ilace, bool replication) |
1775 | u32 fifo_low, u32 fifo_high) | ||
1776 | { | 1761 | { |
1777 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | 1762 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); |
1778 | bool five_taps = false; | 1763 | bool five_taps = true; |
1779 | bool fieldmode = 0; | 1764 | bool fieldmode = 0; |
1780 | int r, cconv = 0; | 1765 | int r, cconv = 0; |
1781 | unsigned offset0, offset1; | 1766 | unsigned offset0, offset1; |
@@ -1783,36 +1768,43 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
1783 | s32 pix_inc; | 1768 | s32 pix_inc; |
1784 | u16 frame_height = oi->height; | 1769 | u16 frame_height = oi->height; |
1785 | unsigned int field_offset = 0; | 1770 | unsigned int field_offset = 0; |
1771 | u16 outw, outh; | ||
1772 | enum omap_channel channel; | ||
1773 | |||
1774 | channel = dispc_ovl_get_channel_out(plane); | ||
1786 | 1775 | ||
1787 | DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " | 1776 | DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " |
1788 | "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d " | 1777 | "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n", |
1789 | "fifo_low %d fifo high %d\n", plane, oi->paddr, oi->p_uv_addr, | 1778 | plane, oi->paddr, oi->p_uv_addr, |
1790 | oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, | 1779 | oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, |
1791 | oi->out_width, oi->out_height, oi->color_mode, oi->rotation, | 1780 | oi->out_width, oi->out_height, oi->color_mode, oi->rotation, |
1792 | oi->mirror, ilace, channel, replication, fifo_low, fifo_high); | 1781 | oi->mirror, ilace, channel, replication); |
1793 | 1782 | ||
1794 | if (oi->paddr == 0) | 1783 | if (oi->paddr == 0) |
1795 | return -EINVAL; | 1784 | return -EINVAL; |
1796 | 1785 | ||
1797 | if (ilace && oi->height == oi->out_height) | 1786 | outw = oi->out_width == 0 ? oi->width : oi->out_width; |
1787 | outh = oi->out_height == 0 ? oi->height : oi->out_height; | ||
1788 | |||
1789 | if (ilace && oi->height == outh) | ||
1798 | fieldmode = 1; | 1790 | fieldmode = 1; |
1799 | 1791 | ||
1800 | if (ilace) { | 1792 | if (ilace) { |
1801 | if (fieldmode) | 1793 | if (fieldmode) |
1802 | oi->height /= 2; | 1794 | oi->height /= 2; |
1803 | oi->pos_y /= 2; | 1795 | oi->pos_y /= 2; |
1804 | oi->out_height /= 2; | 1796 | outh /= 2; |
1805 | 1797 | ||
1806 | DSSDBG("adjusting for ilace: height %d, pos_y %d, " | 1798 | DSSDBG("adjusting for ilace: height %d, pos_y %d, " |
1807 | "out_height %d\n", | 1799 | "out_height %d\n", |
1808 | oi->height, oi->pos_y, oi->out_height); | 1800 | oi->height, oi->pos_y, outh); |
1809 | } | 1801 | } |
1810 | 1802 | ||
1811 | if (!dss_feat_color_mode_supported(plane, oi->color_mode)) | 1803 | if (!dss_feat_color_mode_supported(plane, oi->color_mode)) |
1812 | return -EINVAL; | 1804 | return -EINVAL; |
1813 | 1805 | ||
1814 | r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height, | 1806 | r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height, |
1815 | oi->out_width, oi->out_height, oi->color_mode, | 1807 | outw, outh, oi->color_mode, |
1816 | &five_taps); | 1808 | &five_taps); |
1817 | if (r) | 1809 | if (r) |
1818 | return r; | 1810 | return r; |
@@ -1830,10 +1822,10 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
1830 | * so the integer part must be added to the base address of the | 1822 | * so the integer part must be added to the base address of the |
1831 | * bottom field. | 1823 | * bottom field. |
1832 | */ | 1824 | */ |
1833 | if (!oi->height || oi->height == oi->out_height) | 1825 | if (!oi->height || oi->height == outh) |
1834 | field_offset = 0; | 1826 | field_offset = 0; |
1835 | else | 1827 | else |
1836 | field_offset = oi->height / oi->out_height / 2; | 1828 | field_offset = oi->height / outh / 2; |
1837 | } | 1829 | } |
1838 | 1830 | ||
1839 | /* Fields are independent but interleaved in memory. */ | 1831 | /* Fields are independent but interleaved in memory. */ |
@@ -1869,7 +1861,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
1869 | dispc_ovl_set_pix_inc(plane, pix_inc); | 1861 | dispc_ovl_set_pix_inc(plane, pix_inc); |
1870 | 1862 | ||
1871 | DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width, | 1863 | DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width, |
1872 | oi->height, oi->out_width, oi->out_height); | 1864 | oi->height, outw, outh); |
1873 | 1865 | ||
1874 | dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); | 1866 | dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); |
1875 | 1867 | ||
@@ -1877,10 +1869,10 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
1877 | 1869 | ||
1878 | if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { | 1870 | if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { |
1879 | dispc_ovl_set_scaling(plane, oi->width, oi->height, | 1871 | dispc_ovl_set_scaling(plane, oi->width, oi->height, |
1880 | oi->out_width, oi->out_height, | 1872 | outw, outh, |
1881 | ilace, five_taps, fieldmode, | 1873 | ilace, five_taps, fieldmode, |
1882 | oi->color_mode, oi->rotation); | 1874 | oi->color_mode, oi->rotation); |
1883 | dispc_ovl_set_vid_size(plane, oi->out_width, oi->out_height); | 1875 | dispc_ovl_set_vid_size(plane, outw, outh); |
1884 | dispc_ovl_set_vid_color_conv(plane, cconv); | 1876 | dispc_ovl_set_vid_color_conv(plane, cconv); |
1885 | } | 1877 | } |
1886 | 1878 | ||
@@ -1891,10 +1883,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
1891 | dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); | 1883 | dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); |
1892 | dispc_ovl_setup_global_alpha(plane, oi->global_alpha); | 1884 | dispc_ovl_setup_global_alpha(plane, oi->global_alpha); |
1893 | 1885 | ||
1894 | dispc_ovl_set_channel_out(plane, channel); | ||
1895 | |||
1896 | dispc_ovl_enable_replication(plane, replication); | 1886 | dispc_ovl_enable_replication(plane, replication); |
1897 | dispc_ovl_set_fifo_threshold(plane, fifo_low, fifo_high); | ||
1898 | 1887 | ||
1899 | return 0; | 1888 | return 0; |
1900 | } | 1889 | } |
@@ -1916,10 +1905,14 @@ static void dispc_disable_isr(void *data, u32 mask) | |||
1916 | 1905 | ||
1917 | static void _enable_lcd_out(enum omap_channel channel, bool enable) | 1906 | static void _enable_lcd_out(enum omap_channel channel, bool enable) |
1918 | { | 1907 | { |
1919 | if (channel == OMAP_DSS_CHANNEL_LCD2) | 1908 | if (channel == OMAP_DSS_CHANNEL_LCD2) { |
1920 | REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0); | 1909 | REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0); |
1921 | else | 1910 | /* flush posted write */ |
1911 | dispc_read_reg(DISPC_CONTROL2); | ||
1912 | } else { | ||
1922 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); | 1913 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); |
1914 | dispc_read_reg(DISPC_CONTROL); | ||
1915 | } | ||
1923 | } | 1916 | } |
1924 | 1917 | ||
1925 | static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) | 1918 | static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) |
@@ -1967,6 +1960,8 @@ static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) | |||
1967 | static void _enable_digit_out(bool enable) | 1960 | static void _enable_digit_out(bool enable) |
1968 | { | 1961 | { |
1969 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); | 1962 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); |
1963 | /* flush posted write */ | ||
1964 | dispc_read_reg(DISPC_CONTROL); | ||
1970 | } | 1965 | } |
1971 | 1966 | ||
1972 | static void dispc_mgr_enable_digit_out(bool enable) | 1967 | static void dispc_mgr_enable_digit_out(bool enable) |
@@ -2124,25 +2119,12 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode) | |||
2124 | } | 2119 | } |
2125 | 2120 | ||
2126 | 2121 | ||
2127 | void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) | 2122 | static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) |
2128 | { | 2123 | { |
2129 | dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); | 2124 | dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); |
2130 | } | 2125 | } |
2131 | 2126 | ||
2132 | u32 dispc_mgr_get_default_color(enum omap_channel channel) | 2127 | static void dispc_mgr_set_trans_key(enum omap_channel ch, |
2133 | { | ||
2134 | u32 l; | ||
2135 | |||
2136 | BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT && | ||
2137 | channel != OMAP_DSS_CHANNEL_LCD && | ||
2138 | channel != OMAP_DSS_CHANNEL_LCD2); | ||
2139 | |||
2140 | l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); | ||
2141 | |||
2142 | return l; | ||
2143 | } | ||
2144 | |||
2145 | void dispc_mgr_set_trans_key(enum omap_channel ch, | ||
2146 | enum omap_dss_trans_key_type type, | 2128 | enum omap_dss_trans_key_type type, |
2147 | u32 trans_key) | 2129 | u32 trans_key) |
2148 | { | 2130 | { |
@@ -2156,26 +2138,7 @@ void dispc_mgr_set_trans_key(enum omap_channel ch, | |||
2156 | dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); | 2138 | dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); |
2157 | } | 2139 | } |
2158 | 2140 | ||
2159 | void dispc_mgr_get_trans_key(enum omap_channel ch, | 2141 | static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) |
2160 | enum omap_dss_trans_key_type *type, | ||
2161 | u32 *trans_key) | ||
2162 | { | ||
2163 | if (type) { | ||
2164 | if (ch == OMAP_DSS_CHANNEL_LCD) | ||
2165 | *type = REG_GET(DISPC_CONFIG, 11, 11); | ||
2166 | else if (ch == OMAP_DSS_CHANNEL_DIGIT) | ||
2167 | *type = REG_GET(DISPC_CONFIG, 13, 13); | ||
2168 | else if (ch == OMAP_DSS_CHANNEL_LCD2) | ||
2169 | *type = REG_GET(DISPC_CONFIG2, 11, 11); | ||
2170 | else | ||
2171 | BUG(); | ||
2172 | } | ||
2173 | |||
2174 | if (trans_key) | ||
2175 | *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); | ||
2176 | } | ||
2177 | |||
2178 | void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) | ||
2179 | { | 2142 | { |
2180 | if (ch == OMAP_DSS_CHANNEL_LCD) | 2143 | if (ch == OMAP_DSS_CHANNEL_LCD) |
2181 | REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); | 2144 | REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); |
@@ -2185,7 +2148,8 @@ void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) | |||
2185 | REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); | 2148 | REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); |
2186 | } | 2149 | } |
2187 | 2150 | ||
2188 | void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable) | 2151 | static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, |
2152 | bool enable) | ||
2189 | { | 2153 | { |
2190 | if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) | 2154 | if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) |
2191 | return; | 2155 | return; |
@@ -2196,40 +2160,20 @@ void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable) | |||
2196 | REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); | 2160 | REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); |
2197 | } | 2161 | } |
2198 | 2162 | ||
2199 | bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch) | 2163 | void dispc_mgr_setup(enum omap_channel channel, |
2200 | { | 2164 | struct omap_overlay_manager_info *info) |
2201 | bool enabled; | ||
2202 | |||
2203 | if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) | ||
2204 | return false; | ||
2205 | |||
2206 | if (ch == OMAP_DSS_CHANNEL_LCD) | ||
2207 | enabled = REG_GET(DISPC_CONFIG, 18, 18); | ||
2208 | else if (ch == OMAP_DSS_CHANNEL_DIGIT) | ||
2209 | enabled = REG_GET(DISPC_CONFIG, 19, 19); | ||
2210 | else | ||
2211 | BUG(); | ||
2212 | |||
2213 | return enabled; | ||
2214 | } | ||
2215 | |||
2216 | bool dispc_mgr_trans_key_enabled(enum omap_channel ch) | ||
2217 | { | 2165 | { |
2218 | bool enabled; | 2166 | dispc_mgr_set_default_color(channel, info->default_color); |
2219 | 2167 | dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key); | |
2220 | if (ch == OMAP_DSS_CHANNEL_LCD) | 2168 | dispc_mgr_enable_trans_key(channel, info->trans_enabled); |
2221 | enabled = REG_GET(DISPC_CONFIG, 10, 10); | 2169 | dispc_mgr_enable_alpha_fixed_zorder(channel, |
2222 | else if (ch == OMAP_DSS_CHANNEL_DIGIT) | 2170 | info->partial_alpha_enabled); |
2223 | enabled = REG_GET(DISPC_CONFIG, 12, 12); | 2171 | if (dss_has_feature(FEAT_CPR)) { |
2224 | else if (ch == OMAP_DSS_CHANNEL_LCD2) | 2172 | dispc_mgr_enable_cpr(channel, info->cpr_enable); |
2225 | enabled = REG_GET(DISPC_CONFIG2, 10, 10); | 2173 | dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs); |
2226 | else | 2174 | } |
2227 | BUG(); | ||
2228 | |||
2229 | return enabled; | ||
2230 | } | 2175 | } |
2231 | 2176 | ||
2232 | |||
2233 | void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) | 2177 | void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) |
2234 | { | 2178 | { |
2235 | int code; | 2179 | int code; |
@@ -3184,7 +3128,8 @@ static void dispc_error_worker(struct work_struct *work) | |||
3184 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | 3128 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { |
3185 | struct omap_overlay_manager *mgr; | 3129 | struct omap_overlay_manager *mgr; |
3186 | mgr = omap_dss_get_overlay_manager(i); | 3130 | mgr = omap_dss_get_overlay_manager(i); |
3187 | mgr->device->driver->disable(mgr->device); | 3131 | if (mgr->device && mgr->device->driver) |
3132 | mgr->device->driver->disable(mgr->device); | ||
3188 | } | 3133 | } |
3189 | } | 3134 | } |
3190 | 3135 | ||
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index c06efc38983e..5836bd1650f9 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h | |||
@@ -97,6 +97,17 @@ | |||
97 | #define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \ | 97 | #define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \ |
98 | DISPC_PRELOAD_OFFSET(n)) | 98 | DISPC_PRELOAD_OFFSET(n)) |
99 | 99 | ||
100 | /* DISPC up/downsampling FIR filter coefficient structure */ | ||
101 | struct dispc_coef { | ||
102 | s8 hc4_vc22; | ||
103 | s8 hc3_vc2; | ||
104 | u8 hc2_vc1; | ||
105 | s8 hc1_vc0; | ||
106 | s8 hc0_vc00; | ||
107 | }; | ||
108 | |||
109 | const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps); | ||
110 | |||
100 | /* DISPC manager/channel specific registers */ | 111 | /* DISPC manager/channel specific registers */ |
101 | static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel) | 112 | static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel) |
102 | { | 113 | { |
diff --git a/drivers/video/omap2/dss/dispc_coefs.c b/drivers/video/omap2/dss/dispc_coefs.c new file mode 100644 index 000000000000..069bccbb3f12 --- /dev/null +++ b/drivers/video/omap2/dss/dispc_coefs.c | |||
@@ -0,0 +1,326 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/omap2/dss/dispc_coefs.c | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments | ||
5 | * Author: Chandrabhanu Mahapatra <cmahapatra@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <video/omapdss.h> | ||
22 | #include "dispc.h" | ||
23 | |||
24 | #define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0])) | ||
25 | |||
26 | static const struct dispc_coef coef3_M8[8] = { | ||
27 | { 0, 0, 128, 0, 0 }, | ||
28 | { 0, -4, 123, 9, 0 }, | ||
29 | { 0, -4, 108, 87, 0 }, | ||
30 | { 0, -2, 87, 43, 0 }, | ||
31 | { 0, 64, 64, 0, 0 }, | ||
32 | { 0, 43, 87, -2, 0 }, | ||
33 | { 0, 24, 108, -4, 0 }, | ||
34 | { 0, 9, 123, -4, 0 }, | ||
35 | }; | ||
36 | |||
37 | static const struct dispc_coef coef3_M9[8] = { | ||
38 | { 0, 6, 116, 6, 0 }, | ||
39 | { 0, 0, 112, 16, 0 }, | ||
40 | { 0, -2, 100, 30, 0 }, | ||
41 | { 0, -2, 83, 47, 0 }, | ||
42 | { 0, 64, 64, 0, 0 }, | ||
43 | { 0, 47, 83, -2, 0 }, | ||
44 | { 0, 30, 100, -2, 0 }, | ||
45 | { 0, 16, 112, 0, 0 }, | ||
46 | }; | ||
47 | |||
48 | static const struct dispc_coef coef3_M10[8] = { | ||
49 | { 0, 10, 108, 10, 0 }, | ||
50 | { 0, 3, 104, 21, 0 }, | ||
51 | { 0, 0, 94, 34, 0 }, | ||
52 | { 0, -1, 80, 49, 0 }, | ||
53 | { 0, 64, 64, 0, 0 }, | ||
54 | { 0, 49, 80, -1, 0 }, | ||
55 | { 0, 34, 94, 0, 0 }, | ||
56 | { 0, 21, 104, 3, 0 }, | ||
57 | }; | ||
58 | |||
59 | static const struct dispc_coef coef3_M11[8] = { | ||
60 | { 0, 14, 100, 14, 0 }, | ||
61 | { 0, 6, 98, 24, 0 }, | ||
62 | { 0, 2, 90, 36, 0 }, | ||
63 | { 0, 0, 78, 50, 0 }, | ||
64 | { 0, 64, 64, 0, 0 }, | ||
65 | { 0, 50, 78, 0, 0 }, | ||
66 | { 0, 36, 90, 2, 0 }, | ||
67 | { 0, 24, 98, 6, 0 }, | ||
68 | }; | ||
69 | |||
70 | static const struct dispc_coef coef3_M12[8] = { | ||
71 | { 0, 16, 96, 16, 0 }, | ||
72 | { 0, 9, 93, 26, 0 }, | ||
73 | { 0, 4, 86, 38, 0 }, | ||
74 | { 0, 1, 76, 51, 0 }, | ||
75 | { 0, 64, 64, 0, 0 }, | ||
76 | { 0, 51, 76, 1, 0 }, | ||
77 | { 0, 38, 86, 4, 0 }, | ||
78 | { 0, 26, 93, 9, 0 }, | ||
79 | }; | ||
80 | |||
81 | static const struct dispc_coef coef3_M13[8] = { | ||
82 | { 0, 18, 92, 18, 0 }, | ||
83 | { 0, 10, 90, 28, 0 }, | ||
84 | { 0, 5, 83, 40, 0 }, | ||
85 | { 0, 1, 75, 52, 0 }, | ||
86 | { 0, 64, 64, 0, 0 }, | ||
87 | { 0, 52, 75, 1, 0 }, | ||
88 | { 0, 40, 83, 5, 0 }, | ||
89 | { 0, 28, 90, 10, 0 }, | ||
90 | }; | ||
91 | |||
92 | static const struct dispc_coef coef3_M14[8] = { | ||
93 | { 0, 20, 88, 20, 0 }, | ||
94 | { 0, 12, 86, 30, 0 }, | ||
95 | { 0, 6, 81, 41, 0 }, | ||
96 | { 0, 2, 74, 52, 0 }, | ||
97 | { 0, 64, 64, 0, 0 }, | ||
98 | { 0, 52, 74, 2, 0 }, | ||
99 | { 0, 41, 81, 6, 0 }, | ||
100 | { 0, 30, 86, 12, 0 }, | ||
101 | }; | ||
102 | |||
103 | static const struct dispc_coef coef3_M16[8] = { | ||
104 | { 0, 22, 84, 22, 0 }, | ||
105 | { 0, 14, 82, 32, 0 }, | ||
106 | { 0, 8, 78, 42, 0 }, | ||
107 | { 0, 3, 72, 53, 0 }, | ||
108 | { 0, 64, 64, 0, 0 }, | ||
109 | { 0, 53, 72, 3, 0 }, | ||
110 | { 0, 42, 78, 8, 0 }, | ||
111 | { 0, 32, 82, 14, 0 }, | ||
112 | }; | ||
113 | |||
114 | static const struct dispc_coef coef3_M19[8] = { | ||
115 | { 0, 24, 80, 24, 0 }, | ||
116 | { 0, 16, 79, 33, 0 }, | ||
117 | { 0, 9, 76, 43, 0 }, | ||
118 | { 0, 4, 70, 54, 0 }, | ||
119 | { 0, 64, 64, 0, 0 }, | ||
120 | { 0, 54, 70, 4, 0 }, | ||
121 | { 0, 43, 76, 9, 0 }, | ||
122 | { 0, 33, 79, 16, 0 }, | ||
123 | }; | ||
124 | |||
125 | static const struct dispc_coef coef3_M22[8] = { | ||
126 | { 0, 25, 78, 25, 0 }, | ||
127 | { 0, 17, 77, 34, 0 }, | ||
128 | { 0, 10, 74, 44, 0 }, | ||
129 | { 0, 5, 69, 54, 0 }, | ||
130 | { 0, 64, 64, 0, 0 }, | ||
131 | { 0, 54, 69, 5, 0 }, | ||
132 | { 0, 44, 74, 10, 0 }, | ||
133 | { 0, 34, 77, 17, 0 }, | ||
134 | }; | ||
135 | |||
136 | static const struct dispc_coef coef3_M26[8] = { | ||
137 | { 0, 26, 76, 26, 0 }, | ||
138 | { 0, 19, 74, 35, 0 }, | ||
139 | { 0, 11, 72, 45, 0 }, | ||
140 | { 0, 5, 69, 54, 0 }, | ||
141 | { 0, 64, 64, 0, 0 }, | ||
142 | { 0, 54, 69, 5, 0 }, | ||
143 | { 0, 45, 72, 11, 0 }, | ||
144 | { 0, 35, 74, 19, 0 }, | ||
145 | }; | ||
146 | |||
147 | static const struct dispc_coef coef3_M32[8] = { | ||
148 | { 0, 27, 74, 27, 0 }, | ||
149 | { 0, 19, 73, 36, 0 }, | ||
150 | { 0, 12, 71, 45, 0 }, | ||
151 | { 0, 6, 68, 54, 0 }, | ||
152 | { 0, 64, 64, 0, 0 }, | ||
153 | { 0, 54, 68, 6, 0 }, | ||
154 | { 0, 45, 71, 12, 0 }, | ||
155 | { 0, 36, 73, 19, 0 }, | ||
156 | }; | ||
157 | |||
158 | static const struct dispc_coef coef5_M8[8] = { | ||
159 | { 0, 0, 128, 0, 0 }, | ||
160 | { -2, 14, 125, -10, 1 }, | ||
161 | { -6, 33, 114, -15, 2 }, | ||
162 | { -10, 55, 98, -16, 1 }, | ||
163 | { 0, -14, 78, 78, -14 }, | ||
164 | { 1, -16, 98, 55, -10 }, | ||
165 | { 2, -15, 114, 33, -6 }, | ||
166 | { 1, -10, 125, 14, -2 }, | ||
167 | }; | ||
168 | |||
169 | static const struct dispc_coef coef5_M9[8] = { | ||
170 | { -3, 10, 114, 10, -3 }, | ||
171 | { -6, 24, 110, 0, -1 }, | ||
172 | { -8, 40, 103, -7, 0 }, | ||
173 | { -11, 58, 91, -11, 1 }, | ||
174 | { 0, -12, 76, 76, -12 }, | ||
175 | { 1, -11, 91, 58, -11 }, | ||
176 | { 0, -7, 103, 40, -8 }, | ||
177 | { -1, 0, 111, 24, -6 }, | ||
178 | }; | ||
179 | |||
180 | static const struct dispc_coef coef5_M10[8] = { | ||
181 | { -4, 18, 100, 18, -4 }, | ||
182 | { -6, 30, 99, 8, -3 }, | ||
183 | { -8, 44, 93, 0, -1 }, | ||
184 | { -9, 58, 84, -5, 0 }, | ||
185 | { 0, -8, 72, 72, -8 }, | ||
186 | { 0, -5, 84, 58, -9 }, | ||
187 | { -1, 0, 93, 44, -8 }, | ||
188 | { -3, 8, 99, 30, -6 }, | ||
189 | }; | ||
190 | |||
191 | static const struct dispc_coef coef5_M11[8] = { | ||
192 | { -5, 23, 92, 23, -5 }, | ||
193 | { -6, 34, 90, 13, -3 }, | ||
194 | { -6, 45, 85, 6, -2 }, | ||
195 | { -6, 57, 78, 0, -1 }, | ||
196 | { 0, -4, 68, 68, -4 }, | ||
197 | { -1, 0, 78, 57, -6 }, | ||
198 | { -2, 6, 85, 45, -6 }, | ||
199 | { -3, 13, 90, 34, -6 }, | ||
200 | }; | ||
201 | |||
202 | static const struct dispc_coef coef5_M12[8] = { | ||
203 | { -4, 26, 84, 26, -4 }, | ||
204 | { -5, 36, 82, 18, -3 }, | ||
205 | { -4, 46, 78, 10, -2 }, | ||
206 | { -3, 55, 72, 5, -1 }, | ||
207 | { 0, 0, 64, 64, 0 }, | ||
208 | { -1, 5, 72, 55, -3 }, | ||
209 | { -2, 10, 78, 46, -4 }, | ||
210 | { -3, 18, 82, 36, -5 }, | ||
211 | }; | ||
212 | |||
213 | static const struct dispc_coef coef5_M13[8] = { | ||
214 | { -3, 28, 78, 28, -3 }, | ||
215 | { -3, 37, 76, 21, -3 }, | ||
216 | { -2, 45, 73, 14, -2 }, | ||
217 | { 0, 53, 68, 8, -1 }, | ||
218 | { 0, 3, 61, 61, 3 }, | ||
219 | { -1, 8, 68, 53, 0 }, | ||
220 | { -2, 14, 73, 45, -2 }, | ||
221 | { -3, 21, 76, 37, -3 }, | ||
222 | }; | ||
223 | |||
224 | static const struct dispc_coef coef5_M14[8] = { | ||
225 | { -2, 30, 72, 30, -2 }, | ||
226 | { -1, 37, 71, 23, -2 }, | ||
227 | { 0, 45, 69, 16, -2 }, | ||
228 | { 3, 52, 64, 10, -1 }, | ||
229 | { 0, 6, 58, 58, 6 }, | ||
230 | { -1, 10, 64, 52, 3 }, | ||
231 | { -2, 16, 69, 45, 0 }, | ||
232 | { -2, 23, 71, 37, -1 }, | ||
233 | }; | ||
234 | |||
235 | static const struct dispc_coef coef5_M16[8] = { | ||
236 | { 0, 31, 66, 31, 0 }, | ||
237 | { 1, 38, 65, 25, -1 }, | ||
238 | { 3, 44, 62, 20, -1 }, | ||
239 | { 6, 49, 59, 14, 0 }, | ||
240 | { 0, 10, 54, 54, 10 }, | ||
241 | { 0, 14, 59, 49, 6 }, | ||
242 | { -1, 20, 62, 44, 3 }, | ||
243 | { -1, 25, 65, 38, 1 }, | ||
244 | }; | ||
245 | |||
246 | static const struct dispc_coef coef5_M19[8] = { | ||
247 | { 3, 32, 58, 32, 3 }, | ||
248 | { 4, 38, 58, 27, 1 }, | ||
249 | { 7, 42, 55, 23, 1 }, | ||
250 | { 10, 46, 54, 18, 0 }, | ||
251 | { 0, 14, 50, 50, 14 }, | ||
252 | { 0, 18, 54, 46, 10 }, | ||
253 | { 1, 23, 55, 42, 7 }, | ||
254 | { 1, 27, 58, 38, 4 }, | ||
255 | }; | ||
256 | |||
257 | static const struct dispc_coef coef5_M22[8] = { | ||
258 | { 4, 33, 54, 33, 4 }, | ||
259 | { 6, 37, 54, 28, 3 }, | ||
260 | { 9, 41, 53, 24, 1 }, | ||
261 | { 12, 45, 51, 20, 0 }, | ||
262 | { 0, 16, 48, 48, 16 }, | ||
263 | { 0, 20, 51, 45, 12 }, | ||
264 | { 1, 24, 53, 41, 9 }, | ||
265 | { 3, 28, 54, 37, 6 }, | ||
266 | }; | ||
267 | |||
268 | static const struct dispc_coef coef5_M26[8] = { | ||
269 | { 6, 33, 50, 33, 6 }, | ||
270 | { 8, 36, 51, 29, 4 }, | ||
271 | { 11, 40, 50, 25, 2 }, | ||
272 | { 14, 43, 48, 22, 1 }, | ||
273 | { 0, 18, 46, 46, 18 }, | ||
274 | { 1, 22, 48, 43, 14 }, | ||
275 | { 2, 25, 50, 40, 11 }, | ||
276 | { 4, 29, 51, 36, 8 }, | ||
277 | }; | ||
278 | |||
279 | static const struct dispc_coef coef5_M32[8] = { | ||
280 | { 7, 33, 48, 33, 7 }, | ||
281 | { 10, 36, 48, 29, 5 }, | ||
282 | { 13, 39, 47, 26, 3 }, | ||
283 | { 16, 42, 46, 23, 1 }, | ||
284 | { 0, 19, 45, 45, 19 }, | ||
285 | { 1, 23, 46, 42, 16 }, | ||
286 | { 3, 26, 47, 39, 13 }, | ||
287 | { 5, 29, 48, 36, 10 }, | ||
288 | }; | ||
289 | |||
290 | const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps) | ||
291 | { | ||
292 | int i; | ||
293 | static const struct { | ||
294 | int Mmin; | ||
295 | int Mmax; | ||
296 | const struct dispc_coef *coef_3; | ||
297 | const struct dispc_coef *coef_5; | ||
298 | } coefs[] = { | ||
299 | { 27, 32, coef3_M32, coef5_M32 }, | ||
300 | { 23, 26, coef3_M26, coef5_M26 }, | ||
301 | { 20, 22, coef3_M22, coef5_M22 }, | ||
302 | { 17, 19, coef3_M19, coef5_M19 }, | ||
303 | { 15, 16, coef3_M16, coef5_M16 }, | ||
304 | { 14, 14, coef3_M14, coef5_M14 }, | ||
305 | { 13, 13, coef3_M13, coef5_M13 }, | ||
306 | { 12, 12, coef3_M12, coef5_M12 }, | ||
307 | { 11, 11, coef3_M11, coef5_M11 }, | ||
308 | { 10, 10, coef3_M10, coef5_M10 }, | ||
309 | { 9, 9, coef3_M9, coef5_M9 }, | ||
310 | { 4, 8, coef3_M8, coef5_M8 }, | ||
311 | /* | ||
312 | * When upscaling more than two times, blockiness and outlines | ||
313 | * around the image are observed when M8 tables are used. M11, | ||
314 | * M16 and M19 tables are used to prevent this. | ||
315 | */ | ||
316 | { 3, 3, coef3_M11, coef5_M11 }, | ||
317 | { 2, 2, coef3_M16, coef5_M16 }, | ||
318 | { 0, 1, coef3_M19, coef5_M19 }, | ||
319 | }; | ||
320 | |||
321 | inc /= 128; | ||
322 | for (i = 0; i < ARRAY_LEN(coefs); ++i) | ||
323 | if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax) | ||
324 | return five_taps ? coefs[i].coef_5 : coefs[i].coef_3; | ||
325 | return NULL; | ||
326 | } | ||
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 976ac23dcd0c..395d658a94fc 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c | |||
@@ -223,10 +223,13 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
223 | 223 | ||
224 | mdelay(2); | 224 | mdelay(2); |
225 | 225 | ||
226 | dssdev->manager->enable(dssdev->manager); | 226 | r = dss_mgr_enable(dssdev->manager); |
227 | if (r) | ||
228 | goto err_mgr_enable; | ||
227 | 229 | ||
228 | return 0; | 230 | return 0; |
229 | 231 | ||
232 | err_mgr_enable: | ||
230 | err_set_mode: | 233 | err_set_mode: |
231 | if (dpi_use_dsi_pll(dssdev)) | 234 | if (dpi_use_dsi_pll(dssdev)) |
232 | dsi_pll_uninit(dpi.dsidev, true); | 235 | dsi_pll_uninit(dpi.dsidev, true); |
@@ -249,7 +252,7 @@ EXPORT_SYMBOL(omapdss_dpi_display_enable); | |||
249 | 252 | ||
250 | void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) | 253 | void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) |
251 | { | 254 | { |
252 | dssdev->manager->disable(dssdev->manager); | 255 | dss_mgr_disable(dssdev->manager); |
253 | 256 | ||
254 | if (dpi_use_dsi_pll(dssdev)) { | 257 | if (dpi_use_dsi_pll(dssdev)) { |
255 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | 258 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); |
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 46f37883e499..d4d676c82c12 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -203,6 +203,21 @@ struct dsi_reg { u16 idx; }; | |||
203 | typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); | 203 | typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); |
204 | 204 | ||
205 | #define DSI_MAX_NR_ISRS 2 | 205 | #define DSI_MAX_NR_ISRS 2 |
206 | #define DSI_MAX_NR_LANES 5 | ||
207 | |||
208 | enum dsi_lane_function { | ||
209 | DSI_LANE_UNUSED = 0, | ||
210 | DSI_LANE_CLK, | ||
211 | DSI_LANE_DATA1, | ||
212 | DSI_LANE_DATA2, | ||
213 | DSI_LANE_DATA3, | ||
214 | DSI_LANE_DATA4, | ||
215 | }; | ||
216 | |||
217 | struct dsi_lane_config { | ||
218 | enum dsi_lane_function function; | ||
219 | u8 polarity; | ||
220 | }; | ||
206 | 221 | ||
207 | struct dsi_isr_data { | 222 | struct dsi_isr_data { |
208 | omap_dsi_isr_t isr; | 223 | omap_dsi_isr_t isr; |
@@ -223,24 +238,6 @@ enum dsi_vc_source { | |||
223 | DSI_VC_SOURCE_VP, | 238 | DSI_VC_SOURCE_VP, |
224 | }; | 239 | }; |
225 | 240 | ||
226 | enum dsi_lane { | ||
227 | DSI_CLK_P = 1 << 0, | ||
228 | DSI_CLK_N = 1 << 1, | ||
229 | DSI_DATA1_P = 1 << 2, | ||
230 | DSI_DATA1_N = 1 << 3, | ||
231 | DSI_DATA2_P = 1 << 4, | ||
232 | DSI_DATA2_N = 1 << 5, | ||
233 | DSI_DATA3_P = 1 << 6, | ||
234 | DSI_DATA3_N = 1 << 7, | ||
235 | DSI_DATA4_P = 1 << 8, | ||
236 | DSI_DATA4_N = 1 << 9, | ||
237 | }; | ||
238 | |||
239 | struct dsi_update_region { | ||
240 | u16 x, y, w, h; | ||
241 | struct omap_dss_device *device; | ||
242 | }; | ||
243 | |||
244 | struct dsi_irq_stats { | 241 | struct dsi_irq_stats { |
245 | unsigned long last_reset; | 242 | unsigned long last_reset; |
246 | unsigned irq_count; | 243 | unsigned irq_count; |
@@ -290,7 +287,9 @@ struct dsi_data { | |||
290 | struct dsi_isr_tables isr_tables_copy; | 287 | struct dsi_isr_tables isr_tables_copy; |
291 | 288 | ||
292 | int update_channel; | 289 | int update_channel; |
293 | struct dsi_update_region update_region; | 290 | #ifdef DEBUG |
291 | unsigned update_bytes; | ||
292 | #endif | ||
294 | 293 | ||
295 | bool te_enabled; | 294 | bool te_enabled; |
296 | bool ulps_enabled; | 295 | bool ulps_enabled; |
@@ -327,7 +326,10 @@ struct dsi_data { | |||
327 | unsigned long fint_min, fint_max; | 326 | unsigned long fint_min, fint_max; |
328 | unsigned long lpdiv_max; | 327 | unsigned long lpdiv_max; |
329 | 328 | ||
330 | int num_data_lanes; | 329 | unsigned num_lanes_supported; |
330 | |||
331 | struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; | ||
332 | unsigned num_lanes_used; | ||
331 | 333 | ||
332 | unsigned scp_clk_refcount; | 334 | unsigned scp_clk_refcount; |
333 | }; | 335 | }; |
@@ -413,14 +415,29 @@ static void dsi_completion_handler(void *data, u32 mask) | |||
413 | static inline int wait_for_bit_change(struct platform_device *dsidev, | 415 | static inline int wait_for_bit_change(struct platform_device *dsidev, |
414 | const struct dsi_reg idx, int bitnum, int value) | 416 | const struct dsi_reg idx, int bitnum, int value) |
415 | { | 417 | { |
416 | int t = 100000; | 418 | unsigned long timeout; |
419 | ktime_t wait; | ||
420 | int t; | ||
417 | 421 | ||
418 | while (REG_GET(dsidev, idx, bitnum, bitnum) != value) { | 422 | /* first busyloop to see if the bit changes right away */ |
419 | if (--t == 0) | 423 | t = 100; |
420 | return !value; | 424 | while (t-- > 0) { |
425 | if (REG_GET(dsidev, idx, bitnum, bitnum) == value) | ||
426 | return value; | ||
421 | } | 427 | } |
422 | 428 | ||
423 | return value; | 429 | /* then loop for 500ms, sleeping for 1ms in between */ |
430 | timeout = jiffies + msecs_to_jiffies(500); | ||
431 | while (time_before(jiffies, timeout)) { | ||
432 | if (REG_GET(dsidev, idx, bitnum, bitnum) == value) | ||
433 | return value; | ||
434 | |||
435 | wait = ns_to_ktime(1000 * 1000); | ||
436 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
437 | schedule_hrtimeout(&wait, HRTIMER_MODE_REL); | ||
438 | } | ||
439 | |||
440 | return !value; | ||
424 | } | 441 | } |
425 | 442 | ||
426 | u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) | 443 | u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) |
@@ -454,7 +471,6 @@ static void dsi_perf_mark_start(struct platform_device *dsidev) | |||
454 | static void dsi_perf_show(struct platform_device *dsidev, const char *name) | 471 | static void dsi_perf_show(struct platform_device *dsidev, const char *name) |
455 | { | 472 | { |
456 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 473 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
457 | struct omap_dss_device *dssdev = dsi->update_region.device; | ||
458 | ktime_t t, setup_time, trans_time; | 474 | ktime_t t, setup_time, trans_time; |
459 | u32 total_bytes; | 475 | u32 total_bytes; |
460 | u32 setup_us, trans_us, total_us; | 476 | u32 setup_us, trans_us, total_us; |
@@ -476,9 +492,7 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name) | |||
476 | 492 | ||
477 | total_us = setup_us + trans_us; | 493 | total_us = setup_us + trans_us; |
478 | 494 | ||
479 | total_bytes = dsi->update_region.w * | 495 | total_bytes = dsi->update_bytes; |
480 | dsi->update_region.h * | ||
481 | dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; | ||
482 | 496 | ||
483 | printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " | 497 | printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " |
484 | "%u bytes, %u kbytes/sec\n", | 498 | "%u bytes, %u kbytes/sec\n", |
@@ -1720,17 +1734,19 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, | |||
1720 | seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n", | 1734 | seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n", |
1721 | cinfo->clkin4ddr, cinfo->regm); | 1735 | cinfo->clkin4ddr, cinfo->regm); |
1722 | 1736 | ||
1723 | seq_printf(s, "%s (%s)\t%-16luregm_dispc %u\t(%s)\n", | 1737 | seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16luregm_dispc %u\t(%s)\n", |
1724 | dss_get_generic_clk_source_name(dispc_clk_src), | 1738 | dss_feat_get_clk_source_name(dsi_module == 0 ? |
1725 | dss_feat_get_clk_source_name(dispc_clk_src), | 1739 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : |
1740 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC), | ||
1726 | cinfo->dsi_pll_hsdiv_dispc_clk, | 1741 | cinfo->dsi_pll_hsdiv_dispc_clk, |
1727 | cinfo->regm_dispc, | 1742 | cinfo->regm_dispc, |
1728 | dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ? | 1743 | dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ? |
1729 | "off" : "on"); | 1744 | "off" : "on"); |
1730 | 1745 | ||
1731 | seq_printf(s, "%s (%s)\t%-16luregm_dsi %u\t(%s)\n", | 1746 | seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16luregm_dsi %u\t(%s)\n", |
1732 | dss_get_generic_clk_source_name(dsi_clk_src), | 1747 | dss_feat_get_clk_source_name(dsi_module == 0 ? |
1733 | dss_feat_get_clk_source_name(dsi_clk_src), | 1748 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : |
1749 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI), | ||
1734 | cinfo->dsi_pll_hsdiv_dsi_clk, | 1750 | cinfo->dsi_pll_hsdiv_dsi_clk, |
1735 | cinfo->regm_dsi, | 1751 | cinfo->regm_dsi, |
1736 | dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ? | 1752 | dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ? |
@@ -2029,34 +2045,6 @@ static int dsi_cio_power(struct platform_device *dsidev, | |||
2029 | return 0; | 2045 | return 0; |
2030 | } | 2046 | } |
2031 | 2047 | ||
2032 | /* Number of data lanes present on DSI interface */ | ||
2033 | static inline int dsi_get_num_data_lanes(struct platform_device *dsidev) | ||
2034 | { | ||
2035 | /* DSI on OMAP3 doesn't have register DSI_GNQ, set number | ||
2036 | * of data lanes as 2 by default */ | ||
2037 | if (dss_has_feature(FEAT_DSI_GNQ)) | ||
2038 | return REG_GET(dsidev, DSI_GNQ, 11, 9); /* NB_DATA_LANES */ | ||
2039 | else | ||
2040 | return 2; | ||
2041 | } | ||
2042 | |||
2043 | /* Number of data lanes used by the dss device */ | ||
2044 | static inline int dsi_get_num_data_lanes_dssdev(struct omap_dss_device *dssdev) | ||
2045 | { | ||
2046 | int num_data_lanes = 0; | ||
2047 | |||
2048 | if (dssdev->phy.dsi.data1_lane != 0) | ||
2049 | num_data_lanes++; | ||
2050 | if (dssdev->phy.dsi.data2_lane != 0) | ||
2051 | num_data_lanes++; | ||
2052 | if (dssdev->phy.dsi.data3_lane != 0) | ||
2053 | num_data_lanes++; | ||
2054 | if (dssdev->phy.dsi.data4_lane != 0) | ||
2055 | num_data_lanes++; | ||
2056 | |||
2057 | return num_data_lanes; | ||
2058 | } | ||
2059 | |||
2060 | static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) | 2048 | static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) |
2061 | { | 2049 | { |
2062 | int val; | 2050 | int val; |
@@ -2088,59 +2076,112 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) | |||
2088 | } | 2076 | } |
2089 | } | 2077 | } |
2090 | 2078 | ||
2091 | static void dsi_set_lane_config(struct omap_dss_device *dssdev) | 2079 | static int dsi_parse_lane_config(struct omap_dss_device *dssdev) |
2092 | { | 2080 | { |
2093 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 2081 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2094 | u32 r; | 2082 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2095 | int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev); | 2083 | u8 lanes[DSI_MAX_NR_LANES]; |
2084 | u8 polarities[DSI_MAX_NR_LANES]; | ||
2085 | int num_lanes, i; | ||
2086 | |||
2087 | static const enum dsi_lane_function functions[] = { | ||
2088 | DSI_LANE_CLK, | ||
2089 | DSI_LANE_DATA1, | ||
2090 | DSI_LANE_DATA2, | ||
2091 | DSI_LANE_DATA3, | ||
2092 | DSI_LANE_DATA4, | ||
2093 | }; | ||
2094 | |||
2095 | lanes[0] = dssdev->phy.dsi.clk_lane; | ||
2096 | lanes[1] = dssdev->phy.dsi.data1_lane; | ||
2097 | lanes[2] = dssdev->phy.dsi.data2_lane; | ||
2098 | lanes[3] = dssdev->phy.dsi.data3_lane; | ||
2099 | lanes[4] = dssdev->phy.dsi.data4_lane; | ||
2100 | polarities[0] = dssdev->phy.dsi.clk_pol; | ||
2101 | polarities[1] = dssdev->phy.dsi.data1_pol; | ||
2102 | polarities[2] = dssdev->phy.dsi.data2_pol; | ||
2103 | polarities[3] = dssdev->phy.dsi.data3_pol; | ||
2104 | polarities[4] = dssdev->phy.dsi.data4_pol; | ||
2096 | 2105 | ||
2097 | int clk_lane = dssdev->phy.dsi.clk_lane; | 2106 | num_lanes = 0; |
2098 | int data1_lane = dssdev->phy.dsi.data1_lane; | 2107 | |
2099 | int data2_lane = dssdev->phy.dsi.data2_lane; | 2108 | for (i = 0; i < dsi->num_lanes_supported; ++i) |
2100 | int clk_pol = dssdev->phy.dsi.clk_pol; | 2109 | dsi->lanes[i].function = DSI_LANE_UNUSED; |
2101 | int data1_pol = dssdev->phy.dsi.data1_pol; | 2110 | |
2102 | int data2_pol = dssdev->phy.dsi.data2_pol; | 2111 | for (i = 0; i < dsi->num_lanes_supported; ++i) { |
2112 | int num; | ||
2113 | |||
2114 | if (lanes[i] == DSI_LANE_UNUSED) | ||
2115 | break; | ||
2116 | |||
2117 | num = lanes[i] - 1; | ||
2118 | |||
2119 | if (num >= dsi->num_lanes_supported) | ||
2120 | return -EINVAL; | ||
2121 | |||
2122 | if (dsi->lanes[num].function != DSI_LANE_UNUSED) | ||
2123 | return -EINVAL; | ||
2124 | |||
2125 | dsi->lanes[num].function = functions[i]; | ||
2126 | dsi->lanes[num].polarity = polarities[i]; | ||
2127 | num_lanes++; | ||
2128 | } | ||
2129 | |||
2130 | if (num_lanes < 2 || num_lanes > dsi->num_lanes_supported) | ||
2131 | return -EINVAL; | ||
2132 | |||
2133 | dsi->num_lanes_used = num_lanes; | ||
2134 | |||
2135 | return 0; | ||
2136 | } | ||
2137 | |||
2138 | static int dsi_set_lane_config(struct omap_dss_device *dssdev) | ||
2139 | { | ||
2140 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
2141 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
2142 | static const u8 offsets[] = { 0, 4, 8, 12, 16 }; | ||
2143 | static const enum dsi_lane_function functions[] = { | ||
2144 | DSI_LANE_CLK, | ||
2145 | DSI_LANE_DATA1, | ||
2146 | DSI_LANE_DATA2, | ||
2147 | DSI_LANE_DATA3, | ||
2148 | DSI_LANE_DATA4, | ||
2149 | }; | ||
2150 | u32 r; | ||
2151 | int i; | ||
2103 | 2152 | ||
2104 | r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); | 2153 | r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); |
2105 | r = FLD_MOD(r, clk_lane, 2, 0); | 2154 | |
2106 | r = FLD_MOD(r, clk_pol, 3, 3); | 2155 | for (i = 0; i < dsi->num_lanes_used; ++i) { |
2107 | r = FLD_MOD(r, data1_lane, 6, 4); | 2156 | unsigned offset = offsets[i]; |
2108 | r = FLD_MOD(r, data1_pol, 7, 7); | 2157 | unsigned polarity, lane_number; |
2109 | r = FLD_MOD(r, data2_lane, 10, 8); | 2158 | unsigned t; |
2110 | r = FLD_MOD(r, data2_pol, 11, 11); | 2159 | |
2111 | if (num_data_lanes_dssdev > 2) { | 2160 | for (t = 0; t < dsi->num_lanes_supported; ++t) |
2112 | int data3_lane = dssdev->phy.dsi.data3_lane; | 2161 | if (dsi->lanes[t].function == functions[i]) |
2113 | int data3_pol = dssdev->phy.dsi.data3_pol; | 2162 | break; |
2114 | 2163 | ||
2115 | r = FLD_MOD(r, data3_lane, 14, 12); | 2164 | if (t == dsi->num_lanes_supported) |
2116 | r = FLD_MOD(r, data3_pol, 15, 15); | 2165 | return -EINVAL; |
2166 | |||
2167 | lane_number = t; | ||
2168 | polarity = dsi->lanes[t].polarity; | ||
2169 | |||
2170 | r = FLD_MOD(r, lane_number + 1, offset + 2, offset); | ||
2171 | r = FLD_MOD(r, polarity, offset + 3, offset + 3); | ||
2117 | } | 2172 | } |
2118 | if (num_data_lanes_dssdev > 3) { | ||
2119 | int data4_lane = dssdev->phy.dsi.data4_lane; | ||
2120 | int data4_pol = dssdev->phy.dsi.data4_pol; | ||
2121 | 2173 | ||
2122 | r = FLD_MOD(r, data4_lane, 18, 16); | 2174 | /* clear the unused lanes */ |
2123 | r = FLD_MOD(r, data4_pol, 19, 19); | 2175 | for (; i < dsi->num_lanes_supported; ++i) { |
2176 | unsigned offset = offsets[i]; | ||
2177 | |||
2178 | r = FLD_MOD(r, 0, offset + 2, offset); | ||
2179 | r = FLD_MOD(r, 0, offset + 3, offset + 3); | ||
2124 | } | 2180 | } |
2125 | dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r); | ||
2126 | 2181 | ||
2127 | /* The configuration of the DSI complex I/O (number of data lanes, | 2182 | dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r); |
2128 | position, differential order) should not be changed while | ||
2129 | DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for | ||
2130 | the hardware to take into account a new configuration of the complex | ||
2131 | I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to | ||
2132 | follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, | ||
2133 | then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set | ||
2134 | DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the | ||
2135 | DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the | ||
2136 | DSI complex I/O configuration is unknown. */ | ||
2137 | 2183 | ||
2138 | /* | 2184 | return 0; |
2139 | REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0); | ||
2140 | REG_FLD_MOD(dsidev, DSI_CTRL, 0, 0, 0); | ||
2141 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); | ||
2142 | REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0); | ||
2143 | */ | ||
2144 | } | 2185 | } |
2145 | 2186 | ||
2146 | static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns) | 2187 | static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns) |
@@ -2230,49 +2271,28 @@ static void dsi_cio_timings(struct platform_device *dsidev) | |||
2230 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r); | 2271 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r); |
2231 | } | 2272 | } |
2232 | 2273 | ||
2274 | /* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */ | ||
2233 | static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev, | 2275 | static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev, |
2234 | enum dsi_lane lanes) | 2276 | unsigned mask_p, unsigned mask_n) |
2235 | { | 2277 | { |
2236 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 2278 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2237 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2279 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2238 | int clk_lane = dssdev->phy.dsi.clk_lane; | 2280 | int i; |
2239 | int data1_lane = dssdev->phy.dsi.data1_lane; | 2281 | u32 l; |
2240 | int data2_lane = dssdev->phy.dsi.data2_lane; | 2282 | u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26; |
2241 | int data3_lane = dssdev->phy.dsi.data3_lane; | 2283 | |
2242 | int data4_lane = dssdev->phy.dsi.data4_lane; | 2284 | l = 0; |
2243 | int clk_pol = dssdev->phy.dsi.clk_pol; | 2285 | |
2244 | int data1_pol = dssdev->phy.dsi.data1_pol; | 2286 | for (i = 0; i < dsi->num_lanes_supported; ++i) { |
2245 | int data2_pol = dssdev->phy.dsi.data2_pol; | 2287 | unsigned p = dsi->lanes[i].polarity; |
2246 | int data3_pol = dssdev->phy.dsi.data3_pol; | 2288 | |
2247 | int data4_pol = dssdev->phy.dsi.data4_pol; | 2289 | if (mask_p & (1 << i)) |
2248 | 2290 | l |= 1 << (i * 2 + (p ? 0 : 1)); | |
2249 | u32 l = 0; | 2291 | |
2250 | u8 lptxscp_start = dsi->num_data_lanes == 2 ? 22 : 26; | 2292 | if (mask_n & (1 << i)) |
2251 | 2293 | l |= 1 << (i * 2 + (p ? 1 : 0)); | |
2252 | if (lanes & DSI_CLK_P) | 2294 | } |
2253 | l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 0 : 1)); | 2295 | |
2254 | if (lanes & DSI_CLK_N) | ||
2255 | l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 1 : 0)); | ||
2256 | |||
2257 | if (lanes & DSI_DATA1_P) | ||
2258 | l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 0 : 1)); | ||
2259 | if (lanes & DSI_DATA1_N) | ||
2260 | l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 1 : 0)); | ||
2261 | |||
2262 | if (lanes & DSI_DATA2_P) | ||
2263 | l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 0 : 1)); | ||
2264 | if (lanes & DSI_DATA2_N) | ||
2265 | l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 1 : 0)); | ||
2266 | |||
2267 | if (lanes & DSI_DATA3_P) | ||
2268 | l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 0 : 1)); | ||
2269 | if (lanes & DSI_DATA3_N) | ||
2270 | l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 1 : 0)); | ||
2271 | |||
2272 | if (lanes & DSI_DATA4_P) | ||
2273 | l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 0 : 1)); | ||
2274 | if (lanes & DSI_DATA4_N) | ||
2275 | l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 1 : 0)); | ||
2276 | /* | 2296 | /* |
2277 | * Bits in REGLPTXSCPDAT4TO0DXDY: | 2297 | * Bits in REGLPTXSCPDAT4TO0DXDY: |
2278 | * 17: DY0 18: DX0 | 2298 | * 17: DY0 18: DX0 |
@@ -2305,51 +2325,40 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev) | |||
2305 | static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) | 2325 | static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) |
2306 | { | 2326 | { |
2307 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 2327 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2308 | int t; | 2328 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2309 | int bits[3]; | 2329 | int t, i; |
2310 | bool in_use[3]; | 2330 | bool in_use[DSI_MAX_NR_LANES]; |
2311 | 2331 | static const u8 offsets_old[] = { 28, 27, 26 }; | |
2312 | if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) { | 2332 | static const u8 offsets_new[] = { 24, 25, 26, 27, 28 }; |
2313 | bits[0] = 28; | 2333 | const u8 *offsets; |
2314 | bits[1] = 27; | 2334 | |
2315 | bits[2] = 26; | 2335 | if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) |
2316 | } else { | 2336 | offsets = offsets_old; |
2317 | bits[0] = 24; | 2337 | else |
2318 | bits[1] = 25; | 2338 | offsets = offsets_new; |
2319 | bits[2] = 26; | ||
2320 | } | ||
2321 | |||
2322 | in_use[0] = false; | ||
2323 | in_use[1] = false; | ||
2324 | in_use[2] = false; | ||
2325 | 2339 | ||
2326 | if (dssdev->phy.dsi.clk_lane != 0) | 2340 | for (i = 0; i < dsi->num_lanes_supported; ++i) |
2327 | in_use[dssdev->phy.dsi.clk_lane - 1] = true; | 2341 | in_use[i] = dsi->lanes[i].function != DSI_LANE_UNUSED; |
2328 | if (dssdev->phy.dsi.data1_lane != 0) | ||
2329 | in_use[dssdev->phy.dsi.data1_lane - 1] = true; | ||
2330 | if (dssdev->phy.dsi.data2_lane != 0) | ||
2331 | in_use[dssdev->phy.dsi.data2_lane - 1] = true; | ||
2332 | 2342 | ||
2333 | t = 100000; | 2343 | t = 100000; |
2334 | while (true) { | 2344 | while (true) { |
2335 | u32 l; | 2345 | u32 l; |
2336 | int i; | ||
2337 | int ok; | 2346 | int ok; |
2338 | 2347 | ||
2339 | l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); | 2348 | l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); |
2340 | 2349 | ||
2341 | ok = 0; | 2350 | ok = 0; |
2342 | for (i = 0; i < 3; ++i) { | 2351 | for (i = 0; i < dsi->num_lanes_supported; ++i) { |
2343 | if (!in_use[i] || (l & (1 << bits[i]))) | 2352 | if (!in_use[i] || (l & (1 << offsets[i]))) |
2344 | ok++; | 2353 | ok++; |
2345 | } | 2354 | } |
2346 | 2355 | ||
2347 | if (ok == 3) | 2356 | if (ok == dsi->num_lanes_supported) |
2348 | break; | 2357 | break; |
2349 | 2358 | ||
2350 | if (--t == 0) { | 2359 | if (--t == 0) { |
2351 | for (i = 0; i < 3; ++i) { | 2360 | for (i = 0; i < dsi->num_lanes_supported; ++i) { |
2352 | if (!in_use[i] || (l & (1 << bits[i]))) | 2361 | if (!in_use[i] || (l & (1 << offsets[i]))) |
2353 | continue; | 2362 | continue; |
2354 | 2363 | ||
2355 | DSSERR("CIO TXCLKESC%d domain not coming " \ | 2364 | DSSERR("CIO TXCLKESC%d domain not coming " \ |
@@ -2362,22 +2371,20 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) | |||
2362 | return 0; | 2371 | return 0; |
2363 | } | 2372 | } |
2364 | 2373 | ||
2374 | /* return bitmask of enabled lanes, lane0 being the lsb */ | ||
2365 | static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) | 2375 | static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) |
2366 | { | 2376 | { |
2367 | unsigned lanes = 0; | 2377 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2378 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
2379 | unsigned mask = 0; | ||
2380 | int i; | ||
2368 | 2381 | ||
2369 | if (dssdev->phy.dsi.clk_lane != 0) | 2382 | for (i = 0; i < dsi->num_lanes_supported; ++i) { |
2370 | lanes |= 1 << (dssdev->phy.dsi.clk_lane - 1); | 2383 | if (dsi->lanes[i].function != DSI_LANE_UNUSED) |
2371 | if (dssdev->phy.dsi.data1_lane != 0) | 2384 | mask |= 1 << i; |
2372 | lanes |= 1 << (dssdev->phy.dsi.data1_lane - 1); | 2385 | } |
2373 | if (dssdev->phy.dsi.data2_lane != 0) | ||
2374 | lanes |= 1 << (dssdev->phy.dsi.data2_lane - 1); | ||
2375 | if (dssdev->phy.dsi.data3_lane != 0) | ||
2376 | lanes |= 1 << (dssdev->phy.dsi.data3_lane - 1); | ||
2377 | if (dssdev->phy.dsi.data4_lane != 0) | ||
2378 | lanes |= 1 << (dssdev->phy.dsi.data4_lane - 1); | ||
2379 | 2386 | ||
2380 | return lanes; | 2387 | return mask; |
2381 | } | 2388 | } |
2382 | 2389 | ||
2383 | static int dsi_cio_init(struct omap_dss_device *dssdev) | 2390 | static int dsi_cio_init(struct omap_dss_device *dssdev) |
@@ -2385,7 +2392,6 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) | |||
2385 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 2392 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2386 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2393 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2387 | int r; | 2394 | int r; |
2388 | int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev); | ||
2389 | u32 l; | 2395 | u32 l; |
2390 | 2396 | ||
2391 | DSSDBGF(); | 2397 | DSSDBGF(); |
@@ -2407,7 +2413,9 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) | |||
2407 | goto err_scp_clk_dom; | 2413 | goto err_scp_clk_dom; |
2408 | } | 2414 | } |
2409 | 2415 | ||
2410 | dsi_set_lane_config(dssdev); | 2416 | r = dsi_set_lane_config(dssdev); |
2417 | if (r) | ||
2418 | goto err_scp_clk_dom; | ||
2411 | 2419 | ||
2412 | /* set TX STOP MODE timer to maximum for this operation */ | 2420 | /* set TX STOP MODE timer to maximum for this operation */ |
2413 | l = dsi_read_reg(dsidev, DSI_TIMING1); | 2421 | l = dsi_read_reg(dsidev, DSI_TIMING1); |
@@ -2418,7 +2426,8 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) | |||
2418 | dsi_write_reg(dsidev, DSI_TIMING1, l); | 2426 | dsi_write_reg(dsidev, DSI_TIMING1, l); |
2419 | 2427 | ||
2420 | if (dsi->ulps_enabled) { | 2428 | if (dsi->ulps_enabled) { |
2421 | u32 lane_mask = DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P; | 2429 | unsigned mask_p; |
2430 | int i; | ||
2422 | 2431 | ||
2423 | DSSDBG("manual ulps exit\n"); | 2432 | DSSDBG("manual ulps exit\n"); |
2424 | 2433 | ||
@@ -2427,16 +2436,19 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) | |||
2427 | * ULPS exit sequence, as after reset the DSS HW thinks | 2436 | * ULPS exit sequence, as after reset the DSS HW thinks |
2428 | * that we are not in ULPS mode, and refuses to send the | 2437 | * that we are not in ULPS mode, and refuses to send the |
2429 | * sequence. So we need to send the ULPS exit sequence | 2438 | * sequence. So we need to send the ULPS exit sequence |
2430 | * manually. | 2439 | * manually by setting positive lines high and negative lines |
2440 | * low for 1ms. | ||
2431 | */ | 2441 | */ |
2432 | 2442 | ||
2433 | if (num_data_lanes_dssdev > 2) | 2443 | mask_p = 0; |
2434 | lane_mask |= DSI_DATA3_P; | ||
2435 | 2444 | ||
2436 | if (num_data_lanes_dssdev > 3) | 2445 | for (i = 0; i < dsi->num_lanes_supported; ++i) { |
2437 | lane_mask |= DSI_DATA4_P; | 2446 | if (dsi->lanes[i].function == DSI_LANE_UNUSED) |
2447 | continue; | ||
2448 | mask_p |= 1 << i; | ||
2449 | } | ||
2438 | 2450 | ||
2439 | dsi_cio_enable_lane_override(dssdev, lane_mask); | 2451 | dsi_cio_enable_lane_override(dssdev, mask_p, 0); |
2440 | } | 2452 | } |
2441 | 2453 | ||
2442 | r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); | 2454 | r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); |
@@ -2913,6 +2925,9 @@ static int dsi_vc_send_bta(struct platform_device *dsidev, int channel) | |||
2913 | 2925 | ||
2914 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ | 2926 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ |
2915 | 2927 | ||
2928 | /* flush posted write */ | ||
2929 | dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); | ||
2930 | |||
2916 | return 0; | 2931 | return 0; |
2917 | } | 2932 | } |
2918 | 2933 | ||
@@ -3513,7 +3528,8 @@ static int dsi_enter_ulps(struct platform_device *dsidev) | |||
3513 | { | 3528 | { |
3514 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3529 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
3515 | DECLARE_COMPLETION_ONSTACK(completion); | 3530 | DECLARE_COMPLETION_ONSTACK(completion); |
3516 | int r; | 3531 | int r, i; |
3532 | unsigned mask; | ||
3517 | 3533 | ||
3518 | DSSDBGF(); | 3534 | DSSDBGF(); |
3519 | 3535 | ||
@@ -3524,9 +3540,11 @@ static int dsi_enter_ulps(struct platform_device *dsidev) | |||
3524 | if (dsi->ulps_enabled) | 3540 | if (dsi->ulps_enabled) |
3525 | return 0; | 3541 | return 0; |
3526 | 3542 | ||
3543 | /* DDR_CLK_ALWAYS_ON */ | ||
3527 | if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) { | 3544 | if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) { |
3528 | DSSERR("DDR_CLK_ALWAYS_ON enabled when entering ULPS\n"); | 3545 | dsi_if_enable(dsidev, 0); |
3529 | return -EIO; | 3546 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13); |
3547 | dsi_if_enable(dsidev, 1); | ||
3530 | } | 3548 | } |
3531 | 3549 | ||
3532 | dsi_sync_vc(dsidev, 0); | 3550 | dsi_sync_vc(dsidev, 0); |
@@ -3556,10 +3574,19 @@ static int dsi_enter_ulps(struct platform_device *dsidev) | |||
3556 | if (r) | 3574 | if (r) |
3557 | return r; | 3575 | return r; |
3558 | 3576 | ||
3577 | mask = 0; | ||
3578 | |||
3579 | for (i = 0; i < dsi->num_lanes_supported; ++i) { | ||
3580 | if (dsi->lanes[i].function == DSI_LANE_UNUSED) | ||
3581 | continue; | ||
3582 | mask |= 1 << i; | ||
3583 | } | ||
3559 | /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */ | 3584 | /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */ |
3560 | /* LANEx_ULPS_SIG2 */ | 3585 | /* LANEx_ULPS_SIG2 */ |
3561 | REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (1 << 0) | (1 << 1) | (1 << 2), | 3586 | REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, mask, 9, 5); |
3562 | 7, 5); | 3587 | |
3588 | /* flush posted write and wait for SCP interface to finish the write */ | ||
3589 | dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); | ||
3563 | 3590 | ||
3564 | if (wait_for_completion_timeout(&completion, | 3591 | if (wait_for_completion_timeout(&completion, |
3565 | msecs_to_jiffies(1000)) == 0) { | 3592 | msecs_to_jiffies(1000)) == 0) { |
@@ -3572,8 +3599,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev) | |||
3572 | DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); | 3599 | DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); |
3573 | 3600 | ||
3574 | /* Reset LANEx_ULPS_SIG2 */ | 3601 | /* Reset LANEx_ULPS_SIG2 */ |
3575 | REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (0 << 0) | (0 << 1) | (0 << 2), | 3602 | REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, 0, 9, 5); |
3576 | 7, 5); | 3603 | |
3604 | /* flush posted write and wait for SCP interface to finish the write */ | ||
3605 | dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); | ||
3577 | 3606 | ||
3578 | dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); | 3607 | dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); |
3579 | 3608 | ||
@@ -3836,6 +3865,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
3836 | static void dsi_proto_timings(struct omap_dss_device *dssdev) | 3865 | static void dsi_proto_timings(struct omap_dss_device *dssdev) |
3837 | { | 3866 | { |
3838 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3867 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3868 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
3839 | unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; | 3869 | unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; |
3840 | unsigned tclk_pre, tclk_post; | 3870 | unsigned tclk_pre, tclk_post; |
3841 | unsigned ths_prepare, ths_prepare_ths_zero, ths_zero; | 3871 | unsigned ths_prepare, ths_prepare_ths_zero, ths_zero; |
@@ -3843,7 +3873,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) | |||
3843 | unsigned ddr_clk_pre, ddr_clk_post; | 3873 | unsigned ddr_clk_pre, ddr_clk_post; |
3844 | unsigned enter_hs_mode_lat, exit_hs_mode_lat; | 3874 | unsigned enter_hs_mode_lat, exit_hs_mode_lat; |
3845 | unsigned ths_eot; | 3875 | unsigned ths_eot; |
3846 | int ndl = dsi_get_num_data_lanes_dssdev(dssdev); | 3876 | int ndl = dsi->num_lanes_used - 1; |
3847 | u32 r; | 3877 | u32 r; |
3848 | 3878 | ||
3849 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); | 3879 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); |
@@ -3945,68 +3975,82 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) | |||
3945 | } | 3975 | } |
3946 | } | 3976 | } |
3947 | 3977 | ||
3948 | int dsi_video_mode_enable(struct omap_dss_device *dssdev, int channel) | 3978 | int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) |
3949 | { | 3979 | { |
3950 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3980 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3951 | int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); | 3981 | int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); |
3952 | u8 data_type; | 3982 | u8 data_type; |
3953 | u16 word_count; | 3983 | u16 word_count; |
3984 | int r; | ||
3954 | 3985 | ||
3955 | switch (dssdev->panel.dsi_pix_fmt) { | 3986 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { |
3956 | case OMAP_DSS_DSI_FMT_RGB888: | 3987 | switch (dssdev->panel.dsi_pix_fmt) { |
3957 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; | 3988 | case OMAP_DSS_DSI_FMT_RGB888: |
3958 | break; | 3989 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; |
3959 | case OMAP_DSS_DSI_FMT_RGB666: | 3990 | break; |
3960 | data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; | 3991 | case OMAP_DSS_DSI_FMT_RGB666: |
3961 | break; | 3992 | data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; |
3962 | case OMAP_DSS_DSI_FMT_RGB666_PACKED: | 3993 | break; |
3963 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; | 3994 | case OMAP_DSS_DSI_FMT_RGB666_PACKED: |
3964 | break; | 3995 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; |
3965 | case OMAP_DSS_DSI_FMT_RGB565: | 3996 | break; |
3966 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; | 3997 | case OMAP_DSS_DSI_FMT_RGB565: |
3967 | break; | 3998 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; |
3968 | default: | 3999 | break; |
3969 | BUG(); | 4000 | default: |
3970 | }; | 4001 | BUG(); |
4002 | }; | ||
3971 | 4003 | ||
3972 | dsi_if_enable(dsidev, false); | 4004 | dsi_if_enable(dsidev, false); |
3973 | dsi_vc_enable(dsidev, channel, false); | 4005 | dsi_vc_enable(dsidev, channel, false); |
3974 | 4006 | ||
3975 | /* MODE, 1 = video mode */ | 4007 | /* MODE, 1 = video mode */ |
3976 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); | 4008 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); |
3977 | 4009 | ||
3978 | word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8); | 4010 | word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8); |
3979 | 4011 | ||
3980 | dsi_vc_write_long_header(dsidev, channel, data_type, word_count, 0); | 4012 | dsi_vc_write_long_header(dsidev, channel, data_type, |
4013 | word_count, 0); | ||
3981 | 4014 | ||
3982 | dsi_vc_enable(dsidev, channel, true); | 4015 | dsi_vc_enable(dsidev, channel, true); |
3983 | dsi_if_enable(dsidev, true); | 4016 | dsi_if_enable(dsidev, true); |
4017 | } | ||
3984 | 4018 | ||
3985 | dssdev->manager->enable(dssdev->manager); | 4019 | r = dss_mgr_enable(dssdev->manager); |
4020 | if (r) { | ||
4021 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { | ||
4022 | dsi_if_enable(dsidev, false); | ||
4023 | dsi_vc_enable(dsidev, channel, false); | ||
4024 | } | ||
4025 | |||
4026 | return r; | ||
4027 | } | ||
3986 | 4028 | ||
3987 | return 0; | 4029 | return 0; |
3988 | } | 4030 | } |
3989 | EXPORT_SYMBOL(dsi_video_mode_enable); | 4031 | EXPORT_SYMBOL(dsi_enable_video_output); |
3990 | 4032 | ||
3991 | void dsi_video_mode_disable(struct omap_dss_device *dssdev, int channel) | 4033 | void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) |
3992 | { | 4034 | { |
3993 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4035 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3994 | 4036 | ||
3995 | dsi_if_enable(dsidev, false); | 4037 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { |
3996 | dsi_vc_enable(dsidev, channel, false); | 4038 | dsi_if_enable(dsidev, false); |
4039 | dsi_vc_enable(dsidev, channel, false); | ||
3997 | 4040 | ||
3998 | /* MODE, 0 = command mode */ | 4041 | /* MODE, 0 = command mode */ |
3999 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4); | 4042 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4); |
4000 | 4043 | ||
4001 | dsi_vc_enable(dsidev, channel, true); | 4044 | dsi_vc_enable(dsidev, channel, true); |
4002 | dsi_if_enable(dsidev, true); | 4045 | dsi_if_enable(dsidev, true); |
4046 | } | ||
4003 | 4047 | ||
4004 | dssdev->manager->disable(dssdev->manager); | 4048 | dss_mgr_disable(dssdev->manager); |
4005 | } | 4049 | } |
4006 | EXPORT_SYMBOL(dsi_video_mode_disable); | 4050 | EXPORT_SYMBOL(dsi_disable_video_output); |
4007 | 4051 | ||
4008 | static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | 4052 | static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, |
4009 | u16 x, u16 y, u16 w, u16 h) | 4053 | u16 w, u16 h) |
4010 | { | 4054 | { |
4011 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4055 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4012 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4056 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
@@ -4021,8 +4065,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
4021 | const unsigned channel = dsi->update_channel; | 4065 | const unsigned channel = dsi->update_channel; |
4022 | const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); | 4066 | const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); |
4023 | 4067 | ||
4024 | DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", | 4068 | DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h); |
4025 | x, y, w, h); | ||
4026 | 4069 | ||
4027 | dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); | 4070 | dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); |
4028 | 4071 | ||
@@ -4070,7 +4113,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
4070 | msecs_to_jiffies(250)); | 4113 | msecs_to_jiffies(250)); |
4071 | BUG_ON(r == 0); | 4114 | BUG_ON(r == 0); |
4072 | 4115 | ||
4073 | dss_start_update(dssdev); | 4116 | dss_mgr_start_update(dssdev->manager); |
4074 | 4117 | ||
4075 | if (dsi->te_enabled) { | 4118 | if (dsi->te_enabled) { |
4076 | /* disable LP_RX_TO, so that we can receive TE. Time to wait | 4119 | /* disable LP_RX_TO, so that we can receive TE. Time to wait |
@@ -4146,66 +4189,27 @@ static void dsi_framedone_irq_callback(void *data, u32 mask) | |||
4146 | #endif | 4189 | #endif |
4147 | } | 4190 | } |
4148 | 4191 | ||
4149 | int omap_dsi_prepare_update(struct omap_dss_device *dssdev, | 4192 | int omap_dsi_update(struct omap_dss_device *dssdev, int channel, |
4150 | u16 *x, u16 *y, u16 *w, u16 *h, | 4193 | void (*callback)(int, void *), void *data) |
4151 | bool enlarge_update_area) | ||
4152 | { | 4194 | { |
4153 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4195 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4196 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4154 | u16 dw, dh; | 4197 | u16 dw, dh; |
4155 | 4198 | ||
4156 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | ||
4157 | |||
4158 | if (*x > dw || *y > dh) | ||
4159 | return -EINVAL; | ||
4160 | |||
4161 | if (*x + *w > dw) | ||
4162 | return -EINVAL; | ||
4163 | |||
4164 | if (*y + *h > dh) | ||
4165 | return -EINVAL; | ||
4166 | |||
4167 | if (*w == 1) | ||
4168 | return -EINVAL; | ||
4169 | |||
4170 | if (*w == 0 || *h == 0) | ||
4171 | return -EINVAL; | ||
4172 | |||
4173 | dsi_perf_mark_setup(dsidev); | 4199 | dsi_perf_mark_setup(dsidev); |
4174 | 4200 | ||
4175 | dss_setup_partial_planes(dssdev, x, y, w, h, | ||
4176 | enlarge_update_area); | ||
4177 | dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); | ||
4178 | |||
4179 | return 0; | ||
4180 | } | ||
4181 | EXPORT_SYMBOL(omap_dsi_prepare_update); | ||
4182 | |||
4183 | int omap_dsi_update(struct omap_dss_device *dssdev, | ||
4184 | int channel, | ||
4185 | u16 x, u16 y, u16 w, u16 h, | ||
4186 | void (*callback)(int, void *), void *data) | ||
4187 | { | ||
4188 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4189 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4190 | |||
4191 | dsi->update_channel = channel; | 4201 | dsi->update_channel = channel; |
4192 | 4202 | ||
4193 | /* OMAP DSS cannot send updates of odd widths. | ||
4194 | * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON | ||
4195 | * here to make sure we catch erroneous updates. Otherwise we'll only | ||
4196 | * see rather obscure HW error happening, as DSS halts. */ | ||
4197 | BUG_ON(x % 2 == 1); | ||
4198 | |||
4199 | dsi->framedone_callback = callback; | 4203 | dsi->framedone_callback = callback; |
4200 | dsi->framedone_data = data; | 4204 | dsi->framedone_data = data; |
4201 | 4205 | ||
4202 | dsi->update_region.x = x; | 4206 | dssdev->driver->get_resolution(dssdev, &dw, &dh); |
4203 | dsi->update_region.y = y; | ||
4204 | dsi->update_region.w = w; | ||
4205 | dsi->update_region.h = h; | ||
4206 | dsi->update_region.device = dssdev; | ||
4207 | 4207 | ||
4208 | dsi_update_screen_dispc(dssdev, x, y, w, h); | 4208 | #ifdef DEBUG |
4209 | dsi->update_bytes = dw * dh * | ||
4210 | dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; | ||
4211 | #endif | ||
4212 | dsi_update_screen_dispc(dssdev, dw, dh); | ||
4209 | 4213 | ||
4210 | return 0; | 4214 | return 0; |
4211 | } | 4215 | } |
@@ -4218,6 +4222,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | |||
4218 | int r; | 4222 | int r; |
4219 | 4223 | ||
4220 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { | 4224 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { |
4225 | u16 dw, dh; | ||
4221 | u32 irq; | 4226 | u32 irq; |
4222 | struct omap_video_timings timings = { | 4227 | struct omap_video_timings timings = { |
4223 | .hsw = 1, | 4228 | .hsw = 1, |
@@ -4228,6 +4233,10 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | |||
4228 | .vbp = 0, | 4233 | .vbp = 0, |
4229 | }; | 4234 | }; |
4230 | 4235 | ||
4236 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | ||
4237 | timings.x_res = dw; | ||
4238 | timings.y_res = dh; | ||
4239 | |||
4231 | irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? | 4240 | irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? |
4232 | DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; | 4241 | DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; |
4233 | 4242 | ||
@@ -4330,6 +4339,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | |||
4330 | int dsi_module = dsi_get_dsidev_id(dsidev); | 4339 | int dsi_module = dsi_get_dsidev_id(dsidev); |
4331 | int r; | 4340 | int r; |
4332 | 4341 | ||
4342 | r = dsi_parse_lane_config(dssdev); | ||
4343 | if (r) { | ||
4344 | DSSERR("illegal lane config"); | ||
4345 | goto err0; | ||
4346 | } | ||
4347 | |||
4333 | r = dsi_pll_init(dsidev, true, true); | 4348 | r = dsi_pll_init(dsidev, true, true); |
4334 | if (r) | 4349 | if (r) |
4335 | goto err0; | 4350 | goto err0; |
@@ -4521,7 +4536,6 @@ int dsi_init_display(struct omap_dss_device *dssdev) | |||
4521 | { | 4536 | { |
4522 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4537 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4523 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4538 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4524 | int dsi_module = dsi_get_dsidev_id(dsidev); | ||
4525 | 4539 | ||
4526 | DSSDBG("DSI init\n"); | 4540 | DSSDBG("DSI init\n"); |
4527 | 4541 | ||
@@ -4543,12 +4557,6 @@ int dsi_init_display(struct omap_dss_device *dssdev) | |||
4543 | dsi->vdds_dsi_reg = vdds_dsi; | 4557 | dsi->vdds_dsi_reg = vdds_dsi; |
4544 | } | 4558 | } |
4545 | 4559 | ||
4546 | if (dsi_get_num_data_lanes_dssdev(dssdev) > dsi->num_data_lanes) { | ||
4547 | DSSERR("DSI%d can't support more than %d data lanes\n", | ||
4548 | dsi_module + 1, dsi->num_data_lanes); | ||
4549 | return -EINVAL; | ||
4550 | } | ||
4551 | |||
4552 | return 0; | 4560 | return 0; |
4553 | } | 4561 | } |
4554 | 4562 | ||
@@ -4771,7 +4779,13 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
4771 | dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", | 4779 | dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", |
4772 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); | 4780 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); |
4773 | 4781 | ||
4774 | dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev); | 4782 | /* DSI on OMAP3 doesn't have register DSI_GNQ, set number |
4783 | * of data to 3 by default */ | ||
4784 | if (dss_has_feature(FEAT_DSI_GNQ)) | ||
4785 | /* NB_DATA_LANES */ | ||
4786 | dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9); | ||
4787 | else | ||
4788 | dsi->num_lanes_supported = 3; | ||
4775 | 4789 | ||
4776 | dsi_runtime_put(dsidev); | 4790 | dsi_runtime_put(dsidev); |
4777 | 4791 | ||
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 57a52eecee91..32ff69fb3333 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h | |||
@@ -163,6 +163,34 @@ struct bus_type *dss_get_bus(void); | |||
163 | struct regulator *dss_get_vdds_dsi(void); | 163 | struct regulator *dss_get_vdds_dsi(void); |
164 | struct regulator *dss_get_vdds_sdi(void); | 164 | struct regulator *dss_get_vdds_sdi(void); |
165 | 165 | ||
166 | /* apply */ | ||
167 | void dss_apply_init(void); | ||
168 | int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr); | ||
169 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); | ||
170 | void dss_mgr_start_update(struct omap_overlay_manager *mgr); | ||
171 | int omap_dss_mgr_apply(struct omap_overlay_manager *mgr); | ||
172 | |||
173 | int dss_mgr_enable(struct omap_overlay_manager *mgr); | ||
174 | void dss_mgr_disable(struct omap_overlay_manager *mgr); | ||
175 | int dss_mgr_set_info(struct omap_overlay_manager *mgr, | ||
176 | struct omap_overlay_manager_info *info); | ||
177 | void dss_mgr_get_info(struct omap_overlay_manager *mgr, | ||
178 | struct omap_overlay_manager_info *info); | ||
179 | int dss_mgr_set_device(struct omap_overlay_manager *mgr, | ||
180 | struct omap_dss_device *dssdev); | ||
181 | int dss_mgr_unset_device(struct omap_overlay_manager *mgr); | ||
182 | |||
183 | bool dss_ovl_is_enabled(struct omap_overlay *ovl); | ||
184 | int dss_ovl_enable(struct omap_overlay *ovl); | ||
185 | int dss_ovl_disable(struct omap_overlay *ovl); | ||
186 | int dss_ovl_set_info(struct omap_overlay *ovl, | ||
187 | struct omap_overlay_info *info); | ||
188 | void dss_ovl_get_info(struct omap_overlay *ovl, | ||
189 | struct omap_overlay_info *info); | ||
190 | int dss_ovl_set_manager(struct omap_overlay *ovl, | ||
191 | struct omap_overlay_manager *mgr); | ||
192 | int dss_ovl_unset_manager(struct omap_overlay *ovl); | ||
193 | |||
166 | /* display */ | 194 | /* display */ |
167 | int dss_suspend_all_devices(void); | 195 | int dss_suspend_all_devices(void); |
168 | int dss_resume_all_devices(void); | 196 | int dss_resume_all_devices(void); |
@@ -181,21 +209,22 @@ void default_get_overlay_fifo_thresholds(enum omap_plane plane, | |||
181 | /* manager */ | 209 | /* manager */ |
182 | int dss_init_overlay_managers(struct platform_device *pdev); | 210 | int dss_init_overlay_managers(struct platform_device *pdev); |
183 | void dss_uninit_overlay_managers(struct platform_device *pdev); | 211 | void dss_uninit_overlay_managers(struct platform_device *pdev); |
184 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); | 212 | int dss_mgr_simple_check(struct omap_overlay_manager *mgr, |
185 | void dss_setup_partial_planes(struct omap_dss_device *dssdev, | 213 | const struct omap_overlay_manager_info *info); |
186 | u16 *x, u16 *y, u16 *w, u16 *h, | 214 | int dss_mgr_check(struct omap_overlay_manager *mgr, |
187 | bool enlarge_update_area); | 215 | struct omap_dss_device *dssdev, |
188 | void dss_start_update(struct omap_dss_device *dssdev); | 216 | struct omap_overlay_manager_info *info, |
217 | struct omap_overlay_info **overlay_infos); | ||
189 | 218 | ||
190 | /* overlay */ | 219 | /* overlay */ |
191 | void dss_init_overlays(struct platform_device *pdev); | 220 | void dss_init_overlays(struct platform_device *pdev); |
192 | void dss_uninit_overlays(struct platform_device *pdev); | 221 | void dss_uninit_overlays(struct platform_device *pdev); |
193 | int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev); | ||
194 | void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); | 222 | void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); |
195 | #ifdef L4_EXAMPLE | ||
196 | void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr); | ||
197 | #endif | ||
198 | void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); | 223 | void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); |
224 | int dss_ovl_simple_check(struct omap_overlay *ovl, | ||
225 | const struct omap_overlay_info *info); | ||
226 | int dss_ovl_check(struct omap_overlay *ovl, | ||
227 | struct omap_overlay_info *info, struct omap_dss_device *dssdev); | ||
199 | 228 | ||
200 | /* DSS */ | 229 | /* DSS */ |
201 | int dss_init_platform_driver(void); | 230 | int dss_init_platform_driver(void); |
@@ -399,21 +428,22 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, | |||
399 | struct dispc_clock_info *cinfo); | 428 | struct dispc_clock_info *cinfo); |
400 | 429 | ||
401 | 430 | ||
431 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); | ||
402 | u32 dispc_ovl_get_fifo_size(enum omap_plane plane); | 432 | u32 dispc_ovl_get_fifo_size(enum omap_plane plane); |
403 | u32 dispc_ovl_get_burst_size(enum omap_plane plane); | 433 | u32 dispc_ovl_get_burst_size(enum omap_plane plane); |
404 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | 434 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, |
405 | bool ilace, enum omap_channel channel, bool replication, | 435 | bool ilace, bool replication); |
406 | u32 fifo_low, u32 fifo_high); | ||
407 | int dispc_ovl_enable(enum omap_plane plane, bool enable); | 436 | int dispc_ovl_enable(enum omap_plane plane, bool enable); |
408 | 437 | void dispc_ovl_set_channel_out(enum omap_plane plane, | |
438 | enum omap_channel channel); | ||
409 | 439 | ||
410 | void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable); | 440 | void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable); |
411 | void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height); | 441 | void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height); |
412 | void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable); | 442 | u32 dispc_mgr_get_vsync_irq(enum omap_channel channel); |
413 | void dispc_mgr_set_cpr_coef(enum omap_channel channel, | 443 | u32 dispc_mgr_get_framedone_irq(enum omap_channel channel); |
414 | struct omap_dss_cpr_coefs *coefs); | ||
415 | bool dispc_mgr_go_busy(enum omap_channel channel); | 444 | bool dispc_mgr_go_busy(enum omap_channel channel); |
416 | void dispc_mgr_go(enum omap_channel channel); | 445 | void dispc_mgr_go(enum omap_channel channel); |
446 | bool dispc_mgr_is_enabled(enum omap_channel channel); | ||
417 | void dispc_mgr_enable(enum omap_channel channel, bool enable); | 447 | void dispc_mgr_enable(enum omap_channel channel, bool enable); |
418 | bool dispc_mgr_is_channel_enabled(enum omap_channel channel); | 448 | bool dispc_mgr_is_channel_enabled(enum omap_channel channel); |
419 | void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode); | 449 | void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode); |
@@ -421,18 +451,6 @@ void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable); | |||
421 | void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines); | 451 | void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines); |
422 | void dispc_mgr_set_lcd_display_type(enum omap_channel channel, | 452 | void dispc_mgr_set_lcd_display_type(enum omap_channel channel, |
423 | enum omap_lcd_display_type type); | 453 | enum omap_lcd_display_type type); |
424 | void dispc_mgr_set_default_color(enum omap_channel channel, u32 color); | ||
425 | u32 dispc_mgr_get_default_color(enum omap_channel channel); | ||
426 | void dispc_mgr_set_trans_key(enum omap_channel ch, | ||
427 | enum omap_dss_trans_key_type type, | ||
428 | u32 trans_key); | ||
429 | void dispc_mgr_get_trans_key(enum omap_channel ch, | ||
430 | enum omap_dss_trans_key_type *type, | ||
431 | u32 *trans_key); | ||
432 | void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable); | ||
433 | void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable); | ||
434 | bool dispc_mgr_trans_key_enabled(enum omap_channel ch); | ||
435 | bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch); | ||
436 | void dispc_mgr_set_lcd_timings(enum omap_channel channel, | 454 | void dispc_mgr_set_lcd_timings(enum omap_channel channel, |
437 | struct omap_video_timings *timings); | 455 | struct omap_video_timings *timings); |
438 | void dispc_mgr_set_pol_freq(enum omap_channel channel, | 456 | void dispc_mgr_set_pol_freq(enum omap_channel channel, |
@@ -443,6 +461,8 @@ int dispc_mgr_set_clock_div(enum omap_channel channel, | |||
443 | struct dispc_clock_info *cinfo); | 461 | struct dispc_clock_info *cinfo); |
444 | int dispc_mgr_get_clock_div(enum omap_channel channel, | 462 | int dispc_mgr_get_clock_div(enum omap_channel channel, |
445 | struct dispc_clock_info *cinfo); | 463 | struct dispc_clock_info *cinfo); |
464 | void dispc_mgr_setup(enum omap_channel channel, | ||
465 | struct omap_overlay_manager_info *info); | ||
446 | 466 | ||
447 | /* VENC */ | 467 | /* VENC */ |
448 | #ifdef CONFIG_OMAP2_DSS_VENC | 468 | #ifdef CONFIG_OMAP2_DSS_VENC |
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index b402699168a5..afcb59301c37 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c | |||
@@ -304,6 +304,11 @@ static const struct dss_param_range omap2_dss_param_range[] = { | |||
304 | [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 }, | 304 | [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 }, |
305 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 }, | 305 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 }, |
306 | [FEAT_PARAM_DOWNSCALE] = { 1, 2 }, | 306 | [FEAT_PARAM_DOWNSCALE] = { 1, 2 }, |
307 | /* | ||
308 | * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC | ||
309 | * scaler cannot scale a image with width more than 768. | ||
310 | */ | ||
311 | [FEAT_PARAM_LINEWIDTH] = { 1, 768 }, | ||
307 | }; | 312 | }; |
308 | 313 | ||
309 | static const struct dss_param_range omap3_dss_param_range[] = { | 314 | static const struct dss_param_range omap3_dss_param_range[] = { |
@@ -316,6 +321,7 @@ static const struct dss_param_range omap3_dss_param_range[] = { | |||
316 | [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, | 321 | [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, |
317 | [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, | 322 | [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, |
318 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 323 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
324 | [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, | ||
319 | }; | 325 | }; |
320 | 326 | ||
321 | static const struct dss_param_range omap4_dss_param_range[] = { | 327 | static const struct dss_param_range omap4_dss_param_range[] = { |
@@ -328,6 +334,7 @@ static const struct dss_param_range omap4_dss_param_range[] = { | |||
328 | [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, | 334 | [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, |
329 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, | 335 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, |
330 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 336 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
337 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, | ||
331 | }; | 338 | }; |
332 | 339 | ||
333 | /* OMAP2 DSS Features */ | 340 | /* OMAP2 DSS Features */ |
@@ -465,6 +472,10 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { | |||
465 | .dump_core = ti_hdmi_4xxx_core_dump, | 472 | .dump_core = ti_hdmi_4xxx_core_dump, |
466 | .dump_pll = ti_hdmi_4xxx_pll_dump, | 473 | .dump_pll = ti_hdmi_4xxx_pll_dump, |
467 | .dump_phy = ti_hdmi_4xxx_phy_dump, | 474 | .dump_phy = ti_hdmi_4xxx_phy_dump, |
475 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
476 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
477 | .audio_enable = ti_hdmi_4xxx_wp_audio_enable, | ||
478 | #endif | ||
468 | 479 | ||
469 | }; | 480 | }; |
470 | 481 | ||
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 6a6c05dd45ce..cd833bbaac3d 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h | |||
@@ -86,6 +86,7 @@ enum dss_range_param { | |||
86 | FEAT_PARAM_DSIPLL_FINT, | 86 | FEAT_PARAM_DSIPLL_FINT, |
87 | FEAT_PARAM_DSIPLL_LPDIV, | 87 | FEAT_PARAM_DSIPLL_LPDIV, |
88 | FEAT_PARAM_DOWNSCALE, | 88 | FEAT_PARAM_DOWNSCALE, |
89 | FEAT_PARAM_LINEWIDTH, | ||
89 | }; | 90 | }; |
90 | 91 | ||
91 | /* DSS Feature Functions */ | 92 | /* DSS Feature Functions */ |
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index c56378c555b0..b4c270edb915 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c | |||
@@ -333,7 +333,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
333 | if (r) | 333 | if (r) |
334 | return r; | 334 | return r; |
335 | 335 | ||
336 | dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0); | 336 | dss_mgr_disable(dssdev->manager); |
337 | 337 | ||
338 | p = &dssdev->panel.timings; | 338 | p = &dssdev->panel.timings; |
339 | 339 | ||
@@ -387,9 +387,16 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
387 | 387 | ||
388 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1); | 388 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1); |
389 | 389 | ||
390 | dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 1); | 390 | r = dss_mgr_enable(dssdev->manager); |
391 | if (r) | ||
392 | goto err_mgr_enable; | ||
391 | 393 | ||
392 | return 0; | 394 | return 0; |
395 | |||
396 | err_mgr_enable: | ||
397 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); | ||
398 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | ||
399 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | ||
393 | err: | 400 | err: |
394 | hdmi_runtime_put(); | 401 | hdmi_runtime_put(); |
395 | return -EIO; | 402 | return -EIO; |
@@ -397,7 +404,7 @@ err: | |||
397 | 404 | ||
398 | static void hdmi_power_off(struct omap_dss_device *dssdev) | 405 | static void hdmi_power_off(struct omap_dss_device *dssdev) |
399 | { | 406 | { |
400 | dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0); | 407 | dss_mgr_disable(dssdev->manager); |
401 | 408 | ||
402 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); | 409 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); |
403 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | 410 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); |
@@ -554,11 +561,44 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) | |||
554 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 561 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ |
555 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | 562 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) |
556 | 563 | ||
557 | static int hdmi_audio_hw_params(struct hdmi_ip_data *ip_data, | 564 | static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, |
558 | struct snd_pcm_substream *substream, | 565 | struct snd_soc_dai *dai) |
566 | { | ||
567 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
568 | struct snd_soc_codec *codec = rtd->codec; | ||
569 | struct platform_device *pdev = to_platform_device(codec->dev); | ||
570 | struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec); | ||
571 | int err = 0; | ||
572 | |||
573 | if (!(ip_data->ops) && !(ip_data->ops->audio_enable)) { | ||
574 | dev_err(&pdev->dev, "Cannot enable/disable audio\n"); | ||
575 | return -ENODEV; | ||
576 | } | ||
577 | |||
578 | switch (cmd) { | ||
579 | case SNDRV_PCM_TRIGGER_START: | ||
580 | case SNDRV_PCM_TRIGGER_RESUME: | ||
581 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
582 | ip_data->ops->audio_enable(ip_data, true); | ||
583 | break; | ||
584 | case SNDRV_PCM_TRIGGER_STOP: | ||
585 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
586 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
587 | ip_data->ops->audio_enable(ip_data, false); | ||
588 | break; | ||
589 | default: | ||
590 | err = -EINVAL; | ||
591 | } | ||
592 | return err; | ||
593 | } | ||
594 | |||
595 | static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, | ||
559 | struct snd_pcm_hw_params *params, | 596 | struct snd_pcm_hw_params *params, |
560 | struct snd_soc_dai *dai) | 597 | struct snd_soc_dai *dai) |
561 | { | 598 | { |
599 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
600 | struct snd_soc_codec *codec = rtd->codec; | ||
601 | struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec); | ||
562 | struct hdmi_audio_format audio_format; | 602 | struct hdmi_audio_format audio_format; |
563 | struct hdmi_audio_dma audio_dma; | 603 | struct hdmi_audio_dma audio_dma; |
564 | struct hdmi_core_audio_config core_cfg; | 604 | struct hdmi_core_audio_config core_cfg; |
@@ -698,7 +738,16 @@ static int hdmi_audio_startup(struct snd_pcm_substream *substream, | |||
698 | return 0; | 738 | return 0; |
699 | } | 739 | } |
700 | 740 | ||
741 | static int hdmi_audio_codec_probe(struct snd_soc_codec *codec) | ||
742 | { | ||
743 | struct hdmi_ip_data *priv = &hdmi.ip_data; | ||
744 | |||
745 | snd_soc_codec_set_drvdata(codec, priv); | ||
746 | return 0; | ||
747 | } | ||
748 | |||
701 | static struct snd_soc_codec_driver hdmi_audio_codec_drv = { | 749 | static struct snd_soc_codec_driver hdmi_audio_codec_drv = { |
750 | .probe = hdmi_audio_codec_probe, | ||
702 | }; | 751 | }; |
703 | 752 | ||
704 | static struct snd_soc_dai_ops hdmi_audio_codec_ops = { | 753 | static struct snd_soc_dai_ops hdmi_audio_codec_ops = { |
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 6e63845cc7d7..d1858e71c64e 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c | |||
@@ -26,17 +26,15 @@ | |||
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/jiffies.h> | 29 | #include <linux/jiffies.h> |
31 | 30 | ||
32 | #include <video/omapdss.h> | 31 | #include <video/omapdss.h> |
33 | #include <plat/cpu.h> | ||
34 | 32 | ||
35 | #include "dss.h" | 33 | #include "dss.h" |
36 | #include "dss_features.h" | 34 | #include "dss_features.h" |
37 | 35 | ||
38 | static int num_managers; | 36 | static int num_managers; |
39 | static struct list_head manager_list; | 37 | static struct omap_overlay_manager *managers; |
40 | 38 | ||
41 | static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) | 39 | static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) |
42 | { | 40 | { |
@@ -106,7 +104,11 @@ put_device: | |||
106 | static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, | 104 | static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, |
107 | char *buf) | 105 | char *buf) |
108 | { | 106 | { |
109 | return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.default_color); | 107 | struct omap_overlay_manager_info info; |
108 | |||
109 | mgr->get_manager_info(mgr, &info); | ||
110 | |||
111 | return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); | ||
110 | } | 112 | } |
111 | 113 | ||
112 | static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, | 114 | static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, |
@@ -144,8 +146,11 @@ static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, | |||
144 | char *buf) | 146 | char *buf) |
145 | { | 147 | { |
146 | enum omap_dss_trans_key_type key_type; | 148 | enum omap_dss_trans_key_type key_type; |
149 | struct omap_overlay_manager_info info; | ||
150 | |||
151 | mgr->get_manager_info(mgr, &info); | ||
147 | 152 | ||
148 | key_type = mgr->info.trans_key_type; | 153 | key_type = info.trans_key_type; |
149 | BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); | 154 | BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); |
150 | 155 | ||
151 | return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); | 156 | return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); |
@@ -185,7 +190,11 @@ static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, | |||
185 | static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, | 190 | static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, |
186 | char *buf) | 191 | char *buf) |
187 | { | 192 | { |
188 | return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.trans_key); | 193 | struct omap_overlay_manager_info info; |
194 | |||
195 | mgr->get_manager_info(mgr, &info); | ||
196 | |||
197 | return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); | ||
189 | } | 198 | } |
190 | 199 | ||
191 | static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, | 200 | static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, |
@@ -217,7 +226,11 @@ static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, | |||
217 | static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, | 226 | static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, |
218 | char *buf) | 227 | char *buf) |
219 | { | 228 | { |
220 | return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled); | 229 | struct omap_overlay_manager_info info; |
230 | |||
231 | mgr->get_manager_info(mgr, &info); | ||
232 | |||
233 | return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); | ||
221 | } | 234 | } |
222 | 235 | ||
223 | static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, | 236 | static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, |
@@ -249,10 +262,14 @@ static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, | |||
249 | static ssize_t manager_alpha_blending_enabled_show( | 262 | static ssize_t manager_alpha_blending_enabled_show( |
250 | struct omap_overlay_manager *mgr, char *buf) | 263 | struct omap_overlay_manager *mgr, char *buf) |
251 | { | 264 | { |
265 | struct omap_overlay_manager_info info; | ||
266 | |||
267 | mgr->get_manager_info(mgr, &info); | ||
268 | |||
252 | WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); | 269 | WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); |
253 | 270 | ||
254 | return snprintf(buf, PAGE_SIZE, "%d\n", | 271 | return snprintf(buf, PAGE_SIZE, "%d\n", |
255 | mgr->info.partial_alpha_enabled); | 272 | info.partial_alpha_enabled); |
256 | } | 273 | } |
257 | 274 | ||
258 | static ssize_t manager_alpha_blending_enabled_store( | 275 | static ssize_t manager_alpha_blending_enabled_store( |
@@ -287,7 +304,11 @@ static ssize_t manager_alpha_blending_enabled_store( | |||
287 | static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, | 304 | static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, |
288 | char *buf) | 305 | char *buf) |
289 | { | 306 | { |
290 | return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.cpr_enable); | 307 | struct omap_overlay_manager_info info; |
308 | |||
309 | mgr->get_manager_info(mgr, &info); | ||
310 | |||
311 | return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); | ||
291 | } | 312 | } |
292 | 313 | ||
293 | static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, | 314 | static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, |
@@ -469,143 +490,6 @@ static struct kobj_type manager_ktype = { | |||
469 | .default_attrs = manager_sysfs_attrs, | 490 | .default_attrs = manager_sysfs_attrs, |
470 | }; | 491 | }; |
471 | 492 | ||
472 | /* | ||
473 | * We have 4 levels of cache for the dispc settings. First two are in SW and | ||
474 | * the latter two in HW. | ||
475 | * | ||
476 | * +--------------------+ | ||
477 | * |overlay/manager_info| | ||
478 | * +--------------------+ | ||
479 | * v | ||
480 | * apply() | ||
481 | * v | ||
482 | * +--------------------+ | ||
483 | * | dss_cache | | ||
484 | * +--------------------+ | ||
485 | * v | ||
486 | * configure() | ||
487 | * v | ||
488 | * +--------------------+ | ||
489 | * | shadow registers | | ||
490 | * +--------------------+ | ||
491 | * v | ||
492 | * VFP or lcd/digit_enable | ||
493 | * v | ||
494 | * +--------------------+ | ||
495 | * | registers | | ||
496 | * +--------------------+ | ||
497 | */ | ||
498 | |||
499 | struct overlay_cache_data { | ||
500 | /* If true, cache changed, but not written to shadow registers. Set | ||
501 | * in apply(), cleared when registers written. */ | ||
502 | bool dirty; | ||
503 | /* If true, shadow registers contain changed values not yet in real | ||
504 | * registers. Set when writing to shadow registers, cleared at | ||
505 | * VSYNC/EVSYNC */ | ||
506 | bool shadow_dirty; | ||
507 | |||
508 | bool enabled; | ||
509 | |||
510 | struct omap_overlay_info info; | ||
511 | |||
512 | enum omap_channel channel; | ||
513 | bool replication; | ||
514 | bool ilace; | ||
515 | |||
516 | u32 fifo_low; | ||
517 | u32 fifo_high; | ||
518 | }; | ||
519 | |||
520 | struct manager_cache_data { | ||
521 | /* If true, cache changed, but not written to shadow registers. Set | ||
522 | * in apply(), cleared when registers written. */ | ||
523 | bool dirty; | ||
524 | /* If true, shadow registers contain changed values not yet in real | ||
525 | * registers. Set when writing to shadow registers, cleared at | ||
526 | * VSYNC/EVSYNC */ | ||
527 | bool shadow_dirty; | ||
528 | |||
529 | struct omap_overlay_manager_info info; | ||
530 | |||
531 | bool manual_update; | ||
532 | bool do_manual_update; | ||
533 | |||
534 | /* manual update region */ | ||
535 | u16 x, y, w, h; | ||
536 | |||
537 | /* enlarge the update area if the update area contains scaled | ||
538 | * overlays */ | ||
539 | bool enlarge_update_area; | ||
540 | }; | ||
541 | |||
542 | static struct { | ||
543 | spinlock_t lock; | ||
544 | struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS]; | ||
545 | struct manager_cache_data manager_cache[MAX_DSS_MANAGERS]; | ||
546 | |||
547 | bool irq_enabled; | ||
548 | } dss_cache; | ||
549 | |||
550 | |||
551 | |||
552 | static int omap_dss_set_device(struct omap_overlay_manager *mgr, | ||
553 | struct omap_dss_device *dssdev) | ||
554 | { | ||
555 | int i; | ||
556 | int r; | ||
557 | |||
558 | if (dssdev->manager) { | ||
559 | DSSERR("display '%s' already has a manager '%s'\n", | ||
560 | dssdev->name, dssdev->manager->name); | ||
561 | return -EINVAL; | ||
562 | } | ||
563 | |||
564 | if ((mgr->supported_displays & dssdev->type) == 0) { | ||
565 | DSSERR("display '%s' does not support manager '%s'\n", | ||
566 | dssdev->name, mgr->name); | ||
567 | return -EINVAL; | ||
568 | } | ||
569 | |||
570 | for (i = 0; i < mgr->num_overlays; i++) { | ||
571 | struct omap_overlay *ovl = mgr->overlays[i]; | ||
572 | |||
573 | if (ovl->manager != mgr || !ovl->info.enabled) | ||
574 | continue; | ||
575 | |||
576 | r = dss_check_overlay(ovl, dssdev); | ||
577 | if (r) | ||
578 | return r; | ||
579 | } | ||
580 | |||
581 | dssdev->manager = mgr; | ||
582 | mgr->device = dssdev; | ||
583 | mgr->device_changed = true; | ||
584 | |||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | static int omap_dss_unset_device(struct omap_overlay_manager *mgr) | ||
589 | { | ||
590 | if (!mgr->device) { | ||
591 | DSSERR("failed to unset display, display not set.\n"); | ||
592 | return -EINVAL; | ||
593 | } | ||
594 | |||
595 | /* | ||
596 | * Don't allow currently enabled displays to have the overlay manager | ||
597 | * pulled out from underneath them | ||
598 | */ | ||
599 | if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) | ||
600 | return -EINVAL; | ||
601 | |||
602 | mgr->device->manager = NULL; | ||
603 | mgr->device = NULL; | ||
604 | mgr->device_changed = true; | ||
605 | |||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | 493 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) |
610 | { | 494 | { |
611 | unsigned long timeout = msecs_to_jiffies(500); | 495 | unsigned long timeout = msecs_to_jiffies(500); |
@@ -624,1022 +508,169 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | |||
624 | return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | 508 | return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); |
625 | } | 509 | } |
626 | 510 | ||
627 | static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | 511 | int dss_init_overlay_managers(struct platform_device *pdev) |
628 | { | ||
629 | unsigned long timeout = msecs_to_jiffies(500); | ||
630 | struct manager_cache_data *mc; | ||
631 | u32 irq; | ||
632 | int r; | ||
633 | int i; | ||
634 | struct omap_dss_device *dssdev = mgr->device; | ||
635 | |||
636 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
637 | return 0; | ||
638 | |||
639 | if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) | ||
640 | return 0; | ||
641 | |||
642 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC | ||
643 | || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { | ||
644 | irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; | ||
645 | } else { | ||
646 | irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? | ||
647 | DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; | ||
648 | } | ||
649 | |||
650 | mc = &dss_cache.manager_cache[mgr->id]; | ||
651 | i = 0; | ||
652 | while (1) { | ||
653 | unsigned long flags; | ||
654 | bool shadow_dirty, dirty; | ||
655 | |||
656 | spin_lock_irqsave(&dss_cache.lock, flags); | ||
657 | dirty = mc->dirty; | ||
658 | shadow_dirty = mc->shadow_dirty; | ||
659 | spin_unlock_irqrestore(&dss_cache.lock, flags); | ||
660 | |||
661 | if (!dirty && !shadow_dirty) { | ||
662 | r = 0; | ||
663 | break; | ||
664 | } | ||
665 | |||
666 | /* 4 iterations is the worst case: | ||
667 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | ||
668 | * 2 - first VSYNC, dirty = true | ||
669 | * 3 - dirty = false, shadow_dirty = true | ||
670 | * 4 - shadow_dirty = false */ | ||
671 | if (i++ == 3) { | ||
672 | DSSERR("mgr(%d)->wait_for_go() not finishing\n", | ||
673 | mgr->id); | ||
674 | r = 0; | ||
675 | break; | ||
676 | } | ||
677 | |||
678 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
679 | if (r == -ERESTARTSYS) | ||
680 | break; | ||
681 | |||
682 | if (r) { | ||
683 | DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); | ||
684 | break; | ||
685 | } | ||
686 | } | ||
687 | |||
688 | return r; | ||
689 | } | ||
690 | |||
691 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) | ||
692 | { | ||
693 | unsigned long timeout = msecs_to_jiffies(500); | ||
694 | struct overlay_cache_data *oc; | ||
695 | struct omap_dss_device *dssdev; | ||
696 | u32 irq; | ||
697 | int r; | ||
698 | int i; | ||
699 | |||
700 | if (!ovl->manager) | ||
701 | return 0; | ||
702 | |||
703 | dssdev = ovl->manager->device; | ||
704 | |||
705 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
706 | return 0; | ||
707 | |||
708 | if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) | ||
709 | return 0; | ||
710 | |||
711 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC | ||
712 | || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { | ||
713 | irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; | ||
714 | } else { | ||
715 | irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? | ||
716 | DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; | ||
717 | } | ||
718 | |||
719 | oc = &dss_cache.overlay_cache[ovl->id]; | ||
720 | i = 0; | ||
721 | while (1) { | ||
722 | unsigned long flags; | ||
723 | bool shadow_dirty, dirty; | ||
724 | |||
725 | spin_lock_irqsave(&dss_cache.lock, flags); | ||
726 | dirty = oc->dirty; | ||
727 | shadow_dirty = oc->shadow_dirty; | ||
728 | spin_unlock_irqrestore(&dss_cache.lock, flags); | ||
729 | |||
730 | if (!dirty && !shadow_dirty) { | ||
731 | r = 0; | ||
732 | break; | ||
733 | } | ||
734 | |||
735 | /* 4 iterations is the worst case: | ||
736 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | ||
737 | * 2 - first VSYNC, dirty = true | ||
738 | * 3 - dirty = false, shadow_dirty = true | ||
739 | * 4 - shadow_dirty = false */ | ||
740 | if (i++ == 3) { | ||
741 | DSSERR("ovl(%d)->wait_for_go() not finishing\n", | ||
742 | ovl->id); | ||
743 | r = 0; | ||
744 | break; | ||
745 | } | ||
746 | |||
747 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
748 | if (r == -ERESTARTSYS) | ||
749 | break; | ||
750 | |||
751 | if (r) { | ||
752 | DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); | ||
753 | break; | ||
754 | } | ||
755 | } | ||
756 | |||
757 | return r; | ||
758 | } | ||
759 | |||
760 | static int overlay_enabled(struct omap_overlay *ovl) | ||
761 | { | ||
762 | return ovl->info.enabled && ovl->manager && ovl->manager->device; | ||
763 | } | ||
764 | |||
765 | /* Is rect1 a subset of rect2? */ | ||
766 | static bool rectangle_subset(int x1, int y1, int w1, int h1, | ||
767 | int x2, int y2, int w2, int h2) | ||
768 | { | ||
769 | if (x1 < x2 || y1 < y2) | ||
770 | return false; | ||
771 | |||
772 | if (x1 + w1 > x2 + w2) | ||
773 | return false; | ||
774 | |||
775 | if (y1 + h1 > y2 + h2) | ||
776 | return false; | ||
777 | |||
778 | return true; | ||
779 | } | ||
780 | |||
781 | /* Do rect1 and rect2 overlap? */ | ||
782 | static bool rectangle_intersects(int x1, int y1, int w1, int h1, | ||
783 | int x2, int y2, int w2, int h2) | ||
784 | { | ||
785 | if (x1 >= x2 + w2) | ||
786 | return false; | ||
787 | |||
788 | if (x2 >= x1 + w1) | ||
789 | return false; | ||
790 | |||
791 | if (y1 >= y2 + h2) | ||
792 | return false; | ||
793 | |||
794 | if (y2 >= y1 + h1) | ||
795 | return false; | ||
796 | |||
797 | return true; | ||
798 | } | ||
799 | |||
800 | static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc) | ||
801 | { | ||
802 | struct omap_overlay_info *oi = &oc->info; | ||
803 | |||
804 | if (oi->out_width != 0 && oi->width != oi->out_width) | ||
805 | return true; | ||
806 | |||
807 | if (oi->out_height != 0 && oi->height != oi->out_height) | ||
808 | return true; | ||
809 | |||
810 | return false; | ||
811 | } | ||
812 | |||
813 | static int configure_overlay(enum omap_plane plane) | ||
814 | { | 512 | { |
815 | struct overlay_cache_data *c; | 513 | int i, r; |
816 | struct manager_cache_data *mc; | ||
817 | struct omap_overlay_info *oi, new_oi; | ||
818 | struct omap_overlay_manager_info *mi; | ||
819 | u16 outw, outh; | ||
820 | u16 x, y, w, h; | ||
821 | u32 paddr; | ||
822 | int r; | ||
823 | u16 orig_w, orig_h, orig_outw, orig_outh; | ||
824 | 514 | ||
825 | DSSDBGF("%d", plane); | 515 | num_managers = dss_feat_get_num_mgrs(); |
826 | 516 | ||
827 | c = &dss_cache.overlay_cache[plane]; | 517 | managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers, |
828 | oi = &c->info; | 518 | GFP_KERNEL); |
829 | 519 | ||
830 | if (!c->enabled) { | 520 | BUG_ON(managers == NULL); |
831 | dispc_ovl_enable(plane, 0); | ||
832 | return 0; | ||
833 | } | ||
834 | 521 | ||
835 | mc = &dss_cache.manager_cache[c->channel]; | 522 | for (i = 0; i < num_managers; ++i) { |
836 | mi = &mc->info; | 523 | struct omap_overlay_manager *mgr = &managers[i]; |
837 | |||
838 | x = oi->pos_x; | ||
839 | y = oi->pos_y; | ||
840 | w = oi->width; | ||
841 | h = oi->height; | ||
842 | outw = oi->out_width == 0 ? oi->width : oi->out_width; | ||
843 | outh = oi->out_height == 0 ? oi->height : oi->out_height; | ||
844 | paddr = oi->paddr; | ||
845 | |||
846 | orig_w = w; | ||
847 | orig_h = h; | ||
848 | orig_outw = outw; | ||
849 | orig_outh = outh; | ||
850 | |||
851 | if (mc->manual_update && mc->do_manual_update) { | ||
852 | unsigned bpp; | ||
853 | unsigned scale_x_m = w, scale_x_d = outw; | ||
854 | unsigned scale_y_m = h, scale_y_d = outh; | ||
855 | |||
856 | /* If the overlay is outside the update region, disable it */ | ||
857 | if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h, | ||
858 | x, y, outw, outh)) { | ||
859 | dispc_ovl_enable(plane, 0); | ||
860 | return 0; | ||
861 | } | ||
862 | 524 | ||
863 | switch (oi->color_mode) { | 525 | switch (i) { |
864 | case OMAP_DSS_COLOR_NV12: | 526 | case 0: |
865 | bpp = 8; | 527 | mgr->name = "lcd"; |
866 | break; | 528 | mgr->id = OMAP_DSS_CHANNEL_LCD; |
867 | case OMAP_DSS_COLOR_RGB16: | ||
868 | case OMAP_DSS_COLOR_ARGB16: | ||
869 | case OMAP_DSS_COLOR_YUV2: | ||
870 | case OMAP_DSS_COLOR_UYVY: | ||
871 | case OMAP_DSS_COLOR_RGBA16: | ||
872 | case OMAP_DSS_COLOR_RGBX16: | ||
873 | case OMAP_DSS_COLOR_ARGB16_1555: | ||
874 | case OMAP_DSS_COLOR_XRGB16_1555: | ||
875 | bpp = 16; | ||
876 | break; | 529 | break; |
877 | 530 | case 1: | |
878 | case OMAP_DSS_COLOR_RGB24P: | 531 | mgr->name = "tv"; |
879 | bpp = 24; | 532 | mgr->id = OMAP_DSS_CHANNEL_DIGIT; |
880 | break; | 533 | break; |
881 | 534 | case 2: | |
882 | case OMAP_DSS_COLOR_RGB24U: | 535 | mgr->name = "lcd2"; |
883 | case OMAP_DSS_COLOR_ARGB32: | 536 | mgr->id = OMAP_DSS_CHANNEL_LCD2; |
884 | case OMAP_DSS_COLOR_RGBA32: | ||
885 | case OMAP_DSS_COLOR_RGBX32: | ||
886 | bpp = 32; | ||
887 | break; | 537 | break; |
888 | |||
889 | default: | ||
890 | BUG(); | ||
891 | } | 538 | } |
892 | 539 | ||
893 | if (mc->x > oi->pos_x) { | 540 | mgr->set_device = &dss_mgr_set_device; |
894 | x = 0; | 541 | mgr->unset_device = &dss_mgr_unset_device; |
895 | outw -= (mc->x - oi->pos_x); | 542 | mgr->apply = &omap_dss_mgr_apply; |
896 | paddr += (mc->x - oi->pos_x) * | 543 | mgr->set_manager_info = &dss_mgr_set_info; |
897 | scale_x_m / scale_x_d * bpp / 8; | 544 | mgr->get_manager_info = &dss_mgr_get_info; |
898 | } else { | 545 | mgr->wait_for_go = &dss_mgr_wait_for_go; |
899 | x = oi->pos_x - mc->x; | 546 | mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; |
900 | } | ||
901 | |||
902 | if (mc->y > oi->pos_y) { | ||
903 | y = 0; | ||
904 | outh -= (mc->y - oi->pos_y); | ||
905 | paddr += (mc->y - oi->pos_y) * | ||
906 | scale_y_m / scale_y_d * | ||
907 | oi->screen_width * bpp / 8; | ||
908 | } else { | ||
909 | y = oi->pos_y - mc->y; | ||
910 | } | ||
911 | |||
912 | if (mc->w < (x + outw)) | ||
913 | outw -= (x + outw) - (mc->w); | ||
914 | |||
915 | if (mc->h < (y + outh)) | ||
916 | outh -= (y + outh) - (mc->h); | ||
917 | |||
918 | w = w * outw / orig_outw; | ||
919 | h = h * outh / orig_outh; | ||
920 | |||
921 | /* YUV mode overlay's input width has to be even and the | ||
922 | * algorithm above may adjust the width to be odd. | ||
923 | * | ||
924 | * Here we adjust the width if needed, preferring to increase | ||
925 | * the width if the original width was bigger. | ||
926 | */ | ||
927 | if ((w & 1) && | ||
928 | (oi->color_mode == OMAP_DSS_COLOR_YUV2 || | ||
929 | oi->color_mode == OMAP_DSS_COLOR_UYVY)) { | ||
930 | if (orig_w > w) | ||
931 | w += 1; | ||
932 | else | ||
933 | w -= 1; | ||
934 | } | ||
935 | } | ||
936 | |||
937 | new_oi = *oi; | ||
938 | |||
939 | /* update new_oi members which could have been possibly updated */ | ||
940 | new_oi.pos_x = x; | ||
941 | new_oi.pos_y = y; | ||
942 | new_oi.width = w; | ||
943 | new_oi.height = h; | ||
944 | new_oi.out_width = outw; | ||
945 | new_oi.out_height = outh; | ||
946 | new_oi.paddr = paddr; | ||
947 | |||
948 | r = dispc_ovl_setup(plane, &new_oi, c->ilace, c->channel, | ||
949 | c->replication, c->fifo_low, c->fifo_high); | ||
950 | if (r) { | ||
951 | /* this shouldn't happen */ | ||
952 | DSSERR("dispc_ovl_setup failed for ovl %d\n", plane); | ||
953 | dispc_ovl_enable(plane, 0); | ||
954 | return r; | ||
955 | } | ||
956 | |||
957 | dispc_ovl_enable(plane, 1); | ||
958 | |||
959 | return 0; | ||
960 | } | ||
961 | |||
962 | static void configure_manager(enum omap_channel channel) | ||
963 | { | ||
964 | struct omap_overlay_manager_info *mi; | ||
965 | |||
966 | DSSDBGF("%d", channel); | ||
967 | |||
968 | /* picking info from the cache */ | ||
969 | mi = &dss_cache.manager_cache[channel].info; | ||
970 | |||
971 | dispc_mgr_set_default_color(channel, mi->default_color); | ||
972 | dispc_mgr_set_trans_key(channel, mi->trans_key_type, mi->trans_key); | ||
973 | dispc_mgr_enable_trans_key(channel, mi->trans_enabled); | ||
974 | dispc_mgr_enable_alpha_fixed_zorder(channel, mi->partial_alpha_enabled); | ||
975 | if (dss_has_feature(FEAT_CPR)) { | ||
976 | dispc_mgr_enable_cpr(channel, mi->cpr_enable); | ||
977 | dispc_mgr_set_cpr_coef(channel, &mi->cpr_coefs); | ||
978 | } | ||
979 | } | ||
980 | |||
981 | /* configure_dispc() tries to write values from cache to shadow registers. | ||
982 | * It writes only to those managers/overlays that are not busy. | ||
983 | * returns 0 if everything could be written to shadow registers. | ||
984 | * returns 1 if not everything could be written to shadow registers. */ | ||
985 | static int configure_dispc(void) | ||
986 | { | ||
987 | struct overlay_cache_data *oc; | ||
988 | struct manager_cache_data *mc; | ||
989 | const int num_ovls = dss_feat_get_num_ovls(); | ||
990 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
991 | int i; | ||
992 | int r; | ||
993 | bool mgr_busy[MAX_DSS_MANAGERS]; | ||
994 | bool mgr_go[MAX_DSS_MANAGERS]; | ||
995 | bool busy; | ||
996 | |||
997 | r = 0; | ||
998 | busy = false; | ||
999 | |||
1000 | for (i = 0; i < num_mgrs; i++) { | ||
1001 | mgr_busy[i] = dispc_mgr_go_busy(i); | ||
1002 | mgr_go[i] = false; | ||
1003 | } | ||
1004 | |||
1005 | /* Commit overlay settings */ | ||
1006 | for (i = 0; i < num_ovls; ++i) { | ||
1007 | oc = &dss_cache.overlay_cache[i]; | ||
1008 | mc = &dss_cache.manager_cache[oc->channel]; | ||
1009 | 547 | ||
1010 | if (!oc->dirty) | 548 | mgr->caps = 0; |
1011 | continue; | 549 | mgr->supported_displays = |
550 | dss_feat_get_supported_displays(mgr->id); | ||
1012 | 551 | ||
1013 | if (mc->manual_update && !mc->do_manual_update) | 552 | INIT_LIST_HEAD(&mgr->overlays); |
1014 | continue; | ||
1015 | 553 | ||
1016 | if (mgr_busy[oc->channel]) { | 554 | r = kobject_init_and_add(&mgr->kobj, &manager_ktype, |
1017 | busy = true; | 555 | &pdev->dev.kobj, "manager%d", i); |
1018 | continue; | ||
1019 | } | ||
1020 | 556 | ||
1021 | r = configure_overlay(i); | ||
1022 | if (r) | 557 | if (r) |
1023 | DSSERR("configure_overlay %d failed\n", i); | 558 | DSSERR("failed to create sysfs file\n"); |
1024 | |||
1025 | oc->dirty = false; | ||
1026 | oc->shadow_dirty = true; | ||
1027 | mgr_go[oc->channel] = true; | ||
1028 | } | ||
1029 | |||
1030 | /* Commit manager settings */ | ||
1031 | for (i = 0; i < num_mgrs; ++i) { | ||
1032 | mc = &dss_cache.manager_cache[i]; | ||
1033 | |||
1034 | if (!mc->dirty) | ||
1035 | continue; | ||
1036 | |||
1037 | if (mc->manual_update && !mc->do_manual_update) | ||
1038 | continue; | ||
1039 | |||
1040 | if (mgr_busy[i]) { | ||
1041 | busy = true; | ||
1042 | continue; | ||
1043 | } | ||
1044 | |||
1045 | configure_manager(i); | ||
1046 | mc->dirty = false; | ||
1047 | mc->shadow_dirty = true; | ||
1048 | mgr_go[i] = true; | ||
1049 | } | ||
1050 | |||
1051 | /* set GO */ | ||
1052 | for (i = 0; i < num_mgrs; ++i) { | ||
1053 | mc = &dss_cache.manager_cache[i]; | ||
1054 | |||
1055 | if (!mgr_go[i]) | ||
1056 | continue; | ||
1057 | |||
1058 | /* We don't need GO with manual update display. LCD iface will | ||
1059 | * always be turned off after frame, and new settings will be | ||
1060 | * taken in to use at next update */ | ||
1061 | if (!mc->manual_update) | ||
1062 | dispc_mgr_go(i); | ||
1063 | } | ||
1064 | |||
1065 | if (busy) | ||
1066 | r = 1; | ||
1067 | else | ||
1068 | r = 0; | ||
1069 | |||
1070 | return r; | ||
1071 | } | ||
1072 | |||
1073 | /* Make the coordinates even. There are some strange problems with OMAP and | ||
1074 | * partial DSI update when the update widths are odd. */ | ||
1075 | static void make_even(u16 *x, u16 *w) | ||
1076 | { | ||
1077 | u16 x1, x2; | ||
1078 | |||
1079 | x1 = *x; | ||
1080 | x2 = *x + *w; | ||
1081 | |||
1082 | x1 &= ~1; | ||
1083 | x2 = ALIGN(x2, 2); | ||
1084 | |||
1085 | *x = x1; | ||
1086 | *w = x2 - x1; | ||
1087 | } | ||
1088 | |||
1089 | /* Configure dispc for partial update. Return possibly modified update | ||
1090 | * area */ | ||
1091 | void dss_setup_partial_planes(struct omap_dss_device *dssdev, | ||
1092 | u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area) | ||
1093 | { | ||
1094 | struct overlay_cache_data *oc; | ||
1095 | struct manager_cache_data *mc; | ||
1096 | struct omap_overlay_info *oi; | ||
1097 | const int num_ovls = dss_feat_get_num_ovls(); | ||
1098 | struct omap_overlay_manager *mgr; | ||
1099 | int i; | ||
1100 | u16 x, y, w, h; | ||
1101 | unsigned long flags; | ||
1102 | bool area_changed; | ||
1103 | |||
1104 | x = *xi; | ||
1105 | y = *yi; | ||
1106 | w = *wi; | ||
1107 | h = *hi; | ||
1108 | |||
1109 | DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n", | ||
1110 | *xi, *yi, *wi, *hi); | ||
1111 | |||
1112 | mgr = dssdev->manager; | ||
1113 | |||
1114 | if (!mgr) { | ||
1115 | DSSDBG("no manager\n"); | ||
1116 | return; | ||
1117 | } | 559 | } |
1118 | 560 | ||
1119 | make_even(&x, &w); | 561 | return 0; |
1120 | |||
1121 | spin_lock_irqsave(&dss_cache.lock, flags); | ||
1122 | |||
1123 | /* | ||
1124 | * Execute the outer loop until the inner loop has completed | ||
1125 | * once without increasing the update area. This will ensure that | ||
1126 | * all scaled overlays end up completely within the update area. | ||
1127 | */ | ||
1128 | do { | ||
1129 | area_changed = false; | ||
1130 | |||
1131 | /* We need to show the whole overlay if it is scaled. So look | ||
1132 | * for those, and make the update area larger if found. | ||
1133 | * Also mark the overlay cache dirty */ | ||
1134 | for (i = 0; i < num_ovls; ++i) { | ||
1135 | unsigned x1, y1, x2, y2; | ||
1136 | unsigned outw, outh; | ||
1137 | |||
1138 | oc = &dss_cache.overlay_cache[i]; | ||
1139 | oi = &oc->info; | ||
1140 | |||
1141 | if (oc->channel != mgr->id) | ||
1142 | continue; | ||
1143 | |||
1144 | oc->dirty = true; | ||
1145 | |||
1146 | if (!enlarge_update_area) | ||
1147 | continue; | ||
1148 | |||
1149 | if (!oc->enabled) | ||
1150 | continue; | ||
1151 | |||
1152 | if (!dispc_is_overlay_scaled(oc)) | ||
1153 | continue; | ||
1154 | |||
1155 | outw = oi->out_width == 0 ? | ||
1156 | oi->width : oi->out_width; | ||
1157 | outh = oi->out_height == 0 ? | ||
1158 | oi->height : oi->out_height; | ||
1159 | |||
1160 | /* is the overlay outside the update region? */ | ||
1161 | if (!rectangle_intersects(x, y, w, h, | ||
1162 | oi->pos_x, oi->pos_y, | ||
1163 | outw, outh)) | ||
1164 | continue; | ||
1165 | |||
1166 | /* if the overlay totally inside the update region? */ | ||
1167 | if (rectangle_subset(oi->pos_x, oi->pos_y, outw, outh, | ||
1168 | x, y, w, h)) | ||
1169 | continue; | ||
1170 | |||
1171 | if (x > oi->pos_x) | ||
1172 | x1 = oi->pos_x; | ||
1173 | else | ||
1174 | x1 = x; | ||
1175 | |||
1176 | if (y > oi->pos_y) | ||
1177 | y1 = oi->pos_y; | ||
1178 | else | ||
1179 | y1 = y; | ||
1180 | |||
1181 | if ((x + w) < (oi->pos_x + outw)) | ||
1182 | x2 = oi->pos_x + outw; | ||
1183 | else | ||
1184 | x2 = x + w; | ||
1185 | |||
1186 | if ((y + h) < (oi->pos_y + outh)) | ||
1187 | y2 = oi->pos_y + outh; | ||
1188 | else | ||
1189 | y2 = y + h; | ||
1190 | |||
1191 | x = x1; | ||
1192 | y = y1; | ||
1193 | w = x2 - x1; | ||
1194 | h = y2 - y1; | ||
1195 | |||
1196 | make_even(&x, &w); | ||
1197 | |||
1198 | DSSDBG("changing upd area due to ovl(%d) " | ||
1199 | "scaling %d,%d %dx%d\n", | ||
1200 | i, x, y, w, h); | ||
1201 | |||
1202 | area_changed = true; | ||
1203 | } | ||
1204 | } while (area_changed); | ||
1205 | |||
1206 | mc = &dss_cache.manager_cache[mgr->id]; | ||
1207 | mc->do_manual_update = true; | ||
1208 | mc->enlarge_update_area = enlarge_update_area; | ||
1209 | mc->x = x; | ||
1210 | mc->y = y; | ||
1211 | mc->w = w; | ||
1212 | mc->h = h; | ||
1213 | |||
1214 | configure_dispc(); | ||
1215 | |||
1216 | mc->do_manual_update = false; | ||
1217 | |||
1218 | spin_unlock_irqrestore(&dss_cache.lock, flags); | ||
1219 | |||
1220 | *xi = x; | ||
1221 | *yi = y; | ||
1222 | *wi = w; | ||
1223 | *hi = h; | ||
1224 | } | 562 | } |
1225 | 563 | ||
1226 | void dss_start_update(struct omap_dss_device *dssdev) | 564 | void dss_uninit_overlay_managers(struct platform_device *pdev) |
1227 | { | 565 | { |
1228 | struct manager_cache_data *mc; | ||
1229 | struct overlay_cache_data *oc; | ||
1230 | const int num_ovls = dss_feat_get_num_ovls(); | ||
1231 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
1232 | struct omap_overlay_manager *mgr; | ||
1233 | int i; | 566 | int i; |
1234 | 567 | ||
1235 | mgr = dssdev->manager; | 568 | for (i = 0; i < num_managers; ++i) { |
569 | struct omap_overlay_manager *mgr = &managers[i]; | ||
1236 | 570 | ||
1237 | for (i = 0; i < num_ovls; ++i) { | 571 | kobject_del(&mgr->kobj); |
1238 | oc = &dss_cache.overlay_cache[i]; | 572 | kobject_put(&mgr->kobj); |
1239 | if (oc->channel != mgr->id) | ||
1240 | continue; | ||
1241 | |||
1242 | oc->shadow_dirty = false; | ||
1243 | } | ||
1244 | |||
1245 | for (i = 0; i < num_mgrs; ++i) { | ||
1246 | mc = &dss_cache.manager_cache[i]; | ||
1247 | if (mgr->id != i) | ||
1248 | continue; | ||
1249 | |||
1250 | mc->shadow_dirty = false; | ||
1251 | } | 573 | } |
1252 | 574 | ||
1253 | dssdev->manager->enable(dssdev->manager); | 575 | kfree(managers); |
576 | managers = NULL; | ||
577 | num_managers = 0; | ||
1254 | } | 578 | } |
1255 | 579 | ||
1256 | static void dss_apply_irq_handler(void *data, u32 mask) | 580 | int omap_dss_get_num_overlay_managers(void) |
1257 | { | 581 | { |
1258 | struct manager_cache_data *mc; | 582 | return num_managers; |
1259 | struct overlay_cache_data *oc; | ||
1260 | const int num_ovls = dss_feat_get_num_ovls(); | ||
1261 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
1262 | int i, r; | ||
1263 | bool mgr_busy[MAX_DSS_MANAGERS]; | ||
1264 | u32 irq_mask; | ||
1265 | |||
1266 | for (i = 0; i < num_mgrs; i++) | ||
1267 | mgr_busy[i] = dispc_mgr_go_busy(i); | ||
1268 | |||
1269 | spin_lock(&dss_cache.lock); | ||
1270 | |||
1271 | for (i = 0; i < num_ovls; ++i) { | ||
1272 | oc = &dss_cache.overlay_cache[i]; | ||
1273 | if (!mgr_busy[oc->channel]) | ||
1274 | oc->shadow_dirty = false; | ||
1275 | } | ||
1276 | |||
1277 | for (i = 0; i < num_mgrs; ++i) { | ||
1278 | mc = &dss_cache.manager_cache[i]; | ||
1279 | if (!mgr_busy[i]) | ||
1280 | mc->shadow_dirty = false; | ||
1281 | } | ||
1282 | |||
1283 | r = configure_dispc(); | ||
1284 | if (r == 1) | ||
1285 | goto end; | ||
1286 | |||
1287 | /* re-read busy flags */ | ||
1288 | for (i = 0; i < num_mgrs; i++) | ||
1289 | mgr_busy[i] = dispc_mgr_go_busy(i); | ||
1290 | |||
1291 | /* keep running as long as there are busy managers, so that | ||
1292 | * we can collect overlay-applied information */ | ||
1293 | for (i = 0; i < num_mgrs; ++i) { | ||
1294 | if (mgr_busy[i]) | ||
1295 | goto end; | ||
1296 | } | ||
1297 | |||
1298 | irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | | ||
1299 | DISPC_IRQ_EVSYNC_EVEN; | ||
1300 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
1301 | irq_mask |= DISPC_IRQ_VSYNC2; | ||
1302 | |||
1303 | omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask); | ||
1304 | dss_cache.irq_enabled = false; | ||
1305 | |||
1306 | end: | ||
1307 | spin_unlock(&dss_cache.lock); | ||
1308 | } | 583 | } |
584 | EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); | ||
1309 | 585 | ||
1310 | static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) | 586 | struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) |
1311 | { | 587 | { |
1312 | struct overlay_cache_data *oc; | 588 | if (num >= num_managers) |
1313 | struct manager_cache_data *mc; | 589 | return NULL; |
1314 | int i; | ||
1315 | struct omap_overlay *ovl; | ||
1316 | int num_planes_enabled = 0; | ||
1317 | bool use_fifomerge; | ||
1318 | unsigned long flags; | ||
1319 | int r; | ||
1320 | |||
1321 | DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); | ||
1322 | |||
1323 | r = dispc_runtime_get(); | ||
1324 | if (r) | ||
1325 | return r; | ||
1326 | |||
1327 | spin_lock_irqsave(&dss_cache.lock, flags); | ||
1328 | |||
1329 | /* Configure overlays */ | ||
1330 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
1331 | struct omap_dss_device *dssdev; | ||
1332 | |||
1333 | ovl = omap_dss_get_overlay(i); | ||
1334 | |||
1335 | oc = &dss_cache.overlay_cache[ovl->id]; | ||
1336 | |||
1337 | if (ovl->manager_changed) { | ||
1338 | ovl->manager_changed = false; | ||
1339 | ovl->info_dirty = true; | ||
1340 | } | ||
1341 | |||
1342 | if (!overlay_enabled(ovl)) { | ||
1343 | if (oc->enabled) { | ||
1344 | oc->enabled = false; | ||
1345 | oc->dirty = true; | ||
1346 | } | ||
1347 | continue; | ||
1348 | } | ||
1349 | |||
1350 | if (!ovl->info_dirty) { | ||
1351 | if (oc->enabled) | ||
1352 | ++num_planes_enabled; | ||
1353 | continue; | ||
1354 | } | ||
1355 | |||
1356 | dssdev = ovl->manager->device; | ||
1357 | |||
1358 | if (dss_check_overlay(ovl, dssdev)) { | ||
1359 | if (oc->enabled) { | ||
1360 | oc->enabled = false; | ||
1361 | oc->dirty = true; | ||
1362 | } | ||
1363 | continue; | ||
1364 | } | ||
1365 | |||
1366 | ovl->info_dirty = false; | ||
1367 | oc->dirty = true; | ||
1368 | oc->info = ovl->info; | ||
1369 | |||
1370 | oc->replication = | ||
1371 | dss_use_replication(dssdev, ovl->info.color_mode); | ||
1372 | |||
1373 | oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC; | ||
1374 | |||
1375 | oc->channel = ovl->manager->id; | ||
1376 | |||
1377 | oc->enabled = true; | ||
1378 | |||
1379 | ++num_planes_enabled; | ||
1380 | } | ||
1381 | |||
1382 | /* Configure managers */ | ||
1383 | list_for_each_entry(mgr, &manager_list, list) { | ||
1384 | struct omap_dss_device *dssdev; | ||
1385 | 590 | ||
1386 | mc = &dss_cache.manager_cache[mgr->id]; | 591 | return &managers[num]; |
1387 | |||
1388 | if (mgr->device_changed) { | ||
1389 | mgr->device_changed = false; | ||
1390 | mgr->info_dirty = true; | ||
1391 | } | ||
1392 | |||
1393 | if (!mgr->info_dirty) | ||
1394 | continue; | ||
1395 | |||
1396 | if (!mgr->device) | ||
1397 | continue; | ||
1398 | |||
1399 | dssdev = mgr->device; | ||
1400 | |||
1401 | mgr->info_dirty = false; | ||
1402 | mc->dirty = true; | ||
1403 | mc->info = mgr->info; | ||
1404 | |||
1405 | mc->manual_update = | ||
1406 | dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | ||
1407 | } | ||
1408 | |||
1409 | /* XXX TODO: Try to get fifomerge working. The problem is that it | ||
1410 | * affects both managers, not individually but at the same time. This | ||
1411 | * means the change has to be well synchronized. I guess the proper way | ||
1412 | * is to have a two step process for fifo merge: | ||
1413 | * fifomerge enable: | ||
1414 | * 1. disable other planes, leaving one plane enabled | ||
1415 | * 2. wait until the planes are disabled on HW | ||
1416 | * 3. config merged fifo thresholds, enable fifomerge | ||
1417 | * fifomerge disable: | ||
1418 | * 1. config unmerged fifo thresholds, disable fifomerge | ||
1419 | * 2. wait until fifo changes are in HW | ||
1420 | * 3. enable planes | ||
1421 | */ | ||
1422 | use_fifomerge = false; | ||
1423 | |||
1424 | /* Configure overlay fifos */ | ||
1425 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
1426 | struct omap_dss_device *dssdev; | ||
1427 | u32 size, burst_size; | ||
1428 | |||
1429 | ovl = omap_dss_get_overlay(i); | ||
1430 | |||
1431 | oc = &dss_cache.overlay_cache[ovl->id]; | ||
1432 | |||
1433 | if (!oc->enabled) | ||
1434 | continue; | ||
1435 | |||
1436 | dssdev = ovl->manager->device; | ||
1437 | |||
1438 | size = dispc_ovl_get_fifo_size(ovl->id); | ||
1439 | if (use_fifomerge) | ||
1440 | size *= 3; | ||
1441 | |||
1442 | burst_size = dispc_ovl_get_burst_size(ovl->id); | ||
1443 | |||
1444 | switch (dssdev->type) { | ||
1445 | case OMAP_DISPLAY_TYPE_DPI: | ||
1446 | case OMAP_DISPLAY_TYPE_DBI: | ||
1447 | case OMAP_DISPLAY_TYPE_SDI: | ||
1448 | case OMAP_DISPLAY_TYPE_VENC: | ||
1449 | case OMAP_DISPLAY_TYPE_HDMI: | ||
1450 | default_get_overlay_fifo_thresholds(ovl->id, size, | ||
1451 | burst_size, &oc->fifo_low, | ||
1452 | &oc->fifo_high); | ||
1453 | break; | ||
1454 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
1455 | case OMAP_DISPLAY_TYPE_DSI: | ||
1456 | dsi_get_overlay_fifo_thresholds(ovl->id, size, | ||
1457 | burst_size, &oc->fifo_low, | ||
1458 | &oc->fifo_high); | ||
1459 | break; | ||
1460 | #endif | ||
1461 | default: | ||
1462 | BUG(); | ||
1463 | } | ||
1464 | } | ||
1465 | |||
1466 | r = 0; | ||
1467 | if (!dss_cache.irq_enabled) { | ||
1468 | u32 mask; | ||
1469 | |||
1470 | mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | | ||
1471 | DISPC_IRQ_EVSYNC_EVEN; | ||
1472 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
1473 | mask |= DISPC_IRQ_VSYNC2; | ||
1474 | |||
1475 | r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); | ||
1476 | dss_cache.irq_enabled = true; | ||
1477 | } | ||
1478 | configure_dispc(); | ||
1479 | |||
1480 | spin_unlock_irqrestore(&dss_cache.lock, flags); | ||
1481 | |||
1482 | dispc_runtime_put(); | ||
1483 | |||
1484 | return r; | ||
1485 | } | 592 | } |
593 | EXPORT_SYMBOL(omap_dss_get_overlay_manager); | ||
1486 | 594 | ||
1487 | static int dss_check_manager(struct omap_overlay_manager *mgr) | 595 | int dss_mgr_simple_check(struct omap_overlay_manager *mgr, |
596 | const struct omap_overlay_manager_info *info) | ||
1488 | { | 597 | { |
1489 | if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { | 598 | if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { |
1490 | /* | 599 | /* |
1491 | * OMAP3 supports only graphics source transparency color key | 600 | * OMAP3 supports only graphics source transparency color key |
1492 | * and alpha blending simultaneously. See TRM 15.4.2.4.2.2 | 601 | * and alpha blending simultaneously. See TRM 15.4.2.4.2.2 |
1493 | * Alpha Mode | 602 | * Alpha Mode. |
1494 | */ | 603 | */ |
1495 | if (mgr->info.partial_alpha_enabled && mgr->info.trans_enabled | 604 | if (info->partial_alpha_enabled && info->trans_enabled |
1496 | && mgr->info.trans_key_type != | 605 | && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) { |
1497 | OMAP_DSS_COLOR_KEY_GFX_DST) | 606 | DSSERR("check_manager: illegal transparency key\n"); |
1498 | return -EINVAL; | 607 | return -EINVAL; |
608 | } | ||
1499 | } | 609 | } |
1500 | 610 | ||
1501 | return 0; | 611 | return 0; |
1502 | } | 612 | } |
1503 | 613 | ||
1504 | static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr, | 614 | static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr, |
1505 | struct omap_overlay_manager_info *info) | 615 | struct omap_overlay_info **overlay_infos) |
1506 | { | ||
1507 | int r; | ||
1508 | struct omap_overlay_manager_info old_info; | ||
1509 | |||
1510 | old_info = mgr->info; | ||
1511 | mgr->info = *info; | ||
1512 | |||
1513 | r = dss_check_manager(mgr); | ||
1514 | if (r) { | ||
1515 | mgr->info = old_info; | ||
1516 | return r; | ||
1517 | } | ||
1518 | |||
1519 | mgr->info_dirty = true; | ||
1520 | |||
1521 | return 0; | ||
1522 | } | ||
1523 | |||
1524 | static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr, | ||
1525 | struct omap_overlay_manager_info *info) | ||
1526 | { | 616 | { |
1527 | *info = mgr->info; | 617 | struct omap_overlay *ovl1, *ovl2; |
1528 | } | 618 | struct omap_overlay_info *info1, *info2; |
1529 | 619 | ||
1530 | static int dss_mgr_enable(struct omap_overlay_manager *mgr) | 620 | list_for_each_entry(ovl1, &mgr->overlays, list) { |
1531 | { | 621 | info1 = overlay_infos[ovl1->id]; |
1532 | dispc_mgr_enable(mgr->id, 1); | ||
1533 | return 0; | ||
1534 | } | ||
1535 | 622 | ||
1536 | static int dss_mgr_disable(struct omap_overlay_manager *mgr) | 623 | if (info1 == NULL) |
1537 | { | 624 | continue; |
1538 | dispc_mgr_enable(mgr->id, 0); | ||
1539 | return 0; | ||
1540 | } | ||
1541 | |||
1542 | static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager) | ||
1543 | { | ||
1544 | ++num_managers; | ||
1545 | list_add_tail(&manager->list, &manager_list); | ||
1546 | } | ||
1547 | |||
1548 | int dss_init_overlay_managers(struct platform_device *pdev) | ||
1549 | { | ||
1550 | int i, r; | ||
1551 | |||
1552 | spin_lock_init(&dss_cache.lock); | ||
1553 | |||
1554 | INIT_LIST_HEAD(&manager_list); | ||
1555 | |||
1556 | num_managers = 0; | ||
1557 | |||
1558 | for (i = 0; i < dss_feat_get_num_mgrs(); ++i) { | ||
1559 | struct omap_overlay_manager *mgr; | ||
1560 | mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); | ||
1561 | |||
1562 | BUG_ON(mgr == NULL); | ||
1563 | |||
1564 | switch (i) { | ||
1565 | case 0: | ||
1566 | mgr->name = "lcd"; | ||
1567 | mgr->id = OMAP_DSS_CHANNEL_LCD; | ||
1568 | break; | ||
1569 | case 1: | ||
1570 | mgr->name = "tv"; | ||
1571 | mgr->id = OMAP_DSS_CHANNEL_DIGIT; | ||
1572 | break; | ||
1573 | case 2: | ||
1574 | mgr->name = "lcd2"; | ||
1575 | mgr->id = OMAP_DSS_CHANNEL_LCD2; | ||
1576 | break; | ||
1577 | } | ||
1578 | |||
1579 | mgr->set_device = &omap_dss_set_device; | ||
1580 | mgr->unset_device = &omap_dss_unset_device; | ||
1581 | mgr->apply = &omap_dss_mgr_apply; | ||
1582 | mgr->set_manager_info = &omap_dss_mgr_set_info; | ||
1583 | mgr->get_manager_info = &omap_dss_mgr_get_info; | ||
1584 | mgr->wait_for_go = &dss_mgr_wait_for_go; | ||
1585 | mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; | ||
1586 | |||
1587 | mgr->enable = &dss_mgr_enable; | ||
1588 | mgr->disable = &dss_mgr_disable; | ||
1589 | |||
1590 | mgr->caps = 0; | ||
1591 | mgr->supported_displays = | ||
1592 | dss_feat_get_supported_displays(mgr->id); | ||
1593 | 625 | ||
1594 | dss_overlay_setup_dispc_manager(mgr); | 626 | list_for_each_entry(ovl2, &mgr->overlays, list) { |
627 | if (ovl1 == ovl2) | ||
628 | continue; | ||
1595 | 629 | ||
1596 | omap_dss_add_overlay_manager(mgr); | 630 | info2 = overlay_infos[ovl2->id]; |
1597 | 631 | ||
1598 | r = kobject_init_and_add(&mgr->kobj, &manager_ktype, | 632 | if (info2 == NULL) |
1599 | &pdev->dev.kobj, "manager%d", i); | 633 | continue; |
1600 | 634 | ||
1601 | if (r) { | 635 | if (info1->zorder == info2->zorder) { |
1602 | DSSERR("failed to create sysfs file\n"); | 636 | DSSERR("overlays %d and %d have the same " |
1603 | continue; | 637 | "zorder %d\n", |
638 | ovl1->id, ovl2->id, info1->zorder); | ||
639 | return -EINVAL; | ||
640 | } | ||
1604 | } | 641 | } |
1605 | } | 642 | } |
1606 | 643 | ||
1607 | return 0; | 644 | return 0; |
1608 | } | 645 | } |
1609 | 646 | ||
1610 | void dss_uninit_overlay_managers(struct platform_device *pdev) | 647 | int dss_mgr_check(struct omap_overlay_manager *mgr, |
648 | struct omap_dss_device *dssdev, | ||
649 | struct omap_overlay_manager_info *info, | ||
650 | struct omap_overlay_info **overlay_infos) | ||
1611 | { | 651 | { |
1612 | struct omap_overlay_manager *mgr; | 652 | struct omap_overlay *ovl; |
653 | int r; | ||
1613 | 654 | ||
1614 | while (!list_empty(&manager_list)) { | 655 | if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) { |
1615 | mgr = list_first_entry(&manager_list, | 656 | r = dss_mgr_check_zorder(mgr, overlay_infos); |
1616 | struct omap_overlay_manager, list); | 657 | if (r) |
1617 | list_del(&mgr->list); | 658 | return r; |
1618 | kobject_del(&mgr->kobj); | ||
1619 | kobject_put(&mgr->kobj); | ||
1620 | kfree(mgr); | ||
1621 | } | 659 | } |
1622 | 660 | ||
1623 | num_managers = 0; | 661 | list_for_each_entry(ovl, &mgr->overlays, list) { |
1624 | } | 662 | struct omap_overlay_info *oi; |
663 | int r; | ||
1625 | 664 | ||
1626 | int omap_dss_get_num_overlay_managers(void) | 665 | oi = overlay_infos[ovl->id]; |
1627 | { | ||
1628 | return num_managers; | ||
1629 | } | ||
1630 | EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); | ||
1631 | 666 | ||
1632 | struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) | 667 | if (oi == NULL) |
1633 | { | 668 | continue; |
1634 | int i = 0; | ||
1635 | struct omap_overlay_manager *mgr; | ||
1636 | 669 | ||
1637 | list_for_each_entry(mgr, &manager_list, list) { | 670 | r = dss_ovl_check(ovl, oi, dssdev); |
1638 | if (i++ == num) | 671 | if (r) |
1639 | return mgr; | 672 | return r; |
1640 | } | 673 | } |
1641 | 674 | ||
1642 | return NULL; | 675 | return 0; |
1643 | } | 676 | } |
1644 | EXPORT_SYMBOL(omap_dss_get_overlay_manager); | ||
1645 | |||
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index ab8e40e48759..6e821810deec 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c | |||
@@ -38,7 +38,7 @@ | |||
38 | #include "dss_features.h" | 38 | #include "dss_features.h" |
39 | 39 | ||
40 | static int num_overlays; | 40 | static int num_overlays; |
41 | static struct list_head overlay_list; | 41 | static struct omap_overlay *overlays; |
42 | 42 | ||
43 | static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) | 43 | static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) |
44 | { | 44 | { |
@@ -124,19 +124,31 @@ err: | |||
124 | 124 | ||
125 | static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) | 125 | static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) |
126 | { | 126 | { |
127 | struct omap_overlay_info info; | ||
128 | |||
129 | ovl->get_overlay_info(ovl, &info); | ||
130 | |||
127 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | 131 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", |
128 | ovl->info.width, ovl->info.height); | 132 | info.width, info.height); |
129 | } | 133 | } |
130 | 134 | ||
131 | static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) | 135 | static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) |
132 | { | 136 | { |
133 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width); | 137 | struct omap_overlay_info info; |
138 | |||
139 | ovl->get_overlay_info(ovl, &info); | ||
140 | |||
141 | return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width); | ||
134 | } | 142 | } |
135 | 143 | ||
136 | static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) | 144 | static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) |
137 | { | 145 | { |
146 | struct omap_overlay_info info; | ||
147 | |||
148 | ovl->get_overlay_info(ovl, &info); | ||
149 | |||
138 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | 150 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", |
139 | ovl->info.pos_x, ovl->info.pos_y); | 151 | info.pos_x, info.pos_y); |
140 | } | 152 | } |
141 | 153 | ||
142 | static ssize_t overlay_position_store(struct omap_overlay *ovl, | 154 | static ssize_t overlay_position_store(struct omap_overlay *ovl, |
@@ -170,8 +182,12 @@ static ssize_t overlay_position_store(struct omap_overlay *ovl, | |||
170 | 182 | ||
171 | static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) | 183 | static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) |
172 | { | 184 | { |
185 | struct omap_overlay_info info; | ||
186 | |||
187 | ovl->get_overlay_info(ovl, &info); | ||
188 | |||
173 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | 189 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", |
174 | ovl->info.out_width, ovl->info.out_height); | 190 | info.out_width, info.out_height); |
175 | } | 191 | } |
176 | 192 | ||
177 | static ssize_t overlay_output_size_store(struct omap_overlay *ovl, | 193 | static ssize_t overlay_output_size_store(struct omap_overlay *ovl, |
@@ -205,7 +221,7 @@ static ssize_t overlay_output_size_store(struct omap_overlay *ovl, | |||
205 | 221 | ||
206 | static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) | 222 | static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) |
207 | { | 223 | { |
208 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled); | 224 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); |
209 | } | 225 | } |
210 | 226 | ||
211 | static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, | 227 | static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, |
@@ -213,33 +229,30 @@ static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, | |||
213 | { | 229 | { |
214 | int r; | 230 | int r; |
215 | bool enable; | 231 | bool enable; |
216 | struct omap_overlay_info info; | ||
217 | |||
218 | ovl->get_overlay_info(ovl, &info); | ||
219 | 232 | ||
220 | r = strtobool(buf, &enable); | 233 | r = strtobool(buf, &enable); |
221 | if (r) | 234 | if (r) |
222 | return r; | 235 | return r; |
223 | 236 | ||
224 | info.enabled = enable; | 237 | if (enable) |
238 | r = ovl->enable(ovl); | ||
239 | else | ||
240 | r = ovl->disable(ovl); | ||
225 | 241 | ||
226 | r = ovl->set_overlay_info(ovl, &info); | ||
227 | if (r) | 242 | if (r) |
228 | return r; | 243 | return r; |
229 | 244 | ||
230 | if (ovl->manager) { | ||
231 | r = ovl->manager->apply(ovl->manager); | ||
232 | if (r) | ||
233 | return r; | ||
234 | } | ||
235 | |||
236 | return size; | 245 | return size; |
237 | } | 246 | } |
238 | 247 | ||
239 | static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) | 248 | static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) |
240 | { | 249 | { |
250 | struct omap_overlay_info info; | ||
251 | |||
252 | ovl->get_overlay_info(ovl, &info); | ||
253 | |||
241 | return snprintf(buf, PAGE_SIZE, "%d\n", | 254 | return snprintf(buf, PAGE_SIZE, "%d\n", |
242 | ovl->info.global_alpha); | 255 | info.global_alpha); |
243 | } | 256 | } |
244 | 257 | ||
245 | static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, | 258 | static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, |
@@ -276,8 +289,12 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, | |||
276 | static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, | 289 | static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, |
277 | char *buf) | 290 | char *buf) |
278 | { | 291 | { |
292 | struct omap_overlay_info info; | ||
293 | |||
294 | ovl->get_overlay_info(ovl, &info); | ||
295 | |||
279 | return snprintf(buf, PAGE_SIZE, "%d\n", | 296 | return snprintf(buf, PAGE_SIZE, "%d\n", |
280 | ovl->info.pre_mult_alpha); | 297 | info.pre_mult_alpha); |
281 | } | 298 | } |
282 | 299 | ||
283 | static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, | 300 | static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, |
@@ -313,7 +330,11 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, | |||
313 | 330 | ||
314 | static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) | 331 | static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) |
315 | { | 332 | { |
316 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.zorder); | 333 | struct omap_overlay_info info; |
334 | |||
335 | ovl->get_overlay_info(ovl, &info); | ||
336 | |||
337 | return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder); | ||
317 | } | 338 | } |
318 | 339 | ||
319 | static ssize_t overlay_zorder_store(struct omap_overlay *ovl, | 340 | static ssize_t overlay_zorder_store(struct omap_overlay *ovl, |
@@ -430,183 +451,6 @@ static struct kobj_type overlay_ktype = { | |||
430 | .default_attrs = overlay_sysfs_attrs, | 451 | .default_attrs = overlay_sysfs_attrs, |
431 | }; | 452 | }; |
432 | 453 | ||
433 | /* Check if overlay parameters are compatible with display */ | ||
434 | int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev) | ||
435 | { | ||
436 | struct omap_overlay_info *info; | ||
437 | u16 outw, outh; | ||
438 | u16 dw, dh; | ||
439 | int i; | ||
440 | |||
441 | if (!dssdev) | ||
442 | return 0; | ||
443 | |||
444 | if (!ovl->info.enabled) | ||
445 | return 0; | ||
446 | |||
447 | info = &ovl->info; | ||
448 | |||
449 | if (info->paddr == 0) { | ||
450 | DSSDBG("check_overlay failed: paddr 0\n"); | ||
451 | return -EINVAL; | ||
452 | } | ||
453 | |||
454 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | ||
455 | |||
456 | DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n", | ||
457 | ovl->id, | ||
458 | info->pos_x, info->pos_y, | ||
459 | info->width, info->height, | ||
460 | info->out_width, info->out_height, | ||
461 | dw, dh); | ||
462 | |||
463 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { | ||
464 | outw = info->width; | ||
465 | outh = info->height; | ||
466 | } else { | ||
467 | if (info->out_width == 0) | ||
468 | outw = info->width; | ||
469 | else | ||
470 | outw = info->out_width; | ||
471 | |||
472 | if (info->out_height == 0) | ||
473 | outh = info->height; | ||
474 | else | ||
475 | outh = info->out_height; | ||
476 | } | ||
477 | |||
478 | if (dw < info->pos_x + outw) { | ||
479 | DSSDBG("check_overlay failed 1: %d < %d + %d\n", | ||
480 | dw, info->pos_x, outw); | ||
481 | return -EINVAL; | ||
482 | } | ||
483 | |||
484 | if (dh < info->pos_y + outh) { | ||
485 | DSSDBG("check_overlay failed 2: %d < %d + %d\n", | ||
486 | dh, info->pos_y, outh); | ||
487 | return -EINVAL; | ||
488 | } | ||
489 | |||
490 | if ((ovl->supported_modes & info->color_mode) == 0) { | ||
491 | DSSERR("overlay doesn't support mode %d\n", info->color_mode); | ||
492 | return -EINVAL; | ||
493 | } | ||
494 | |||
495 | if (ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) { | ||
496 | if (info->zorder < 0 || info->zorder > 3) { | ||
497 | DSSERR("zorder out of range: %d\n", | ||
498 | info->zorder); | ||
499 | return -EINVAL; | ||
500 | } | ||
501 | /* | ||
502 | * Check that zorder doesn't match with zorder of any other | ||
503 | * overlay which is enabled and is also connected to the same | ||
504 | * manager | ||
505 | */ | ||
506 | for (i = 0; i < omap_dss_get_num_overlays(); i++) { | ||
507 | struct omap_overlay *tmp_ovl = omap_dss_get_overlay(i); | ||
508 | |||
509 | if (tmp_ovl->id != ovl->id && | ||
510 | tmp_ovl->manager == ovl->manager && | ||
511 | tmp_ovl->info.enabled == true && | ||
512 | tmp_ovl->info.zorder == info->zorder) { | ||
513 | DSSERR("%s and %s have same zorder: %d\n", | ||
514 | ovl->name, tmp_ovl->name, info->zorder); | ||
515 | return -EINVAL; | ||
516 | } | ||
517 | } | ||
518 | } | ||
519 | |||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | static int dss_ovl_set_overlay_info(struct omap_overlay *ovl, | ||
524 | struct omap_overlay_info *info) | ||
525 | { | ||
526 | int r; | ||
527 | struct omap_overlay_info old_info; | ||
528 | |||
529 | old_info = ovl->info; | ||
530 | ovl->info = *info; | ||
531 | |||
532 | if (ovl->manager) { | ||
533 | r = dss_check_overlay(ovl, ovl->manager->device); | ||
534 | if (r) { | ||
535 | ovl->info = old_info; | ||
536 | return r; | ||
537 | } | ||
538 | } | ||
539 | |||
540 | ovl->info_dirty = true; | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static void dss_ovl_get_overlay_info(struct omap_overlay *ovl, | ||
546 | struct omap_overlay_info *info) | ||
547 | { | ||
548 | *info = ovl->info; | ||
549 | } | ||
550 | |||
551 | static int dss_ovl_wait_for_go(struct omap_overlay *ovl) | ||
552 | { | ||
553 | return dss_mgr_wait_for_go_ovl(ovl); | ||
554 | } | ||
555 | |||
556 | static int omap_dss_set_manager(struct omap_overlay *ovl, | ||
557 | struct omap_overlay_manager *mgr) | ||
558 | { | ||
559 | if (!mgr) | ||
560 | return -EINVAL; | ||
561 | |||
562 | if (ovl->manager) { | ||
563 | DSSERR("overlay '%s' already has a manager '%s'\n", | ||
564 | ovl->name, ovl->manager->name); | ||
565 | return -EINVAL; | ||
566 | } | ||
567 | |||
568 | if (ovl->info.enabled) { | ||
569 | DSSERR("overlay has to be disabled to change the manager\n"); | ||
570 | return -EINVAL; | ||
571 | } | ||
572 | |||
573 | ovl->manager = mgr; | ||
574 | ovl->manager_changed = true; | ||
575 | |||
576 | /* XXX: When there is an overlay on a DSI manual update display, and | ||
577 | * the overlay is first disabled, then moved to tv, and enabled, we | ||
578 | * seem to get SYNC_LOST_DIGIT error. | ||
579 | * | ||
580 | * Waiting doesn't seem to help, but updating the manual update display | ||
581 | * after disabling the overlay seems to fix this. This hints that the | ||
582 | * overlay is perhaps somehow tied to the LCD output until the output | ||
583 | * is updated. | ||
584 | * | ||
585 | * Userspace workaround for this is to update the LCD after disabling | ||
586 | * the overlay, but before moving the overlay to TV. | ||
587 | */ | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int omap_dss_unset_manager(struct omap_overlay *ovl) | ||
593 | { | ||
594 | if (!ovl->manager) { | ||
595 | DSSERR("failed to detach overlay: manager not set\n"); | ||
596 | return -EINVAL; | ||
597 | } | ||
598 | |||
599 | if (ovl->info.enabled) { | ||
600 | DSSERR("overlay has to be disabled to unset the manager\n"); | ||
601 | return -EINVAL; | ||
602 | } | ||
603 | |||
604 | ovl->manager = NULL; | ||
605 | ovl->manager_changed = true; | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | int omap_dss_get_num_overlays(void) | 454 | int omap_dss_get_num_overlays(void) |
611 | { | 455 | { |
612 | return num_overlays; | 456 | return num_overlays; |
@@ -615,134 +459,65 @@ EXPORT_SYMBOL(omap_dss_get_num_overlays); | |||
615 | 459 | ||
616 | struct omap_overlay *omap_dss_get_overlay(int num) | 460 | struct omap_overlay *omap_dss_get_overlay(int num) |
617 | { | 461 | { |
618 | int i = 0; | 462 | if (num >= num_overlays) |
619 | struct omap_overlay *ovl; | 463 | return NULL; |
620 | 464 | ||
621 | list_for_each_entry(ovl, &overlay_list, list) { | 465 | return &overlays[num]; |
622 | if (i++ == num) | ||
623 | return ovl; | ||
624 | } | ||
625 | |||
626 | return NULL; | ||
627 | } | 466 | } |
628 | EXPORT_SYMBOL(omap_dss_get_overlay); | 467 | EXPORT_SYMBOL(omap_dss_get_overlay); |
629 | 468 | ||
630 | static void omap_dss_add_overlay(struct omap_overlay *overlay) | ||
631 | { | ||
632 | ++num_overlays; | ||
633 | list_add_tail(&overlay->list, &overlay_list); | ||
634 | } | ||
635 | |||
636 | static struct omap_overlay *dispc_overlays[MAX_DSS_OVERLAYS]; | ||
637 | |||
638 | void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr) | ||
639 | { | ||
640 | mgr->num_overlays = dss_feat_get_num_ovls(); | ||
641 | mgr->overlays = dispc_overlays; | ||
642 | } | ||
643 | |||
644 | #ifdef L4_EXAMPLE | ||
645 | static struct omap_overlay *l4_overlays[1]; | ||
646 | void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr) | ||
647 | { | ||
648 | mgr->num_overlays = 1; | ||
649 | mgr->overlays = l4_overlays; | ||
650 | } | ||
651 | #endif | ||
652 | |||
653 | void dss_init_overlays(struct platform_device *pdev) | 469 | void dss_init_overlays(struct platform_device *pdev) |
654 | { | 470 | { |
655 | int i, r; | 471 | int i, r; |
656 | 472 | ||
657 | INIT_LIST_HEAD(&overlay_list); | 473 | num_overlays = dss_feat_get_num_ovls(); |
658 | 474 | ||
659 | num_overlays = 0; | 475 | overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays, |
476 | GFP_KERNEL); | ||
660 | 477 | ||
661 | for (i = 0; i < dss_feat_get_num_ovls(); ++i) { | 478 | BUG_ON(overlays == NULL); |
662 | struct omap_overlay *ovl; | ||
663 | ovl = kzalloc(sizeof(*ovl), GFP_KERNEL); | ||
664 | 479 | ||
665 | BUG_ON(ovl == NULL); | 480 | for (i = 0; i < num_overlays; ++i) { |
481 | struct omap_overlay *ovl = &overlays[i]; | ||
666 | 482 | ||
667 | switch (i) { | 483 | switch (i) { |
668 | case 0: | 484 | case 0: |
669 | ovl->name = "gfx"; | 485 | ovl->name = "gfx"; |
670 | ovl->id = OMAP_DSS_GFX; | 486 | ovl->id = OMAP_DSS_GFX; |
671 | ovl->info.global_alpha = 255; | ||
672 | ovl->info.zorder = 0; | ||
673 | break; | 487 | break; |
674 | case 1: | 488 | case 1: |
675 | ovl->name = "vid1"; | 489 | ovl->name = "vid1"; |
676 | ovl->id = OMAP_DSS_VIDEO1; | 490 | ovl->id = OMAP_DSS_VIDEO1; |
677 | ovl->info.global_alpha = 255; | ||
678 | ovl->info.zorder = | ||
679 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0; | ||
680 | break; | 491 | break; |
681 | case 2: | 492 | case 2: |
682 | ovl->name = "vid2"; | 493 | ovl->name = "vid2"; |
683 | ovl->id = OMAP_DSS_VIDEO2; | 494 | ovl->id = OMAP_DSS_VIDEO2; |
684 | ovl->info.global_alpha = 255; | ||
685 | ovl->info.zorder = | ||
686 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0; | ||
687 | break; | 495 | break; |
688 | case 3: | 496 | case 3: |
689 | ovl->name = "vid3"; | 497 | ovl->name = "vid3"; |
690 | ovl->id = OMAP_DSS_VIDEO3; | 498 | ovl->id = OMAP_DSS_VIDEO3; |
691 | ovl->info.global_alpha = 255; | ||
692 | ovl->info.zorder = | ||
693 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0; | ||
694 | break; | 499 | break; |
695 | } | 500 | } |
696 | 501 | ||
697 | ovl->set_manager = &omap_dss_set_manager; | 502 | ovl->is_enabled = &dss_ovl_is_enabled; |
698 | ovl->unset_manager = &omap_dss_unset_manager; | 503 | ovl->enable = &dss_ovl_enable; |
699 | ovl->set_overlay_info = &dss_ovl_set_overlay_info; | 504 | ovl->disable = &dss_ovl_disable; |
700 | ovl->get_overlay_info = &dss_ovl_get_overlay_info; | 505 | ovl->set_manager = &dss_ovl_set_manager; |
701 | ovl->wait_for_go = &dss_ovl_wait_for_go; | 506 | ovl->unset_manager = &dss_ovl_unset_manager; |
507 | ovl->set_overlay_info = &dss_ovl_set_info; | ||
508 | ovl->get_overlay_info = &dss_ovl_get_info; | ||
509 | ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; | ||
702 | 510 | ||
703 | ovl->caps = dss_feat_get_overlay_caps(ovl->id); | 511 | ovl->caps = dss_feat_get_overlay_caps(ovl->id); |
704 | ovl->supported_modes = | 512 | ovl->supported_modes = |
705 | dss_feat_get_supported_color_modes(ovl->id); | 513 | dss_feat_get_supported_color_modes(ovl->id); |
706 | 514 | ||
707 | omap_dss_add_overlay(ovl); | ||
708 | |||
709 | r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, | 515 | r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, |
710 | &pdev->dev.kobj, "overlay%d", i); | 516 | &pdev->dev.kobj, "overlay%d", i); |
711 | 517 | ||
712 | if (r) { | ||
713 | DSSERR("failed to create sysfs file\n"); | ||
714 | continue; | ||
715 | } | ||
716 | |||
717 | dispc_overlays[i] = ovl; | ||
718 | } | ||
719 | |||
720 | #ifdef L4_EXAMPLE | ||
721 | { | ||
722 | struct omap_overlay *ovl; | ||
723 | ovl = kzalloc(sizeof(*ovl), GFP_KERNEL); | ||
724 | |||
725 | BUG_ON(ovl == NULL); | ||
726 | |||
727 | ovl->name = "l4"; | ||
728 | ovl->supported_modes = OMAP_DSS_COLOR_RGB24U; | ||
729 | |||
730 | ovl->set_manager = &omap_dss_set_manager; | ||
731 | ovl->unset_manager = &omap_dss_unset_manager; | ||
732 | ovl->set_overlay_info = &dss_ovl_set_overlay_info; | ||
733 | ovl->get_overlay_info = &dss_ovl_get_overlay_info; | ||
734 | |||
735 | omap_dss_add_overlay(ovl); | ||
736 | |||
737 | r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, | ||
738 | &pdev->dev.kobj, "overlayl4"); | ||
739 | |||
740 | if (r) | 518 | if (r) |
741 | DSSERR("failed to create sysfs file\n"); | 519 | DSSERR("failed to create sysfs file\n"); |
742 | |||
743 | l4_overlays[0] = ovl; | ||
744 | } | 520 | } |
745 | #endif | ||
746 | } | 521 | } |
747 | 522 | ||
748 | /* connect overlays to the new device, if not already connected. if force | 523 | /* connect overlays to the new device, if not already connected. if force |
@@ -795,8 +570,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) | |||
795 | ovl = omap_dss_get_overlay(i); | 570 | ovl = omap_dss_get_overlay(i); |
796 | if (!ovl->manager || force) { | 571 | if (!ovl->manager || force) { |
797 | if (ovl->manager) | 572 | if (ovl->manager) |
798 | omap_dss_unset_manager(ovl); | 573 | ovl->unset_manager(ovl); |
799 | omap_dss_set_manager(ovl, mgr); | 574 | ovl->set_manager(ovl, mgr); |
800 | } | 575 | } |
801 | } | 576 | } |
802 | 577 | ||
@@ -806,17 +581,95 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) | |||
806 | 581 | ||
807 | void dss_uninit_overlays(struct platform_device *pdev) | 582 | void dss_uninit_overlays(struct platform_device *pdev) |
808 | { | 583 | { |
809 | struct omap_overlay *ovl; | 584 | int i; |
585 | |||
586 | for (i = 0; i < num_overlays; ++i) { | ||
587 | struct omap_overlay *ovl = &overlays[i]; | ||
810 | 588 | ||
811 | while (!list_empty(&overlay_list)) { | ||
812 | ovl = list_first_entry(&overlay_list, | ||
813 | struct omap_overlay, list); | ||
814 | list_del(&ovl->list); | ||
815 | kobject_del(&ovl->kobj); | 589 | kobject_del(&ovl->kobj); |
816 | kobject_put(&ovl->kobj); | 590 | kobject_put(&ovl->kobj); |
817 | kfree(ovl); | ||
818 | } | 591 | } |
819 | 592 | ||
593 | kfree(overlays); | ||
594 | overlays = NULL; | ||
820 | num_overlays = 0; | 595 | num_overlays = 0; |
821 | } | 596 | } |
822 | 597 | ||
598 | int dss_ovl_simple_check(struct omap_overlay *ovl, | ||
599 | const struct omap_overlay_info *info) | ||
600 | { | ||
601 | if (info->paddr == 0) { | ||
602 | DSSERR("check_overlay: paddr cannot be 0\n"); | ||
603 | return -EINVAL; | ||
604 | } | ||
605 | |||
606 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { | ||
607 | if (info->out_width != 0 && info->width != info->out_width) { | ||
608 | DSSERR("check_overlay: overlay %d doesn't support " | ||
609 | "scaling\n", ovl->id); | ||
610 | return -EINVAL; | ||
611 | } | ||
612 | |||
613 | if (info->out_height != 0 && info->height != info->out_height) { | ||
614 | DSSERR("check_overlay: overlay %d doesn't support " | ||
615 | "scaling\n", ovl->id); | ||
616 | return -EINVAL; | ||
617 | } | ||
618 | } | ||
619 | |||
620 | if ((ovl->supported_modes & info->color_mode) == 0) { | ||
621 | DSSERR("check_overlay: overlay %d doesn't support mode %d\n", | ||
622 | ovl->id, info->color_mode); | ||
623 | return -EINVAL; | ||
624 | } | ||
625 | |||
626 | if (info->zorder >= omap_dss_get_num_overlays()) { | ||
627 | DSSERR("check_overlay: zorder %d too high\n", info->zorder); | ||
628 | return -EINVAL; | ||
629 | } | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | int dss_ovl_check(struct omap_overlay *ovl, | ||
635 | struct omap_overlay_info *info, struct omap_dss_device *dssdev) | ||
636 | { | ||
637 | u16 outw, outh; | ||
638 | u16 dw, dh; | ||
639 | |||
640 | if (dssdev == NULL) | ||
641 | return 0; | ||
642 | |||
643 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | ||
644 | |||
645 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { | ||
646 | outw = info->width; | ||
647 | outh = info->height; | ||
648 | } else { | ||
649 | if (info->out_width == 0) | ||
650 | outw = info->width; | ||
651 | else | ||
652 | outw = info->out_width; | ||
653 | |||
654 | if (info->out_height == 0) | ||
655 | outh = info->height; | ||
656 | else | ||
657 | outh = info->out_height; | ||
658 | } | ||
659 | |||
660 | if (dw < info->pos_x + outw) { | ||
661 | DSSERR("overlay %d horizontally not inside the display area " | ||
662 | "(%d + %d >= %d)\n", | ||
663 | ovl->id, info->pos_x, outw, dw); | ||
664 | return -EINVAL; | ||
665 | } | ||
666 | |||
667 | if (dh < info->pos_y + outh) { | ||
668 | DSSERR("overlay %d vertically not inside the display area " | ||
669 | "(%d + %d >= %d)\n", | ||
670 | ovl->id, info->pos_y, outh, dh); | ||
671 | return -EINVAL; | ||
672 | } | ||
673 | |||
674 | return 0; | ||
675 | } | ||
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 1130c608a561..814bb9500dca 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c | |||
@@ -784,7 +784,6 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, | |||
784 | if (*w == 0 || *h == 0) | 784 | if (*w == 0 || *h == 0) |
785 | return -EINVAL; | 785 | return -EINVAL; |
786 | 786 | ||
787 | dss_setup_partial_planes(dssdev, x, y, w, h, true); | ||
788 | dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); | 787 | dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); |
789 | 788 | ||
790 | return 0; | 789 | return 0; |
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 40305ad7841e..8266ca0d666b 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c | |||
@@ -123,10 +123,14 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | |||
123 | goto err_sdi_enable; | 123 | goto err_sdi_enable; |
124 | mdelay(2); | 124 | mdelay(2); |
125 | 125 | ||
126 | dssdev->manager->enable(dssdev->manager); | 126 | r = dss_mgr_enable(dssdev->manager); |
127 | if (r) | ||
128 | goto err_mgr_enable; | ||
127 | 129 | ||
128 | return 0; | 130 | return 0; |
129 | 131 | ||
132 | err_mgr_enable: | ||
133 | dss_sdi_disable(); | ||
130 | err_sdi_enable: | 134 | err_sdi_enable: |
131 | err_set_dispc_clock_div: | 135 | err_set_dispc_clock_div: |
132 | err_set_dss_clock_div: | 136 | err_set_dss_clock_div: |
@@ -145,7 +149,7 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable); | |||
145 | 149 | ||
146 | void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) | 150 | void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) |
147 | { | 151 | { |
148 | dssdev->manager->disable(dssdev->manager); | 152 | dss_mgr_disable(dssdev->manager); |
149 | 153 | ||
150 | dss_sdi_disable(); | 154 | dss_sdi_disable(); |
151 | 155 | ||
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index 2c3443dabb14..7503f7f619a7 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h | |||
@@ -110,6 +110,11 @@ struct ti_hdmi_ip_ops { | |||
110 | 110 | ||
111 | void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); | 111 | void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); |
112 | 112 | ||
113 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
114 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
115 | void (*audio_enable)(struct hdmi_ip_data *ip_data, bool start); | ||
116 | #endif | ||
117 | |||
113 | }; | 118 | }; |
114 | 119 | ||
115 | struct hdmi_ip_data { | 120 | struct hdmi_ip_data { |
@@ -134,5 +139,8 @@ void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | |||
134 | void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 139 | void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); |
135 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 140 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); |
136 | void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 141 | void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); |
137 | 142 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | |
143 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
144 | void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable); | ||
145 | #endif | ||
138 | #endif | 146 | #endif |
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index e1a6ce518af6..9af81f18f163 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | |||
@@ -1204,36 +1204,13 @@ int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, | |||
1204 | return 0; | 1204 | return 0; |
1205 | } | 1205 | } |
1206 | 1206 | ||
1207 | int hdmi_audio_trigger(struct hdmi_ip_data *ip_data, | 1207 | void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable) |
1208 | struct snd_pcm_substream *substream, int cmd, | ||
1209 | struct snd_soc_dai *dai) | ||
1210 | { | 1208 | { |
1211 | int err = 0; | 1209 | REG_FLD_MOD(hdmi_av_base(ip_data), |
1212 | switch (cmd) { | 1210 | HDMI_CORE_AV_AUD_MODE, enable, 0, 0); |
1213 | case SNDRV_PCM_TRIGGER_START: | 1211 | REG_FLD_MOD(hdmi_wp_base(ip_data), |
1214 | case SNDRV_PCM_TRIGGER_RESUME: | 1212 | HDMI_WP_AUDIO_CTRL, enable, 31, 31); |
1215 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 1213 | REG_FLD_MOD(hdmi_wp_base(ip_data), |
1216 | REG_FLD_MOD(hdmi_av_base(ip_data), | 1214 | HDMI_WP_AUDIO_CTRL, enable, 30, 30); |
1217 | HDMI_CORE_AV_AUD_MODE, 1, 0, 0); | ||
1218 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1219 | HDMI_WP_AUDIO_CTRL, 1, 31, 31); | ||
1220 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1221 | HDMI_WP_AUDIO_CTRL, 1, 30, 30); | ||
1222 | break; | ||
1223 | |||
1224 | case SNDRV_PCM_TRIGGER_STOP: | ||
1225 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1226 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
1227 | REG_FLD_MOD(hdmi_av_base(ip_data), | ||
1228 | HDMI_CORE_AV_AUD_MODE, 0, 0, 0); | ||
1229 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1230 | HDMI_WP_AUDIO_CTRL, 0, 30, 30); | ||
1231 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1232 | HDMI_WP_AUDIO_CTRL, 0, 31, 31); | ||
1233 | break; | ||
1234 | default: | ||
1235 | err = -EINVAL; | ||
1236 | } | ||
1237 | return err; | ||
1238 | } | 1215 | } |
1239 | #endif | 1216 | #endif |
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h index 204095632d27..a442998980f1 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h | |||
@@ -576,9 +576,6 @@ struct hdmi_core_audio_config { | |||
576 | 576 | ||
577 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 577 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ |
578 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | 578 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) |
579 | int hdmi_audio_trigger(struct hdmi_ip_data *ip_data, | ||
580 | struct snd_pcm_substream *substream, int cmd, | ||
581 | struct snd_soc_dai *dai); | ||
582 | int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, | 579 | int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, |
583 | u32 sample_freq, u32 *n, u32 *cts); | 580 | u32 sample_freq, u32 *n, u32 *cts); |
584 | void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, | 581 | void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, |
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 7533458ba4d2..b3e9f9091581 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c | |||
@@ -417,9 +417,10 @@ static const struct venc_config *venc_timings_to_config( | |||
417 | BUG(); | 417 | BUG(); |
418 | } | 418 | } |
419 | 419 | ||
420 | static void venc_power_on(struct omap_dss_device *dssdev) | 420 | static int venc_power_on(struct omap_dss_device *dssdev) |
421 | { | 421 | { |
422 | u32 l; | 422 | u32 l; |
423 | int r; | ||
423 | 424 | ||
424 | venc_reset(); | 425 | venc_reset(); |
425 | venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); | 426 | venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); |
@@ -447,7 +448,22 @@ static void venc_power_on(struct omap_dss_device *dssdev) | |||
447 | if (dssdev->platform_enable) | 448 | if (dssdev->platform_enable) |
448 | dssdev->platform_enable(dssdev); | 449 | dssdev->platform_enable(dssdev); |
449 | 450 | ||
450 | dssdev->manager->enable(dssdev->manager); | 451 | r = dss_mgr_enable(dssdev->manager); |
452 | if (r) | ||
453 | goto err; | ||
454 | |||
455 | return 0; | ||
456 | |||
457 | err: | ||
458 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); | ||
459 | dss_set_dac_pwrdn_bgz(0); | ||
460 | |||
461 | if (dssdev->platform_disable) | ||
462 | dssdev->platform_disable(dssdev); | ||
463 | |||
464 | regulator_disable(venc.vdda_dac_reg); | ||
465 | |||
466 | return r; | ||
451 | } | 467 | } |
452 | 468 | ||
453 | static void venc_power_off(struct omap_dss_device *dssdev) | 469 | static void venc_power_off(struct omap_dss_device *dssdev) |
@@ -455,7 +471,7 @@ static void venc_power_off(struct omap_dss_device *dssdev) | |||
455 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); | 471 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); |
456 | dss_set_dac_pwrdn_bgz(0); | 472 | dss_set_dac_pwrdn_bgz(0); |
457 | 473 | ||
458 | dssdev->manager->disable(dssdev->manager); | 474 | dss_mgr_disable(dssdev->manager); |
459 | 475 | ||
460 | if (dssdev->platform_disable) | 476 | if (dssdev->platform_disable) |
461 | dssdev->platform_disable(dssdev); | 477 | dssdev->platform_disable(dssdev); |
@@ -504,7 +520,9 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) | |||
504 | if (r) | 520 | if (r) |
505 | goto err1; | 521 | goto err1; |
506 | 522 | ||
507 | venc_power_on(dssdev); | 523 | r = venc_power_on(dssdev); |
524 | if (r) | ||
525 | goto err2; | ||
508 | 526 | ||
509 | venc.wss_data = 0; | 527 | venc.wss_data = 0; |
510 | 528 | ||
@@ -512,6 +530,8 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) | |||
512 | 530 | ||
513 | mutex_unlock(&venc.venc_lock); | 531 | mutex_unlock(&venc.venc_lock); |
514 | return 0; | 532 | return 0; |
533 | err2: | ||
534 | venc_runtime_put(); | ||
515 | err1: | 535 | err1: |
516 | omap_dss_stop_device(dssdev); | 536 | omap_dss_stop_device(dssdev); |
517 | err0: | 537 | err0: |