apply.c revision dbce0160af31d2ea323656c201d8debf5af789bf
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 * +--------------------+
35 * |overlay/manager_info|
36 * +--------------------+
37 *          v
38 *        apply()
39 *          v
40 * +--------------------+
41 * |     dss_cache      |
42 * +--------------------+
43 *          v
44 *      configure()
45 *          v
46 * +--------------------+
47 * |  shadow registers  |
48 * +--------------------+
49 *          v
50 * VFP or lcd/digit_enable
51 *          v
52 * +--------------------+
53 * |      registers     |
54 * +--------------------+
55 */
56
57struct overlay_cache_data {
58	/* If true, cache changed, but not written to shadow registers. Set
59	 * in apply(), cleared when registers written. */
60	bool dirty;
61	/* If true, shadow registers contain changed values not yet in real
62	 * registers. Set when writing to shadow registers, cleared at
63	 * VSYNC/EVSYNC */
64	bool shadow_dirty;
65
66	bool enabled;
67
68	struct omap_overlay_info info;
69
70	enum omap_channel channel;
71
72	u32 fifo_low;
73	u32 fifo_high;
74};
75
76struct manager_cache_data {
77	/* If true, cache changed, but not written to shadow registers. Set
78	 * in apply(), cleared when registers written. */
79	bool dirty;
80	/* If true, shadow registers contain changed values not yet in real
81	 * registers. Set when writing to shadow registers, cleared at
82	 * VSYNC/EVSYNC */
83	bool shadow_dirty;
84
85	struct omap_overlay_manager_info info;
86
87	bool manual_update;
88	bool do_manual_update;
89};
90
91static struct {
92	spinlock_t lock;
93	struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS];
94	struct manager_cache_data manager_cache[MAX_DSS_MANAGERS];
95
96	bool irq_enabled;
97} dss_cache;
98
99void dss_apply_init(void)
100{
101	spin_lock_init(&dss_cache.lock);
102}
103
104static bool ovl_manual_update(struct omap_overlay *ovl)
105{
106	return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
107}
108
109static bool mgr_manual_update(struct omap_overlay_manager *mgr)
110{
111	return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
112}
113
114static int overlay_enabled(struct omap_overlay *ovl)
115{
116	return ovl->info.enabled && ovl->manager && ovl->manager->device;
117}
118
119int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
120{
121	unsigned long timeout = msecs_to_jiffies(500);
122	struct manager_cache_data *mc;
123	u32 irq;
124	int r;
125	int i;
126	struct omap_dss_device *dssdev = mgr->device;
127
128	if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
129		return 0;
130
131	if (mgr_manual_update(mgr))
132		return 0;
133
134	if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
135			|| dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
136		irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
137	} else {
138		irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
139			DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
140	}
141
142	mc = &dss_cache.manager_cache[mgr->id];
143	i = 0;
144	while (1) {
145		unsigned long flags;
146		bool shadow_dirty, dirty;
147
148		spin_lock_irqsave(&dss_cache.lock, flags);
149		dirty = mc->dirty;
150		shadow_dirty = mc->shadow_dirty;
151		spin_unlock_irqrestore(&dss_cache.lock, flags);
152
153		if (!dirty && !shadow_dirty) {
154			r = 0;
155			break;
156		}
157
158		/* 4 iterations is the worst case:
159		 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
160		 * 2 - first VSYNC, dirty = true
161		 * 3 - dirty = false, shadow_dirty = true
162		 * 4 - shadow_dirty = false */
163		if (i++ == 3) {
164			DSSERR("mgr(%d)->wait_for_go() not finishing\n",
165					mgr->id);
166			r = 0;
167			break;
168		}
169
170		r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
171		if (r == -ERESTARTSYS)
172			break;
173
174		if (r) {
175			DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
176			break;
177		}
178	}
179
180	return r;
181}
182
183int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
184{
185	unsigned long timeout = msecs_to_jiffies(500);
186	struct overlay_cache_data *oc;
187	struct omap_dss_device *dssdev;
188	u32 irq;
189	int r;
190	int i;
191
192	if (!ovl->manager)
193		return 0;
194
195	dssdev = ovl->manager->device;
196
197	if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
198		return 0;
199
200	if (ovl_manual_update(ovl))
201		return 0;
202
203	if (dssdev->type == OMAP_DISPLAY_TYPE_VENC
204			|| dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
205		irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
206	} else {
207		irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ?
208			DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2;
209	}
210
211	oc = &dss_cache.overlay_cache[ovl->id];
212	i = 0;
213	while (1) {
214		unsigned long flags;
215		bool shadow_dirty, dirty;
216
217		spin_lock_irqsave(&dss_cache.lock, flags);
218		dirty = oc->dirty;
219		shadow_dirty = oc->shadow_dirty;
220		spin_unlock_irqrestore(&dss_cache.lock, flags);
221
222		if (!dirty && !shadow_dirty) {
223			r = 0;
224			break;
225		}
226
227		/* 4 iterations is the worst case:
228		 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
229		 * 2 - first VSYNC, dirty = true
230		 * 3 - dirty = false, shadow_dirty = true
231		 * 4 - shadow_dirty = false */
232		if (i++ == 3) {
233			DSSERR("ovl(%d)->wait_for_go() not finishing\n",
234					ovl->id);
235			r = 0;
236			break;
237		}
238
239		r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
240		if (r == -ERESTARTSYS)
241			break;
242
243		if (r) {
244			DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
245			break;
246		}
247	}
248
249	return r;
250}
251
252static int configure_overlay(enum omap_plane plane)
253{
254	struct omap_overlay *ovl;
255	struct overlay_cache_data *c;
256	struct omap_overlay_info *oi;
257	bool ilace, replication;
258	int r;
259
260	DSSDBGF("%d", plane);
261
262	c = &dss_cache.overlay_cache[plane];
263	oi = &c->info;
264
265	if (!c->enabled) {
266		dispc_ovl_enable(plane, 0);
267		return 0;
268	}
269
270	ovl = omap_dss_get_overlay(plane);
271
272	replication = dss_use_replication(ovl->manager->device, oi->color_mode);
273
274	ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC;
275
276	dispc_ovl_set_channel_out(plane, c->channel);
277
278	r = dispc_ovl_setup(plane, oi, ilace, replication);
279	if (r) {
280		/* this shouldn't happen */
281		DSSERR("dispc_ovl_setup failed for ovl %d\n", plane);
282		dispc_ovl_enable(plane, 0);
283		return r;
284	}
285
286	dispc_ovl_set_fifo_threshold(plane, c->fifo_low, c->fifo_high);
287
288	dispc_ovl_enable(plane, 1);
289
290	return 0;
291}
292
293static void configure_manager(enum omap_channel channel)
294{
295	struct omap_overlay_manager_info *mi;
296
297	DSSDBGF("%d", channel);
298
299	/* picking info from the cache */
300	mi = &dss_cache.manager_cache[channel].info;
301
302	dispc_mgr_setup(channel, mi);
303}
304
305/* configure_dispc() tries to write values from cache to shadow registers.
306 * It writes only to those managers/overlays that are not busy.
307 * returns 0 if everything could be written to shadow registers.
308 * returns 1 if not everything could be written to shadow registers. */
309static int configure_dispc(void)
310{
311	struct overlay_cache_data *oc;
312	struct manager_cache_data *mc;
313	const int num_ovls = dss_feat_get_num_ovls();
314	const int num_mgrs = dss_feat_get_num_mgrs();
315	int i;
316	int r;
317	bool mgr_busy[MAX_DSS_MANAGERS];
318	bool mgr_go[MAX_DSS_MANAGERS];
319	bool busy;
320
321	r = 0;
322	busy = false;
323
324	for (i = 0; i < num_mgrs; i++) {
325		mgr_busy[i] = dispc_mgr_go_busy(i);
326		mgr_go[i] = false;
327	}
328
329	/* Commit overlay settings */
330	for (i = 0; i < num_ovls; ++i) {
331		oc = &dss_cache.overlay_cache[i];
332		mc = &dss_cache.manager_cache[oc->channel];
333
334		if (!oc->dirty)
335			continue;
336
337		if (mc->manual_update && !mc->do_manual_update)
338			continue;
339
340		if (mgr_busy[oc->channel]) {
341			busy = true;
342			continue;
343		}
344
345		r = configure_overlay(i);
346		if (r)
347			DSSERR("configure_overlay %d failed\n", i);
348
349		oc->dirty = false;
350		oc->shadow_dirty = true;
351		mgr_go[oc->channel] = true;
352	}
353
354	/* Commit manager settings */
355	for (i = 0; i < num_mgrs; ++i) {
356		mc = &dss_cache.manager_cache[i];
357
358		if (!mc->dirty)
359			continue;
360
361		if (mc->manual_update && !mc->do_manual_update)
362			continue;
363
364		if (mgr_busy[i]) {
365			busy = true;
366			continue;
367		}
368
369		configure_manager(i);
370		mc->dirty = false;
371		mc->shadow_dirty = true;
372		mgr_go[i] = true;
373	}
374
375	/* set GO */
376	for (i = 0; i < num_mgrs; ++i) {
377		mc = &dss_cache.manager_cache[i];
378
379		if (!mgr_go[i])
380			continue;
381
382		/* We don't need GO with manual update display. LCD iface will
383		 * always be turned off after frame, and new settings will be
384		 * taken in to use at next update */
385		if (!mc->manual_update)
386			dispc_mgr_go(i);
387	}
388
389	if (busy)
390		r = 1;
391	else
392		r = 0;
393
394	return r;
395}
396
397void dss_mgr_start_update(struct omap_overlay_manager *mgr)
398{
399	struct manager_cache_data *mc;
400	struct overlay_cache_data *oc;
401	struct omap_overlay *ovl;
402
403	mc = &dss_cache.manager_cache[mgr->id];
404
405	mc->do_manual_update = true;
406	configure_dispc();
407	mc->do_manual_update = false;
408
409	list_for_each_entry(ovl, &mgr->overlays, list) {
410		oc = &dss_cache.overlay_cache[ovl->id];
411		oc->shadow_dirty = false;
412	}
413
414	mc = &dss_cache.manager_cache[mgr->id];
415	mc->shadow_dirty = false;
416
417	dispc_mgr_enable(mgr->id, true);
418}
419
420static void dss_apply_irq_handler(void *data, u32 mask);
421
422static void dss_register_vsync_isr(void)
423{
424	u32 mask;
425	int r;
426
427	mask = DISPC_IRQ_VSYNC	| DISPC_IRQ_EVSYNC_ODD |
428		DISPC_IRQ_EVSYNC_EVEN;
429	if (dss_has_feature(FEAT_MGR_LCD2))
430		mask |= DISPC_IRQ_VSYNC2;
431
432	r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
433	WARN_ON(r);
434
435	dss_cache.irq_enabled = true;
436}
437
438static void dss_unregister_vsync_isr(void)
439{
440	u32 mask;
441	int r;
442
443	mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
444			DISPC_IRQ_EVSYNC_EVEN;
445	if (dss_has_feature(FEAT_MGR_LCD2))
446		mask |= DISPC_IRQ_VSYNC2;
447
448	r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
449	WARN_ON(r);
450
451	dss_cache.irq_enabled = false;
452}
453
454static void dss_apply_irq_handler(void *data, u32 mask)
455{
456	struct manager_cache_data *mc;
457	struct overlay_cache_data *oc;
458	const int num_ovls = dss_feat_get_num_ovls();
459	const int num_mgrs = dss_feat_get_num_mgrs();
460	int i, r;
461	bool mgr_busy[MAX_DSS_MANAGERS];
462
463	for (i = 0; i < num_mgrs; i++)
464		mgr_busy[i] = dispc_mgr_go_busy(i);
465
466	spin_lock(&dss_cache.lock);
467
468	for (i = 0; i < num_ovls; ++i) {
469		oc = &dss_cache.overlay_cache[i];
470		if (!mgr_busy[oc->channel])
471			oc->shadow_dirty = false;
472	}
473
474	for (i = 0; i < num_mgrs; ++i) {
475		mc = &dss_cache.manager_cache[i];
476		if (!mgr_busy[i])
477			mc->shadow_dirty = false;
478	}
479
480	r = configure_dispc();
481	if (r == 1)
482		goto end;
483
484	/* re-read busy flags */
485	for (i = 0; i < num_mgrs; i++)
486		mgr_busy[i] = dispc_mgr_go_busy(i);
487
488	/* keep running as long as there are busy managers, so that
489	 * we can collect overlay-applied information */
490	for (i = 0; i < num_mgrs; ++i) {
491		if (mgr_busy[i])
492			goto end;
493	}
494
495	dss_unregister_vsync_isr();
496
497end:
498	spin_unlock(&dss_cache.lock);
499}
500
501static int omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
502{
503	struct overlay_cache_data *oc;
504	struct omap_dss_device *dssdev;
505
506	oc = &dss_cache.overlay_cache[ovl->id];
507
508	if (ovl->manager_changed) {
509		ovl->manager_changed = false;
510		ovl->info_dirty  = true;
511	}
512
513	if (!overlay_enabled(ovl)) {
514		if (oc->enabled) {
515			oc->enabled = false;
516			oc->dirty = true;
517		}
518		return 0;
519	}
520
521	if (!ovl->info_dirty)
522		return 0;
523
524	dssdev = ovl->manager->device;
525
526	if (dss_check_overlay(ovl, dssdev)) {
527		if (oc->enabled) {
528			oc->enabled = false;
529			oc->dirty = true;
530		}
531		return -EINVAL;
532	}
533
534	ovl->info_dirty = false;
535	oc->dirty = true;
536	oc->info = ovl->info;
537
538	oc->channel = ovl->manager->id;
539
540	oc->enabled = true;
541
542	return 0;
543}
544
545static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
546{
547	struct manager_cache_data *mc;
548
549	mc = &dss_cache.manager_cache[mgr->id];
550
551	if (mgr->device_changed) {
552		mgr->device_changed = false;
553		mgr->info_dirty  = true;
554	}
555
556	if (!mgr->info_dirty)
557		return;
558
559	if (!mgr->device)
560		return;
561
562	mgr->info_dirty = false;
563	mc->dirty = true;
564	mc->info = mgr->info;
565
566	mc->manual_update = mgr_manual_update(mgr);
567}
568
569static void omap_dss_mgr_apply_ovl_fifos(struct omap_overlay *ovl)
570{
571	struct overlay_cache_data *oc;
572	struct omap_dss_device *dssdev;
573	u32 size, burst_size;
574
575	oc = &dss_cache.overlay_cache[ovl->id];
576
577	if (!oc->enabled)
578		return;
579
580	dssdev = ovl->manager->device;
581
582	size = dispc_ovl_get_fifo_size(ovl->id);
583
584	burst_size = dispc_ovl_get_burst_size(ovl->id);
585
586	switch (dssdev->type) {
587	case OMAP_DISPLAY_TYPE_DPI:
588	case OMAP_DISPLAY_TYPE_DBI:
589	case OMAP_DISPLAY_TYPE_SDI:
590	case OMAP_DISPLAY_TYPE_VENC:
591	case OMAP_DISPLAY_TYPE_HDMI:
592		default_get_overlay_fifo_thresholds(ovl->id, size,
593				burst_size, &oc->fifo_low,
594				&oc->fifo_high);
595		break;
596#ifdef CONFIG_OMAP2_DSS_DSI
597	case OMAP_DISPLAY_TYPE_DSI:
598		dsi_get_overlay_fifo_thresholds(ovl->id, size,
599				burst_size, &oc->fifo_low,
600				&oc->fifo_high);
601		break;
602#endif
603	default:
604		BUG();
605	}
606}
607
608int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
609{
610	int r;
611	unsigned long flags;
612	struct omap_overlay *ovl;
613
614	DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
615
616	r = dispc_runtime_get();
617	if (r)
618		return r;
619
620	spin_lock_irqsave(&dss_cache.lock, flags);
621
622	/* Configure overlays */
623	list_for_each_entry(ovl, &mgr->overlays, list)
624		omap_dss_mgr_apply_ovl(ovl);
625
626	/* Configure manager */
627	omap_dss_mgr_apply_mgr(mgr);
628
629	/* Configure overlay fifos */
630	list_for_each_entry(ovl, &mgr->overlays, list)
631		omap_dss_mgr_apply_ovl_fifos(ovl);
632
633	r = 0;
634	if (mgr->enabled && !mgr_manual_update(mgr)) {
635		if (!dss_cache.irq_enabled)
636			dss_register_vsync_isr();
637
638		configure_dispc();
639	}
640
641	spin_unlock_irqrestore(&dss_cache.lock, flags);
642
643	dispc_runtime_put();
644
645	return r;
646}
647
648void dss_mgr_enable(struct omap_overlay_manager *mgr)
649{
650	dispc_mgr_enable(mgr->id, true);
651	mgr->enabled = true;
652}
653
654void dss_mgr_disable(struct omap_overlay_manager *mgr)
655{
656	dispc_mgr_enable(mgr->id, false);
657	mgr->enabled = false;
658}
659
660