/drivers/video/omap2/dsscomp/queue.c
C | 807 lines | 567 code | 124 blank | 116 comment | 144 complexity | 0c995781fe14bc13eaeb49080eae0339 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
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 */
21
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>
27
28#include <video/omapdss.h>
29#include <video/dsscomp.h>
30#include <plat/dsscomp.h>
31
32#include <linux/debugfs.h>
33
34#include "dsscomp.h"
35/* queue state */
36
37static DEFINE_MUTEX(mtx);
38
39/* free overlay structs */
40struct maskref {
41 u32 mask;
42 u32 refs[MAX_OVERLAYS];
43};
44
45static struct {
46 struct workqueue_struct *apply_workq;
47
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];
52
53static struct workqueue_struct *cb_wkq; /* callback work queue */
54static struct dsscomp_dev *cdev;
55
56#ifdef CONFIG_DEBUG_FS
57LIST_HEAD(dbg_comps);
58DEFINE_MUTEX(dbg_mtx);
59#endif
60
61#ifdef CONFIG_DSSCOMP_DEBUG_LOG
62struct dbg_event_t dbg_events[128];
63u32 dbg_event_ix;
64#endif
65
66static inline void __log_state(dsscomp_t 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))
79
80static inline void maskref_incbit(struct maskref *om, u32 ix)
81{
82 om->refs[ix]++;
83 om->mask |= 1 << ix;
84}
85
86static 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}
95
96/*
97 * ===========================================================================
98 * EXIT
99 * ===========================================================================
100 */
101
102/* Initialize queue structures, and set up state of the displays */
103int dsscomp_queue_init(struct dsscomp_dev *cdev_)
104{
105 u32 i, j;
106 cdev = cdev_;
107
108 if (ARRAY_SIZE(mgrq) < cdev->num_mgrs)
109 return -EINVAL;
110
111 ZERO(mgrq);
112 for (i = 0; i < cdev->num_mgrs; i++) {
113 struct omap_overlay_manager *mgr;
114 mgrq[i].apply_workq = create_singlethread_workqueue("dsscomp_apply");
115 if (!mgrq[i].apply_workq)
116 goto error;
117
118 /* record overlays on this display */
119 mgr = cdev->mgrs[i];
120 for (j = 0; j < cdev->num_ovls; j++) {
121 if (cdev->ovls[j]->info.enabled &&
122 mgr &&
123 cdev->ovls[j]->manager == mgr)
124 mgrq[i].ovl_mask |= 1 << j;
125 }
126 }
127
128 cb_wkq = create_singlethread_workqueue("dsscomp_cb");
129 if (!cb_wkq)
130 goto error;
131
132 return 0;
133error:
134 while (i--)
135 destroy_workqueue(mgrq[i].apply_workq);
136 return -ENOMEM;
137}
138
139/* get display index from manager */
140static u32 get_display_ix(struct omap_overlay_manager *mgr)
141{
142 u32 i;
143
144 /* handle if manager is not attached to a display */
145 if (!mgr || !mgr->device)
146 return cdev->num_displays;
147
148 /* find manager's display */
149 for (i = 0; i < cdev->num_displays; i++)
150 if (cdev->displays[i] == mgr->device)
151 break;
152
153 return i;
154}
155
156/*
157 * ===========================================================================
158 * QUEUING SETUP OPERATIONS
159 * ===========================================================================
160 */
161
162/* create a new composition for a display */
163dsscomp_t dsscomp_new(struct omap_overlay_manager *mgr)
164{
165 struct dsscomp_data *comp = NULL;
166 u32 display_ix = get_display_ix(mgr);
167
168 /* check manager */
169 u32 ix = mgr ? mgr->id : cdev->num_mgrs;
170 if (ix >= cdev->num_mgrs || display_ix >= cdev->num_displays)
171 return ERR_PTR(-EINVAL);
172
173 /* allocate composition */
174 comp = kzalloc(sizeof(*comp), GFP_KERNEL);
175 if (!comp)
176 return NULL;
177
178 /* initialize new composition */
179 comp->ix = ix; /* save where this composition came from */
180 comp->ovl_mask = comp->ovl_dmask = 0;
181 comp->frm.sync_id = 0;
182 comp->frm.mgr.ix = display_ix;
183 comp->state = DSSCOMP_STATE_ACTIVE;
184
185 DO_IF_DEBUG_FS({
186 __log_state(comp, dsscomp_new, 0);
187 list_add(&comp->dbg_q, &dbg_comps);
188 });
189
190 return comp;
191}
192EXPORT_SYMBOL(dsscomp_new);
193
194/* returns overlays used in a composition */
195u32 dsscomp_get_ovls(dsscomp_t comp)
196{
197 u32 mask;
198
199 mutex_lock(&mtx);
200 BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
201 mask = comp->ovl_mask;
202 mutex_unlock(&mtx);
203
204 return mask;
205}
206EXPORT_SYMBOL(dsscomp_get_ovls);
207
208/* set overlay info */
209int dsscomp_set_ovl(dsscomp_t comp, struct dss2_ovl_info *ovl)
210{
211 int r = -EBUSY;
212 u32 i, mask, oix, ix;
213 struct omap_overlay *o;
214
215 mutex_lock(&mtx);
216
217 BUG_ON(!ovl);
218 BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
219
220 ix = comp->ix;
221
222 if (ovl->cfg.ix >= cdev->num_ovls) {
223 r = -EINVAL;
224 goto done;
225 }
226
227 /* if overlay is already part of the composition */
228 mask = 1 << ovl->cfg.ix;
229 if (mask & comp->ovl_mask) {
230 /* look up overlay */
231 for (oix = 0; oix < comp->frm.num_ovls; oix++) {
232 if (comp->ovls[oix].cfg.ix == ovl->cfg.ix)
233 break;
234 }
235 BUG_ON(oix == comp->frm.num_ovls);
236 } else {
237 /* check if ovl is free to use */
238 if (comp->frm.num_ovls >= ARRAY_SIZE(comp->ovls))
239 goto done;
240
241 /* not in any other displays queue */
242 if (mask & ~mgrq[ix].ovl_qmask.mask) {
243 for (i = 0; i < cdev->num_mgrs; i++) {
244 if (i == ix)
245 continue;
246 if (mgrq[i].ovl_qmask.mask & mask)
247 goto done;
248 }
249 }
250
251 /* and disabled (unless forced) if on another manager */
252 o = cdev->ovls[ovl->cfg.ix];
253 if (o->info.enabled && (!o->manager || o->manager->id != ix))
254 goto done;
255
256 /* add overlay to composition & display */
257 comp->ovl_mask |= mask;
258 oix = comp->frm.num_ovls++;
259 maskref_incbit(&mgrq[ix].ovl_qmask, ovl->cfg.ix);
260 }
261
262 comp->ovls[oix] = *ovl;
263 r = 0;
264done:
265 mutex_unlock(&mtx);
266
267 return r;
268}
269EXPORT_SYMBOL(dsscomp_set_ovl);
270
271/* get overlay info */
272int dsscomp_get_ovl(dsscomp_t comp, u32 ix, struct dss2_ovl_info *ovl)
273{
274 int r;
275 u32 oix;
276
277 mutex_lock(&mtx);
278
279 BUG_ON(!ovl);
280 BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
281
282 if (ix >= cdev->num_ovls) {
283 r = -EINVAL;
284 } else if (comp->ovl_mask & (1 << ix)) {
285 r = 0;
286 for (oix = 0; oix < comp->frm.num_ovls; oix++)
287 if (comp->ovls[oix].cfg.ix == ovl->cfg.ix) {
288 *ovl = comp->ovls[oix];
289 break;
290 }
291 BUG_ON(oix == comp->frm.num_ovls);
292 } else {
293 r = -ENOENT;
294 }
295
296 mutex_unlock(&mtx);
297
298 return r;
299}
300EXPORT_SYMBOL(dsscomp_get_ovl);
301
302/* set manager info */
303int dsscomp_set_mgr(dsscomp_t comp, struct dss2_mgr_info *mgr)
304{
305 mutex_lock(&mtx);
306
307 BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
308 BUG_ON(mgr->ix != comp->frm.mgr.ix);
309
310 comp->frm.mgr = *mgr;
311
312 mutex_unlock(&mtx);
313
314 return 0;
315}
316EXPORT_SYMBOL(dsscomp_set_mgr);
317
318/* get manager info */
319int dsscomp_get_mgr(dsscomp_t comp, struct dss2_mgr_info *mgr)
320{
321 mutex_lock(&mtx);
322
323 BUG_ON(!mgr);
324 BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
325
326 *mgr = comp->frm.mgr;
327
328 mutex_unlock(&mtx);
329
330 return 0;
331}
332EXPORT_SYMBOL(dsscomp_get_mgr);
333
334/* get manager info */
335int dsscomp_setup(dsscomp_t comp, enum dsscomp_setup_mode mode,
336 struct dss2_rect_t win)
337{
338 mutex_lock(&mtx);
339
340 BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
341
342 comp->frm.mode = mode;
343 comp->frm.win = win;
344
345 mutex_unlock(&mtx);
346
347 return 0;
348}
349EXPORT_SYMBOL(dsscomp_setup);
350
351/*
352 * ===========================================================================
353 * QUEUING COMMITTING OPERATIONS
354 * ===========================================================================
355 */
356void dsscomp_drop(dsscomp_t comp)
357{
358 /* decrement unprogrammed references */
359 if (comp->state < DSSCOMP_STATE_PROGRAMMED)
360 maskref_decmask(&mgrq[comp->ix].ovl_qmask, comp->ovl_mask);
361 comp->state = 0;
362
363 if (debug & DEBUG_COMPOSITIONS)
364 dev_info(DEV(cdev), "[%p] released\n", comp);
365
366 DO_IF_DEBUG_FS(list_del(&comp->dbg_q));
367
368 kfree(comp);
369}
370EXPORT_SYMBOL(dsscomp_drop);
371
372struct dsscomp_cb_work {
373 struct work_struct work;
374 struct dsscomp_data *comp;
375 int status;
376};
377
378static void dsscomp_mgr_delayed_cb(struct work_struct *work)
379{
380 struct dsscomp_cb_work *wk = container_of(work, typeof(*wk), work);
381 struct dsscomp_data *comp = wk->comp;
382 int status = wk->status;
383 u32 ix;
384
385 kfree(work);
386
387 mutex_lock(&mtx);
388
389 BUG_ON(comp->state == DSSCOMP_STATE_ACTIVE);
390 ix = comp->ix;
391
392 /* call extra callbacks if requested */
393 if (comp->extra_cb)
394 comp->extra_cb(comp->extra_cb_data, status);
395
396 /* handle programming & release */
397 if (status == DSS_COMPLETION_PROGRAMMED) {
398 comp->state = DSSCOMP_STATE_PROGRAMMED;
399 log_state(comp, dsscomp_mgr_delayed_cb, status);
400
401 /* update used overlay mask */
402 mgrq[ix].ovl_mask = comp->ovl_mask & ~comp->ovl_dmask;
403 maskref_decmask(&mgrq[ix].ovl_qmask, comp->ovl_mask);
404
405 if (debug & DEBUG_PHASES)
406 dev_info(DEV(cdev), "[%p] programmed\n", comp);
407 } else if ((status == DSS_COMPLETION_DISPLAYED) &&
408 comp->state == DSSCOMP_STATE_PROGRAMMED) {
409 /* composition is 1st displayed */
410 comp->state = DSSCOMP_STATE_DISPLAYED;
411 log_state(comp, dsscomp_mgr_delayed_cb, status);
412 if (debug & DEBUG_PHASES)
413 dev_info(DEV(cdev), "[%p] displayed\n", comp);
414 } else if (status & DSS_COMPLETION_RELEASED) {
415 /* composition is no longer displayed */
416 log_event(20 * comp->ix + 20, 0, comp, "%pf on %s",
417 (u32) dsscomp_mgr_delayed_cb,
418 (u32) log_status_str(status));
419 dsscomp_drop(comp);
420 }
421 mutex_unlock(&mtx);
422}
423
424static u32 dsscomp_mgr_callback(void *data, int id, int status)
425{
426 struct dsscomp_data *comp = data;
427
428 if (status == DSS_COMPLETION_PROGRAMMED ||
429 (status == DSS_COMPLETION_DISPLAYED &&
430 comp->state != DSSCOMP_STATE_DISPLAYED) ||
431 (status & DSS_COMPLETION_RELEASED)) {
432 struct dsscomp_cb_work *wk = kzalloc(sizeof(*wk), GFP_ATOMIC);
433 wk->comp = comp;
434 wk->status = status;
435 INIT_WORK(&wk->work, dsscomp_mgr_delayed_cb);
436 queue_work(cb_wkq, &wk->work);
437 }
438
439 /* get each callback only once */
440 return ~status;
441}
442
443static inline bool dssdev_manually_updated(struct omap_dss_device *dev)
444{
445 return dev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
446 dev->driver->get_update_mode(dev) != OMAP_DSS_UPDATE_AUTO;
447}
448
449/* apply composition */
450/* at this point the composition is not on any queue */
451static int dsscomp_apply(dsscomp_t comp)
452{
453 int i, r = -EFAULT;
454 u32 dmask, display_ix;
455 struct omap_dss_device *dssdev;
456 struct omap_dss_driver *drv;
457 struct omap_overlay_manager *mgr;
458 struct omap_overlay *ovl;
459 struct dsscomp_setup_mgr_data *d;
460 u32 oix;
461 bool cb_programmed = false;
462
463 struct omapdss_ovl_cb cb = {
464 .fn = dsscomp_mgr_callback,
465 .data = comp,
466 .mask = DSS_COMPLETION_DISPLAYED |
467 DSS_COMPLETION_PROGRAMMED | DSS_COMPLETION_RELEASED,
468 };
469
470 BUG_ON(comp->state != DSSCOMP_STATE_APPLYING);
471
472 /* check if the display is valid and used */
473 r = -ENODEV;
474 d = &comp->frm;
475 display_ix = d->mgr.ix;
476 if (display_ix >= cdev->num_displays)
477 goto done;
478 dssdev = cdev->displays[display_ix];
479 if (!dssdev)
480 goto done;
481
482 drv = dssdev->driver;
483 mgr = dssdev->manager;
484 if (!mgr || !drv || mgr->id >= cdev->num_mgrs)
485 goto done;
486
487 dump_comp_info(cdev, d, "apply");
488
489 r = 0;
490 dmask = 0;
491 for (oix = 0; oix < comp->frm.num_ovls; oix++) {
492 struct dss2_ovl_info *oi = comp->ovls + oix;
493
494 /* keep track of disabled overlays */
495 if (!oi->cfg.enabled)
496 dmask |= 1 << oi->cfg.ix;
497
498 if (r && !comp->must_apply)
499 continue;
500
501 dump_ovl_info(cdev, oi);
502
503 if (oi->cfg.ix >= cdev->num_ovls) {
504 r = -EINVAL;
505 continue;
506 }
507 ovl = cdev->ovls[oi->cfg.ix];
508
509 /* set overlays' manager & info */
510 if (ovl->info.enabled && ovl->manager != mgr) {
511 r = -EBUSY;
512 goto skip_ovl_set;
513 }
514 if (ovl->manager != mgr) {
515 /*
516 * Ideally, we should call ovl->unset_manager(ovl),
517 * but it may block on go even though the disabling
518 * of the overlay already went through. So instead,
519 * we are just clearing the manager.
520 */
521 ovl->manager = NULL;
522 r = ovl->set_manager(ovl, mgr);
523 if (r)
524 goto skip_ovl_set;
525 }
526
527 r = set_dss_ovl_info(oi);
528skip_ovl_set:
529 if (r && comp->must_apply) {
530 dev_err(DEV(cdev), "[%p] set ovl%d failed %d", comp,
531 oi->cfg.ix, r);
532 oi->cfg.enabled = false;
533 dmask |= 1 << oi->cfg.ix;
534 set_dss_ovl_info(oi);
535 }
536 }
537
538 /*
539 * set manager's info - this also sets the completion callback,
540 * so if it succeeds, we will use the callback to complete the
541 * composition. Otherwise, we can skip the composition now.
542 */
543 if (!r || comp->must_apply) {
544 r = set_dss_mgr_info(&d->mgr, &cb);
545 cb_programmed = r == 0;
546 }
547
548 if (r && !comp->must_apply) {
549 dev_err(DEV(cdev), "[%p] set failed %d\n", comp, r);
550 goto done;
551 } else {
552 if (r)
553 dev_warn(DEV(cdev), "[%p] ignoring set failure %d\n",
554 comp, r);
555 comp->blank = dmask == comp->ovl_mask;
556 comp->ovl_dmask = dmask;
557
558 /*
559 * Check other overlays that may also use this display.
560 * NOTE: This is only needed in case someone changes
561 * overlays via sysfs. We use comp->ovl_mask to refresh
562 * the overlays actually used on a manager when the
563 * composition is programmed.
564 */
565 for (i = 0; i < cdev->num_ovls; i++) {
566 u32 mask = 1 << i;
567 if ((~comp->ovl_mask & mask) &&
568 cdev->ovls[i]->info.enabled &&
569 cdev->ovls[i]->manager == mgr) {
570 mutex_lock(&mtx);
571 comp->ovl_mask |= mask;
572 maskref_incbit(&mgrq[comp->ix].ovl_qmask, i);
573 mutex_unlock(&mtx);
574 }
575 }
576 }
577
578 /* apply changes and call update on manual panels */
579 /* no need for mutex as no callbacks are scheduled yet */
580 comp->state = DSSCOMP_STATE_APPLIED;
581 log_state(comp, dsscomp_apply, 0);
582
583 if (!d->win.w && !d->win.x)
584 d->win.w = dssdev->panel.timings.x_res - d->win.x;
585 if (!d->win.h && !d->win.y)
586 d->win.h = dssdev->panel.timings.y_res - d->win.y;
587
588 mutex_lock(&mtx);
589 if (mgrq[comp->ix].blanking) {
590 pr_info_ratelimited("ignoring apply mgr(%s) while blanking\n",
591 mgr->name);
592 r = -ENODEV;
593 } else {
594 r = mgr->apply(mgr);
595 if (r)
596 dev_err(DEV(cdev), "failed while applying %d", r);
597 /* keep error if set_mgr_info failed */
598 if (!r && !cb_programmed)
599 r = -EINVAL;
600 }
601 mutex_unlock(&mtx);
602
603 /*
604 * TRICKY: try to unregister callback to see if callbacks have
605 * been applied (moved into DSS2 pipeline). Unregistering also
606 * avoids having to unnecessarily kick out compositions (which
607 * would result in screen blinking). If callbacks failed to apply,
608 * (e.g. could not set them or apply them) we will need to call
609 * them ourselves (we note this by returning an error).
610 */
611 if (cb_programmed && r) {
612 /* clear error if callback already registered */
613 if (omap_dss_manager_unregister_callback(mgr, &cb))
614 r = 0;
615 }
616 /* if failed to apply, kick out prior composition */
617 if (comp->must_apply && r)
618 mgr->blank(mgr, true);
619
620 if (!r && (d->mode & DSSCOMP_SETUP_MODE_DISPLAY)) {
621 /* cannot handle update errors, so ignore them */
622 if (dssdev_manually_updated(dssdev) && drv->update)
623 drv->update(dssdev, d->win.x,
624 d->win.y, d->win.w, d->win.h);
625 else
626 /* wait for sync to do smooth animations */
627 mgr->wait_for_vsync(mgr);
628 }
629
630done:
631 return r;
632}
633
634struct dsscomp_apply_work {
635 struct work_struct work;
636 dsscomp_t comp;
637};
638
639int dsscomp_state_notifier(struct notifier_block *nb,
640 unsigned long arg, void *ptr)
641{
642 struct omap_dss_device *dssdev = ptr;
643 enum omap_dss_display_state state = arg;
644 struct omap_overlay_manager *mgr = dssdev->manager;
645 if (mgr) {
646 mutex_lock(&mtx);
647 if (state == OMAP_DSS_DISPLAY_DISABLED) {
648 mgr->blank(mgr, true);
649 mgrq[mgr->id].blanking = true;
650 } else if (state == OMAP_DSS_DISPLAY_ACTIVE) {
651 mgrq[mgr->id].blanking = false;
652 }
653 mutex_unlock(&mtx);
654 }
655 return 0;
656}
657
658
659static void dsscomp_do_apply(struct work_struct *work)
660{
661 struct dsscomp_apply_work *wk = container_of(work, typeof(*wk), work);
662 /* complete compositions that failed to apply */
663 if (dsscomp_apply(wk->comp))
664 dsscomp_mgr_callback(wk->comp, -1, DSS_COMPLETION_ECLIPSED_SET);
665 kfree(wk);
666}
667
668int dsscomp_delayed_apply(dsscomp_t comp)
669{
670 /* don't block in case we are called from interrupt context */
671 struct dsscomp_apply_work *wk = kzalloc(sizeof(*wk), GFP_NOWAIT);
672 if (!wk)
673 return -ENOMEM;
674
675 mutex_lock(&mtx);
676
677 BUG_ON(comp->state != DSSCOMP_STATE_ACTIVE);
678 comp->state = DSSCOMP_STATE_APPLYING;
679 log_state(comp, dsscomp_delayed_apply, 0);
680
681 if (debug & DEBUG_PHASES)
682 dev_info(DEV(cdev), "[%p] applying\n", comp);
683 mutex_unlock(&mtx);
684
685 wk->comp = comp;
686 INIT_WORK(&wk->work, dsscomp_do_apply);
687 return queue_work(mgrq[comp->ix].apply_workq, &wk->work) ? 0 : -EBUSY;
688}
689EXPORT_SYMBOL(dsscomp_delayed_apply);
690
691/*
692 * ===========================================================================
693 * DEBUGFS
694 * ===========================================================================
695 */
696
697#ifdef CONFIG_DEBUG_FS
698void seq_print_comp(struct seq_file *s, dsscomp_t c)
699{
700 struct dsscomp_setup_mgr_data *d = &c->frm;
701 int i;
702
703 seq_printf(s, " [%p]: %s%s\n", c, c->blank ? "blank " : "",
704 c->state == DSSCOMP_STATE_ACTIVE ? "ACTIVE" :
705 c->state == DSSCOMP_STATE_APPLYING ? "APPLYING" :
706 c->state == DSSCOMP_STATE_APPLIED ? "APPLIED" :
707 c->state == DSSCOMP_STATE_PROGRAMMED ? "PROGRAMMED" :
708 c->state == DSSCOMP_STATE_DISPLAYED ? "DISPLAYED" :
709 "???");
710 seq_printf(s, " sync_id=%x, flags=%c%c%c\n",
711 d->sync_id,
712 (d->mode & DSSCOMP_SETUP_MODE_APPLY) ? 'A' : '-',
713 (d->mode & DSSCOMP_SETUP_MODE_DISPLAY) ? 'D' : '-',
714 (d->mode & DSSCOMP_SETUP_MODE_CAPTURE) ? 'C' : '-');
715 for (i = 0; i < d->num_ovls; i++) {
716 struct dss2_ovl_info *oi;
717 struct dss2_ovl_cfg *g;
718 oi = d->ovls + i;
719 g = &oi->cfg;
720 if (g->zonly) {
721 seq_printf(s, " ovl%d={%s z%d}\n",
722 g->ix, g->enabled ? "ON" : "off", g->zorder);
723 } else {
724 seq_printf(s, " ovl%d={%s z%d %s%s *%d%%"
725 " %d*%d:%d,%d+%d,%d rot%d%s"
726 " => %d,%d+%d,%d %p/%p|%d}\n",
727 g->ix, g->enabled ? "ON" : "off", g->zorder,
728 dsscomp_get_color_name(g->color_mode) ? : "N/A",
729 g->pre_mult_alpha ? " premult" : "",
730 (g->global_alpha * 100 + 128) / 255,
731 g->width, g->height, g->crop.x, g->crop.y,
732 g->crop.w, g->crop.h,
733 g->rotation, g->mirror ? "+mir" : "",
734 g->win.x, g->win.y, g->win.w, g->win.h,
735 (void *) oi->ba, (void *) oi->uv, g->stride);
736 }
737 }
738 if (c->extra_cb)
739 seq_printf(s, " gsync=[%p] %pf\n\n", c->extra_cb_data,
740 c->extra_cb);
741 else
742 seq_printf(s, " gsync=[%p] (called)\n\n", c->extra_cb_data);
743}
744#endif
745
746void dsscomp_dbg_comps(struct seq_file *s)
747{
748#ifdef CONFIG_DEBUG_FS
749 dsscomp_t c;
750 u32 i;
751
752 mutex_lock(&dbg_mtx);
753 for (i = 0; i < cdev->num_mgrs; i++) {
754 struct omap_overlay_manager *mgr = cdev->mgrs[i];
755 seq_printf(s, "ACTIVE COMPOSITIONS on %s\n\n", mgr->name);
756 list_for_each_entry(c, &dbg_comps, dbg_q) {
757 struct dss2_mgr_info *mi = &c->frm.mgr;
758 if (mi->ix < cdev->num_displays &&
759 cdev->displays[mi->ix]->manager == mgr)
760 seq_print_comp(s, c);
761 }
762
763 /* print manager cache */
764 mgr->dump_cb(mgr, s);
765 }
766 mutex_unlock(&dbg_mtx);
767#endif
768}
769
770void dsscomp_dbg_events(struct seq_file *s)
771{
772#ifdef CONFIG_DSSCOMP_DEBUG_LOG
773 u32 i;
774 struct dbg_event_t *d;
775
776 mutex_lock(&dbg_mtx);
777 for (i = dbg_event_ix; i < dbg_event_ix + ARRAY_SIZE(dbg_events); i++) {
778 d = dbg_events + (i % ARRAY_SIZE(dbg_events));
779 if (!d->ms)
780 continue;
781 seq_printf(s, "[% 5d.%03d] %*s[%08x] ",
782 d->ms / 1000, d->ms % 1000,
783 d->ix + ((u32) d->data) % 7,
784 "", (u32) d->data);
785 seq_printf(s, d->fmt, d->a1, d->a2);
786 seq_printf(s, "\n");
787 }
788 mutex_unlock(&dbg_mtx);
789#endif
790}
791
792/*
793 * ===========================================================================
794 * EXIT
795 * ===========================================================================
796 */
797void dsscomp_queue_exit(void)
798{
799 if (cdev) {
800 int i;
801 for (i = 0; i < cdev->num_displays; i++)
802 destroy_workqueue(mgrq[i].apply_workq);
803 destroy_workqueue(cb_wkq);
804 cdev = NULL;
805 }
806}
807EXPORT_SYMBOL(dsscomp_queue_exit);