]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/kernel-video.git/blob - drivers/video/omap2/dsscomp/queue.c
OMAPDSS: DSSCOMP: Handle inactive state in composition apply
[android-sdk/kernel-video.git] / drivers / video / omap2 / dsscomp / queue.c
1 /*
2  * linux/drivers/video/omap2/dsscomp/queue.c
3  *
4  * DSS Composition queueing support
5  *
6  * Copyright (C) 2011 Texas Instruments, Inc
7  * Author: Lajos Molnar <molnar@ti.com>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License version 2 as published by
11  * the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along with
19  * this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
22 #include <linux/kernel.h>
23 #include <linux/vmalloc.h>
24 #include <linux/sched.h>
25 #include <linux/slab.h>
26 #include <linux/ratelimit.h>
28 #include <video/omapdss.h>
29 #include <video/dsscomp.h>
30 #include <plat/dsscomp.h>
32 #include <linux/debugfs.h>
34 #include "dsscomp.h"
35 /* queue state */
37 static DEFINE_MUTEX(mtx);
39 /* free overlay structs */
40 struct maskref {
41         u32 mask;
42         u32 refs[MAX_OVERLAYS];
43 };
45 static struct {
46         struct workqueue_struct *apply_workq;
48         u32 ovl_mask;                   /* overlays used on this display */
49         struct maskref ovl_qmask;       /* overlays queued to this display */
50         bool blanking;
51 } mgrq[MAX_MANAGERS];
53 static struct workqueue_struct *cb_wkq;         /* callback work queue */
54 static struct dsscomp_dev *cdev;
56 #ifdef CONFIG_DEBUG_FS
57 LIST_HEAD(dbg_comps);
58 DEFINE_MUTEX(dbg_mtx); /* Mutex for debug operations */
59 #endif
61 #ifdef CONFIG_DSSCOMP_DEBUG_LOG
62 struct dbg_event_t dbg_events[128];
63 u32 dbg_event_ix;
64 #endif
66 static inline void __log_state(struct dsscomp *c, void *fn, u32 ev)
67 {
68 #ifdef CONFIG_DSSCOMP_DEBUG_LOG
69         if (c->dbg_used < ARRAY_SIZE(c->dbg_log)) {
70                 u32 t = (u32) ktime_to_ms(ktime_get());
71                 c->dbg_log[c->dbg_used].t = t;
72                 c->dbg_log[c->dbg_used++].state = c->state;
73                 __log_event(20 * c->ix + 20, t, c, ev ? "%pf on %s" : "%pf",
74                                 (u32) fn, (u32) log_status_str(ev));
75         }
76 #endif
77 }
78 #define log_state(c, fn, ev) DO_IF_DEBUG_FS(__log_state(c, fn, ev))
80 static inline void maskref_incbit(struct maskref *om, u32 ix)
81 {
82         om->refs[ix]++;
83         om->mask |= 1 << ix;
84 }
86 static void maskref_decmask(struct maskref *om, u32 mask)
87 {
88         while (mask) {
89                 u32 ix = fls(mask) - 1, m = 1 << ix;
90                 if (!--om->refs[ix])
91                         om->mask &= ~m;
92                 mask &= ~m;
93         }
94 }
96 /*
97  * ===========================================================================
98  *              EXIT
99  * ===========================================================================
100  */
102 /* Initialize queue structures, and set up state of the displays */
103 int dsscomp_queue_init(struct dsscomp_dev *cdev_)
105         u32 i, j;
106         cdev = cdev_;
108         if (ARRAY_SIZE(mgrq) < cdev->num_mgrs)
109                 return -EINVAL;
111         ZERO(mgrq);
112         for (i = 0; i < cdev->num_mgrs; i++) {
113                 struct omap_overlay_manager *mgr;
114                 mgrq[i].apply_workq =
115                         create_singlethread_workqueue("dsscomp_apply");
116                 if (!mgrq[i].apply_workq)
117                         goto error;
119                 /* record overlays on this display */
120                 mgr = cdev->mgrs[i];
121                 for (j = 0; j < cdev->num_ovls; j++) {
122                         if (cdev->ovls[j]->is_enabled(cdev->ovls[j]) &&
123                             mgr &&
124                             cdev->ovls[j]->manager == mgr)
125                                 mgrq[i].ovl_mask |= 1 << j;
126                 }
127         }
129         cb_wkq = create_singlethread_workqueue("dsscomp_cb");
130         if (!cb_wkq)
131                 goto error;
133         return 0;
134 error:
135         while (i--)
136                 destroy_workqueue(mgrq[i].apply_workq);
137         return -ENOMEM;
140 /* get display index from manager */
141 static u32 get_display_ix(struct omap_overlay_manager *mgr)
143         u32 i;
145         /* handle if manager is not attached to a display */
146         if (!mgr || !mgr->output->device)
147                 return cdev->num_displays;
149         /* find manager's display */
150         for (i = 0; i < cdev->num_displays; i++)
151                 if (cdev->displays[i] == mgr->output->device)
152                         break;
154         return i;
157 /*
158  * ===========================================================================
159  *              QUEUING SETUP OPERATIONS
160  * ===========================================================================
161  */
163 /* create a new composition for a display */
164 struct dsscomp *dsscomp_new(struct omap_overlay_manager *mgr)
166         struct dsscomp *comp = NULL;
167         u32 display_ix = get_display_ix(mgr);
169         /* check manager */
170         u32 ix = mgr ? mgr->id : cdev->num_mgrs;
171         if (ix >= cdev->num_mgrs || display_ix >= cdev->num_displays)
172                 return ERR_PTR(-EINVAL);
174         /* allocate composition */
175         comp = kzalloc(sizeof(*comp), GFP_KERNEL);
176         if (!comp)
177                 return NULL;
179         /* initialize new composition */
180         comp->ix = ix;  /* save where this composition came from */
181         comp->ovl_mask = 0;
182         comp->ovl_dmask = 0;
183         comp->frm.sync_id = 0;
184         comp->frm.mgr.ix = display_ix;
185         comp->state = DSSCOMP_STATE_ACTIVE;
187         DO_IF_DEBUG_FS({
188                 __log_state(comp, dsscomp_new, 0);
189                 list_add(&comp->dbg_q, &dbg_comps);
190         });
192         return comp;
194 EXPORT_SYMBOL(dsscomp_new);
196 /* returns overlays used in a composition */
197 u32 dsscomp_get_ovls(struct dsscomp *comp)
199         u32 mask;
201         mutex_lock(&mtx);
202         BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
203         mask = comp->ovl_mask;
204         mutex_unlock(&mtx);
206         return mask;
208 EXPORT_SYMBOL(dsscomp_get_ovls);
210 /* set overlay info */
211 int dsscomp_set_ovl(struct dsscomp *comp, struct dss2_ovl_info *ovl)
213         int r = -EBUSY;
214         u32 i, mask, oix, ix;
215         struct omap_overlay *o;
217         mutex_lock(&mtx);
219         BUG_ON(!ovl);
220         BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
222         ix = comp->ix;
224         if (ovl->cfg.ix >= cdev->num_ovls) {
225                 r = -EINVAL;
226                 goto done;
227         }
229         /* if overlay is already part of the composition */
230         mask = 1 << ovl->cfg.ix;
231         if (mask & comp->ovl_mask) {
232                 /* look up overlay */
233                 for (oix = 0; oix < comp->frm.num_ovls; oix++) {
234                         if (comp->ovls[oix].cfg.ix == ovl->cfg.ix)
235                                 break;
236                 }
237                 BUG_ON(oix == comp->frm.num_ovls);
238         } else {
239                 /* check if ovl is free to use */
240                 if (comp->frm.num_ovls >= ARRAY_SIZE(comp->ovls))
241                         goto done;
243                 /* not in any other displays queue */
244                 if (mask & ~mgrq[ix].ovl_qmask.mask) {
245                         for (i = 0; i < cdev->num_mgrs; i++) {
246                                 if (i == ix)
247                                         continue;
248                                 if (mgrq[i].ovl_qmask.mask & mask)
249                                         goto done;
250                         }
251                 }
253                 /* and disabled (unless forced) if on another manager */
254                 o = cdev->ovls[ovl->cfg.ix];
255                 if (o->is_enabled(o) && (!o->manager || o->manager->id != ix))
256                         goto done;
258                 /* add overlay to composition & display */
259                 comp->ovl_mask |= mask;
260                 oix = comp->frm.num_ovls++;
261                 maskref_incbit(&mgrq[ix].ovl_qmask, ovl->cfg.ix);
262         }
264         comp->ovls[oix] = *ovl;
265         r = 0;
266 done:
267         mutex_unlock(&mtx);
269         return r;
271 EXPORT_SYMBOL(dsscomp_set_ovl);
273 /* get overlay info */
274 int dsscomp_get_ovl(struct dsscomp *comp, u32 ix, struct dss2_ovl_info *ovl)
276         int r;
277         u32 oix;
279         mutex_lock(&mtx);
281         BUG_ON(!ovl);
282         BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
284         if (ix >= cdev->num_ovls) {
285                 r = -EINVAL;
286         } else if (comp->ovl_mask & (1 << ix)) {
287                 r = 0;
288                 for (oix = 0; oix < comp->frm.num_ovls; oix++)
289                         if (comp->ovls[oix].cfg.ix == ovl->cfg.ix) {
290                                 *ovl = comp->ovls[oix];
291                                 break;
292                         }
293                 BUG_ON(oix == comp->frm.num_ovls);
294         } else {
295                 r = -ENOENT;
296         }
298         mutex_unlock(&mtx);
300         return r;
302 EXPORT_SYMBOL(dsscomp_get_ovl);
304 /* set manager info */
305 int dsscomp_set_mgr(struct dsscomp *comp, struct dss2_mgr_info *mgr)
307         mutex_lock(&mtx);
309         BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
310         BUG_ON(mgr->ix != comp->frm.mgr.ix);
312         comp->frm.mgr = *mgr;
314         mutex_unlock(&mtx);
316         return 0;
318 EXPORT_SYMBOL(dsscomp_set_mgr);
320 /* get manager info */
321 int dsscomp_get_mgr(struct dsscomp *comp, struct dss2_mgr_info *mgr)
323         mutex_lock(&mtx);
325         BUG_ON(!mgr);
326         BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
328         *mgr = comp->frm.mgr;
330         mutex_unlock(&mtx);
332         return 0;
334 EXPORT_SYMBOL(dsscomp_get_mgr);
336 /* get manager info */
337 int dsscomp_setup(struct dsscomp *comp, enum dsscomp_setup_mode mode,
338                         struct dss2_rect_t win)
340         mutex_lock(&mtx);
342         BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
344         comp->frm.mode = mode;
345         comp->frm.win = win;
347         mutex_unlock(&mtx);
349         return 0;
351 EXPORT_SYMBOL(dsscomp_setup);
353 /*
354  * ===========================================================================
355  *              QUEUING COMMITTING OPERATIONS
356  * ===========================================================================
357  */
358 void dsscomp_drop(struct dsscomp *comp)
360         /* decrement unprogrammed references */
361         if (comp->state < DSSCOMP_STATE_PROGRAMMED)
362                 maskref_decmask(&mgrq[comp->ix].ovl_qmask, comp->ovl_mask);
363         comp->state = 0;
365         if (debug & DEBUG_COMPOSITIONS)
366                 dev_info(DEV(cdev), "[%p] released\n", comp);
368         DO_IF_DEBUG_FS(list_del(&comp->dbg_q));
370         kfree(comp);
372 EXPORT_SYMBOL(dsscomp_drop);
374 struct dsscomp_cb_work {
375         struct work_struct work;
376         struct dsscomp *comp;
377         int status;
378 };
380 static void dsscomp_mgr_delayed_cb(struct work_struct *work)
382         struct dsscomp_cb_work *wk = container_of(work, typeof(*wk), work);
383         struct dsscomp *comp = wk->comp;
384         int status = wk->status;
385         u32 ix;
387         kfree(work);
389         mutex_lock(&mtx);
391         BUG_ON(comp->state == DSSCOMP_STATE_ACTIVE);
392         ix = comp->ix;
394         /* call extra callbacks if requested */
395         if (comp->extra_cb)
396                 comp->extra_cb(comp->extra_cb_data, status);
398         /* handle programming & release */
399         if (status == DSS_COMPLETION_PROGRAMMED) {
400                 comp->state = DSSCOMP_STATE_PROGRAMMED;
401                 log_state(comp, dsscomp_mgr_delayed_cb, status);
403                 /* update used overlay mask */
404                 mgrq[ix].ovl_mask = comp->ovl_mask & ~comp->ovl_dmask;
405                 maskref_decmask(&mgrq[ix].ovl_qmask, comp->ovl_mask);
407                 if (debug & DEBUG_PHASES)
408                         dev_info(DEV(cdev), "[%p] programmed\n", comp);
409         } else if ((status == DSS_COMPLETION_DISPLAYED) &&
410                    comp->state == DSSCOMP_STATE_PROGRAMMED) {
411                 /* composition is 1st displayed */
412                 comp->state = DSSCOMP_STATE_DISPLAYED;
413                 log_state(comp, dsscomp_mgr_delayed_cb, status);
414                 if (debug & DEBUG_PHASES)
415                         dev_info(DEV(cdev), "[%p] displayed\n", comp);
416         } else if (status & DSS_COMPLETION_RELEASED) {
417                 /* composition is no longer displayed */
418                 log_event(20 * comp->ix + 20, 0, comp, "%pf on %s",
419                                 (u32)dsscomp_mgr_delayed_cb,
420                                 (u32)log_status_str(status));
421                 dsscomp_drop(comp);
422         }
423         mutex_unlock(&mtx);
426 static u32 dsscomp_mgr_callback(void *data, int id, int status)
428         struct dsscomp *comp = data;
430         if (status == DSS_COMPLETION_PROGRAMMED ||
431             (status == DSS_COMPLETION_DISPLAYED &&
432              comp->state != DSSCOMP_STATE_DISPLAYED) ||
433             (status & DSS_COMPLETION_RELEASED)) {
434                 struct dsscomp_cb_work *wk = kzalloc(sizeof(*wk), GFP_ATOMIC);
435                 wk->comp = comp;
436                 wk->status = status;
437                 INIT_WORK(&wk->work, dsscomp_mgr_delayed_cb);
438                 queue_work(cb_wkq, &wk->work);
439         }
441         /* get each callback only once */
442         return ~status;
445 static inline bool dssdev_manually_updated(struct omap_dss_device *dev)
447         return dev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
450 /* apply composition */
451 /* at this point the composition is not on any queue */
452 static int dsscomp_apply(struct dsscomp *comp)
454         int i, r = -EFAULT;
455         u32 dmask, display_ix;
456         struct omap_dss_device *dssdev;
457         struct omap_dss_driver *drv;
458         struct omap_overlay_manager *mgr;
459         struct omap_overlay *ovl;
460         struct dsscomp_setup_mgr_data *d;
461         u32 oix;
462         bool cb_programmed = false;
464         struct omapdss_ovl_cb cb = {
465                 .fn = dsscomp_mgr_callback,
466                 .data = comp,
467                 .mask = DSS_COMPLETION_DISPLAYED |
468                 DSS_COMPLETION_PROGRAMMED | DSS_COMPLETION_RELEASED,
469         };
471         BUG_ON(comp->state != DSSCOMP_STATE_APPLYING);
473         /* check if the display is valid and used */
474         r = -ENODEV;
475         d = &comp->frm;
476         display_ix = d->mgr.ix;
477         if (display_ix >= cdev->num_displays)
478                 goto done;
479         dssdev = cdev->displays[display_ix];
480         if (!dssdev)
481                 goto done;
483         drv = dssdev->driver;
484         mgr = dssdev->output->manager;
485         if (!mgr || !drv || mgr->id >= cdev->num_mgrs)
486                 goto done;
488         dump_comp_info(cdev, d, "apply");
490         r = 0;
491         dmask = 0;
492         for (oix = 0; oix < comp->frm.num_ovls; oix++) {
493                 struct dss2_ovl_info *oi = comp->ovls + oix;
495                 /* keep track of disabled overlays */
496                 if (!oi->cfg.enabled)
497                         dmask |= 1 << oi->cfg.ix;
499                 if (r && !comp->must_apply)
500                         continue;
502                 dump_ovl_info(cdev, oi);
504                 if (oi->cfg.ix >= cdev->num_ovls) {
505                         r = -EINVAL;
506                         continue;
507                 }
508                 ovl = cdev->ovls[oi->cfg.ix];
510                 /* set overlays' manager & info */
511                 if (ovl->is_enabled(ovl) && ovl->manager != mgr) {
512                         r = -EBUSY;
513                         goto skip_ovl_set;
514                 }
515                 if (ovl->manager != mgr) {
516                         /* :NOTE: ignore error from unset */
517                         ovl->unset_manager(ovl);
518                         r = ovl->set_manager(ovl, mgr);
519                         if (r)
520                                 goto skip_ovl_set;
521                 }
523                 r = set_dss_ovl_info(oi);
524 skip_ovl_set:
525                 if (r && comp->must_apply) {
526                         dev_err(DEV(cdev), "[%p] set ovl%d failed %d",
527                                         comp, oi->cfg.ix, r);
528                         oi->cfg.enabled = false;
529                         dmask |= 1 << oi->cfg.ix;
530                         set_dss_ovl_info(oi);
531                 }
532         }
534         /*
535          * set manager's info - this also sets the completion callback,
536          * so if it succeeds, we will use the callback to complete the
537          * composition.  Otherwise, we can skip the composition now.
538          */
539         if (!r || comp->must_apply) {
540                 r = set_dss_mgr_info(&d->mgr, &cb);
541                 cb_programmed = r == 0;
542         }
544         if (r && !comp->must_apply) {
545                 dev_err(DEV(cdev), "[%p] set failed %d\n", comp, r);
546                 goto done;
547         } else {
548                 if (r)
549                         dev_warn(DEV(cdev), "[%p] ignoring set failure %d\n",
550                                         comp, r);
551                 comp->blank = dmask == comp->ovl_mask;
552                 comp->ovl_dmask = dmask;
554                 /*
555                  * Check other overlays that may also use this display.
556                  * NOTE: This is only needed in case someone changes
557                  * overlays via sysfs.  We use comp->ovl_mask to refresh
558                  * the overlays actually used on a manager when the
559                  * composition is programmed.
560                  */
561                 for (i = 0; i < cdev->num_ovls; i++) {
562                         u32 mask = 1 << i;
563                         if ((~comp->ovl_mask & mask) &&
564                             cdev->ovls[i]->is_enabled(cdev->ovls[i]) &&
565                             cdev->ovls[i]->manager == mgr) {
566                                 mutex_lock(&mtx);
567                                 comp->ovl_mask |= mask;
568                                 maskref_incbit(&mgrq[comp->ix].ovl_qmask, i);
569                                 mutex_unlock(&mtx);
570                         }
571                 }
572         }
574         /* apply changes and call update on manual panels */
575         /* no need for mutex as no callbacks are scheduled yet */
576         comp->state = DSSCOMP_STATE_APPLIED;
577         log_state(comp, dsscomp_apply, 0);
579         if (!d->win.w && !d->win.x)
580                 d->win.w = dssdev->panel.timings.x_res - d->win.x;
581         if (!d->win.h && !d->win.y)
582                 d->win.h = dssdev->panel.timings.y_res - d->win.y;
584         mutex_lock(&mtx);
585         if (mgrq[comp->ix].blanking) {
586                 pr_info_ratelimited("ignoring apply mgr(%s) while blanking\n",
587                                     mgr->name);
588                 r = -ENODEV;
589         } else {
590                 r = mgr->apply(mgr);
591                 if (r)
592                         dev_err(DEV(cdev), "failed while applying %d", r);
593                 /* keep error if set_mgr_info failed */
594                 if (!r && !cb_programmed)
595                         r = -EINVAL;
596                 mgr->num_ovls = comp->frm.num_ovls;
597                 for (oix = 0; oix < comp->frm.num_ovls; oix++) {
598                         struct dss2_ovl_info *oi;
599                         oi = comp->ovls + oix;
600                         mgr->ovls[oix] = cdev->ovls[oi->cfg.ix];
601                         mgr->ovls[oix]->enabled = oi->cfg.enabled;
602                 }
603                 if (!r) {
604                         r = mgr->set_ovl(mgr);
605                         if (r) {
606                                 dev_err(DEV(cdev), "[%p] "
607                                         "set_ovl failed\n", comp);
608                                 goto err;
609                         }
610                 }
611         }
612         mutex_unlock(&mtx);
614         /*
615          * TRICKY: try to unregister callback to see if callbacks have
616          * been applied (moved into DSS2 pipeline).  Unregistering also
617          * avoids having to unnecessarily kick out compositions (which
618          * would result in screen blinking).  If callbacks failed to apply,
619          * (e.g. could not set them or apply them) we will need to call
620          * them ourselves (we note this by returning an error).
621          */
622         if (cb_programmed && r) {
623                 /* clear error if callback already registered */
624                 if (omap_dss_manager_unregister_callback(mgr, &cb))
625                         r = 0;
626         }
627         /* if failed to apply, kick out prior composition */
628         if (comp->must_apply && r)
629                 mgr->blank(mgr, true);
631         if (!r && (d->mode & DSSCOMP_SETUP_MODE_DISPLAY)) {
632                 /* cannot handle update errors, so ignore them */
633                 if (dssdev_manually_updated(dssdev) && drv->sync)
634                         drv->update(dssdev, d->win.x, d->win.y, d->win.w,
635                                         d->win.h);
636                 else
637                         /* wait for sync to do smooth animations */
638                         mgr->wait_for_vsync(mgr);
639         }
641         return r;
642 err:
643         mutex_unlock(&mtx);
644 done:
645         return r;
648 struct dsscomp_apply_work {
649         struct work_struct work;
650         struct dsscomp *comp;
651 };
653 int dsscomp_state_notifier(struct notifier_block *nb,
654                                                 unsigned long arg, void *ptr)
656         struct omap_dss_device *dssdev = ptr;
657         enum omap_dss_display_state state = arg;
658         struct omap_overlay_manager *mgr = dssdev->output->manager;
659         if (mgr) {
660                 mutex_lock(&mtx);
661                 if (state == OMAP_DSS_DISPLAY_DISABLED) {
662                         mgr->blank(mgr, true);
663                         mgrq[mgr->id].blanking = true;
664                 } else if (state == OMAP_DSS_DISPLAY_ACTIVE) {
665                         mgrq[mgr->id].blanking = false;
666                 }
667                 mutex_unlock(&mtx);
668         }
669         return 0;
673 static void dsscomp_do_apply(struct work_struct *work)
675         struct dsscomp_apply_work *wk = container_of(work, typeof(*wk), work);
676         /* complete compositions that failed to apply */
677         if (dsscomp_apply(wk->comp))
678                 dsscomp_mgr_callback(wk->comp, -1, DSS_COMPLETION_ECLIPSED_SET);
679         kfree(wk);
682 int dsscomp_delayed_apply(struct dsscomp *comp)
684         /* don't block in case we are called from interrupt context */
685         struct dsscomp_apply_work *wk = kzalloc(sizeof(*wk), GFP_NOWAIT);
686         if (!wk)
687                 return -ENOMEM;
689         mutex_lock(&mtx);
691         BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
692         comp->state = DSSCOMP_STATE_APPLYING;
693         log_state(comp, dsscomp_delayed_apply, 0);
695         if (debug & DEBUG_PHASES)
696                 dev_info(DEV(cdev), "[%p] applying\n", comp);
697         mutex_unlock(&mtx);
699         wk->comp = comp;
700         INIT_WORK(&wk->work, dsscomp_do_apply);
701         return queue_work(mgrq[comp->ix].apply_workq, &wk->work) ? 0 : -EBUSY;
703 EXPORT_SYMBOL(dsscomp_delayed_apply);
705 /*
706  * ===========================================================================
707  *              DEBUGFS
708  * ===========================================================================
709  */
711 #ifdef CONFIG_DEBUG_FS
712 static void seq_print_comp(struct seq_file *s, struct dsscomp *c)
714         struct dsscomp_setup_mgr_data *d = &c->frm;
715         int i;
717         seq_printf(s, "  [%p]: %s%s\n", c, c->blank ? "blank " : "",
718                    c->state == DSSCOMP_STATE_ACTIVE ? "ACTIVE" :
719                    c->state == DSSCOMP_STATE_APPLYING ? "APPLYING" :
720                    c->state == DSSCOMP_STATE_APPLIED ? "APPLIED" :
721                    c->state == DSSCOMP_STATE_PROGRAMMED ? "PROGRAMMED" :
722                    c->state == DSSCOMP_STATE_DISPLAYED ? "DISPLAYED" :
723                    "???");
724         seq_printf(s, "    sync_id=%x, flags=%c%c%c\n",
725                    d->sync_id,
726                    (d->mode & DSSCOMP_SETUP_MODE_APPLY) ? 'A' : '-',
727                    (d->mode & DSSCOMP_SETUP_MODE_DISPLAY) ? 'D' : '-',
728                    (d->mode & DSSCOMP_SETUP_MODE_CAPTURE) ? 'C' : '-');
729         for (i = 0; i < d->num_ovls; i++) {
730                 struct dss2_ovl_info *oi;
731                 struct dss2_ovl_cfg *g;
732                 oi = d->ovls + i;
733                 g = &oi->cfg;
734                 if (g->zonly) {
735                         seq_printf(s, "    ovl%d={%s z%d}\n", g->ix,
736                                         g->enabled ? "ON" : "off",
737                                         g->zorder);
738                 } else {
739                         seq_printf(s, "    ovl%d={%s ", g->ix,
740                                         g->enabled ? "ON" : "off");
741                         seq_printf(s, "z%d %s", g->zorder,
742                                         dsscomp_get_color_name(g->color_mode) ?
743                                         : "N/A");
744                         seq_printf(s, "%s ", g->pre_mult_alpha ?
745                                         " premult" : "");
746                         seq_printf(s, "*%d%%", (g->global_alpha * 100 + 128) /
747                                         255);
748                         seq_printf(s, "%d*%d:%d,", g->width, g->height,
749                                         g->crop.x);
750                         seq_printf(s, "%d+%d,%d ", g->crop.y, g->crop.w,
751                                         g->crop.h);
752                         seq_printf(s, "rot%d%s => ", g->rotation, g->mirror ?
753                                         "+mir" : "");
754                         seq_printf(s, "%d,%d+%d, ", g->win.x, g->win.y,
755                                         g->win.w);
756                         seq_printf(s, "%d %p/%p|%d}\n", g->win.h,
757                                         (void *)oi->ba, (void *)oi->uv,
758                                         g->stride);
759                 }
760         }
761         if (c->extra_cb)
762                 seq_printf(s, "    gsync=[%p] %pf\n\n", c->extra_cb_data,
763                                         c->extra_cb);
764         else
765                 seq_printf(s, "    gsync=[%p] (called)\n\n", c->extra_cb_data);
767 #endif
769 void dsscomp_dbg_comps(struct seq_file *s)
771 #ifdef CONFIG_DEBUG_FS
772         struct dsscomp *c;
773         u32 i;
775         mutex_lock(&dbg_mtx);
776         for (i = 0; i < cdev->num_mgrs; i++) {
777                 struct omap_overlay_manager *mgr = cdev->mgrs[i];
778                 seq_printf(s, "ACTIVE COMPOSITIONS on %s\n\n", mgr->name);
779                 list_for_each_entry(c, &dbg_comps, dbg_q) {
780                         struct dss2_mgr_info *mi = &c->frm.mgr;
781                         if (mi->ix < cdev->num_displays &&
782                             cdev->displays[mi->ix]->output->manager == mgr)
783                                 seq_print_comp(s, c);
784                 }
786                 /* print manager cache */
787                 mgr->dump_cb(mgr, s);
788         }
789         mutex_unlock(&dbg_mtx);
790 #endif
793 void dsscomp_dbg_events(struct seq_file *s)
795 #ifdef CONFIG_DSSCOMP_DEBUG_LOG
796         u32 i;
797         struct dbg_event_t *d;
799         mutex_lock(&dbg_mtx);
800         for (i = dbg_event_ix; i < dbg_event_ix + ARRAY_SIZE(dbg_events); i++) {
801                 d = dbg_events + (i % ARRAY_SIZE(dbg_events));
802                 if (!d->ms)
803                         continue;
804                 seq_printf(s, "[% 5d.%03d] %*s[%08x] ",
805                            d->ms / 1000, d->ms % 1000,
806                            d->ix + ((u32) d->data) % 7,
807                            "", (u32) d->data);
808                 seq_printf(s, d->fmt, d->a1, d->a2);
809                 seq_printf(s, "\n");
810         }
811         mutex_unlock(&dbg_mtx);
812 #endif
815 /*
816  * ===========================================================================
817  *              EXIT
818  * ===========================================================================
819  */
820 void dsscomp_queue_exit(void)
822         if (cdev) {
823                 int i;
824                 for (i = 0; i < cdev->num_displays; i++)
825                         destroy_workqueue(mgrq[i].apply_workq);
826                 destroy_workqueue(cb_wkq);
827                 cdev = NULL;
828         }
830 EXPORT_SYMBOL(dsscomp_queue_exit);