• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/video/omap2/dss/
1/*
2 * linux/drivers/video/omap2/dss/dispc.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DISPC"
24
25#include <linux/kernel.h>
26#include <linux/dma-mapping.h>
27#include <linux/vmalloc.h>
28#include <linux/clk.h>
29#include <linux/io.h>
30#include <linux/jiffies.h>
31#include <linux/seq_file.h>
32#include <linux/delay.h>
33#include <linux/workqueue.h>
34#include <linux/hardirq.h>
35
36#include <plat/sram.h>
37#include <plat/clock.h>
38
39#include <plat/display.h>
40
41#include "dss.h"
42
43/* DISPC */
44#define DISPC_BASE			0x48050400
45
46#define DISPC_SZ_REGS			SZ_1K
47
48struct dispc_reg { u16 idx; };
49
50#define DISPC_REG(idx)			((const struct dispc_reg) { idx })
51
52/* DISPC common */
53#define DISPC_REVISION			DISPC_REG(0x0000)
54#define DISPC_SYSCONFIG			DISPC_REG(0x0010)
55#define DISPC_SYSSTATUS			DISPC_REG(0x0014)
56#define DISPC_IRQSTATUS			DISPC_REG(0x0018)
57#define DISPC_IRQENABLE			DISPC_REG(0x001C)
58#define DISPC_CONTROL			DISPC_REG(0x0040)
59#define DISPC_CONFIG			DISPC_REG(0x0044)
60#define DISPC_CAPABLE			DISPC_REG(0x0048)
61#define DISPC_DEFAULT_COLOR0		DISPC_REG(0x004C)
62#define DISPC_DEFAULT_COLOR1		DISPC_REG(0x0050)
63#define DISPC_TRANS_COLOR0		DISPC_REG(0x0054)
64#define DISPC_TRANS_COLOR1		DISPC_REG(0x0058)
65#define DISPC_LINE_STATUS		DISPC_REG(0x005C)
66#define DISPC_LINE_NUMBER		DISPC_REG(0x0060)
67#define DISPC_TIMING_H			DISPC_REG(0x0064)
68#define DISPC_TIMING_V			DISPC_REG(0x0068)
69#define DISPC_POL_FREQ			DISPC_REG(0x006C)
70#define DISPC_DIVISOR			DISPC_REG(0x0070)
71#define DISPC_GLOBAL_ALPHA		DISPC_REG(0x0074)
72#define DISPC_SIZE_DIG			DISPC_REG(0x0078)
73#define DISPC_SIZE_LCD			DISPC_REG(0x007C)
74
75/* DISPC GFX plane */
76#define DISPC_GFX_BA0			DISPC_REG(0x0080)
77#define DISPC_GFX_BA1			DISPC_REG(0x0084)
78#define DISPC_GFX_POSITION		DISPC_REG(0x0088)
79#define DISPC_GFX_SIZE			DISPC_REG(0x008C)
80#define DISPC_GFX_ATTRIBUTES		DISPC_REG(0x00A0)
81#define DISPC_GFX_FIFO_THRESHOLD	DISPC_REG(0x00A4)
82#define DISPC_GFX_FIFO_SIZE_STATUS	DISPC_REG(0x00A8)
83#define DISPC_GFX_ROW_INC		DISPC_REG(0x00AC)
84#define DISPC_GFX_PIXEL_INC		DISPC_REG(0x00B0)
85#define DISPC_GFX_WINDOW_SKIP		DISPC_REG(0x00B4)
86#define DISPC_GFX_TABLE_BA		DISPC_REG(0x00B8)
87
88#define DISPC_DATA_CYCLE1		DISPC_REG(0x01D4)
89#define DISPC_DATA_CYCLE2		DISPC_REG(0x01D8)
90#define DISPC_DATA_CYCLE3		DISPC_REG(0x01DC)
91
92#define DISPC_CPR_COEF_R		DISPC_REG(0x0220)
93#define DISPC_CPR_COEF_G		DISPC_REG(0x0224)
94#define DISPC_CPR_COEF_B		DISPC_REG(0x0228)
95
96#define DISPC_GFX_PRELOAD		DISPC_REG(0x022C)
97
98/* DISPC Video plane, n = 0 for VID1 and n = 1 for VID2 */
99#define DISPC_VID_REG(n, idx)		DISPC_REG(0x00BC + (n)*0x90 + idx)
100
101#define DISPC_VID_BA0(n)		DISPC_VID_REG(n, 0x0000)
102#define DISPC_VID_BA1(n)		DISPC_VID_REG(n, 0x0004)
103#define DISPC_VID_POSITION(n)		DISPC_VID_REG(n, 0x0008)
104#define DISPC_VID_SIZE(n)		DISPC_VID_REG(n, 0x000C)
105#define DISPC_VID_ATTRIBUTES(n)		DISPC_VID_REG(n, 0x0010)
106#define DISPC_VID_FIFO_THRESHOLD(n)	DISPC_VID_REG(n, 0x0014)
107#define DISPC_VID_FIFO_SIZE_STATUS(n)	DISPC_VID_REG(n, 0x0018)
108#define DISPC_VID_ROW_INC(n)		DISPC_VID_REG(n, 0x001C)
109#define DISPC_VID_PIXEL_INC(n)		DISPC_VID_REG(n, 0x0020)
110#define DISPC_VID_FIR(n)		DISPC_VID_REG(n, 0x0024)
111#define DISPC_VID_PICTURE_SIZE(n)	DISPC_VID_REG(n, 0x0028)
112#define DISPC_VID_ACCU0(n)		DISPC_VID_REG(n, 0x002C)
113#define DISPC_VID_ACCU1(n)		DISPC_VID_REG(n, 0x0030)
114
115/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
116#define DISPC_VID_FIR_COEF_H(n, i)	DISPC_REG(0x00F0 + (n)*0x90 + (i)*0x8)
117/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
118#define DISPC_VID_FIR_COEF_HV(n, i)	DISPC_REG(0x00F4 + (n)*0x90 + (i)*0x8)
119/* coef index i = {0, 1, 2, 3, 4} */
120#define DISPC_VID_CONV_COEF(n, i)	DISPC_REG(0x0130 + (n)*0x90 + (i)*0x4)
121/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
122#define DISPC_VID_FIR_COEF_V(n, i)	DISPC_REG(0x01E0 + (n)*0x20 + (i)*0x4)
123
124#define DISPC_VID_PRELOAD(n)		DISPC_REG(0x230 + (n)*0x04)
125
126
127#define DISPC_IRQ_MASK_ERROR            (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
128					 DISPC_IRQ_OCP_ERR | \
129					 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
130					 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
131					 DISPC_IRQ_SYNC_LOST | \
132					 DISPC_IRQ_SYNC_LOST_DIGIT)
133
134#define DISPC_MAX_NR_ISRS		8
135
136struct omap_dispc_isr_data {
137	omap_dispc_isr_t	isr;
138	void			*arg;
139	u32			mask;
140};
141
142#define REG_GET(idx, start, end) \
143	FLD_GET(dispc_read_reg(idx), start, end)
144
145#define REG_FLD_MOD(idx, val, start, end)				\
146	dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
147
148static const struct dispc_reg dispc_reg_att[] = { DISPC_GFX_ATTRIBUTES,
149	DISPC_VID_ATTRIBUTES(0),
150	DISPC_VID_ATTRIBUTES(1) };
151
152struct dispc_irq_stats {
153	unsigned long last_reset;
154	unsigned irq_count;
155	unsigned irqs[32];
156};
157
158static struct {
159	void __iomem    *base;
160
161	u32	fifo_size[3];
162
163	spinlock_t irq_lock;
164	u32 irq_error_mask;
165	struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
166	u32 error_irqs;
167	struct work_struct error_work;
168
169	u32		ctx[DISPC_SZ_REGS / sizeof(u32)];
170
171#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
172	spinlock_t irq_stats_lock;
173	struct dispc_irq_stats irq_stats;
174#endif
175} dispc;
176
177static void _omap_dispc_set_irqs(void);
178
179static inline void dispc_write_reg(const struct dispc_reg idx, u32 val)
180{
181	__raw_writel(val, dispc.base + idx.idx);
182}
183
184static inline u32 dispc_read_reg(const struct dispc_reg idx)
185{
186	return __raw_readl(dispc.base + idx.idx);
187}
188
189#define SR(reg) \
190	dispc.ctx[(DISPC_##reg).idx / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
191#define RR(reg) \
192	dispc_write_reg(DISPC_##reg, dispc.ctx[(DISPC_##reg).idx / sizeof(u32)])
193
194void dispc_save_context(void)
195{
196	if (cpu_is_omap24xx())
197		return;
198
199	SR(SYSCONFIG);
200	SR(IRQENABLE);
201	SR(CONTROL);
202	SR(CONFIG);
203	SR(DEFAULT_COLOR0);
204	SR(DEFAULT_COLOR1);
205	SR(TRANS_COLOR0);
206	SR(TRANS_COLOR1);
207	SR(LINE_NUMBER);
208	SR(TIMING_H);
209	SR(TIMING_V);
210	SR(POL_FREQ);
211	SR(DIVISOR);
212	SR(GLOBAL_ALPHA);
213	SR(SIZE_DIG);
214	SR(SIZE_LCD);
215
216	SR(GFX_BA0);
217	SR(GFX_BA1);
218	SR(GFX_POSITION);
219	SR(GFX_SIZE);
220	SR(GFX_ATTRIBUTES);
221	SR(GFX_FIFO_THRESHOLD);
222	SR(GFX_ROW_INC);
223	SR(GFX_PIXEL_INC);
224	SR(GFX_WINDOW_SKIP);
225	SR(GFX_TABLE_BA);
226
227	SR(DATA_CYCLE1);
228	SR(DATA_CYCLE2);
229	SR(DATA_CYCLE3);
230
231	SR(CPR_COEF_R);
232	SR(CPR_COEF_G);
233	SR(CPR_COEF_B);
234
235	SR(GFX_PRELOAD);
236
237	/* VID1 */
238	SR(VID_BA0(0));
239	SR(VID_BA1(0));
240	SR(VID_POSITION(0));
241	SR(VID_SIZE(0));
242	SR(VID_ATTRIBUTES(0));
243	SR(VID_FIFO_THRESHOLD(0));
244	SR(VID_ROW_INC(0));
245	SR(VID_PIXEL_INC(0));
246	SR(VID_FIR(0));
247	SR(VID_PICTURE_SIZE(0));
248	SR(VID_ACCU0(0));
249	SR(VID_ACCU1(0));
250
251	SR(VID_FIR_COEF_H(0, 0));
252	SR(VID_FIR_COEF_H(0, 1));
253	SR(VID_FIR_COEF_H(0, 2));
254	SR(VID_FIR_COEF_H(0, 3));
255	SR(VID_FIR_COEF_H(0, 4));
256	SR(VID_FIR_COEF_H(0, 5));
257	SR(VID_FIR_COEF_H(0, 6));
258	SR(VID_FIR_COEF_H(0, 7));
259
260	SR(VID_FIR_COEF_HV(0, 0));
261	SR(VID_FIR_COEF_HV(0, 1));
262	SR(VID_FIR_COEF_HV(0, 2));
263	SR(VID_FIR_COEF_HV(0, 3));
264	SR(VID_FIR_COEF_HV(0, 4));
265	SR(VID_FIR_COEF_HV(0, 5));
266	SR(VID_FIR_COEF_HV(0, 6));
267	SR(VID_FIR_COEF_HV(0, 7));
268
269	SR(VID_CONV_COEF(0, 0));
270	SR(VID_CONV_COEF(0, 1));
271	SR(VID_CONV_COEF(0, 2));
272	SR(VID_CONV_COEF(0, 3));
273	SR(VID_CONV_COEF(0, 4));
274
275	SR(VID_FIR_COEF_V(0, 0));
276	SR(VID_FIR_COEF_V(0, 1));
277	SR(VID_FIR_COEF_V(0, 2));
278	SR(VID_FIR_COEF_V(0, 3));
279	SR(VID_FIR_COEF_V(0, 4));
280	SR(VID_FIR_COEF_V(0, 5));
281	SR(VID_FIR_COEF_V(0, 6));
282	SR(VID_FIR_COEF_V(0, 7));
283
284	SR(VID_PRELOAD(0));
285
286	/* VID2 */
287	SR(VID_BA0(1));
288	SR(VID_BA1(1));
289	SR(VID_POSITION(1));
290	SR(VID_SIZE(1));
291	SR(VID_ATTRIBUTES(1));
292	SR(VID_FIFO_THRESHOLD(1));
293	SR(VID_ROW_INC(1));
294	SR(VID_PIXEL_INC(1));
295	SR(VID_FIR(1));
296	SR(VID_PICTURE_SIZE(1));
297	SR(VID_ACCU0(1));
298	SR(VID_ACCU1(1));
299
300	SR(VID_FIR_COEF_H(1, 0));
301	SR(VID_FIR_COEF_H(1, 1));
302	SR(VID_FIR_COEF_H(1, 2));
303	SR(VID_FIR_COEF_H(1, 3));
304	SR(VID_FIR_COEF_H(1, 4));
305	SR(VID_FIR_COEF_H(1, 5));
306	SR(VID_FIR_COEF_H(1, 6));
307	SR(VID_FIR_COEF_H(1, 7));
308
309	SR(VID_FIR_COEF_HV(1, 0));
310	SR(VID_FIR_COEF_HV(1, 1));
311	SR(VID_FIR_COEF_HV(1, 2));
312	SR(VID_FIR_COEF_HV(1, 3));
313	SR(VID_FIR_COEF_HV(1, 4));
314	SR(VID_FIR_COEF_HV(1, 5));
315	SR(VID_FIR_COEF_HV(1, 6));
316	SR(VID_FIR_COEF_HV(1, 7));
317
318	SR(VID_CONV_COEF(1, 0));
319	SR(VID_CONV_COEF(1, 1));
320	SR(VID_CONV_COEF(1, 2));
321	SR(VID_CONV_COEF(1, 3));
322	SR(VID_CONV_COEF(1, 4));
323
324	SR(VID_FIR_COEF_V(1, 0));
325	SR(VID_FIR_COEF_V(1, 1));
326	SR(VID_FIR_COEF_V(1, 2));
327	SR(VID_FIR_COEF_V(1, 3));
328	SR(VID_FIR_COEF_V(1, 4));
329	SR(VID_FIR_COEF_V(1, 5));
330	SR(VID_FIR_COEF_V(1, 6));
331	SR(VID_FIR_COEF_V(1, 7));
332
333	SR(VID_PRELOAD(1));
334}
335
336void dispc_restore_context(void)
337{
338	RR(SYSCONFIG);
339	/*RR(IRQENABLE);*/
340	/*RR(CONTROL);*/
341	RR(CONFIG);
342	RR(DEFAULT_COLOR0);
343	RR(DEFAULT_COLOR1);
344	RR(TRANS_COLOR0);
345	RR(TRANS_COLOR1);
346	RR(LINE_NUMBER);
347	RR(TIMING_H);
348	RR(TIMING_V);
349	RR(POL_FREQ);
350	RR(DIVISOR);
351	RR(GLOBAL_ALPHA);
352	RR(SIZE_DIG);
353	RR(SIZE_LCD);
354
355	RR(GFX_BA0);
356	RR(GFX_BA1);
357	RR(GFX_POSITION);
358	RR(GFX_SIZE);
359	RR(GFX_ATTRIBUTES);
360	RR(GFX_FIFO_THRESHOLD);
361	RR(GFX_ROW_INC);
362	RR(GFX_PIXEL_INC);
363	RR(GFX_WINDOW_SKIP);
364	RR(GFX_TABLE_BA);
365
366	RR(DATA_CYCLE1);
367	RR(DATA_CYCLE2);
368	RR(DATA_CYCLE3);
369
370	RR(CPR_COEF_R);
371	RR(CPR_COEF_G);
372	RR(CPR_COEF_B);
373
374	RR(GFX_PRELOAD);
375
376	/* VID1 */
377	RR(VID_BA0(0));
378	RR(VID_BA1(0));
379	RR(VID_POSITION(0));
380	RR(VID_SIZE(0));
381	RR(VID_ATTRIBUTES(0));
382	RR(VID_FIFO_THRESHOLD(0));
383	RR(VID_ROW_INC(0));
384	RR(VID_PIXEL_INC(0));
385	RR(VID_FIR(0));
386	RR(VID_PICTURE_SIZE(0));
387	RR(VID_ACCU0(0));
388	RR(VID_ACCU1(0));
389
390	RR(VID_FIR_COEF_H(0, 0));
391	RR(VID_FIR_COEF_H(0, 1));
392	RR(VID_FIR_COEF_H(0, 2));
393	RR(VID_FIR_COEF_H(0, 3));
394	RR(VID_FIR_COEF_H(0, 4));
395	RR(VID_FIR_COEF_H(0, 5));
396	RR(VID_FIR_COEF_H(0, 6));
397	RR(VID_FIR_COEF_H(0, 7));
398
399	RR(VID_FIR_COEF_HV(0, 0));
400	RR(VID_FIR_COEF_HV(0, 1));
401	RR(VID_FIR_COEF_HV(0, 2));
402	RR(VID_FIR_COEF_HV(0, 3));
403	RR(VID_FIR_COEF_HV(0, 4));
404	RR(VID_FIR_COEF_HV(0, 5));
405	RR(VID_FIR_COEF_HV(0, 6));
406	RR(VID_FIR_COEF_HV(0, 7));
407
408	RR(VID_CONV_COEF(0, 0));
409	RR(VID_CONV_COEF(0, 1));
410	RR(VID_CONV_COEF(0, 2));
411	RR(VID_CONV_COEF(0, 3));
412	RR(VID_CONV_COEF(0, 4));
413
414	RR(VID_FIR_COEF_V(0, 0));
415	RR(VID_FIR_COEF_V(0, 1));
416	RR(VID_FIR_COEF_V(0, 2));
417	RR(VID_FIR_COEF_V(0, 3));
418	RR(VID_FIR_COEF_V(0, 4));
419	RR(VID_FIR_COEF_V(0, 5));
420	RR(VID_FIR_COEF_V(0, 6));
421	RR(VID_FIR_COEF_V(0, 7));
422
423	RR(VID_PRELOAD(0));
424
425	/* VID2 */
426	RR(VID_BA0(1));
427	RR(VID_BA1(1));
428	RR(VID_POSITION(1));
429	RR(VID_SIZE(1));
430	RR(VID_ATTRIBUTES(1));
431	RR(VID_FIFO_THRESHOLD(1));
432	RR(VID_ROW_INC(1));
433	RR(VID_PIXEL_INC(1));
434	RR(VID_FIR(1));
435	RR(VID_PICTURE_SIZE(1));
436	RR(VID_ACCU0(1));
437	RR(VID_ACCU1(1));
438
439	RR(VID_FIR_COEF_H(1, 0));
440	RR(VID_FIR_COEF_H(1, 1));
441	RR(VID_FIR_COEF_H(1, 2));
442	RR(VID_FIR_COEF_H(1, 3));
443	RR(VID_FIR_COEF_H(1, 4));
444	RR(VID_FIR_COEF_H(1, 5));
445	RR(VID_FIR_COEF_H(1, 6));
446	RR(VID_FIR_COEF_H(1, 7));
447
448	RR(VID_FIR_COEF_HV(1, 0));
449	RR(VID_FIR_COEF_HV(1, 1));
450	RR(VID_FIR_COEF_HV(1, 2));
451	RR(VID_FIR_COEF_HV(1, 3));
452	RR(VID_FIR_COEF_HV(1, 4));
453	RR(VID_FIR_COEF_HV(1, 5));
454	RR(VID_FIR_COEF_HV(1, 6));
455	RR(VID_FIR_COEF_HV(1, 7));
456
457	RR(VID_CONV_COEF(1, 0));
458	RR(VID_CONV_COEF(1, 1));
459	RR(VID_CONV_COEF(1, 2));
460	RR(VID_CONV_COEF(1, 3));
461	RR(VID_CONV_COEF(1, 4));
462
463	RR(VID_FIR_COEF_V(1, 0));
464	RR(VID_FIR_COEF_V(1, 1));
465	RR(VID_FIR_COEF_V(1, 2));
466	RR(VID_FIR_COEF_V(1, 3));
467	RR(VID_FIR_COEF_V(1, 4));
468	RR(VID_FIR_COEF_V(1, 5));
469	RR(VID_FIR_COEF_V(1, 6));
470	RR(VID_FIR_COEF_V(1, 7));
471
472	RR(VID_PRELOAD(1));
473
474	/* enable last, because LCD & DIGIT enable are here */
475	RR(CONTROL);
476
477	/* clear spurious SYNC_LOST_DIGIT interrupts */
478	dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
479
480	/*
481	 * enable last so IRQs won't trigger before
482	 * the context is fully restored
483	 */
484	RR(IRQENABLE);
485}
486
487#undef SR
488#undef RR
489
490static inline void enable_clocks(bool enable)
491{
492	if (enable)
493		dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
494	else
495		dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
496}
497
498bool dispc_go_busy(enum omap_channel channel)
499{
500	int bit;
501
502	if (channel == OMAP_DSS_CHANNEL_LCD)
503		bit = 5; /* GOLCD */
504	else
505		bit = 6; /* GODIGIT */
506
507	return REG_GET(DISPC_CONTROL, bit, bit) == 1;
508}
509
510void dispc_go(enum omap_channel channel)
511{
512	int bit;
513
514	enable_clocks(1);
515
516	if (channel == OMAP_DSS_CHANNEL_LCD)
517		bit = 0; /* LCDENABLE */
518	else
519		bit = 1; /* DIGITALENABLE */
520
521	/* if the channel is not enabled, we don't need GO */
522	if (REG_GET(DISPC_CONTROL, bit, bit) == 0)
523		goto end;
524
525	if (channel == OMAP_DSS_CHANNEL_LCD)
526		bit = 5; /* GOLCD */
527	else
528		bit = 6; /* GODIGIT */
529
530	if (REG_GET(DISPC_CONTROL, bit, bit) == 1) {
531		DSSERR("GO bit not down for channel %d\n", channel);
532		goto end;
533	}
534
535	DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT");
536
537	REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
538end:
539	enable_clocks(0);
540}
541
542static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
543{
544	BUG_ON(plane == OMAP_DSS_GFX);
545
546	dispc_write_reg(DISPC_VID_FIR_COEF_H(plane-1, reg), value);
547}
548
549static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
550{
551	BUG_ON(plane == OMAP_DSS_GFX);
552
553	dispc_write_reg(DISPC_VID_FIR_COEF_HV(plane-1, reg), value);
554}
555
556static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
557{
558	BUG_ON(plane == OMAP_DSS_GFX);
559
560	dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
561}
562
563static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
564		int vscaleup, int five_taps)
565{
566	/* Coefficients for horizontal up-sampling */
567	static const u32 coef_hup[8] = {
568		0x00800000,
569		0x0D7CF800,
570		0x1E70F5FF,
571		0x335FF5FE,
572		0xF74949F7,
573		0xF55F33FB,
574		0xF5701EFE,
575		0xF87C0DFF,
576	};
577
578	/* Coefficients for horizontal down-sampling */
579	static const u32 coef_hdown[8] = {
580		0x24382400,
581		0x28371FFE,
582		0x2C361BFB,
583		0x303516F9,
584		0x11343311,
585		0x1635300C,
586		0x1B362C08,
587		0x1F372804,
588	};
589
590	/* Coefficients for horizontal and vertical up-sampling */
591	static const u32 coef_hvup[2][8] = {
592		{
593		0x00800000,
594		0x037B02FF,
595		0x0C6F05FE,
596		0x205907FB,
597		0x00404000,
598		0x075920FE,
599		0x056F0CFF,
600		0x027B0300,
601		},
602		{
603		0x00800000,
604		0x0D7CF8FF,
605		0x1E70F5FE,
606		0x335FF5FB,
607		0xF7404000,
608		0xF55F33FE,
609		0xF5701EFF,
610		0xF87C0D00,
611		},
612	};
613
614	/* Coefficients for horizontal and vertical down-sampling */
615	static const u32 coef_hvdown[2][8] = {
616		{
617		0x24382400,
618		0x28391F04,
619		0x2D381B08,
620		0x3237170C,
621		0x123737F7,
622		0x173732F9,
623		0x1B382DFB,
624		0x1F3928FE,
625		},
626		{
627		0x24382400,
628		0x28371F04,
629		0x2C361B08,
630		0x3035160C,
631		0x113433F7,
632		0x163530F9,
633		0x1B362CFB,
634		0x1F3728FE,
635		},
636	};
637
638	/* Coefficients for vertical up-sampling */
639	static const u32 coef_vup[8] = {
640		0x00000000,
641		0x0000FF00,
642		0x0000FEFF,
643		0x0000FBFE,
644		0x000000F7,
645		0x0000FEFB,
646		0x0000FFFE,
647		0x000000FF,
648	};
649
650
651	/* Coefficients for vertical down-sampling */
652	static const u32 coef_vdown[8] = {
653		0x00000000,
654		0x000004FE,
655		0x000008FB,
656		0x00000CF9,
657		0x0000F711,
658		0x0000F90C,
659		0x0000FB08,
660		0x0000FE04,
661	};
662
663	const u32 *h_coef;
664	const u32 *hv_coef;
665	const u32 *hv_coef_mod;
666	const u32 *v_coef;
667	int i;
668
669	if (hscaleup)
670		h_coef = coef_hup;
671	else
672		h_coef = coef_hdown;
673
674	if (vscaleup) {
675		hv_coef = coef_hvup[five_taps];
676		v_coef = coef_vup;
677
678		if (hscaleup)
679			hv_coef_mod = NULL;
680		else
681			hv_coef_mod = coef_hvdown[five_taps];
682	} else {
683		hv_coef = coef_hvdown[five_taps];
684		v_coef = coef_vdown;
685
686		if (hscaleup)
687			hv_coef_mod = coef_hvup[five_taps];
688		else
689			hv_coef_mod = NULL;
690	}
691
692	for (i = 0; i < 8; i++) {
693		u32 h, hv;
694
695		h = h_coef[i];
696
697		hv = hv_coef[i];
698
699		if (hv_coef_mod) {
700			hv &= 0xffffff00;
701			hv |= (hv_coef_mod[i] & 0xff);
702		}
703
704		_dispc_write_firh_reg(plane, i, h);
705		_dispc_write_firhv_reg(plane, i, hv);
706	}
707
708	if (!five_taps)
709		return;
710
711	for (i = 0; i < 8; i++) {
712		u32 v;
713		v = v_coef[i];
714		_dispc_write_firv_reg(plane, i, v);
715	}
716}
717
718static void _dispc_setup_color_conv_coef(void)
719{
720	const struct color_conv_coef {
721		int  ry,  rcr,  rcb,   gy,  gcr,  gcb,   by,  bcr,  bcb;
722		int  full_range;
723	}  ctbl_bt601_5 = {
724		298,  409,    0,  298, -208, -100,  298,    0,  517, 0,
725	};
726
727	const struct color_conv_coef *ct;
728
729#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
730
731	ct = &ctbl_bt601_5;
732
733	dispc_write_reg(DISPC_VID_CONV_COEF(0, 0), CVAL(ct->rcr, ct->ry));
734	dispc_write_reg(DISPC_VID_CONV_COEF(0, 1), CVAL(ct->gy,	 ct->rcb));
735	dispc_write_reg(DISPC_VID_CONV_COEF(0, 2), CVAL(ct->gcb, ct->gcr));
736	dispc_write_reg(DISPC_VID_CONV_COEF(0, 3), CVAL(ct->bcr, ct->by));
737	dispc_write_reg(DISPC_VID_CONV_COEF(0, 4), CVAL(0,       ct->bcb));
738
739	dispc_write_reg(DISPC_VID_CONV_COEF(1, 0), CVAL(ct->rcr, ct->ry));
740	dispc_write_reg(DISPC_VID_CONV_COEF(1, 1), CVAL(ct->gy,	 ct->rcb));
741	dispc_write_reg(DISPC_VID_CONV_COEF(1, 2), CVAL(ct->gcb, ct->gcr));
742	dispc_write_reg(DISPC_VID_CONV_COEF(1, 3), CVAL(ct->bcr, ct->by));
743	dispc_write_reg(DISPC_VID_CONV_COEF(1, 4), CVAL(0,       ct->bcb));
744
745#undef CVAL
746
747	REG_FLD_MOD(DISPC_VID_ATTRIBUTES(0), ct->full_range, 11, 11);
748	REG_FLD_MOD(DISPC_VID_ATTRIBUTES(1), ct->full_range, 11, 11);
749}
750
751
752static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
753{
754	const struct dispc_reg ba0_reg[] = { DISPC_GFX_BA0,
755		DISPC_VID_BA0(0),
756		DISPC_VID_BA0(1) };
757
758	dispc_write_reg(ba0_reg[plane], paddr);
759}
760
761static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr)
762{
763	const struct dispc_reg ba1_reg[] = { DISPC_GFX_BA1,
764				      DISPC_VID_BA1(0),
765				      DISPC_VID_BA1(1) };
766
767	dispc_write_reg(ba1_reg[plane], paddr);
768}
769
770static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
771{
772	const struct dispc_reg pos_reg[] = { DISPC_GFX_POSITION,
773				      DISPC_VID_POSITION(0),
774				      DISPC_VID_POSITION(1) };
775
776	u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
777	dispc_write_reg(pos_reg[plane], val);
778}
779
780static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
781{
782	const struct dispc_reg siz_reg[] = { DISPC_GFX_SIZE,
783				      DISPC_VID_PICTURE_SIZE(0),
784				      DISPC_VID_PICTURE_SIZE(1) };
785	u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
786	dispc_write_reg(siz_reg[plane], val);
787}
788
789static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
790{
791	u32 val;
792	const struct dispc_reg vsi_reg[] = { DISPC_VID_SIZE(0),
793				      DISPC_VID_SIZE(1) };
794
795	BUG_ON(plane == OMAP_DSS_GFX);
796
797	val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
798	dispc_write_reg(vsi_reg[plane-1], val);
799}
800
801static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
802{
803
804	BUG_ON(plane == OMAP_DSS_VIDEO1);
805
806	if (cpu_is_omap24xx())
807		return;
808
809	if (plane == OMAP_DSS_GFX)
810		REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
811	else if (plane == OMAP_DSS_VIDEO2)
812		REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16);
813}
814
815static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
816{
817	const struct dispc_reg ri_reg[] = { DISPC_GFX_PIXEL_INC,
818				     DISPC_VID_PIXEL_INC(0),
819				     DISPC_VID_PIXEL_INC(1) };
820
821	dispc_write_reg(ri_reg[plane], inc);
822}
823
824static void _dispc_set_row_inc(enum omap_plane plane, s32 inc)
825{
826	const struct dispc_reg ri_reg[] = { DISPC_GFX_ROW_INC,
827				     DISPC_VID_ROW_INC(0),
828				     DISPC_VID_ROW_INC(1) };
829
830	dispc_write_reg(ri_reg[plane], inc);
831}
832
833static void _dispc_set_color_mode(enum omap_plane plane,
834		enum omap_color_mode color_mode)
835{
836	u32 m = 0;
837
838	switch (color_mode) {
839	case OMAP_DSS_COLOR_CLUT1:
840		m = 0x0; break;
841	case OMAP_DSS_COLOR_CLUT2:
842		m = 0x1; break;
843	case OMAP_DSS_COLOR_CLUT4:
844		m = 0x2; break;
845	case OMAP_DSS_COLOR_CLUT8:
846		m = 0x3; break;
847	case OMAP_DSS_COLOR_RGB12U:
848		m = 0x4; break;
849	case OMAP_DSS_COLOR_ARGB16:
850		m = 0x5; break;
851	case OMAP_DSS_COLOR_RGB16:
852		m = 0x6; break;
853	case OMAP_DSS_COLOR_RGB24U:
854		m = 0x8; break;
855	case OMAP_DSS_COLOR_RGB24P:
856		m = 0x9; break;
857	case OMAP_DSS_COLOR_YUV2:
858		m = 0xa; break;
859	case OMAP_DSS_COLOR_UYVY:
860		m = 0xb; break;
861	case OMAP_DSS_COLOR_ARGB32:
862		m = 0xc; break;
863	case OMAP_DSS_COLOR_RGBA32:
864		m = 0xd; break;
865	case OMAP_DSS_COLOR_RGBX32:
866		m = 0xe; break;
867	default:
868		BUG(); break;
869	}
870
871	REG_FLD_MOD(dispc_reg_att[plane], m, 4, 1);
872}
873
874static void _dispc_set_channel_out(enum omap_plane plane,
875		enum omap_channel channel)
876{
877	int shift;
878	u32 val;
879
880	switch (plane) {
881	case OMAP_DSS_GFX:
882		shift = 8;
883		break;
884	case OMAP_DSS_VIDEO1:
885	case OMAP_DSS_VIDEO2:
886		shift = 16;
887		break;
888	default:
889		BUG();
890		return;
891	}
892
893	val = dispc_read_reg(dispc_reg_att[plane]);
894	val = FLD_MOD(val, channel, shift, shift);
895	dispc_write_reg(dispc_reg_att[plane], val);
896}
897
898void dispc_set_burst_size(enum omap_plane plane,
899		enum omap_burst_size burst_size)
900{
901	int shift;
902	u32 val;
903
904	enable_clocks(1);
905
906	switch (plane) {
907	case OMAP_DSS_GFX:
908		shift = 6;
909		break;
910	case OMAP_DSS_VIDEO1:
911	case OMAP_DSS_VIDEO2:
912		shift = 14;
913		break;
914	default:
915		BUG();
916		return;
917	}
918
919	val = dispc_read_reg(dispc_reg_att[plane]);
920	val = FLD_MOD(val, burst_size, shift+1, shift);
921	dispc_write_reg(dispc_reg_att[plane], val);
922
923	enable_clocks(0);
924}
925
926static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
927{
928	u32 val;
929
930	BUG_ON(plane == OMAP_DSS_GFX);
931
932	val = dispc_read_reg(dispc_reg_att[plane]);
933	val = FLD_MOD(val, enable, 9, 9);
934	dispc_write_reg(dispc_reg_att[plane], val);
935}
936
937void dispc_enable_replication(enum omap_plane plane, bool enable)
938{
939	int bit;
940
941	if (plane == OMAP_DSS_GFX)
942		bit = 5;
943	else
944		bit = 10;
945
946	enable_clocks(1);
947	REG_FLD_MOD(dispc_reg_att[plane], enable, bit, bit);
948	enable_clocks(0);
949}
950
951void dispc_set_lcd_size(u16 width, u16 height)
952{
953	u32 val;
954	BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
955	val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
956	enable_clocks(1);
957	dispc_write_reg(DISPC_SIZE_LCD, val);
958	enable_clocks(0);
959}
960
961void dispc_set_digit_size(u16 width, u16 height)
962{
963	u32 val;
964	BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
965	val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
966	enable_clocks(1);
967	dispc_write_reg(DISPC_SIZE_DIG, val);
968	enable_clocks(0);
969}
970
971static void dispc_read_plane_fifo_sizes(void)
972{
973	const struct dispc_reg fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
974				      DISPC_VID_FIFO_SIZE_STATUS(0),
975				      DISPC_VID_FIFO_SIZE_STATUS(1) };
976	u32 size;
977	int plane;
978
979	enable_clocks(1);
980
981	for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
982		if (cpu_is_omap24xx())
983			size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 8, 0);
984		else if (cpu_is_omap34xx())
985			size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 10, 0);
986		else
987			BUG();
988
989		dispc.fifo_size[plane] = size;
990	}
991
992	enable_clocks(0);
993}
994
995u32 dispc_get_plane_fifo_size(enum omap_plane plane)
996{
997	return dispc.fifo_size[plane];
998}
999
1000void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
1001{
1002	const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
1003				       DISPC_VID_FIFO_THRESHOLD(0),
1004				       DISPC_VID_FIFO_THRESHOLD(1) };
1005	enable_clocks(1);
1006
1007	DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
1008			plane,
1009			REG_GET(ftrs_reg[plane], 11, 0),
1010			REG_GET(ftrs_reg[plane], 27, 16),
1011			low, high);
1012
1013	if (cpu_is_omap24xx())
1014		dispc_write_reg(ftrs_reg[plane],
1015				FLD_VAL(high, 24, 16) | FLD_VAL(low, 8, 0));
1016	else
1017		dispc_write_reg(ftrs_reg[plane],
1018				FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0));
1019
1020	enable_clocks(0);
1021}
1022
1023void dispc_enable_fifomerge(bool enable)
1024{
1025	enable_clocks(1);
1026
1027	DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1028	REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
1029
1030	enable_clocks(0);
1031}
1032
1033static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
1034{
1035	u32 val;
1036	const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0),
1037				      DISPC_VID_FIR(1) };
1038
1039	BUG_ON(plane == OMAP_DSS_GFX);
1040
1041	if (cpu_is_omap24xx())
1042		val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0);
1043	else
1044		val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1045	dispc_write_reg(fir_reg[plane-1], val);
1046}
1047
1048static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
1049{
1050	u32 val;
1051	const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
1052				      DISPC_VID_ACCU0(1) };
1053
1054	BUG_ON(plane == OMAP_DSS_GFX);
1055
1056	val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
1057	dispc_write_reg(ac0_reg[plane-1], val);
1058}
1059
1060static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
1061{
1062	u32 val;
1063	const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
1064				      DISPC_VID_ACCU1(1) };
1065
1066	BUG_ON(plane == OMAP_DSS_GFX);
1067
1068	val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
1069	dispc_write_reg(ac1_reg[plane-1], val);
1070}
1071
1072
1073static void _dispc_set_scaling(enum omap_plane plane,
1074		u16 orig_width, u16 orig_height,
1075		u16 out_width, u16 out_height,
1076		bool ilace, bool five_taps,
1077		bool fieldmode)
1078{
1079	int fir_hinc;
1080	int fir_vinc;
1081	int hscaleup, vscaleup;
1082	int accu0 = 0;
1083	int accu1 = 0;
1084	u32 l;
1085
1086	BUG_ON(plane == OMAP_DSS_GFX);
1087
1088	hscaleup = orig_width <= out_width;
1089	vscaleup = orig_height <= out_height;
1090
1091	_dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps);
1092
1093	if (!orig_width || orig_width == out_width)
1094		fir_hinc = 0;
1095	else
1096		fir_hinc = 1024 * orig_width / out_width;
1097
1098	if (!orig_height || orig_height == out_height)
1099		fir_vinc = 0;
1100	else
1101		fir_vinc = 1024 * orig_height / out_height;
1102
1103	_dispc_set_fir(plane, fir_hinc, fir_vinc);
1104
1105	l = dispc_read_reg(dispc_reg_att[plane]);
1106	l &= ~((0x0f << 5) | (0x3 << 21));
1107
1108	l |= fir_hinc ? (1 << 5) : 0;
1109	l |= fir_vinc ? (1 << 6) : 0;
1110
1111	l |= hscaleup ? 0 : (1 << 7);
1112	l |= vscaleup ? 0 : (1 << 8);
1113
1114	l |= five_taps ? (1 << 21) : 0;
1115	l |= five_taps ? (1 << 22) : 0;
1116
1117	dispc_write_reg(dispc_reg_att[plane], l);
1118
1119	/*
1120	 * field 0 = even field = bottom field
1121	 * field 1 = odd field = top field
1122	 */
1123	if (ilace && !fieldmode) {
1124		accu1 = 0;
1125		accu0 = (fir_vinc / 2) & 0x3ff;
1126		if (accu0 >= 1024/2) {
1127			accu1 = 1024/2;
1128			accu0 -= accu1;
1129		}
1130	}
1131
1132	_dispc_set_vid_accu0(plane, 0, accu0);
1133	_dispc_set_vid_accu1(plane, 0, accu1);
1134}
1135
1136static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
1137		bool mirroring, enum omap_color_mode color_mode)
1138{
1139	if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1140			color_mode == OMAP_DSS_COLOR_UYVY) {
1141		int vidrot = 0;
1142
1143		if (mirroring) {
1144			switch (rotation) {
1145			case OMAP_DSS_ROT_0:
1146				vidrot = 2;
1147				break;
1148			case OMAP_DSS_ROT_90:
1149				vidrot = 1;
1150				break;
1151			case OMAP_DSS_ROT_180:
1152				vidrot = 0;
1153				break;
1154			case OMAP_DSS_ROT_270:
1155				vidrot = 3;
1156				break;
1157			}
1158		} else {
1159			switch (rotation) {
1160			case OMAP_DSS_ROT_0:
1161				vidrot = 0;
1162				break;
1163			case OMAP_DSS_ROT_90:
1164				vidrot = 1;
1165				break;
1166			case OMAP_DSS_ROT_180:
1167				vidrot = 2;
1168				break;
1169			case OMAP_DSS_ROT_270:
1170				vidrot = 3;
1171				break;
1172			}
1173		}
1174
1175		REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
1176
1177		if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
1178			REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
1179		else
1180			REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
1181	} else {
1182		REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
1183		REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
1184	}
1185}
1186
1187static int color_mode_to_bpp(enum omap_color_mode color_mode)
1188{
1189	switch (color_mode) {
1190	case OMAP_DSS_COLOR_CLUT1:
1191		return 1;
1192	case OMAP_DSS_COLOR_CLUT2:
1193		return 2;
1194	case OMAP_DSS_COLOR_CLUT4:
1195		return 4;
1196	case OMAP_DSS_COLOR_CLUT8:
1197		return 8;
1198	case OMAP_DSS_COLOR_RGB12U:
1199	case OMAP_DSS_COLOR_RGB16:
1200	case OMAP_DSS_COLOR_ARGB16:
1201	case OMAP_DSS_COLOR_YUV2:
1202	case OMAP_DSS_COLOR_UYVY:
1203		return 16;
1204	case OMAP_DSS_COLOR_RGB24P:
1205		return 24;
1206	case OMAP_DSS_COLOR_RGB24U:
1207	case OMAP_DSS_COLOR_ARGB32:
1208	case OMAP_DSS_COLOR_RGBA32:
1209	case OMAP_DSS_COLOR_RGBX32:
1210		return 32;
1211	default:
1212		BUG();
1213	}
1214}
1215
1216static s32 pixinc(int pixels, u8 ps)
1217{
1218	if (pixels == 1)
1219		return 1;
1220	else if (pixels > 1)
1221		return 1 + (pixels - 1) * ps;
1222	else if (pixels < 0)
1223		return 1 - (-pixels + 1) * ps;
1224	else
1225		BUG();
1226}
1227
1228static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
1229		u16 screen_width,
1230		u16 width, u16 height,
1231		enum omap_color_mode color_mode, bool fieldmode,
1232		unsigned int field_offset,
1233		unsigned *offset0, unsigned *offset1,
1234		s32 *row_inc, s32 *pix_inc)
1235{
1236	u8 ps;
1237
1238	switch (color_mode) {
1239	case OMAP_DSS_COLOR_CLUT1:
1240	case OMAP_DSS_COLOR_CLUT2:
1241	case OMAP_DSS_COLOR_CLUT4:
1242	case OMAP_DSS_COLOR_CLUT8:
1243		BUG();
1244		return;
1245	case OMAP_DSS_COLOR_YUV2:
1246	case OMAP_DSS_COLOR_UYVY:
1247		ps = 4;
1248		break;
1249	default:
1250		ps = color_mode_to_bpp(color_mode) / 8;
1251		break;
1252	}
1253
1254	DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1255			width, height);
1256
1257	/*
1258	 * field 0 = even field = bottom field
1259	 * field 1 = odd field = top field
1260	 */
1261	switch (rotation + mirror * 4) {
1262	case OMAP_DSS_ROT_0:
1263	case OMAP_DSS_ROT_180:
1264		/*
1265		 * If the pixel format is YUV or UYVY divide the width
1266		 * of the image by 2 for 0 and 180 degree rotation.
1267		 */
1268		if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1269			color_mode == OMAP_DSS_COLOR_UYVY)
1270			width = width >> 1;
1271	case OMAP_DSS_ROT_90:
1272	case OMAP_DSS_ROT_270:
1273		*offset1 = 0;
1274		if (field_offset)
1275			*offset0 = field_offset * screen_width * ps;
1276		else
1277			*offset0 = 0;
1278
1279		*row_inc = pixinc(1 + (screen_width - width) +
1280				(fieldmode ? screen_width : 0),
1281				ps);
1282		*pix_inc = pixinc(1, ps);
1283		break;
1284
1285	case OMAP_DSS_ROT_0 + 4:
1286	case OMAP_DSS_ROT_180 + 4:
1287		/* If the pixel format is YUV or UYVY divide the width
1288		 * of the image by 2  for 0 degree and 180 degree
1289		 */
1290		if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1291			color_mode == OMAP_DSS_COLOR_UYVY)
1292			width = width >> 1;
1293	case OMAP_DSS_ROT_90 + 4:
1294	case OMAP_DSS_ROT_270 + 4:
1295		*offset1 = 0;
1296		if (field_offset)
1297			*offset0 = field_offset * screen_width * ps;
1298		else
1299			*offset0 = 0;
1300		*row_inc = pixinc(1 - (screen_width + width) -
1301				(fieldmode ? screen_width : 0),
1302				ps);
1303		*pix_inc = pixinc(1, ps);
1304		break;
1305
1306	default:
1307		BUG();
1308	}
1309}
1310
1311static void calc_dma_rotation_offset(u8 rotation, bool mirror,
1312		u16 screen_width,
1313		u16 width, u16 height,
1314		enum omap_color_mode color_mode, bool fieldmode,
1315		unsigned int field_offset,
1316		unsigned *offset0, unsigned *offset1,
1317		s32 *row_inc, s32 *pix_inc)
1318{
1319	u8 ps;
1320	u16 fbw, fbh;
1321
1322	switch (color_mode) {
1323	case OMAP_DSS_COLOR_CLUT1:
1324	case OMAP_DSS_COLOR_CLUT2:
1325	case OMAP_DSS_COLOR_CLUT4:
1326	case OMAP_DSS_COLOR_CLUT8:
1327		BUG();
1328		return;
1329	default:
1330		ps = color_mode_to_bpp(color_mode) / 8;
1331		break;
1332	}
1333
1334	DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1335			width, height);
1336
1337	/* width & height are overlay sizes, convert to fb sizes */
1338
1339	if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) {
1340		fbw = width;
1341		fbh = height;
1342	} else {
1343		fbw = height;
1344		fbh = width;
1345	}
1346
1347	/*
1348	 * field 0 = even field = bottom field
1349	 * field 1 = odd field = top field
1350	 */
1351	switch (rotation + mirror * 4) {
1352	case OMAP_DSS_ROT_0:
1353		*offset1 = 0;
1354		if (field_offset)
1355			*offset0 = *offset1 + field_offset * screen_width * ps;
1356		else
1357			*offset0 = *offset1;
1358		*row_inc = pixinc(1 + (screen_width - fbw) +
1359				(fieldmode ? screen_width : 0),
1360				ps);
1361		*pix_inc = pixinc(1, ps);
1362		break;
1363	case OMAP_DSS_ROT_90:
1364		*offset1 = screen_width * (fbh - 1) * ps;
1365		if (field_offset)
1366			*offset0 = *offset1 + field_offset * ps;
1367		else
1368			*offset0 = *offset1;
1369		*row_inc = pixinc(screen_width * (fbh - 1) + 1 +
1370				(fieldmode ? 1 : 0), ps);
1371		*pix_inc = pixinc(-screen_width, ps);
1372		break;
1373	case OMAP_DSS_ROT_180:
1374		*offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1375		if (field_offset)
1376			*offset0 = *offset1 - field_offset * screen_width * ps;
1377		else
1378			*offset0 = *offset1;
1379		*row_inc = pixinc(-1 -
1380				(screen_width - fbw) -
1381				(fieldmode ? screen_width : 0),
1382				ps);
1383		*pix_inc = pixinc(-1, ps);
1384		break;
1385	case OMAP_DSS_ROT_270:
1386		*offset1 = (fbw - 1) * ps;
1387		if (field_offset)
1388			*offset0 = *offset1 - field_offset * ps;
1389		else
1390			*offset0 = *offset1;
1391		*row_inc = pixinc(-screen_width * (fbh - 1) - 1 -
1392				(fieldmode ? 1 : 0), ps);
1393		*pix_inc = pixinc(screen_width, ps);
1394		break;
1395
1396	/* mirroring */
1397	case OMAP_DSS_ROT_0 + 4:
1398		*offset1 = (fbw - 1) * ps;
1399		if (field_offset)
1400			*offset0 = *offset1 + field_offset * screen_width * ps;
1401		else
1402			*offset0 = *offset1;
1403		*row_inc = pixinc(screen_width * 2 - 1 +
1404				(fieldmode ? screen_width : 0),
1405				ps);
1406		*pix_inc = pixinc(-1, ps);
1407		break;
1408
1409	case OMAP_DSS_ROT_90 + 4:
1410		*offset1 = 0;
1411		if (field_offset)
1412			*offset0 = *offset1 + field_offset * ps;
1413		else
1414			*offset0 = *offset1;
1415		*row_inc = pixinc(-screen_width * (fbh - 1) + 1 +
1416				(fieldmode ? 1 : 0),
1417				ps);
1418		*pix_inc = pixinc(screen_width, ps);
1419		break;
1420
1421	case OMAP_DSS_ROT_180 + 4:
1422		*offset1 = screen_width * (fbh - 1) * ps;
1423		if (field_offset)
1424			*offset0 = *offset1 - field_offset * screen_width * ps;
1425		else
1426			*offset0 = *offset1;
1427		*row_inc = pixinc(1 - screen_width * 2 -
1428				(fieldmode ? screen_width : 0),
1429				ps);
1430		*pix_inc = pixinc(1, ps);
1431		break;
1432
1433	case OMAP_DSS_ROT_270 + 4:
1434		*offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1435		if (field_offset)
1436			*offset0 = *offset1 - field_offset * ps;
1437		else
1438			*offset0 = *offset1;
1439		*row_inc = pixinc(screen_width * (fbh - 1) - 1 -
1440				(fieldmode ? 1 : 0),
1441				ps);
1442		*pix_inc = pixinc(-screen_width, ps);
1443		break;
1444
1445	default:
1446		BUG();
1447	}
1448}
1449
1450static unsigned long calc_fclk_five_taps(u16 width, u16 height,
1451		u16 out_width, u16 out_height, enum omap_color_mode color_mode)
1452{
1453	u32 fclk = 0;
1454	u64 tmp, pclk = dispc_pclk_rate();
1455
1456	if (height > out_height) {
1457		unsigned int ppl = 800;
1458
1459		tmp = pclk * height * out_width;
1460		do_div(tmp, 2 * out_height * ppl);
1461		fclk = tmp;
1462
1463		if (height > 2 * out_height) {
1464			if (ppl == out_width)
1465				return 0;
1466
1467			tmp = pclk * (height - 2 * out_height) * out_width;
1468			do_div(tmp, 2 * out_height * (ppl - out_width));
1469			fclk = max(fclk, (u32) tmp);
1470		}
1471	}
1472
1473	if (width > out_width) {
1474		tmp = pclk * width;
1475		do_div(tmp, out_width);
1476		fclk = max(fclk, (u32) tmp);
1477
1478		if (color_mode == OMAP_DSS_COLOR_RGB24U)
1479			fclk <<= 1;
1480	}
1481
1482	return fclk;
1483}
1484
1485static unsigned long calc_fclk(u16 width, u16 height,
1486		u16 out_width, u16 out_height)
1487{
1488	unsigned int hf, vf;
1489
1490
1491	if (width > 3 * out_width)
1492		hf = 4;
1493	else if (width > 2 * out_width)
1494		hf = 3;
1495	else if (width > out_width)
1496		hf = 2;
1497	else
1498		hf = 1;
1499
1500	if (height > out_height)
1501		vf = 2;
1502	else
1503		vf = 1;
1504
1505	return dispc_pclk_rate() * vf * hf;
1506}
1507
1508void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
1509{
1510	enable_clocks(1);
1511	_dispc_set_channel_out(plane, channel_out);
1512	enable_clocks(0);
1513}
1514
1515static int _dispc_setup_plane(enum omap_plane plane,
1516		u32 paddr, u16 screen_width,
1517		u16 pos_x, u16 pos_y,
1518		u16 width, u16 height,
1519		u16 out_width, u16 out_height,
1520		enum omap_color_mode color_mode,
1521		bool ilace,
1522		enum omap_dss_rotation_type rotation_type,
1523		u8 rotation, int mirror,
1524		u8 global_alpha)
1525{
1526	const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
1527	bool five_taps = 0;
1528	bool fieldmode = 0;
1529	int cconv = 0;
1530	unsigned offset0, offset1;
1531	s32 row_inc;
1532	s32 pix_inc;
1533	u16 frame_height = height;
1534	unsigned int field_offset = 0;
1535
1536	if (paddr == 0)
1537		return -EINVAL;
1538
1539	if (ilace && height == out_height)
1540		fieldmode = 1;
1541
1542	if (ilace) {
1543		if (fieldmode)
1544			height /= 2;
1545		pos_y /= 2;
1546		out_height /= 2;
1547
1548		DSSDBG("adjusting for ilace: height %d, pos_y %d, "
1549				"out_height %d\n",
1550				height, pos_y, out_height);
1551	}
1552
1553	if (plane == OMAP_DSS_GFX) {
1554		if (width != out_width || height != out_height)
1555			return -EINVAL;
1556
1557		switch (color_mode) {
1558		case OMAP_DSS_COLOR_ARGB16:
1559		case OMAP_DSS_COLOR_ARGB32:
1560		case OMAP_DSS_COLOR_RGBA32:
1561		case OMAP_DSS_COLOR_RGBX32:
1562			if (cpu_is_omap24xx())
1563				return -EINVAL;
1564			/* fall through */
1565		case OMAP_DSS_COLOR_RGB12U:
1566		case OMAP_DSS_COLOR_RGB16:
1567		case OMAP_DSS_COLOR_RGB24P:
1568		case OMAP_DSS_COLOR_RGB24U:
1569			break;
1570
1571		default:
1572			return -EINVAL;
1573		}
1574	} else {
1575		/* video plane */
1576
1577		unsigned long fclk = 0;
1578
1579		if (out_width < width / maxdownscale ||
1580		   out_width > width * 8)
1581			return -EINVAL;
1582
1583		if (out_height < height / maxdownscale ||
1584		   out_height > height * 8)
1585			return -EINVAL;
1586
1587		switch (color_mode) {
1588		case OMAP_DSS_COLOR_RGBX32:
1589		case OMAP_DSS_COLOR_RGB12U:
1590			if (cpu_is_omap24xx())
1591				return -EINVAL;
1592			/* fall through */
1593		case OMAP_DSS_COLOR_RGB16:
1594		case OMAP_DSS_COLOR_RGB24P:
1595		case OMAP_DSS_COLOR_RGB24U:
1596			break;
1597
1598		case OMAP_DSS_COLOR_ARGB16:
1599		case OMAP_DSS_COLOR_ARGB32:
1600		case OMAP_DSS_COLOR_RGBA32:
1601			if (cpu_is_omap24xx())
1602				return -EINVAL;
1603			if (plane == OMAP_DSS_VIDEO1)
1604				return -EINVAL;
1605			break;
1606
1607		case OMAP_DSS_COLOR_YUV2:
1608		case OMAP_DSS_COLOR_UYVY:
1609			cconv = 1;
1610			break;
1611
1612		default:
1613			return -EINVAL;
1614		}
1615
1616		/* Must use 5-tap filter? */
1617		five_taps = height > out_height * 2;
1618
1619		if (!five_taps) {
1620			fclk = calc_fclk(width, height,
1621					out_width, out_height);
1622
1623			/* Try 5-tap filter if 3-tap fclk is too high */
1624			if (cpu_is_omap34xx() && height > out_height &&
1625					fclk > dispc_fclk_rate())
1626				five_taps = true;
1627		}
1628
1629		if (width > (2048 >> five_taps)) {
1630			DSSERR("failed to set up scaling, fclk too low\n");
1631			return -EINVAL;
1632		}
1633
1634		if (five_taps)
1635			fclk = calc_fclk_five_taps(width, height,
1636					out_width, out_height, color_mode);
1637
1638		DSSDBG("required fclk rate = %lu Hz\n", fclk);
1639		DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
1640
1641		if (!fclk || fclk > dispc_fclk_rate()) {
1642			DSSERR("failed to set up scaling, "
1643					"required fclk rate = %lu Hz, "
1644					"current fclk rate = %lu Hz\n",
1645					fclk, dispc_fclk_rate());
1646			return -EINVAL;
1647		}
1648	}
1649
1650	if (ilace && !fieldmode) {
1651		/*
1652		 * when downscaling the bottom field may have to start several
1653		 * source lines below the top field. Unfortunately ACCUI
1654		 * registers will only hold the fractional part of the offset
1655		 * so the integer part must be added to the base address of the
1656		 * bottom field.
1657		 */
1658		if (!height || height == out_height)
1659			field_offset = 0;
1660		else
1661			field_offset = height / out_height / 2;
1662	}
1663
1664	/* Fields are independent but interleaved in memory. */
1665	if (fieldmode)
1666		field_offset = 1;
1667
1668	if (rotation_type == OMAP_DSS_ROT_DMA)
1669		calc_dma_rotation_offset(rotation, mirror,
1670				screen_width, width, frame_height, color_mode,
1671				fieldmode, field_offset,
1672				&offset0, &offset1, &row_inc, &pix_inc);
1673	else
1674		calc_vrfb_rotation_offset(rotation, mirror,
1675				screen_width, width, frame_height, color_mode,
1676				fieldmode, field_offset,
1677				&offset0, &offset1, &row_inc, &pix_inc);
1678
1679	DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
1680			offset0, offset1, row_inc, pix_inc);
1681
1682	_dispc_set_color_mode(plane, color_mode);
1683
1684	_dispc_set_plane_ba0(plane, paddr + offset0);
1685	_dispc_set_plane_ba1(plane, paddr + offset1);
1686
1687	_dispc_set_row_inc(plane, row_inc);
1688	_dispc_set_pix_inc(plane, pix_inc);
1689
1690	DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height,
1691			out_width, out_height);
1692
1693	_dispc_set_plane_pos(plane, pos_x, pos_y);
1694
1695	_dispc_set_pic_size(plane, width, height);
1696
1697	if (plane != OMAP_DSS_GFX) {
1698		_dispc_set_scaling(plane, width, height,
1699				   out_width, out_height,
1700				   ilace, five_taps, fieldmode);
1701		_dispc_set_vid_size(plane, out_width, out_height);
1702		_dispc_set_vid_color_conv(plane, cconv);
1703	}
1704
1705	_dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
1706
1707	if (plane != OMAP_DSS_VIDEO1)
1708		_dispc_setup_global_alpha(plane, global_alpha);
1709
1710	return 0;
1711}
1712
1713static void _dispc_enable_plane(enum omap_plane plane, bool enable)
1714{
1715	REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 0, 0);
1716}
1717
1718static void dispc_disable_isr(void *data, u32 mask)
1719{
1720	struct completion *compl = data;
1721	complete(compl);
1722}
1723
1724static void _enable_lcd_out(bool enable)
1725{
1726	REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
1727}
1728
1729static void dispc_enable_lcd_out(bool enable)
1730{
1731	struct completion frame_done_completion;
1732	bool is_on;
1733	int r;
1734
1735	enable_clocks(1);
1736
1737	/* When we disable LCD output, we need to wait until frame is done.
1738	 * Otherwise the DSS is still working, and turning off the clocks
1739	 * prevents DSS from going to OFF mode */
1740	is_on = REG_GET(DISPC_CONTROL, 0, 0);
1741
1742	if (!enable && is_on) {
1743		init_completion(&frame_done_completion);
1744
1745		r = omap_dispc_register_isr(dispc_disable_isr,
1746				&frame_done_completion,
1747				DISPC_IRQ_FRAMEDONE);
1748
1749		if (r)
1750			DSSERR("failed to register FRAMEDONE isr\n");
1751	}
1752
1753	_enable_lcd_out(enable);
1754
1755	if (!enable && is_on) {
1756		if (!wait_for_completion_timeout(&frame_done_completion,
1757					msecs_to_jiffies(100)))
1758			DSSERR("timeout waiting for FRAME DONE\n");
1759
1760		r = omap_dispc_unregister_isr(dispc_disable_isr,
1761				&frame_done_completion,
1762				DISPC_IRQ_FRAMEDONE);
1763
1764		if (r)
1765			DSSERR("failed to unregister FRAMEDONE isr\n");
1766	}
1767
1768	enable_clocks(0);
1769}
1770
1771static void _enable_digit_out(bool enable)
1772{
1773	REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
1774}
1775
1776static void dispc_enable_digit_out(bool enable)
1777{
1778	struct completion frame_done_completion;
1779	int r;
1780
1781	enable_clocks(1);
1782
1783	if (REG_GET(DISPC_CONTROL, 1, 1) == enable) {
1784		enable_clocks(0);
1785		return;
1786	}
1787
1788	if (enable) {
1789		unsigned long flags;
1790		/* When we enable digit output, we'll get an extra digit
1791		 * sync lost interrupt, that we need to ignore */
1792		spin_lock_irqsave(&dispc.irq_lock, flags);
1793		dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
1794		_omap_dispc_set_irqs();
1795		spin_unlock_irqrestore(&dispc.irq_lock, flags);
1796	}
1797
1798	/* When we disable digit output, we need to wait until fields are done.
1799	 * Otherwise the DSS is still working, and turning off the clocks
1800	 * prevents DSS from going to OFF mode. And when enabling, we need to
1801	 * wait for the extra sync losts */
1802	init_completion(&frame_done_completion);
1803
1804	r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion,
1805			DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
1806	if (r)
1807		DSSERR("failed to register EVSYNC isr\n");
1808
1809	_enable_digit_out(enable);
1810
1811	if (!wait_for_completion_timeout(&frame_done_completion,
1812				msecs_to_jiffies(100)))
1813		DSSERR("timeout waiting for EVSYNC\n");
1814
1815	if (!wait_for_completion_timeout(&frame_done_completion,
1816				msecs_to_jiffies(100)))
1817		DSSERR("timeout waiting for EVSYNC\n");
1818
1819	r = omap_dispc_unregister_isr(dispc_disable_isr,
1820			&frame_done_completion,
1821			DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
1822	if (r)
1823		DSSERR("failed to unregister EVSYNC isr\n");
1824
1825	if (enable) {
1826		unsigned long flags;
1827		spin_lock_irqsave(&dispc.irq_lock, flags);
1828		dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
1829		dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
1830		_omap_dispc_set_irqs();
1831		spin_unlock_irqrestore(&dispc.irq_lock, flags);
1832	}
1833
1834	enable_clocks(0);
1835}
1836
1837bool dispc_is_channel_enabled(enum omap_channel channel)
1838{
1839	if (channel == OMAP_DSS_CHANNEL_LCD)
1840		return !!REG_GET(DISPC_CONTROL, 0, 0);
1841	else if (channel == OMAP_DSS_CHANNEL_DIGIT)
1842		return !!REG_GET(DISPC_CONTROL, 1, 1);
1843	else
1844		BUG();
1845}
1846
1847void dispc_enable_channel(enum omap_channel channel, bool enable)
1848{
1849	if (channel == OMAP_DSS_CHANNEL_LCD)
1850		dispc_enable_lcd_out(enable);
1851	else if (channel == OMAP_DSS_CHANNEL_DIGIT)
1852		dispc_enable_digit_out(enable);
1853	else
1854		BUG();
1855}
1856
1857void dispc_lcd_enable_signal_polarity(bool act_high)
1858{
1859	enable_clocks(1);
1860	REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
1861	enable_clocks(0);
1862}
1863
1864void dispc_lcd_enable_signal(bool enable)
1865{
1866	enable_clocks(1);
1867	REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
1868	enable_clocks(0);
1869}
1870
1871void dispc_pck_free_enable(bool enable)
1872{
1873	enable_clocks(1);
1874	REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
1875	enable_clocks(0);
1876}
1877
1878void dispc_enable_fifohandcheck(bool enable)
1879{
1880	enable_clocks(1);
1881	REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
1882	enable_clocks(0);
1883}
1884
1885
1886void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
1887{
1888	int mode;
1889
1890	switch (type) {
1891	case OMAP_DSS_LCD_DISPLAY_STN:
1892		mode = 0;
1893		break;
1894
1895	case OMAP_DSS_LCD_DISPLAY_TFT:
1896		mode = 1;
1897		break;
1898
1899	default:
1900		BUG();
1901		return;
1902	}
1903
1904	enable_clocks(1);
1905	REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
1906	enable_clocks(0);
1907}
1908
1909void dispc_set_loadmode(enum omap_dss_load_mode mode)
1910{
1911	enable_clocks(1);
1912	REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
1913	enable_clocks(0);
1914}
1915
1916
1917void dispc_set_default_color(enum omap_channel channel, u32 color)
1918{
1919	const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1920				DISPC_DEFAULT_COLOR1 };
1921
1922	enable_clocks(1);
1923	dispc_write_reg(def_reg[channel], color);
1924	enable_clocks(0);
1925}
1926
1927u32 dispc_get_default_color(enum omap_channel channel)
1928{
1929	const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1930				DISPC_DEFAULT_COLOR1 };
1931	u32 l;
1932
1933	BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
1934	       channel != OMAP_DSS_CHANNEL_LCD);
1935
1936	enable_clocks(1);
1937	l = dispc_read_reg(def_reg[channel]);
1938	enable_clocks(0);
1939
1940	return l;
1941}
1942
1943void dispc_set_trans_key(enum omap_channel ch,
1944		enum omap_dss_trans_key_type type,
1945		u32 trans_key)
1946{
1947	const struct dispc_reg tr_reg[] = {
1948		DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1949
1950	enable_clocks(1);
1951	if (ch == OMAP_DSS_CHANNEL_LCD)
1952		REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
1953	else /* OMAP_DSS_CHANNEL_DIGIT */
1954		REG_FLD_MOD(DISPC_CONFIG, type, 13, 13);
1955
1956	dispc_write_reg(tr_reg[ch], trans_key);
1957	enable_clocks(0);
1958}
1959
1960void dispc_get_trans_key(enum omap_channel ch,
1961		enum omap_dss_trans_key_type *type,
1962		u32 *trans_key)
1963{
1964	const struct dispc_reg tr_reg[] = {
1965		DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1966
1967	enable_clocks(1);
1968	if (type) {
1969		if (ch == OMAP_DSS_CHANNEL_LCD)
1970			*type = REG_GET(DISPC_CONFIG, 11, 11);
1971		else if (ch == OMAP_DSS_CHANNEL_DIGIT)
1972			*type = REG_GET(DISPC_CONFIG, 13, 13);
1973		else
1974			BUG();
1975	}
1976
1977	if (trans_key)
1978		*trans_key = dispc_read_reg(tr_reg[ch]);
1979	enable_clocks(0);
1980}
1981
1982void dispc_enable_trans_key(enum omap_channel ch, bool enable)
1983{
1984	enable_clocks(1);
1985	if (ch == OMAP_DSS_CHANNEL_LCD)
1986		REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
1987	else /* OMAP_DSS_CHANNEL_DIGIT */
1988		REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
1989	enable_clocks(0);
1990}
1991void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
1992{
1993	if (cpu_is_omap24xx())
1994		return;
1995
1996	enable_clocks(1);
1997	if (ch == OMAP_DSS_CHANNEL_LCD)
1998		REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
1999	else /* OMAP_DSS_CHANNEL_DIGIT */
2000		REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
2001	enable_clocks(0);
2002}
2003bool dispc_alpha_blending_enabled(enum omap_channel ch)
2004{
2005	bool enabled;
2006
2007	if (cpu_is_omap24xx())
2008		return false;
2009
2010	enable_clocks(1);
2011	if (ch == OMAP_DSS_CHANNEL_LCD)
2012		enabled = REG_GET(DISPC_CONFIG, 18, 18);
2013	else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2014		enabled = REG_GET(DISPC_CONFIG, 18, 18);
2015	else
2016		BUG();
2017	enable_clocks(0);
2018
2019	return enabled;
2020
2021}
2022
2023
2024bool dispc_trans_key_enabled(enum omap_channel ch)
2025{
2026	bool enabled;
2027
2028	enable_clocks(1);
2029	if (ch == OMAP_DSS_CHANNEL_LCD)
2030		enabled = REG_GET(DISPC_CONFIG, 10, 10);
2031	else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2032		enabled = REG_GET(DISPC_CONFIG, 12, 12);
2033	else
2034		BUG();
2035	enable_clocks(0);
2036
2037	return enabled;
2038}
2039
2040
2041void dispc_set_tft_data_lines(u8 data_lines)
2042{
2043	int code;
2044
2045	switch (data_lines) {
2046	case 12:
2047		code = 0;
2048		break;
2049	case 16:
2050		code = 1;
2051		break;
2052	case 18:
2053		code = 2;
2054		break;
2055	case 24:
2056		code = 3;
2057		break;
2058	default:
2059		BUG();
2060		return;
2061	}
2062
2063	enable_clocks(1);
2064	REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
2065	enable_clocks(0);
2066}
2067
2068void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
2069{
2070	u32 l;
2071	int stallmode;
2072	int gpout0 = 1;
2073	int gpout1;
2074
2075	switch (mode) {
2076	case OMAP_DSS_PARALLELMODE_BYPASS:
2077		stallmode = 0;
2078		gpout1 = 1;
2079		break;
2080
2081	case OMAP_DSS_PARALLELMODE_RFBI:
2082		stallmode = 1;
2083		gpout1 = 0;
2084		break;
2085
2086	case OMAP_DSS_PARALLELMODE_DSI:
2087		stallmode = 1;
2088		gpout1 = 1;
2089		break;
2090
2091	default:
2092		BUG();
2093		return;
2094	}
2095
2096	enable_clocks(1);
2097
2098	l = dispc_read_reg(DISPC_CONTROL);
2099
2100	l = FLD_MOD(l, stallmode, 11, 11);
2101	l = FLD_MOD(l, gpout0, 15, 15);
2102	l = FLD_MOD(l, gpout1, 16, 16);
2103
2104	dispc_write_reg(DISPC_CONTROL, l);
2105
2106	enable_clocks(0);
2107}
2108
2109static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
2110		int vsw, int vfp, int vbp)
2111{
2112	if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2113		if (hsw < 1 || hsw > 64 ||
2114				hfp < 1 || hfp > 256 ||
2115				hbp < 1 || hbp > 256 ||
2116				vsw < 1 || vsw > 64 ||
2117				vfp < 0 || vfp > 255 ||
2118				vbp < 0 || vbp > 255)
2119			return false;
2120	} else {
2121		if (hsw < 1 || hsw > 256 ||
2122				hfp < 1 || hfp > 4096 ||
2123				hbp < 1 || hbp > 4096 ||
2124				vsw < 1 || vsw > 256 ||
2125				vfp < 0 || vfp > 4095 ||
2126				vbp < 0 || vbp > 4095)
2127			return false;
2128	}
2129
2130	return true;
2131}
2132
2133bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
2134{
2135	return _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2136			timings->hbp, timings->vsw,
2137			timings->vfp, timings->vbp);
2138}
2139
2140static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
2141				   int vsw, int vfp, int vbp)
2142{
2143	u32 timing_h, timing_v;
2144
2145	if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2146		timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
2147			FLD_VAL(hbp-1, 27, 20);
2148
2149		timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
2150			FLD_VAL(vbp, 27, 20);
2151	} else {
2152		timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
2153			FLD_VAL(hbp-1, 31, 20);
2154
2155		timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
2156			FLD_VAL(vbp, 31, 20);
2157	}
2158
2159	enable_clocks(1);
2160	dispc_write_reg(DISPC_TIMING_H, timing_h);
2161	dispc_write_reg(DISPC_TIMING_V, timing_v);
2162	enable_clocks(0);
2163}
2164
2165/* change name to mode? */
2166void dispc_set_lcd_timings(struct omap_video_timings *timings)
2167{
2168	unsigned xtot, ytot;
2169	unsigned long ht, vt;
2170
2171	if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2172				timings->hbp, timings->vsw,
2173				timings->vfp, timings->vbp))
2174		BUG();
2175
2176	_dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp,
2177			timings->vsw, timings->vfp, timings->vbp);
2178
2179	dispc_set_lcd_size(timings->x_res, timings->y_res);
2180
2181	xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
2182	ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
2183
2184	ht = (timings->pixel_clock * 1000) / xtot;
2185	vt = (timings->pixel_clock * 1000) / xtot / ytot;
2186
2187	DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res);
2188	DSSDBG("pck %u\n", timings->pixel_clock);
2189	DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
2190			timings->hsw, timings->hfp, timings->hbp,
2191			timings->vsw, timings->vfp, timings->vbp);
2192
2193	DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
2194}
2195
2196static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div)
2197{
2198	BUG_ON(lck_div < 1);
2199	BUG_ON(pck_div < 2);
2200
2201	enable_clocks(1);
2202	dispc_write_reg(DISPC_DIVISOR,
2203			FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
2204	enable_clocks(0);
2205}
2206
2207static void dispc_get_lcd_divisor(int *lck_div, int *pck_div)
2208{
2209	u32 l;
2210	l = dispc_read_reg(DISPC_DIVISOR);
2211	*lck_div = FLD_GET(l, 23, 16);
2212	*pck_div = FLD_GET(l, 7, 0);
2213}
2214
2215unsigned long dispc_fclk_rate(void)
2216{
2217	unsigned long r = 0;
2218
2219	if (dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK)
2220		r = dss_clk_get_rate(DSS_CLK_FCK1);
2221	else
2222#ifdef CONFIG_OMAP2_DSS_DSI
2223		r = dsi_get_dsi1_pll_rate();
2224#else
2225	BUG();
2226#endif
2227	return r;
2228}
2229
2230unsigned long dispc_lclk_rate(void)
2231{
2232	int lcd;
2233	unsigned long r;
2234	u32 l;
2235
2236	l = dispc_read_reg(DISPC_DIVISOR);
2237
2238	lcd = FLD_GET(l, 23, 16);
2239
2240	r = dispc_fclk_rate();
2241
2242	return r / lcd;
2243}
2244
2245unsigned long dispc_pclk_rate(void)
2246{
2247	int lcd, pcd;
2248	unsigned long r;
2249	u32 l;
2250
2251	l = dispc_read_reg(DISPC_DIVISOR);
2252
2253	lcd = FLD_GET(l, 23, 16);
2254	pcd = FLD_GET(l, 7, 0);
2255
2256	r = dispc_fclk_rate();
2257
2258	return r / lcd / pcd;
2259}
2260
2261void dispc_dump_clocks(struct seq_file *s)
2262{
2263	int lcd, pcd;
2264
2265	enable_clocks(1);
2266
2267	dispc_get_lcd_divisor(&lcd, &pcd);
2268
2269	seq_printf(s, "- DISPC -\n");
2270
2271	seq_printf(s, "dispc fclk source = %s\n",
2272			dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
2273			"dss1_alwon_fclk" : "dsi1_pll_fclk");
2274
2275	seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
2276	seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd);
2277	seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd);
2278
2279	enable_clocks(0);
2280}
2281
2282#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2283void dispc_dump_irqs(struct seq_file *s)
2284{
2285	unsigned long flags;
2286	struct dispc_irq_stats stats;
2287
2288	spin_lock_irqsave(&dispc.irq_stats_lock, flags);
2289
2290	stats = dispc.irq_stats;
2291	memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats));
2292	dispc.irq_stats.last_reset = jiffies;
2293
2294	spin_unlock_irqrestore(&dispc.irq_stats_lock, flags);
2295
2296	seq_printf(s, "period %u ms\n",
2297			jiffies_to_msecs(jiffies - stats.last_reset));
2298
2299	seq_printf(s, "irqs %d\n", stats.irq_count);
2300#define PIS(x) \
2301	seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
2302
2303	PIS(FRAMEDONE);
2304	PIS(VSYNC);
2305	PIS(EVSYNC_EVEN);
2306	PIS(EVSYNC_ODD);
2307	PIS(ACBIAS_COUNT_STAT);
2308	PIS(PROG_LINE_NUM);
2309	PIS(GFX_FIFO_UNDERFLOW);
2310	PIS(GFX_END_WIN);
2311	PIS(PAL_GAMMA_MASK);
2312	PIS(OCP_ERR);
2313	PIS(VID1_FIFO_UNDERFLOW);
2314	PIS(VID1_END_WIN);
2315	PIS(VID2_FIFO_UNDERFLOW);
2316	PIS(VID2_END_WIN);
2317	PIS(SYNC_LOST);
2318	PIS(SYNC_LOST_DIGIT);
2319	PIS(WAKEUP);
2320#undef PIS
2321}
2322#endif
2323
2324void dispc_dump_regs(struct seq_file *s)
2325{
2326#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
2327
2328	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
2329
2330	DUMPREG(DISPC_REVISION);
2331	DUMPREG(DISPC_SYSCONFIG);
2332	DUMPREG(DISPC_SYSSTATUS);
2333	DUMPREG(DISPC_IRQSTATUS);
2334	DUMPREG(DISPC_IRQENABLE);
2335	DUMPREG(DISPC_CONTROL);
2336	DUMPREG(DISPC_CONFIG);
2337	DUMPREG(DISPC_CAPABLE);
2338	DUMPREG(DISPC_DEFAULT_COLOR0);
2339	DUMPREG(DISPC_DEFAULT_COLOR1);
2340	DUMPREG(DISPC_TRANS_COLOR0);
2341	DUMPREG(DISPC_TRANS_COLOR1);
2342	DUMPREG(DISPC_LINE_STATUS);
2343	DUMPREG(DISPC_LINE_NUMBER);
2344	DUMPREG(DISPC_TIMING_H);
2345	DUMPREG(DISPC_TIMING_V);
2346	DUMPREG(DISPC_POL_FREQ);
2347	DUMPREG(DISPC_DIVISOR);
2348	DUMPREG(DISPC_GLOBAL_ALPHA);
2349	DUMPREG(DISPC_SIZE_DIG);
2350	DUMPREG(DISPC_SIZE_LCD);
2351
2352	DUMPREG(DISPC_GFX_BA0);
2353	DUMPREG(DISPC_GFX_BA1);
2354	DUMPREG(DISPC_GFX_POSITION);
2355	DUMPREG(DISPC_GFX_SIZE);
2356	DUMPREG(DISPC_GFX_ATTRIBUTES);
2357	DUMPREG(DISPC_GFX_FIFO_THRESHOLD);
2358	DUMPREG(DISPC_GFX_FIFO_SIZE_STATUS);
2359	DUMPREG(DISPC_GFX_ROW_INC);
2360	DUMPREG(DISPC_GFX_PIXEL_INC);
2361	DUMPREG(DISPC_GFX_WINDOW_SKIP);
2362	DUMPREG(DISPC_GFX_TABLE_BA);
2363
2364	DUMPREG(DISPC_DATA_CYCLE1);
2365	DUMPREG(DISPC_DATA_CYCLE2);
2366	DUMPREG(DISPC_DATA_CYCLE3);
2367
2368	DUMPREG(DISPC_CPR_COEF_R);
2369	DUMPREG(DISPC_CPR_COEF_G);
2370	DUMPREG(DISPC_CPR_COEF_B);
2371
2372	DUMPREG(DISPC_GFX_PRELOAD);
2373
2374	DUMPREG(DISPC_VID_BA0(0));
2375	DUMPREG(DISPC_VID_BA1(0));
2376	DUMPREG(DISPC_VID_POSITION(0));
2377	DUMPREG(DISPC_VID_SIZE(0));
2378	DUMPREG(DISPC_VID_ATTRIBUTES(0));
2379	DUMPREG(DISPC_VID_FIFO_THRESHOLD(0));
2380	DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(0));
2381	DUMPREG(DISPC_VID_ROW_INC(0));
2382	DUMPREG(DISPC_VID_PIXEL_INC(0));
2383	DUMPREG(DISPC_VID_FIR(0));
2384	DUMPREG(DISPC_VID_PICTURE_SIZE(0));
2385	DUMPREG(DISPC_VID_ACCU0(0));
2386	DUMPREG(DISPC_VID_ACCU1(0));
2387
2388	DUMPREG(DISPC_VID_BA0(1));
2389	DUMPREG(DISPC_VID_BA1(1));
2390	DUMPREG(DISPC_VID_POSITION(1));
2391	DUMPREG(DISPC_VID_SIZE(1));
2392	DUMPREG(DISPC_VID_ATTRIBUTES(1));
2393	DUMPREG(DISPC_VID_FIFO_THRESHOLD(1));
2394	DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(1));
2395	DUMPREG(DISPC_VID_ROW_INC(1));
2396	DUMPREG(DISPC_VID_PIXEL_INC(1));
2397	DUMPREG(DISPC_VID_FIR(1));
2398	DUMPREG(DISPC_VID_PICTURE_SIZE(1));
2399	DUMPREG(DISPC_VID_ACCU0(1));
2400	DUMPREG(DISPC_VID_ACCU1(1));
2401
2402	DUMPREG(DISPC_VID_FIR_COEF_H(0, 0));
2403	DUMPREG(DISPC_VID_FIR_COEF_H(0, 1));
2404	DUMPREG(DISPC_VID_FIR_COEF_H(0, 2));
2405	DUMPREG(DISPC_VID_FIR_COEF_H(0, 3));
2406	DUMPREG(DISPC_VID_FIR_COEF_H(0, 4));
2407	DUMPREG(DISPC_VID_FIR_COEF_H(0, 5));
2408	DUMPREG(DISPC_VID_FIR_COEF_H(0, 6));
2409	DUMPREG(DISPC_VID_FIR_COEF_H(0, 7));
2410	DUMPREG(DISPC_VID_FIR_COEF_HV(0, 0));
2411	DUMPREG(DISPC_VID_FIR_COEF_HV(0, 1));
2412	DUMPREG(DISPC_VID_FIR_COEF_HV(0, 2));
2413	DUMPREG(DISPC_VID_FIR_COEF_HV(0, 3));
2414	DUMPREG(DISPC_VID_FIR_COEF_HV(0, 4));
2415	DUMPREG(DISPC_VID_FIR_COEF_HV(0, 5));
2416	DUMPREG(DISPC_VID_FIR_COEF_HV(0, 6));
2417	DUMPREG(DISPC_VID_FIR_COEF_HV(0, 7));
2418	DUMPREG(DISPC_VID_CONV_COEF(0, 0));
2419	DUMPREG(DISPC_VID_CONV_COEF(0, 1));
2420	DUMPREG(DISPC_VID_CONV_COEF(0, 2));
2421	DUMPREG(DISPC_VID_CONV_COEF(0, 3));
2422	DUMPREG(DISPC_VID_CONV_COEF(0, 4));
2423	DUMPREG(DISPC_VID_FIR_COEF_V(0, 0));
2424	DUMPREG(DISPC_VID_FIR_COEF_V(0, 1));
2425	DUMPREG(DISPC_VID_FIR_COEF_V(0, 2));
2426	DUMPREG(DISPC_VID_FIR_COEF_V(0, 3));
2427	DUMPREG(DISPC_VID_FIR_COEF_V(0, 4));
2428	DUMPREG(DISPC_VID_FIR_COEF_V(0, 5));
2429	DUMPREG(DISPC_VID_FIR_COEF_V(0, 6));
2430	DUMPREG(DISPC_VID_FIR_COEF_V(0, 7));
2431
2432	DUMPREG(DISPC_VID_FIR_COEF_H(1, 0));
2433	DUMPREG(DISPC_VID_FIR_COEF_H(1, 1));
2434	DUMPREG(DISPC_VID_FIR_COEF_H(1, 2));
2435	DUMPREG(DISPC_VID_FIR_COEF_H(1, 3));
2436	DUMPREG(DISPC_VID_FIR_COEF_H(1, 4));
2437	DUMPREG(DISPC_VID_FIR_COEF_H(1, 5));
2438	DUMPREG(DISPC_VID_FIR_COEF_H(1, 6));
2439	DUMPREG(DISPC_VID_FIR_COEF_H(1, 7));
2440	DUMPREG(DISPC_VID_FIR_COEF_HV(1, 0));
2441	DUMPREG(DISPC_VID_FIR_COEF_HV(1, 1));
2442	DUMPREG(DISPC_VID_FIR_COEF_HV(1, 2));
2443	DUMPREG(DISPC_VID_FIR_COEF_HV(1, 3));
2444	DUMPREG(DISPC_VID_FIR_COEF_HV(1, 4));
2445	DUMPREG(DISPC_VID_FIR_COEF_HV(1, 5));
2446	DUMPREG(DISPC_VID_FIR_COEF_HV(1, 6));
2447	DUMPREG(DISPC_VID_FIR_COEF_HV(1, 7));
2448	DUMPREG(DISPC_VID_CONV_COEF(1, 0));
2449	DUMPREG(DISPC_VID_CONV_COEF(1, 1));
2450	DUMPREG(DISPC_VID_CONV_COEF(1, 2));
2451	DUMPREG(DISPC_VID_CONV_COEF(1, 3));
2452	DUMPREG(DISPC_VID_CONV_COEF(1, 4));
2453	DUMPREG(DISPC_VID_FIR_COEF_V(1, 0));
2454	DUMPREG(DISPC_VID_FIR_COEF_V(1, 1));
2455	DUMPREG(DISPC_VID_FIR_COEF_V(1, 2));
2456	DUMPREG(DISPC_VID_FIR_COEF_V(1, 3));
2457	DUMPREG(DISPC_VID_FIR_COEF_V(1, 4));
2458	DUMPREG(DISPC_VID_FIR_COEF_V(1, 5));
2459	DUMPREG(DISPC_VID_FIR_COEF_V(1, 6));
2460	DUMPREG(DISPC_VID_FIR_COEF_V(1, 7));
2461
2462	DUMPREG(DISPC_VID_PRELOAD(0));
2463	DUMPREG(DISPC_VID_PRELOAD(1));
2464
2465	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
2466#undef DUMPREG
2467}
2468
2469static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
2470				bool ihs, bool ivs, u8 acbi, u8 acb)
2471{
2472	u32 l = 0;
2473
2474	DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n",
2475			onoff, rf, ieo, ipc, ihs, ivs, acbi, acb);
2476
2477	l |= FLD_VAL(onoff, 17, 17);
2478	l |= FLD_VAL(rf, 16, 16);
2479	l |= FLD_VAL(ieo, 15, 15);
2480	l |= FLD_VAL(ipc, 14, 14);
2481	l |= FLD_VAL(ihs, 13, 13);
2482	l |= FLD_VAL(ivs, 12, 12);
2483	l |= FLD_VAL(acbi, 11, 8);
2484	l |= FLD_VAL(acb, 7, 0);
2485
2486	enable_clocks(1);
2487	dispc_write_reg(DISPC_POL_FREQ, l);
2488	enable_clocks(0);
2489}
2490
2491void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb)
2492{
2493	_dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0,
2494			(config & OMAP_DSS_LCD_RF) != 0,
2495			(config & OMAP_DSS_LCD_IEO) != 0,
2496			(config & OMAP_DSS_LCD_IPC) != 0,
2497			(config & OMAP_DSS_LCD_IHS) != 0,
2498			(config & OMAP_DSS_LCD_IVS) != 0,
2499			acbi, acb);
2500}
2501
2502/* with fck as input clock rate, find dispc dividers that produce req_pck */
2503void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
2504		struct dispc_clock_info *cinfo)
2505{
2506	u16 pcd_min = is_tft ? 2 : 3;
2507	unsigned long best_pck;
2508	u16 best_ld, cur_ld;
2509	u16 best_pd, cur_pd;
2510
2511	best_pck = 0;
2512	best_ld = 0;
2513	best_pd = 0;
2514
2515	for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
2516		unsigned long lck = fck / cur_ld;
2517
2518		for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) {
2519			unsigned long pck = lck / cur_pd;
2520			long old_delta = abs(best_pck - req_pck);
2521			long new_delta = abs(pck - req_pck);
2522
2523			if (best_pck == 0 || new_delta < old_delta) {
2524				best_pck = pck;
2525				best_ld = cur_ld;
2526				best_pd = cur_pd;
2527
2528				if (pck == req_pck)
2529					goto found;
2530			}
2531
2532			if (pck < req_pck)
2533				break;
2534		}
2535
2536		if (lck / pcd_min < req_pck)
2537			break;
2538	}
2539
2540found:
2541	cinfo->lck_div = best_ld;
2542	cinfo->pck_div = best_pd;
2543	cinfo->lck = fck / cinfo->lck_div;
2544	cinfo->pck = cinfo->lck / cinfo->pck_div;
2545}
2546
2547/* calculate clock rates using dividers in cinfo */
2548int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
2549		struct dispc_clock_info *cinfo)
2550{
2551	if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
2552		return -EINVAL;
2553	if (cinfo->pck_div < 2 || cinfo->pck_div > 255)
2554		return -EINVAL;
2555
2556	cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
2557	cinfo->pck = cinfo->lck / cinfo->pck_div;
2558
2559	return 0;
2560}
2561
2562int dispc_set_clock_div(struct dispc_clock_info *cinfo)
2563{
2564	DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
2565	DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
2566
2567	dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div);
2568
2569	return 0;
2570}
2571
2572int dispc_get_clock_div(struct dispc_clock_info *cinfo)
2573{
2574	unsigned long fck;
2575
2576	fck = dispc_fclk_rate();
2577
2578	cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
2579	cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
2580
2581	cinfo->lck = fck / cinfo->lck_div;
2582	cinfo->pck = cinfo->lck / cinfo->pck_div;
2583
2584	return 0;
2585}
2586
2587/* dispc.irq_lock has to be locked by the caller */
2588static void _omap_dispc_set_irqs(void)
2589{
2590	u32 mask;
2591	u32 old_mask;
2592	int i;
2593	struct omap_dispc_isr_data *isr_data;
2594
2595	mask = dispc.irq_error_mask;
2596
2597	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2598		isr_data = &dispc.registered_isr[i];
2599
2600		if (isr_data->isr == NULL)
2601			continue;
2602
2603		mask |= isr_data->mask;
2604	}
2605
2606	enable_clocks(1);
2607
2608	old_mask = dispc_read_reg(DISPC_IRQENABLE);
2609	/* clear the irqstatus for newly enabled irqs */
2610	dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
2611
2612	dispc_write_reg(DISPC_IRQENABLE, mask);
2613
2614	enable_clocks(0);
2615}
2616
2617int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2618{
2619	int i;
2620	int ret;
2621	unsigned long flags;
2622	struct omap_dispc_isr_data *isr_data;
2623
2624	if (isr == NULL)
2625		return -EINVAL;
2626
2627	spin_lock_irqsave(&dispc.irq_lock, flags);
2628
2629	/* check for duplicate entry */
2630	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2631		isr_data = &dispc.registered_isr[i];
2632		if (isr_data->isr == isr && isr_data->arg == arg &&
2633				isr_data->mask == mask) {
2634			ret = -EINVAL;
2635			goto err;
2636		}
2637	}
2638
2639	isr_data = NULL;
2640	ret = -EBUSY;
2641
2642	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2643		isr_data = &dispc.registered_isr[i];
2644
2645		if (isr_data->isr != NULL)
2646			continue;
2647
2648		isr_data->isr = isr;
2649		isr_data->arg = arg;
2650		isr_data->mask = mask;
2651		ret = 0;
2652
2653		break;
2654	}
2655
2656	_omap_dispc_set_irqs();
2657
2658	spin_unlock_irqrestore(&dispc.irq_lock, flags);
2659
2660	return 0;
2661err:
2662	spin_unlock_irqrestore(&dispc.irq_lock, flags);
2663
2664	return ret;
2665}
2666EXPORT_SYMBOL(omap_dispc_register_isr);
2667
2668int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2669{
2670	int i;
2671	unsigned long flags;
2672	int ret = -EINVAL;
2673	struct omap_dispc_isr_data *isr_data;
2674
2675	spin_lock_irqsave(&dispc.irq_lock, flags);
2676
2677	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2678		isr_data = &dispc.registered_isr[i];
2679		if (isr_data->isr != isr || isr_data->arg != arg ||
2680				isr_data->mask != mask)
2681			continue;
2682
2683		/* found the correct isr */
2684
2685		isr_data->isr = NULL;
2686		isr_data->arg = NULL;
2687		isr_data->mask = 0;
2688
2689		ret = 0;
2690		break;
2691	}
2692
2693	if (ret == 0)
2694		_omap_dispc_set_irqs();
2695
2696	spin_unlock_irqrestore(&dispc.irq_lock, flags);
2697
2698	return ret;
2699}
2700EXPORT_SYMBOL(omap_dispc_unregister_isr);
2701
2702#ifdef DEBUG
2703static void print_irq_status(u32 status)
2704{
2705	if ((status & dispc.irq_error_mask) == 0)
2706		return;
2707
2708	printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status);
2709
2710#define PIS(x) \
2711	if (status & DISPC_IRQ_##x) \
2712		printk(#x " ");
2713	PIS(GFX_FIFO_UNDERFLOW);
2714	PIS(OCP_ERR);
2715	PIS(VID1_FIFO_UNDERFLOW);
2716	PIS(VID2_FIFO_UNDERFLOW);
2717	PIS(SYNC_LOST);
2718	PIS(SYNC_LOST_DIGIT);
2719#undef PIS
2720
2721	printk("\n");
2722}
2723#endif
2724
2725/* Called from dss.c. Note that we don't touch clocks here,
2726 * but we presume they are on because we got an IRQ. However,
2727 * an irq handler may turn the clocks off, so we may not have
2728 * clock later in the function. */
2729void dispc_irq_handler(void)
2730{
2731	int i;
2732	u32 irqstatus;
2733	u32 handledirqs = 0;
2734	u32 unhandled_errors;
2735	struct omap_dispc_isr_data *isr_data;
2736	struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
2737
2738	spin_lock(&dispc.irq_lock);
2739
2740	irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
2741
2742#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2743	spin_lock(&dispc.irq_stats_lock);
2744	dispc.irq_stats.irq_count++;
2745	dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs);
2746	spin_unlock(&dispc.irq_stats_lock);
2747#endif
2748
2749#ifdef DEBUG
2750	if (dss_debug)
2751		print_irq_status(irqstatus);
2752#endif
2753	/* Ack the interrupt. Do it here before clocks are possibly turned
2754	 * off */
2755	dispc_write_reg(DISPC_IRQSTATUS, irqstatus);
2756	/* flush posted write */
2757	dispc_read_reg(DISPC_IRQSTATUS);
2758
2759	/* make a copy and unlock, so that isrs can unregister
2760	 * themselves */
2761	memcpy(registered_isr, dispc.registered_isr,
2762			sizeof(registered_isr));
2763
2764	spin_unlock(&dispc.irq_lock);
2765
2766	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2767		isr_data = &registered_isr[i];
2768
2769		if (!isr_data->isr)
2770			continue;
2771
2772		if (isr_data->mask & irqstatus) {
2773			isr_data->isr(isr_data->arg, irqstatus);
2774			handledirqs |= isr_data->mask;
2775		}
2776	}
2777
2778	spin_lock(&dispc.irq_lock);
2779
2780	unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
2781
2782	if (unhandled_errors) {
2783		dispc.error_irqs |= unhandled_errors;
2784
2785		dispc.irq_error_mask &= ~unhandled_errors;
2786		_omap_dispc_set_irqs();
2787
2788		schedule_work(&dispc.error_work);
2789	}
2790
2791	spin_unlock(&dispc.irq_lock);
2792}
2793
2794static void dispc_error_worker(struct work_struct *work)
2795{
2796	int i;
2797	u32 errors;
2798	unsigned long flags;
2799
2800	spin_lock_irqsave(&dispc.irq_lock, flags);
2801	errors = dispc.error_irqs;
2802	dispc.error_irqs = 0;
2803	spin_unlock_irqrestore(&dispc.irq_lock, flags);
2804
2805	if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) {
2806		DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n");
2807		for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2808			struct omap_overlay *ovl;
2809			ovl = omap_dss_get_overlay(i);
2810
2811			if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2812				continue;
2813
2814			if (ovl->id == 0) {
2815				dispc_enable_plane(ovl->id, 0);
2816				dispc_go(ovl->manager->id);
2817				mdelay(50);
2818				break;
2819			}
2820		}
2821	}
2822
2823	if (errors & DISPC_IRQ_VID1_FIFO_UNDERFLOW) {
2824		DSSERR("VID1_FIFO_UNDERFLOW, disabling VID1\n");
2825		for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2826			struct omap_overlay *ovl;
2827			ovl = omap_dss_get_overlay(i);
2828
2829			if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2830				continue;
2831
2832			if (ovl->id == 1) {
2833				dispc_enable_plane(ovl->id, 0);
2834				dispc_go(ovl->manager->id);
2835				mdelay(50);
2836				break;
2837			}
2838		}
2839	}
2840
2841	if (errors & DISPC_IRQ_VID2_FIFO_UNDERFLOW) {
2842		DSSERR("VID2_FIFO_UNDERFLOW, disabling VID2\n");
2843		for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2844			struct omap_overlay *ovl;
2845			ovl = omap_dss_get_overlay(i);
2846
2847			if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2848				continue;
2849
2850			if (ovl->id == 2) {
2851				dispc_enable_plane(ovl->id, 0);
2852				dispc_go(ovl->manager->id);
2853				mdelay(50);
2854				break;
2855			}
2856		}
2857	}
2858
2859	if (errors & DISPC_IRQ_SYNC_LOST) {
2860		struct omap_overlay_manager *manager = NULL;
2861		bool enable = false;
2862
2863		DSSERR("SYNC_LOST, disabling LCD\n");
2864
2865		for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2866			struct omap_overlay_manager *mgr;
2867			mgr = omap_dss_get_overlay_manager(i);
2868
2869			if (mgr->id == OMAP_DSS_CHANNEL_LCD) {
2870				manager = mgr;
2871				enable = mgr->device->state ==
2872						OMAP_DSS_DISPLAY_ACTIVE;
2873				mgr->device->driver->disable(mgr->device);
2874				break;
2875			}
2876		}
2877
2878		if (manager) {
2879			struct omap_dss_device *dssdev = manager->device;
2880			for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2881				struct omap_overlay *ovl;
2882				ovl = omap_dss_get_overlay(i);
2883
2884				if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2885					continue;
2886
2887				if (ovl->id != 0 && ovl->manager == manager)
2888					dispc_enable_plane(ovl->id, 0);
2889			}
2890
2891			dispc_go(manager->id);
2892			mdelay(50);
2893			if (enable)
2894				dssdev->driver->enable(dssdev);
2895		}
2896	}
2897
2898	if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) {
2899		struct omap_overlay_manager *manager = NULL;
2900		bool enable = false;
2901
2902		DSSERR("SYNC_LOST_DIGIT, disabling TV\n");
2903
2904		for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2905			struct omap_overlay_manager *mgr;
2906			mgr = omap_dss_get_overlay_manager(i);
2907
2908			if (mgr->id == OMAP_DSS_CHANNEL_DIGIT) {
2909				manager = mgr;
2910				enable = mgr->device->state ==
2911						OMAP_DSS_DISPLAY_ACTIVE;
2912				mgr->device->driver->disable(mgr->device);
2913				break;
2914			}
2915		}
2916
2917		if (manager) {
2918			struct omap_dss_device *dssdev = manager->device;
2919			for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2920				struct omap_overlay *ovl;
2921				ovl = omap_dss_get_overlay(i);
2922
2923				if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2924					continue;
2925
2926				if (ovl->id != 0 && ovl->manager == manager)
2927					dispc_enable_plane(ovl->id, 0);
2928			}
2929
2930			dispc_go(manager->id);
2931			mdelay(50);
2932			if (enable)
2933				dssdev->driver->enable(dssdev);
2934		}
2935	}
2936
2937	if (errors & DISPC_IRQ_OCP_ERR) {
2938		DSSERR("OCP_ERR\n");
2939		for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2940			struct omap_overlay_manager *mgr;
2941			mgr = omap_dss_get_overlay_manager(i);
2942
2943			if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC)
2944				mgr->device->driver->disable(mgr->device);
2945		}
2946	}
2947
2948	spin_lock_irqsave(&dispc.irq_lock, flags);
2949	dispc.irq_error_mask |= errors;
2950	_omap_dispc_set_irqs();
2951	spin_unlock_irqrestore(&dispc.irq_lock, flags);
2952}
2953
2954int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
2955{
2956	void dispc_irq_wait_handler(void *data, u32 mask)
2957	{
2958		complete((struct completion *)data);
2959	}
2960
2961	int r;
2962	DECLARE_COMPLETION_ONSTACK(completion);
2963
2964	r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2965			irqmask);
2966
2967	if (r)
2968		return r;
2969
2970	timeout = wait_for_completion_timeout(&completion, timeout);
2971
2972	omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
2973
2974	if (timeout == 0)
2975		return -ETIMEDOUT;
2976
2977	if (timeout == -ERESTARTSYS)
2978		return -ERESTARTSYS;
2979
2980	return 0;
2981}
2982
2983int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
2984		unsigned long timeout)
2985{
2986	void dispc_irq_wait_handler(void *data, u32 mask)
2987	{
2988		complete((struct completion *)data);
2989	}
2990
2991	int r;
2992	DECLARE_COMPLETION_ONSTACK(completion);
2993
2994	r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2995			irqmask);
2996
2997	if (r)
2998		return r;
2999
3000	timeout = wait_for_completion_interruptible_timeout(&completion,
3001			timeout);
3002
3003	omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
3004
3005	if (timeout == 0)
3006		return -ETIMEDOUT;
3007
3008	if (timeout == -ERESTARTSYS)
3009		return -ERESTARTSYS;
3010
3011	return 0;
3012}
3013
3014#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
3015void dispc_fake_vsync_irq(void)
3016{
3017	u32 irqstatus = DISPC_IRQ_VSYNC;
3018	int i;
3019
3020	WARN_ON(!in_interrupt());
3021
3022	for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3023		struct omap_dispc_isr_data *isr_data;
3024		isr_data = &dispc.registered_isr[i];
3025
3026		if (!isr_data->isr)
3027			continue;
3028
3029		if (isr_data->mask & irqstatus)
3030			isr_data->isr(isr_data->arg, irqstatus);
3031	}
3032}
3033#endif
3034
3035static void _omap_dispc_initialize_irq(void)
3036{
3037	unsigned long flags;
3038
3039	spin_lock_irqsave(&dispc.irq_lock, flags);
3040
3041	memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
3042
3043	dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
3044
3045	/* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
3046	 * so clear it */
3047	dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS));
3048
3049	_omap_dispc_set_irqs();
3050
3051	spin_unlock_irqrestore(&dispc.irq_lock, flags);
3052}
3053
3054void dispc_enable_sidle(void)
3055{
3056	REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3);	/* SIDLEMODE: smart idle */
3057}
3058
3059void dispc_disable_sidle(void)
3060{
3061	REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3);	/* SIDLEMODE: no idle */
3062}
3063
3064static void _omap_dispc_initial_config(void)
3065{
3066	u32 l;
3067
3068	l = dispc_read_reg(DISPC_SYSCONFIG);
3069	l = FLD_MOD(l, 2, 13, 12);	/* MIDLEMODE: smart standby */
3070	l = FLD_MOD(l, 2, 4, 3);	/* SIDLEMODE: smart idle */
3071	l = FLD_MOD(l, 1, 2, 2);	/* ENWAKEUP */
3072	l = FLD_MOD(l, 1, 0, 0);	/* AUTOIDLE */
3073	dispc_write_reg(DISPC_SYSCONFIG, l);
3074
3075	/* FUNCGATED */
3076	REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
3077
3078	/* L3 firewall setting: enable access to OCM RAM */
3079	if (cpu_is_omap24xx())
3080		__raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0));
3081
3082	_dispc_setup_color_conv_coef();
3083
3084	dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3085
3086	dispc_read_plane_fifo_sizes();
3087}
3088
3089int dispc_init(void)
3090{
3091	u32 rev;
3092
3093	spin_lock_init(&dispc.irq_lock);
3094
3095#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3096	spin_lock_init(&dispc.irq_stats_lock);
3097	dispc.irq_stats.last_reset = jiffies;
3098#endif
3099
3100	INIT_WORK(&dispc.error_work, dispc_error_worker);
3101
3102	dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
3103	if (!dispc.base) {
3104		DSSERR("can't ioremap DISPC\n");
3105		return -ENOMEM;
3106	}
3107
3108	enable_clocks(1);
3109
3110	_omap_dispc_initial_config();
3111
3112	_omap_dispc_initialize_irq();
3113
3114	dispc_save_context();
3115
3116	rev = dispc_read_reg(DISPC_REVISION);
3117	printk(KERN_INFO "OMAP DISPC rev %d.%d\n",
3118	       FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
3119
3120	enable_clocks(0);
3121
3122	return 0;
3123}
3124
3125void dispc_exit(void)
3126{
3127	iounmap(dispc.base);
3128}
3129
3130int dispc_enable_plane(enum omap_plane plane, bool enable)
3131{
3132	DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
3133
3134	enable_clocks(1);
3135	_dispc_enable_plane(plane, enable);
3136	enable_clocks(0);
3137
3138	return 0;
3139}
3140
3141int dispc_setup_plane(enum omap_plane plane,
3142		       u32 paddr, u16 screen_width,
3143		       u16 pos_x, u16 pos_y,
3144		       u16 width, u16 height,
3145		       u16 out_width, u16 out_height,
3146		       enum omap_color_mode color_mode,
3147		       bool ilace,
3148		       enum omap_dss_rotation_type rotation_type,
3149		       u8 rotation, bool mirror, u8 global_alpha)
3150{
3151	int r = 0;
3152
3153	DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
3154	       "%dx%d, ilace %d, cmode %x, rot %d, mir %d\n",
3155	       plane, paddr, screen_width, pos_x, pos_y,
3156	       width, height,
3157	       out_width, out_height,
3158	       ilace, color_mode,
3159	       rotation, mirror);
3160
3161	enable_clocks(1);
3162
3163	r = _dispc_setup_plane(plane,
3164			   paddr, screen_width,
3165			   pos_x, pos_y,
3166			   width, height,
3167			   out_width, out_height,
3168			   color_mode, ilace,
3169			   rotation_type,
3170			   rotation, mirror,
3171			   global_alpha);
3172
3173	enable_clocks(0);
3174
3175	return r;
3176}
3177