Merge branches 'devel', 'devel-stable' and 'fixes' into for-linus
[pandora-kernel.git] / drivers / video / omap2 / dss / dispc.c
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 #include <linux/interrupt.h>
36
37 #include <plat/sram.h>
38 #include <plat/clock.h>
39
40 #include <video/omapdss.h>
41
42 #include "dss.h"
43 #include "dss_features.h"
44 #include "dispc.h"
45
46 /* DISPC */
47 #define DISPC_SZ_REGS                   SZ_4K
48
49 #define DISPC_IRQ_MASK_ERROR            (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
50                                          DISPC_IRQ_OCP_ERR | \
51                                          DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
52                                          DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
53                                          DISPC_IRQ_SYNC_LOST | \
54                                          DISPC_IRQ_SYNC_LOST_DIGIT)
55
56 #define DISPC_MAX_NR_ISRS               8
57
58 struct omap_dispc_isr_data {
59         omap_dispc_isr_t        isr;
60         void                    *arg;
61         u32                     mask;
62 };
63
64 struct dispc_h_coef {
65         s8 hc4;
66         s8 hc3;
67         u8 hc2;
68         s8 hc1;
69         s8 hc0;
70 };
71
72 struct dispc_v_coef {
73         s8 vc22;
74         s8 vc2;
75         u8 vc1;
76         s8 vc0;
77         s8 vc00;
78 };
79
80 #define REG_GET(idx, start, end) \
81         FLD_GET(dispc_read_reg(idx), start, end)
82
83 #define REG_FLD_MOD(idx, val, start, end)                               \
84         dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
85
86 struct dispc_irq_stats {
87         unsigned long last_reset;
88         unsigned irq_count;
89         unsigned irqs[32];
90 };
91
92 static struct {
93         struct platform_device *pdev;
94         void __iomem    *base;
95         int irq;
96
97         u32     fifo_size[3];
98
99         spinlock_t irq_lock;
100         u32 irq_error_mask;
101         struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
102         u32 error_irqs;
103         struct work_struct error_work;
104
105         u32             ctx[DISPC_SZ_REGS / sizeof(u32)];
106
107 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
108         spinlock_t irq_stats_lock;
109         struct dispc_irq_stats irq_stats;
110 #endif
111 } dispc;
112
113 enum omap_color_component {
114         /* used for all color formats for OMAP3 and earlier
115          * and for RGB and Y color component on OMAP4
116          */
117         DISPC_COLOR_COMPONENT_RGB_Y             = 1 << 0,
118         /* used for UV component for
119          * OMAP_DSS_COLOR_YUV2, OMAP_DSS_COLOR_UYVY, OMAP_DSS_COLOR_NV12
120          * color formats on OMAP4
121          */
122         DISPC_COLOR_COMPONENT_UV                = 1 << 1,
123 };
124
125 static void _omap_dispc_set_irqs(void);
126
127 static inline void dispc_write_reg(const u16 idx, u32 val)
128 {
129         __raw_writel(val, dispc.base + idx);
130 }
131
132 static inline u32 dispc_read_reg(const u16 idx)
133 {
134         return __raw_readl(dispc.base + idx);
135 }
136
137 #define SR(reg) \
138         dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
139 #define RR(reg) \
140         dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
141
142 void dispc_save_context(void)
143 {
144         int i;
145         if (cpu_is_omap24xx())
146                 return;
147
148         SR(SYSCONFIG);
149         SR(IRQENABLE);
150         SR(CONTROL);
151         SR(CONFIG);
152         SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD));
153         SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT));
154         SR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD));
155         SR(TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT));
156         SR(LINE_NUMBER);
157         SR(TIMING_H(OMAP_DSS_CHANNEL_LCD));
158         SR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
159         SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
160         SR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
161         SR(GLOBAL_ALPHA);
162         SR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
163         SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
164         if (dss_has_feature(FEAT_MGR_LCD2)) {
165                 SR(CONTROL2);
166                 SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2));
167                 SR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2));
168                 SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD2));
169                 SR(TIMING_H(OMAP_DSS_CHANNEL_LCD2));
170                 SR(TIMING_V(OMAP_DSS_CHANNEL_LCD2));
171                 SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD2));
172                 SR(DIVISORo(OMAP_DSS_CHANNEL_LCD2));
173                 SR(CONFIG2);
174         }
175
176         SR(OVL_BA0(OMAP_DSS_GFX));
177         SR(OVL_BA1(OMAP_DSS_GFX));
178         SR(OVL_POSITION(OMAP_DSS_GFX));
179         SR(OVL_SIZE(OMAP_DSS_GFX));
180         SR(OVL_ATTRIBUTES(OMAP_DSS_GFX));
181         SR(OVL_FIFO_THRESHOLD(OMAP_DSS_GFX));
182         SR(OVL_ROW_INC(OMAP_DSS_GFX));
183         SR(OVL_PIXEL_INC(OMAP_DSS_GFX));
184         SR(OVL_WINDOW_SKIP(OMAP_DSS_GFX));
185         SR(OVL_TABLE_BA(OMAP_DSS_GFX));
186
187         SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD));
188         SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
189         SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
190
191         SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
192         SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
193         SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
194         if (dss_has_feature(FEAT_MGR_LCD2)) {
195                 SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
196                 SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
197                 SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
198
199                 SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
200                 SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
201                 SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
202         }
203
204         SR(OVL_PRELOAD(OMAP_DSS_GFX));
205
206         /* VID1 */
207         SR(OVL_BA0(OMAP_DSS_VIDEO1));
208         SR(OVL_BA1(OMAP_DSS_VIDEO1));
209         SR(OVL_POSITION(OMAP_DSS_VIDEO1));
210         SR(OVL_SIZE(OMAP_DSS_VIDEO1));
211         SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
212         SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
213         SR(OVL_ROW_INC(OMAP_DSS_VIDEO1));
214         SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
215         SR(OVL_FIR(OMAP_DSS_VIDEO1));
216         SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
217         SR(OVL_ACCU0(OMAP_DSS_VIDEO1));
218         SR(OVL_ACCU1(OMAP_DSS_VIDEO1));
219
220         for (i = 0; i < 8; i++)
221                 SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i));
222
223         for (i = 0; i < 8; i++)
224                 SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i));
225
226         for (i = 0; i < 5; i++)
227                 SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
228
229         for (i = 0; i < 8; i++)
230                 SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
231
232         if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
233                 SR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
234                 SR(OVL_BA1_UV(OMAP_DSS_VIDEO1));
235                 SR(OVL_FIR2(OMAP_DSS_VIDEO1));
236                 SR(OVL_ACCU2_0(OMAP_DSS_VIDEO1));
237                 SR(OVL_ACCU2_1(OMAP_DSS_VIDEO1));
238
239                 for (i = 0; i < 8; i++)
240                         SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i));
241
242                 for (i = 0; i < 8; i++)
243                         SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i));
244
245                 for (i = 0; i < 8; i++)
246                         SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i));
247         }
248         if (dss_has_feature(FEAT_ATTR2))
249                 SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
250
251         SR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
252
253         /* VID2 */
254         SR(OVL_BA0(OMAP_DSS_VIDEO2));
255         SR(OVL_BA1(OMAP_DSS_VIDEO2));
256         SR(OVL_POSITION(OMAP_DSS_VIDEO2));
257         SR(OVL_SIZE(OMAP_DSS_VIDEO2));
258         SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
259         SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
260         SR(OVL_ROW_INC(OMAP_DSS_VIDEO2));
261         SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
262         SR(OVL_FIR(OMAP_DSS_VIDEO2));
263         SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
264         SR(OVL_ACCU0(OMAP_DSS_VIDEO2));
265         SR(OVL_ACCU1(OMAP_DSS_VIDEO2));
266
267         for (i = 0; i < 8; i++)
268                 SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i));
269
270         for (i = 0; i < 8; i++)
271                 SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i));
272
273         for (i = 0; i < 5; i++)
274                 SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
275
276         for (i = 0; i < 8; i++)
277                 SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
278
279         if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
280                 SR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
281                 SR(OVL_BA1_UV(OMAP_DSS_VIDEO2));
282                 SR(OVL_FIR2(OMAP_DSS_VIDEO2));
283                 SR(OVL_ACCU2_0(OMAP_DSS_VIDEO2));
284                 SR(OVL_ACCU2_1(OMAP_DSS_VIDEO2));
285
286                 for (i = 0; i < 8; i++)
287                         SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i));
288
289                 for (i = 0; i < 8; i++)
290                         SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i));
291
292                 for (i = 0; i < 8; i++)
293                         SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i));
294         }
295         if (dss_has_feature(FEAT_ATTR2))
296                 SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
297
298         SR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
299
300         if (dss_has_feature(FEAT_CORE_CLK_DIV))
301                 SR(DIVISOR);
302 }
303
304 void dispc_restore_context(void)
305 {
306         int i;
307         RR(SYSCONFIG);
308         /*RR(IRQENABLE);*/
309         /*RR(CONTROL);*/
310         RR(CONFIG);
311         RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD));
312         RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT));
313         RR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD));
314         RR(TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT));
315         RR(LINE_NUMBER);
316         RR(TIMING_H(OMAP_DSS_CHANNEL_LCD));
317         RR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
318         RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
319         RR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
320         RR(GLOBAL_ALPHA);
321         RR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
322         RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
323         if (dss_has_feature(FEAT_MGR_LCD2)) {
324                 RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2));
325                 RR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2));
326                 RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD2));
327                 RR(TIMING_H(OMAP_DSS_CHANNEL_LCD2));
328                 RR(TIMING_V(OMAP_DSS_CHANNEL_LCD2));
329                 RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD2));
330                 RR(DIVISORo(OMAP_DSS_CHANNEL_LCD2));
331                 RR(CONFIG2);
332         }
333
334         RR(OVL_BA0(OMAP_DSS_GFX));
335         RR(OVL_BA1(OMAP_DSS_GFX));
336         RR(OVL_POSITION(OMAP_DSS_GFX));
337         RR(OVL_SIZE(OMAP_DSS_GFX));
338         RR(OVL_ATTRIBUTES(OMAP_DSS_GFX));
339         RR(OVL_FIFO_THRESHOLD(OMAP_DSS_GFX));
340         RR(OVL_ROW_INC(OMAP_DSS_GFX));
341         RR(OVL_PIXEL_INC(OMAP_DSS_GFX));
342         RR(OVL_WINDOW_SKIP(OMAP_DSS_GFX));
343         RR(OVL_TABLE_BA(OMAP_DSS_GFX));
344
345
346         RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD));
347         RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
348         RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
349
350         RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
351         RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
352         RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
353         if (dss_has_feature(FEAT_MGR_LCD2)) {
354                 RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
355                 RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
356                 RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
357
358                 RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
359                 RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
360                 RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
361         }
362
363         RR(OVL_PRELOAD(OMAP_DSS_GFX));
364
365         /* VID1 */
366         RR(OVL_BA0(OMAP_DSS_VIDEO1));
367         RR(OVL_BA1(OMAP_DSS_VIDEO1));
368         RR(OVL_POSITION(OMAP_DSS_VIDEO1));
369         RR(OVL_SIZE(OMAP_DSS_VIDEO1));
370         RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
371         RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
372         RR(OVL_ROW_INC(OMAP_DSS_VIDEO1));
373         RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
374         RR(OVL_FIR(OMAP_DSS_VIDEO1));
375         RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
376         RR(OVL_ACCU0(OMAP_DSS_VIDEO1));
377         RR(OVL_ACCU1(OMAP_DSS_VIDEO1));
378
379         for (i = 0; i < 8; i++)
380                 RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i));
381
382         for (i = 0; i < 8; i++)
383                 RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i));
384
385         for (i = 0; i < 5; i++)
386                 RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
387
388         for (i = 0; i < 8; i++)
389                 RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
390
391         if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
392                 RR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
393                 RR(OVL_BA1_UV(OMAP_DSS_VIDEO1));
394                 RR(OVL_FIR2(OMAP_DSS_VIDEO1));
395                 RR(OVL_ACCU2_0(OMAP_DSS_VIDEO1));
396                 RR(OVL_ACCU2_1(OMAP_DSS_VIDEO1));
397
398                 for (i = 0; i < 8; i++)
399                         RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i));
400
401                 for (i = 0; i < 8; i++)
402                         RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i));
403
404                 for (i = 0; i < 8; i++)
405                         RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i));
406         }
407         if (dss_has_feature(FEAT_ATTR2))
408                 RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
409
410         RR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
411
412         /* VID2 */
413         RR(OVL_BA0(OMAP_DSS_VIDEO2));
414         RR(OVL_BA1(OMAP_DSS_VIDEO2));
415         RR(OVL_POSITION(OMAP_DSS_VIDEO2));
416         RR(OVL_SIZE(OMAP_DSS_VIDEO2));
417         RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
418         RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
419         RR(OVL_ROW_INC(OMAP_DSS_VIDEO2));
420         RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
421         RR(OVL_FIR(OMAP_DSS_VIDEO2));
422         RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
423         RR(OVL_ACCU0(OMAP_DSS_VIDEO2));
424         RR(OVL_ACCU1(OMAP_DSS_VIDEO2));
425
426         for (i = 0; i < 8; i++)
427                 RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i));
428
429         for (i = 0; i < 8; i++)
430                 RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i));
431
432         for (i = 0; i < 5; i++)
433                 RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
434
435         for (i = 0; i < 8; i++)
436                 RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
437
438         if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
439                 RR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
440                 RR(OVL_BA1_UV(OMAP_DSS_VIDEO2));
441                 RR(OVL_FIR2(OMAP_DSS_VIDEO2));
442                 RR(OVL_ACCU2_0(OMAP_DSS_VIDEO2));
443                 RR(OVL_ACCU2_1(OMAP_DSS_VIDEO2));
444
445                 for (i = 0; i < 8; i++)
446                         RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i));
447
448                 for (i = 0; i < 8; i++)
449                         RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i));
450
451                 for (i = 0; i < 8; i++)
452                         RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i));
453         }
454         if (dss_has_feature(FEAT_ATTR2))
455                 RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
456
457         RR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
458
459         if (dss_has_feature(FEAT_CORE_CLK_DIV))
460                 RR(DIVISOR);
461
462         /* enable last, because LCD & DIGIT enable are here */
463         RR(CONTROL);
464         if (dss_has_feature(FEAT_MGR_LCD2))
465                 RR(CONTROL2);
466         /* clear spurious SYNC_LOST_DIGIT interrupts */
467         dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
468
469         /*
470          * enable last so IRQs won't trigger before
471          * the context is fully restored
472          */
473         RR(IRQENABLE);
474 }
475
476 #undef SR
477 #undef RR
478
479 static inline void enable_clocks(bool enable)
480 {
481         if (enable)
482                 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
483         else
484                 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
485 }
486
487 bool dispc_go_busy(enum omap_channel channel)
488 {
489         int bit;
490
491         if (channel == OMAP_DSS_CHANNEL_LCD ||
492                         channel == OMAP_DSS_CHANNEL_LCD2)
493                 bit = 5; /* GOLCD */
494         else
495                 bit = 6; /* GODIGIT */
496
497         if (channel == OMAP_DSS_CHANNEL_LCD2)
498                 return REG_GET(DISPC_CONTROL2, bit, bit) == 1;
499         else
500                 return REG_GET(DISPC_CONTROL, bit, bit) == 1;
501 }
502
503 void dispc_go(enum omap_channel channel)
504 {
505         int bit;
506         bool enable_bit, go_bit;
507
508         enable_clocks(1);
509
510         if (channel == OMAP_DSS_CHANNEL_LCD ||
511                         channel == OMAP_DSS_CHANNEL_LCD2)
512                 bit = 0; /* LCDENABLE */
513         else
514                 bit = 1; /* DIGITALENABLE */
515
516         /* if the channel is not enabled, we don't need GO */
517         if (channel == OMAP_DSS_CHANNEL_LCD2)
518                 enable_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1;
519         else
520                 enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1;
521
522         if (!enable_bit)
523                 goto end;
524
525         if (channel == OMAP_DSS_CHANNEL_LCD ||
526                         channel == OMAP_DSS_CHANNEL_LCD2)
527                 bit = 5; /* GOLCD */
528         else
529                 bit = 6; /* GODIGIT */
530
531         if (channel == OMAP_DSS_CHANNEL_LCD2)
532                 go_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1;
533         else
534                 go_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1;
535
536         if (go_bit) {
537                 DSSERR("GO bit not down for channel %d\n", channel);
538                 goto end;
539         }
540
541         DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" :
542                 (channel == OMAP_DSS_CHANNEL_LCD2 ? "LCD2" : "DIGIT"));
543
544         if (channel == OMAP_DSS_CHANNEL_LCD2)
545                 REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit);
546         else
547                 REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
548 end:
549         enable_clocks(0);
550 }
551
552 static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
553 {
554         dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
555 }
556
557 static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
558 {
559         dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value);
560 }
561
562 static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
563 {
564         dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value);
565 }
566
567 static void _dispc_write_firh2_reg(enum omap_plane plane, int reg, u32 value)
568 {
569         BUG_ON(plane == OMAP_DSS_GFX);
570
571         dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value);
572 }
573
574 static void _dispc_write_firhv2_reg(enum omap_plane plane, int reg, u32 value)
575 {
576         BUG_ON(plane == OMAP_DSS_GFX);
577
578         dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
579 }
580
581 static void _dispc_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
582 {
583         BUG_ON(plane == OMAP_DSS_GFX);
584
585         dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
586 }
587
588 static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
589                                   int vscaleup, int five_taps,
590                                   enum omap_color_component color_comp)
591 {
592         /* Coefficients for horizontal up-sampling */
593         static const struct dispc_h_coef coef_hup[8] = {
594                 {  0,   0, 128,   0,  0 },
595                 { -1,  13, 124,  -8,  0 },
596                 { -2,  30, 112, -11, -1 },
597                 { -5,  51,  95, -11, -2 },
598                 {  0,  -9,  73,  73, -9 },
599                 { -2, -11,  95,  51, -5 },
600                 { -1, -11, 112,  30, -2 },
601                 {  0,  -8, 124,  13, -1 },
602         };
603
604         /* Coefficients for vertical up-sampling */
605         static const struct dispc_v_coef coef_vup_3tap[8] = {
606                 { 0,  0, 128,  0, 0 },
607                 { 0,  3, 123,  2, 0 },
608                 { 0, 12, 111,  5, 0 },
609                 { 0, 32,  89,  7, 0 },
610                 { 0,  0,  64, 64, 0 },
611                 { 0,  7,  89, 32, 0 },
612                 { 0,  5, 111, 12, 0 },
613                 { 0,  2, 123,  3, 0 },
614         };
615
616         static const struct dispc_v_coef coef_vup_5tap[8] = {
617                 {  0,   0, 128,   0,  0 },
618                 { -1,  13, 124,  -8,  0 },
619                 { -2,  30, 112, -11, -1 },
620                 { -5,  51,  95, -11, -2 },
621                 {  0,  -9,  73,  73, -9 },
622                 { -2, -11,  95,  51, -5 },
623                 { -1, -11, 112,  30, -2 },
624                 {  0,  -8, 124,  13, -1 },
625         };
626
627         /* Coefficients for horizontal down-sampling */
628         static const struct dispc_h_coef coef_hdown[8] = {
629                 {   0, 36, 56, 36,  0 },
630                 {   4, 40, 55, 31, -2 },
631                 {   8, 44, 54, 27, -5 },
632                 {  12, 48, 53, 22, -7 },
633                 {  -9, 17, 52, 51, 17 },
634                 {  -7, 22, 53, 48, 12 },
635                 {  -5, 27, 54, 44,  8 },
636                 {  -2, 31, 55, 40,  4 },
637         };
638
639         /* Coefficients for vertical down-sampling */
640         static const struct dispc_v_coef coef_vdown_3tap[8] = {
641                 { 0, 36, 56, 36, 0 },
642                 { 0, 40, 57, 31, 0 },
643                 { 0, 45, 56, 27, 0 },
644                 { 0, 50, 55, 23, 0 },
645                 { 0, 18, 55, 55, 0 },
646                 { 0, 23, 55, 50, 0 },
647                 { 0, 27, 56, 45, 0 },
648                 { 0, 31, 57, 40, 0 },
649         };
650
651         static const struct dispc_v_coef coef_vdown_5tap[8] = {
652                 {   0, 36, 56, 36,  0 },
653                 {   4, 40, 55, 31, -2 },
654                 {   8, 44, 54, 27, -5 },
655                 {  12, 48, 53, 22, -7 },
656                 {  -9, 17, 52, 51, 17 },
657                 {  -7, 22, 53, 48, 12 },
658                 {  -5, 27, 54, 44,  8 },
659                 {  -2, 31, 55, 40,  4 },
660         };
661
662         const struct dispc_h_coef *h_coef;
663         const struct dispc_v_coef *v_coef;
664         int i;
665
666         if (hscaleup)
667                 h_coef = coef_hup;
668         else
669                 h_coef = coef_hdown;
670
671         if (vscaleup)
672                 v_coef = five_taps ? coef_vup_5tap : coef_vup_3tap;
673         else
674                 v_coef = five_taps ? coef_vdown_5tap : coef_vdown_3tap;
675
676         for (i = 0; i < 8; i++) {
677                 u32 h, hv;
678
679                 h = FLD_VAL(h_coef[i].hc0, 7, 0)
680                         | FLD_VAL(h_coef[i].hc1, 15, 8)
681                         | FLD_VAL(h_coef[i].hc2, 23, 16)
682                         | FLD_VAL(h_coef[i].hc3, 31, 24);
683                 hv = FLD_VAL(h_coef[i].hc4, 7, 0)
684                         | FLD_VAL(v_coef[i].vc0, 15, 8)
685                         | FLD_VAL(v_coef[i].vc1, 23, 16)
686                         | FLD_VAL(v_coef[i].vc2, 31, 24);
687
688                 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
689                         _dispc_write_firh_reg(plane, i, h);
690                         _dispc_write_firhv_reg(plane, i, hv);
691                 } else {
692                         _dispc_write_firh2_reg(plane, i, h);
693                         _dispc_write_firhv2_reg(plane, i, hv);
694                 }
695
696         }
697
698         if (five_taps) {
699                 for (i = 0; i < 8; i++) {
700                         u32 v;
701                         v = FLD_VAL(v_coef[i].vc00, 7, 0)
702                                 | FLD_VAL(v_coef[i].vc22, 15, 8);
703                         if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
704                                 _dispc_write_firv_reg(plane, i, v);
705                         else
706                                 _dispc_write_firv2_reg(plane, i, v);
707                 }
708         }
709 }
710
711 static void _dispc_setup_color_conv_coef(void)
712 {
713         const struct color_conv_coef {
714                 int  ry,  rcr,  rcb,   gy,  gcr,  gcb,   by,  bcr,  bcb;
715                 int  full_range;
716         }  ctbl_bt601_5 = {
717                 298,  409,    0,  298, -208, -100,  298,    0,  517, 0,
718         };
719
720         const struct color_conv_coef *ct;
721
722 #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
723
724         ct = &ctbl_bt601_5;
725
726         dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0),
727                 CVAL(ct->rcr, ct->ry));
728         dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1),
729                 CVAL(ct->gy,  ct->rcb));
730         dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2),
731                 CVAL(ct->gcb, ct->gcr));
732         dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3),
733                 CVAL(ct->bcr, ct->by));
734         dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4),
735                 CVAL(0, ct->bcb));
736
737         dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0),
738                 CVAL(ct->rcr, ct->ry));
739         dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1),
740                 CVAL(ct->gy, ct->rcb));
741         dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2),
742                 CVAL(ct->gcb, ct->gcr));
743         dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3),
744                 CVAL(ct->bcr, ct->by));
745         dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4),
746                 CVAL(0, ct->bcb));
747
748 #undef CVAL
749
750         REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1),
751                 ct->full_range, 11, 11);
752         REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2),
753                 ct->full_range, 11, 11);
754 }
755
756
757 static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
758 {
759         dispc_write_reg(DISPC_OVL_BA0(plane), paddr);
760 }
761
762 static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr)
763 {
764         dispc_write_reg(DISPC_OVL_BA1(plane), paddr);
765 }
766
767 static void _dispc_set_plane_ba0_uv(enum omap_plane plane, u32 paddr)
768 {
769         dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr);
770 }
771
772 static void _dispc_set_plane_ba1_uv(enum omap_plane plane, u32 paddr)
773 {
774         dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
775 }
776
777 static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
778 {
779         u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
780
781         dispc_write_reg(DISPC_OVL_POSITION(plane), val);
782 }
783
784 static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
785 {
786         u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
787
788         if (plane == OMAP_DSS_GFX)
789                 dispc_write_reg(DISPC_OVL_SIZE(plane), val);
790         else
791                 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
792 }
793
794 static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
795 {
796         u32 val;
797
798         BUG_ON(plane == OMAP_DSS_GFX);
799
800         val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
801
802         dispc_write_reg(DISPC_OVL_SIZE(plane), val);
803 }
804
805 static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable)
806 {
807         if (!dss_has_feature(FEAT_PRE_MULT_ALPHA))
808                 return;
809
810         if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
811                 plane == OMAP_DSS_VIDEO1)
812                 return;
813
814         REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
815 }
816
817 static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
818 {
819         if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
820                 return;
821
822         if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) &&
823                 plane == OMAP_DSS_VIDEO1)
824                 return;
825
826         if (plane == OMAP_DSS_GFX)
827                 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
828         else if (plane == OMAP_DSS_VIDEO2)
829                 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16);
830 }
831
832 static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
833 {
834         dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc);
835 }
836
837 static void _dispc_set_row_inc(enum omap_plane plane, s32 inc)
838 {
839         dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc);
840 }
841
842 static void _dispc_set_color_mode(enum omap_plane plane,
843                 enum omap_color_mode color_mode)
844 {
845         u32 m = 0;
846         if (plane != OMAP_DSS_GFX) {
847                 switch (color_mode) {
848                 case OMAP_DSS_COLOR_NV12:
849                         m = 0x0; break;
850                 case OMAP_DSS_COLOR_RGB12U:
851                         m = 0x1; break;
852                 case OMAP_DSS_COLOR_RGBA16:
853                         m = 0x2; break;
854                 case OMAP_DSS_COLOR_RGBX16:
855                         m = 0x4; break;
856                 case OMAP_DSS_COLOR_ARGB16:
857                         m = 0x5; break;
858                 case OMAP_DSS_COLOR_RGB16:
859                         m = 0x6; break;
860                 case OMAP_DSS_COLOR_ARGB16_1555:
861                         m = 0x7; break;
862                 case OMAP_DSS_COLOR_RGB24U:
863                         m = 0x8; break;
864                 case OMAP_DSS_COLOR_RGB24P:
865                         m = 0x9; break;
866                 case OMAP_DSS_COLOR_YUV2:
867                         m = 0xa; break;
868                 case OMAP_DSS_COLOR_UYVY:
869                         m = 0xb; break;
870                 case OMAP_DSS_COLOR_ARGB32:
871                         m = 0xc; break;
872                 case OMAP_DSS_COLOR_RGBA32:
873                         m = 0xd; break;
874                 case OMAP_DSS_COLOR_RGBX32:
875                         m = 0xe; break;
876                 case OMAP_DSS_COLOR_XRGB16_1555:
877                         m = 0xf; break;
878                 default:
879                         BUG(); break;
880                 }
881         } else {
882                 switch (color_mode) {
883                 case OMAP_DSS_COLOR_CLUT1:
884                         m = 0x0; break;
885                 case OMAP_DSS_COLOR_CLUT2:
886                         m = 0x1; break;
887                 case OMAP_DSS_COLOR_CLUT4:
888                         m = 0x2; break;
889                 case OMAP_DSS_COLOR_CLUT8:
890                         m = 0x3; break;
891                 case OMAP_DSS_COLOR_RGB12U:
892                         m = 0x4; break;
893                 case OMAP_DSS_COLOR_ARGB16:
894                         m = 0x5; break;
895                 case OMAP_DSS_COLOR_RGB16:
896                         m = 0x6; break;
897                 case OMAP_DSS_COLOR_ARGB16_1555:
898                         m = 0x7; break;
899                 case OMAP_DSS_COLOR_RGB24U:
900                         m = 0x8; break;
901                 case OMAP_DSS_COLOR_RGB24P:
902                         m = 0x9; break;
903                 case OMAP_DSS_COLOR_YUV2:
904                         m = 0xa; break;
905                 case OMAP_DSS_COLOR_UYVY:
906                         m = 0xb; break;
907                 case OMAP_DSS_COLOR_ARGB32:
908                         m = 0xc; break;
909                 case OMAP_DSS_COLOR_RGBA32:
910                         m = 0xd; break;
911                 case OMAP_DSS_COLOR_RGBX32:
912                         m = 0xe; break;
913                 case OMAP_DSS_COLOR_XRGB16_1555:
914                         m = 0xf; break;
915                 default:
916                         BUG(); break;
917                 }
918         }
919
920         REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
921 }
922
923 static void _dispc_set_channel_out(enum omap_plane plane,
924                 enum omap_channel channel)
925 {
926         int shift;
927         u32 val;
928         int chan = 0, chan2 = 0;
929
930         switch (plane) {
931         case OMAP_DSS_GFX:
932                 shift = 8;
933                 break;
934         case OMAP_DSS_VIDEO1:
935         case OMAP_DSS_VIDEO2:
936                 shift = 16;
937                 break;
938         default:
939                 BUG();
940                 return;
941         }
942
943         val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
944         if (dss_has_feature(FEAT_MGR_LCD2)) {
945                 switch (channel) {
946                 case OMAP_DSS_CHANNEL_LCD:
947                         chan = 0;
948                         chan2 = 0;
949                         break;
950                 case OMAP_DSS_CHANNEL_DIGIT:
951                         chan = 1;
952                         chan2 = 0;
953                         break;
954                 case OMAP_DSS_CHANNEL_LCD2:
955                         chan = 0;
956                         chan2 = 1;
957                         break;
958                 default:
959                         BUG();
960                 }
961
962                 val = FLD_MOD(val, chan, shift, shift);
963                 val = FLD_MOD(val, chan2, 31, 30);
964         } else {
965                 val = FLD_MOD(val, channel, shift, shift);
966         }
967         dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
968 }
969
970 void dispc_set_burst_size(enum omap_plane plane,
971                 enum omap_burst_size burst_size)
972 {
973         int shift;
974         u32 val;
975
976         enable_clocks(1);
977
978         switch (plane) {
979         case OMAP_DSS_GFX:
980                 shift = 6;
981                 break;
982         case OMAP_DSS_VIDEO1:
983         case OMAP_DSS_VIDEO2:
984                 shift = 14;
985                 break;
986         default:
987                 BUG();
988                 return;
989         }
990
991         val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
992         val = FLD_MOD(val, burst_size, shift+1, shift);
993         dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
994
995         enable_clocks(0);
996 }
997
998 void dispc_enable_gamma_table(bool enable)
999 {
1000         /*
1001          * This is partially implemented to support only disabling of
1002          * the gamma table.
1003          */
1004         if (enable) {
1005                 DSSWARN("Gamma table enabling for TV not yet supported");
1006                 return;
1007         }
1008
1009         REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
1010 }
1011
1012 static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
1013 {
1014         u32 val;
1015
1016         BUG_ON(plane == OMAP_DSS_GFX);
1017
1018         val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
1019         val = FLD_MOD(val, enable, 9, 9);
1020         dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
1021 }
1022
1023 void dispc_enable_replication(enum omap_plane plane, bool enable)
1024 {
1025         int bit;
1026
1027         if (plane == OMAP_DSS_GFX)
1028                 bit = 5;
1029         else
1030                 bit = 10;
1031
1032         enable_clocks(1);
1033         REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
1034         enable_clocks(0);
1035 }
1036
1037 void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
1038 {
1039         u32 val;
1040         BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
1041         val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
1042         enable_clocks(1);
1043         dispc_write_reg(DISPC_SIZE_MGR(channel), val);
1044         enable_clocks(0);
1045 }
1046
1047 void dispc_set_digit_size(u16 width, u16 height)
1048 {
1049         u32 val;
1050         BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
1051         val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
1052         enable_clocks(1);
1053         dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT), val);
1054         enable_clocks(0);
1055 }
1056
1057 static void dispc_read_plane_fifo_sizes(void)
1058 {
1059         u32 size;
1060         int plane;
1061         u8 start, end;
1062
1063         enable_clocks(1);
1064
1065         dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
1066
1067         for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
1068                 size = FLD_GET(dispc_read_reg(DISPC_OVL_FIFO_SIZE_STATUS(plane)),
1069                         start, end);
1070                 dispc.fifo_size[plane] = size;
1071         }
1072
1073         enable_clocks(0);
1074 }
1075
1076 u32 dispc_get_plane_fifo_size(enum omap_plane plane)
1077 {
1078         return dispc.fifo_size[plane];
1079 }
1080
1081 void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
1082 {
1083         u8 hi_start, hi_end, lo_start, lo_end;
1084
1085         dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
1086         dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
1087
1088         enable_clocks(1);
1089
1090         DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
1091                         plane,
1092                         REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
1093                                 lo_start, lo_end),
1094                         REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
1095                                 hi_start, hi_end),
1096                         low, high);
1097
1098         dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
1099                         FLD_VAL(high, hi_start, hi_end) |
1100                         FLD_VAL(low, lo_start, lo_end));
1101
1102         enable_clocks(0);
1103 }
1104
1105 void dispc_enable_fifomerge(bool enable)
1106 {
1107         enable_clocks(1);
1108
1109         DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1110         REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
1111
1112         enable_clocks(0);
1113 }
1114
1115 static void _dispc_set_fir(enum omap_plane plane,
1116                                 int hinc, int vinc,
1117                                 enum omap_color_component color_comp)
1118 {
1119         u32 val;
1120
1121         if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
1122                 u8 hinc_start, hinc_end, vinc_start, vinc_end;
1123
1124                 dss_feat_get_reg_field(FEAT_REG_FIRHINC,
1125                                         &hinc_start, &hinc_end);
1126                 dss_feat_get_reg_field(FEAT_REG_FIRVINC,
1127                                         &vinc_start, &vinc_end);
1128                 val = FLD_VAL(vinc, vinc_start, vinc_end) |
1129                                 FLD_VAL(hinc, hinc_start, hinc_end);
1130
1131                 dispc_write_reg(DISPC_OVL_FIR(plane), val);
1132         } else {
1133                 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1134                 dispc_write_reg(DISPC_OVL_FIR2(plane), val);
1135         }
1136 }
1137
1138 static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
1139 {
1140         u32 val;
1141         u8 hor_start, hor_end, vert_start, vert_end;
1142
1143         dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1144         dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1145
1146         val = FLD_VAL(vaccu, vert_start, vert_end) |
1147                         FLD_VAL(haccu, hor_start, hor_end);
1148
1149         dispc_write_reg(DISPC_OVL_ACCU0(plane), val);
1150 }
1151
1152 static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
1153 {
1154         u32 val;
1155         u8 hor_start, hor_end, vert_start, vert_end;
1156
1157         dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1158         dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1159
1160         val = FLD_VAL(vaccu, vert_start, vert_end) |
1161                         FLD_VAL(haccu, hor_start, hor_end);
1162
1163         dispc_write_reg(DISPC_OVL_ACCU1(plane), val);
1164 }
1165
1166 static void _dispc_set_vid_accu2_0(enum omap_plane plane, int haccu, int vaccu)
1167 {
1168         u32 val;
1169
1170         val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1171         dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val);
1172 }
1173
1174 static void _dispc_set_vid_accu2_1(enum omap_plane plane, int haccu, int vaccu)
1175 {
1176         u32 val;
1177
1178         val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1179         dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val);
1180 }
1181
1182 static void _dispc_set_scale_param(enum omap_plane plane,
1183                 u16 orig_width, u16 orig_height,
1184                 u16 out_width, u16 out_height,
1185                 bool five_taps, u8 rotation,
1186                 enum omap_color_component color_comp)
1187 {
1188         int fir_hinc, fir_vinc;
1189         int hscaleup, vscaleup;
1190
1191         hscaleup = orig_width <= out_width;
1192         vscaleup = orig_height <= out_height;
1193
1194         _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps, color_comp);
1195
1196         fir_hinc = 1024 * orig_width / out_width;
1197         fir_vinc = 1024 * orig_height / out_height;
1198
1199         _dispc_set_fir(plane, fir_hinc, fir_vinc, color_comp);
1200 }
1201
1202 static void _dispc_set_scaling_common(enum omap_plane plane,
1203                 u16 orig_width, u16 orig_height,
1204                 u16 out_width, u16 out_height,
1205                 bool ilace, bool five_taps,
1206                 bool fieldmode, enum omap_color_mode color_mode,
1207                 u8 rotation)
1208 {
1209         int accu0 = 0;
1210         int accu1 = 0;
1211         u32 l;
1212
1213         _dispc_set_scale_param(plane, orig_width, orig_height,
1214                                 out_width, out_height, five_taps,
1215                                 rotation, DISPC_COLOR_COMPONENT_RGB_Y);
1216         l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
1217
1218         /* RESIZEENABLE and VERTICALTAPS */
1219         l &= ~((0x3 << 5) | (0x1 << 21));
1220         l |= (orig_width != out_width) ? (1 << 5) : 0;
1221         l |= (orig_height != out_height) ? (1 << 6) : 0;
1222         l |= five_taps ? (1 << 21) : 0;
1223
1224         /* VRESIZECONF and HRESIZECONF */
1225         if (dss_has_feature(FEAT_RESIZECONF)) {
1226                 l &= ~(0x3 << 7);
1227                 l |= (orig_width <= out_width) ? 0 : (1 << 7);
1228                 l |= (orig_height <= out_height) ? 0 : (1 << 8);
1229         }
1230
1231         /* LINEBUFFERSPLIT */
1232         if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) {
1233                 l &= ~(0x1 << 22);
1234                 l |= five_taps ? (1 << 22) : 0;
1235         }
1236
1237         dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
1238
1239         /*
1240          * field 0 = even field = bottom field
1241          * field 1 = odd field = top field
1242          */
1243         if (ilace && !fieldmode) {
1244                 accu1 = 0;
1245                 accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff;
1246                 if (accu0 >= 1024/2) {
1247                         accu1 = 1024/2;
1248                         accu0 -= accu1;
1249                 }
1250         }
1251
1252         _dispc_set_vid_accu0(plane, 0, accu0);
1253         _dispc_set_vid_accu1(plane, 0, accu1);
1254 }
1255
1256 static void _dispc_set_scaling_uv(enum omap_plane plane,
1257                 u16 orig_width, u16 orig_height,
1258                 u16 out_width, u16 out_height,
1259                 bool ilace, bool five_taps,
1260                 bool fieldmode, enum omap_color_mode color_mode,
1261                 u8 rotation)
1262 {
1263         int scale_x = out_width != orig_width;
1264         int scale_y = out_height != orig_height;
1265
1266         if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE))
1267                 return;
1268         if ((color_mode != OMAP_DSS_COLOR_YUV2 &&
1269                         color_mode != OMAP_DSS_COLOR_UYVY &&
1270                         color_mode != OMAP_DSS_COLOR_NV12)) {
1271                 /* reset chroma resampling for RGB formats  */
1272                 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
1273                 return;
1274         }
1275         switch (color_mode) {
1276         case OMAP_DSS_COLOR_NV12:
1277                 /* UV is subsampled by 2 vertically*/
1278                 orig_height >>= 1;
1279                 /* UV is subsampled by 2 horz.*/
1280                 orig_width >>= 1;
1281                 break;
1282         case OMAP_DSS_COLOR_YUV2:
1283         case OMAP_DSS_COLOR_UYVY:
1284                 /*For YUV422 with 90/270 rotation,
1285                  *we don't upsample chroma
1286                  */
1287                 if (rotation == OMAP_DSS_ROT_0 ||
1288                         rotation == OMAP_DSS_ROT_180)
1289                         /* UV is subsampled by 2 hrz*/
1290                         orig_width >>= 1;
1291                 /* must use FIR for YUV422 if rotated */
1292                 if (rotation != OMAP_DSS_ROT_0)
1293                         scale_x = scale_y = true;
1294                 break;
1295         default:
1296                 BUG();
1297         }
1298
1299         if (out_width != orig_width)
1300                 scale_x = true;
1301         if (out_height != orig_height)
1302                 scale_y = true;
1303
1304         _dispc_set_scale_param(plane, orig_width, orig_height,
1305                         out_width, out_height, five_taps,
1306                                 rotation, DISPC_COLOR_COMPONENT_UV);
1307
1308         REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane),
1309                 (scale_x || scale_y) ? 1 : 0, 8, 8);
1310         /* set H scaling */
1311         REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
1312         /* set V scaling */
1313         REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
1314
1315         _dispc_set_vid_accu2_0(plane, 0x80, 0);
1316         _dispc_set_vid_accu2_1(plane, 0x80, 0);
1317 }
1318
1319 static void _dispc_set_scaling(enum omap_plane plane,
1320                 u16 orig_width, u16 orig_height,
1321                 u16 out_width, u16 out_height,
1322                 bool ilace, bool five_taps,
1323                 bool fieldmode, enum omap_color_mode color_mode,
1324                 u8 rotation)
1325 {
1326         BUG_ON(plane == OMAP_DSS_GFX);
1327
1328         _dispc_set_scaling_common(plane,
1329                         orig_width, orig_height,
1330                         out_width, out_height,
1331                         ilace, five_taps,
1332                         fieldmode, color_mode,
1333                         rotation);
1334
1335         _dispc_set_scaling_uv(plane,
1336                 orig_width, orig_height,
1337                 out_width, out_height,
1338                 ilace, five_taps,
1339                 fieldmode, color_mode,
1340                 rotation);
1341 }
1342
1343 static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
1344                 bool mirroring, enum omap_color_mode color_mode)
1345 {
1346         bool row_repeat = false;
1347         int vidrot = 0;
1348
1349         if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1350                         color_mode == OMAP_DSS_COLOR_UYVY) {
1351
1352                 if (mirroring) {
1353                         switch (rotation) {
1354                         case OMAP_DSS_ROT_0:
1355                                 vidrot = 2;
1356                                 break;
1357                         case OMAP_DSS_ROT_90:
1358                                 vidrot = 1;
1359                                 break;
1360                         case OMAP_DSS_ROT_180:
1361                                 vidrot = 0;
1362                                 break;
1363                         case OMAP_DSS_ROT_270:
1364                                 vidrot = 3;
1365                                 break;
1366                         }
1367                 } else {
1368                         switch (rotation) {
1369                         case OMAP_DSS_ROT_0:
1370                                 vidrot = 0;
1371                                 break;
1372                         case OMAP_DSS_ROT_90:
1373                                 vidrot = 1;
1374                                 break;
1375                         case OMAP_DSS_ROT_180:
1376                                 vidrot = 2;
1377                                 break;
1378                         case OMAP_DSS_ROT_270:
1379                                 vidrot = 3;
1380                                 break;
1381                         }
1382                 }
1383
1384                 if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
1385                         row_repeat = true;
1386                 else
1387                         row_repeat = false;
1388         }
1389
1390         REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
1391         if (dss_has_feature(FEAT_ROWREPEATENABLE))
1392                 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
1393                         row_repeat ? 1 : 0, 18, 18);
1394 }
1395
1396 static int color_mode_to_bpp(enum omap_color_mode color_mode)
1397 {
1398         switch (color_mode) {
1399         case OMAP_DSS_COLOR_CLUT1:
1400                 return 1;
1401         case OMAP_DSS_COLOR_CLUT2:
1402                 return 2;
1403         case OMAP_DSS_COLOR_CLUT4:
1404                 return 4;
1405         case OMAP_DSS_COLOR_CLUT8:
1406         case OMAP_DSS_COLOR_NV12:
1407                 return 8;
1408         case OMAP_DSS_COLOR_RGB12U:
1409         case OMAP_DSS_COLOR_RGB16:
1410         case OMAP_DSS_COLOR_ARGB16:
1411         case OMAP_DSS_COLOR_YUV2:
1412         case OMAP_DSS_COLOR_UYVY:
1413         case OMAP_DSS_COLOR_RGBA16:
1414         case OMAP_DSS_COLOR_RGBX16:
1415         case OMAP_DSS_COLOR_ARGB16_1555:
1416         case OMAP_DSS_COLOR_XRGB16_1555:
1417                 return 16;
1418         case OMAP_DSS_COLOR_RGB24P:
1419                 return 24;
1420         case OMAP_DSS_COLOR_RGB24U:
1421         case OMAP_DSS_COLOR_ARGB32:
1422         case OMAP_DSS_COLOR_RGBA32:
1423         case OMAP_DSS_COLOR_RGBX32:
1424                 return 32;
1425         default:
1426                 BUG();
1427         }
1428 }
1429
1430 static s32 pixinc(int pixels, u8 ps)
1431 {
1432         if (pixels == 1)
1433                 return 1;
1434         else if (pixels > 1)
1435                 return 1 + (pixels - 1) * ps;
1436         else if (pixels < 0)
1437                 return 1 - (-pixels + 1) * ps;
1438         else
1439                 BUG();
1440 }
1441
1442 static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
1443                 u16 screen_width,
1444                 u16 width, u16 height,
1445                 enum omap_color_mode color_mode, bool fieldmode,
1446                 unsigned int field_offset,
1447                 unsigned *offset0, unsigned *offset1,
1448                 s32 *row_inc, s32 *pix_inc)
1449 {
1450         u8 ps;
1451
1452         /* FIXME CLUT formats */
1453         switch (color_mode) {
1454         case OMAP_DSS_COLOR_CLUT1:
1455         case OMAP_DSS_COLOR_CLUT2:
1456         case OMAP_DSS_COLOR_CLUT4:
1457         case OMAP_DSS_COLOR_CLUT8:
1458                 BUG();
1459                 return;
1460         case OMAP_DSS_COLOR_YUV2:
1461         case OMAP_DSS_COLOR_UYVY:
1462                 ps = 4;
1463                 break;
1464         default:
1465                 ps = color_mode_to_bpp(color_mode) / 8;
1466                 break;
1467         }
1468
1469         DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1470                         width, height);
1471
1472         /*
1473          * field 0 = even field = bottom field
1474          * field 1 = odd field = top field
1475          */
1476         switch (rotation + mirror * 4) {
1477         case OMAP_DSS_ROT_0:
1478         case OMAP_DSS_ROT_180:
1479                 /*
1480                  * If the pixel format is YUV or UYVY divide the width
1481                  * of the image by 2 for 0 and 180 degree rotation.
1482                  */
1483                 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1484                         color_mode == OMAP_DSS_COLOR_UYVY)
1485                         width = width >> 1;
1486         case OMAP_DSS_ROT_90:
1487         case OMAP_DSS_ROT_270:
1488                 *offset1 = 0;
1489                 if (field_offset)
1490                         *offset0 = field_offset * screen_width * ps;
1491                 else
1492                         *offset0 = 0;
1493
1494                 *row_inc = pixinc(1 + (screen_width - width) +
1495                                 (fieldmode ? screen_width : 0),
1496                                 ps);
1497                 *pix_inc = pixinc(1, ps);
1498                 break;
1499
1500         case OMAP_DSS_ROT_0 + 4:
1501         case OMAP_DSS_ROT_180 + 4:
1502                 /* If the pixel format is YUV or UYVY divide the width
1503                  * of the image by 2  for 0 degree and 180 degree
1504                  */
1505                 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1506                         color_mode == OMAP_DSS_COLOR_UYVY)
1507                         width = width >> 1;
1508         case OMAP_DSS_ROT_90 + 4:
1509         case OMAP_DSS_ROT_270 + 4:
1510                 *offset1 = 0;
1511                 if (field_offset)
1512                         *offset0 = field_offset * screen_width * ps;
1513                 else
1514                         *offset0 = 0;
1515                 *row_inc = pixinc(1 - (screen_width + width) -
1516                                 (fieldmode ? screen_width : 0),
1517                                 ps);
1518                 *pix_inc = pixinc(1, ps);
1519                 break;
1520
1521         default:
1522                 BUG();
1523         }
1524 }
1525
1526 static void calc_dma_rotation_offset(u8 rotation, bool mirror,
1527                 u16 screen_width,
1528                 u16 width, u16 height,
1529                 enum omap_color_mode color_mode, bool fieldmode,
1530                 unsigned int field_offset,
1531                 unsigned *offset0, unsigned *offset1,
1532                 s32 *row_inc, s32 *pix_inc)
1533 {
1534         u8 ps;
1535         u16 fbw, fbh;
1536
1537         /* FIXME CLUT formats */
1538         switch (color_mode) {
1539         case OMAP_DSS_COLOR_CLUT1:
1540         case OMAP_DSS_COLOR_CLUT2:
1541         case OMAP_DSS_COLOR_CLUT4:
1542         case OMAP_DSS_COLOR_CLUT8:
1543                 BUG();
1544                 return;
1545         default:
1546                 ps = color_mode_to_bpp(color_mode) / 8;
1547                 break;
1548         }
1549
1550         DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1551                         width, height);
1552
1553         /* width & height are overlay sizes, convert to fb sizes */
1554
1555         if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) {
1556                 fbw = width;
1557                 fbh = height;
1558         } else {
1559                 fbw = height;
1560                 fbh = width;
1561         }
1562
1563         /*
1564          * field 0 = even field = bottom field
1565          * field 1 = odd field = top field
1566          */
1567         switch (rotation + mirror * 4) {
1568         case OMAP_DSS_ROT_0:
1569                 *offset1 = 0;
1570                 if (field_offset)
1571                         *offset0 = *offset1 + field_offset * screen_width * ps;
1572                 else
1573                         *offset0 = *offset1;
1574                 *row_inc = pixinc(1 + (screen_width - fbw) +
1575                                 (fieldmode ? screen_width : 0),
1576                                 ps);
1577                 *pix_inc = pixinc(1, ps);
1578                 break;
1579         case OMAP_DSS_ROT_90:
1580                 *offset1 = screen_width * (fbh - 1) * ps;
1581                 if (field_offset)
1582                         *offset0 = *offset1 + field_offset * ps;
1583                 else
1584                         *offset0 = *offset1;
1585                 *row_inc = pixinc(screen_width * (fbh - 1) + 1 +
1586                                 (fieldmode ? 1 : 0), ps);
1587                 *pix_inc = pixinc(-screen_width, ps);
1588                 break;
1589         case OMAP_DSS_ROT_180:
1590                 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1591                 if (field_offset)
1592                         *offset0 = *offset1 - field_offset * screen_width * ps;
1593                 else
1594                         *offset0 = *offset1;
1595                 *row_inc = pixinc(-1 -
1596                                 (screen_width - fbw) -
1597                                 (fieldmode ? screen_width : 0),
1598                                 ps);
1599                 *pix_inc = pixinc(-1, ps);
1600                 break;
1601         case OMAP_DSS_ROT_270:
1602                 *offset1 = (fbw - 1) * ps;
1603                 if (field_offset)
1604                         *offset0 = *offset1 - field_offset * ps;
1605                 else
1606                         *offset0 = *offset1;
1607                 *row_inc = pixinc(-screen_width * (fbh - 1) - 1 -
1608                                 (fieldmode ? 1 : 0), ps);
1609                 *pix_inc = pixinc(screen_width, ps);
1610                 break;
1611
1612         /* mirroring */
1613         case OMAP_DSS_ROT_0 + 4:
1614                 *offset1 = (fbw - 1) * ps;
1615                 if (field_offset)
1616                         *offset0 = *offset1 + field_offset * screen_width * ps;
1617                 else
1618                         *offset0 = *offset1;
1619                 *row_inc = pixinc(screen_width * 2 - 1 +
1620                                 (fieldmode ? screen_width : 0),
1621                                 ps);
1622                 *pix_inc = pixinc(-1, ps);
1623                 break;
1624
1625         case OMAP_DSS_ROT_90 + 4:
1626                 *offset1 = 0;
1627                 if (field_offset)
1628                         *offset0 = *offset1 + field_offset * ps;
1629                 else
1630                         *offset0 = *offset1;
1631                 *row_inc = pixinc(-screen_width * (fbh - 1) + 1 +
1632                                 (fieldmode ? 1 : 0),
1633                                 ps);
1634                 *pix_inc = pixinc(screen_width, ps);
1635                 break;
1636
1637         case OMAP_DSS_ROT_180 + 4:
1638                 *offset1 = screen_width * (fbh - 1) * ps;
1639                 if (field_offset)
1640                         *offset0 = *offset1 - field_offset * screen_width * ps;
1641                 else
1642                         *offset0 = *offset1;
1643                 *row_inc = pixinc(1 - screen_width * 2 -
1644                                 (fieldmode ? screen_width : 0),
1645                                 ps);
1646                 *pix_inc = pixinc(1, ps);
1647                 break;
1648
1649         case OMAP_DSS_ROT_270 + 4:
1650                 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1651                 if (field_offset)
1652                         *offset0 = *offset1 - field_offset * ps;
1653                 else
1654                         *offset0 = *offset1;
1655                 *row_inc = pixinc(screen_width * (fbh - 1) - 1 -
1656                                 (fieldmode ? 1 : 0),
1657                                 ps);
1658                 *pix_inc = pixinc(-screen_width, ps);
1659                 break;
1660
1661         default:
1662                 BUG();
1663         }
1664 }
1665
1666 static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width,
1667                 u16 height, u16 out_width, u16 out_height,
1668                 enum omap_color_mode color_mode)
1669 {
1670         u32 fclk = 0;
1671         /* FIXME venc pclk? */
1672         u64 tmp, pclk = dispc_pclk_rate(channel);
1673
1674         if (height > out_height) {
1675                 /* FIXME get real display PPL */
1676                 unsigned int ppl = 800;
1677
1678                 tmp = pclk * height * out_width;
1679                 do_div(tmp, 2 * out_height * ppl);
1680                 fclk = tmp;
1681
1682                 if (height > 2 * out_height) {
1683                         if (ppl == out_width)
1684                                 return 0;
1685
1686                         tmp = pclk * (height - 2 * out_height) * out_width;
1687                         do_div(tmp, 2 * out_height * (ppl - out_width));
1688                         fclk = max(fclk, (u32) tmp);
1689                 }
1690         }
1691
1692         if (width > out_width) {
1693                 tmp = pclk * width;
1694                 do_div(tmp, out_width);
1695                 fclk = max(fclk, (u32) tmp);
1696
1697                 if (color_mode == OMAP_DSS_COLOR_RGB24U)
1698                         fclk <<= 1;
1699         }
1700
1701         return fclk;
1702 }
1703
1704 static unsigned long calc_fclk(enum omap_channel channel, u16 width,
1705                 u16 height, u16 out_width, u16 out_height)
1706 {
1707         unsigned int hf, vf;
1708
1709         /*
1710          * FIXME how to determine the 'A' factor
1711          * for the no downscaling case ?
1712          */
1713
1714         if (width > 3 * out_width)
1715                 hf = 4;
1716         else if (width > 2 * out_width)
1717                 hf = 3;
1718         else if (width > out_width)
1719                 hf = 2;
1720         else
1721                 hf = 1;
1722
1723         if (height > out_height)
1724                 vf = 2;
1725         else
1726                 vf = 1;
1727
1728         /* FIXME venc pclk? */
1729         return dispc_pclk_rate(channel) * vf * hf;
1730 }
1731
1732 void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
1733 {
1734         enable_clocks(1);
1735         _dispc_set_channel_out(plane, channel_out);
1736         enable_clocks(0);
1737 }
1738
1739 static int _dispc_setup_plane(enum omap_plane plane,
1740                 u32 paddr, u16 screen_width,
1741                 u16 pos_x, u16 pos_y,
1742                 u16 width, u16 height,
1743                 u16 out_width, u16 out_height,
1744                 enum omap_color_mode color_mode,
1745                 bool ilace,
1746                 enum omap_dss_rotation_type rotation_type,
1747                 u8 rotation, int mirror,
1748                 u8 global_alpha, u8 pre_mult_alpha,
1749                 enum omap_channel channel, u32 puv_addr)
1750 {
1751         const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
1752         bool five_taps = 0;
1753         bool fieldmode = 0;
1754         int cconv = 0;
1755         unsigned offset0, offset1;
1756         s32 row_inc;
1757         s32 pix_inc;
1758         u16 frame_height = height;
1759         unsigned int field_offset = 0;
1760
1761         if (paddr == 0)
1762                 return -EINVAL;
1763
1764         if (ilace && height == out_height)
1765                 fieldmode = 1;
1766
1767         if (ilace) {
1768                 if (fieldmode)
1769                         height /= 2;
1770                 pos_y /= 2;
1771                 out_height /= 2;
1772
1773                 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
1774                                 "out_height %d\n",
1775                                 height, pos_y, out_height);
1776         }
1777
1778         if (!dss_feat_color_mode_supported(plane, color_mode))
1779                 return -EINVAL;
1780
1781         if (plane == OMAP_DSS_GFX) {
1782                 if (width != out_width || height != out_height)
1783                         return -EINVAL;
1784         } else {
1785                 /* video plane */
1786
1787                 unsigned long fclk = 0;
1788
1789                 if (out_width < width / maxdownscale ||
1790                    out_width > width * 8)
1791                         return -EINVAL;
1792
1793                 if (out_height < height / maxdownscale ||
1794                    out_height > height * 8)
1795                         return -EINVAL;
1796
1797                 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1798                         color_mode == OMAP_DSS_COLOR_UYVY ||
1799                         color_mode == OMAP_DSS_COLOR_NV12)
1800                         cconv = 1;
1801
1802                 /* Must use 5-tap filter? */
1803                 five_taps = height > out_height * 2;
1804
1805                 if (!five_taps) {
1806                         fclk = calc_fclk(channel, width, height, out_width,
1807                                         out_height);
1808
1809                         /* Try 5-tap filter if 3-tap fclk is too high */
1810                         if (cpu_is_omap34xx() && height > out_height &&
1811                                         fclk > dispc_fclk_rate())
1812                                 five_taps = true;
1813                 }
1814
1815                 if (width > (2048 >> five_taps)) {
1816                         DSSERR("failed to set up scaling, fclk too low\n");
1817                         return -EINVAL;
1818                 }
1819
1820                 if (five_taps)
1821                         fclk = calc_fclk_five_taps(channel, width, height,
1822                                         out_width, out_height, color_mode);
1823
1824                 DSSDBG("required fclk rate = %lu Hz\n", fclk);
1825                 DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
1826
1827                 if (!fclk || fclk > dispc_fclk_rate()) {
1828                         DSSERR("failed to set up scaling, "
1829                                         "required fclk rate = %lu Hz, "
1830                                         "current fclk rate = %lu Hz\n",
1831                                         fclk, dispc_fclk_rate());
1832                         return -EINVAL;
1833                 }
1834         }
1835
1836         if (ilace && !fieldmode) {
1837                 /*
1838                  * when downscaling the bottom field may have to start several
1839                  * source lines below the top field. Unfortunately ACCUI
1840                  * registers will only hold the fractional part of the offset
1841                  * so the integer part must be added to the base address of the
1842                  * bottom field.
1843                  */
1844                 if (!height || height == out_height)
1845                         field_offset = 0;
1846                 else
1847                         field_offset = height / out_height / 2;
1848         }
1849
1850         /* Fields are independent but interleaved in memory. */
1851         if (fieldmode)
1852                 field_offset = 1;
1853
1854         if (rotation_type == OMAP_DSS_ROT_DMA)
1855                 calc_dma_rotation_offset(rotation, mirror,
1856                                 screen_width, width, frame_height, color_mode,
1857                                 fieldmode, field_offset,
1858                                 &offset0, &offset1, &row_inc, &pix_inc);
1859         else
1860                 calc_vrfb_rotation_offset(rotation, mirror,
1861                                 screen_width, width, frame_height, color_mode,
1862                                 fieldmode, field_offset,
1863                                 &offset0, &offset1, &row_inc, &pix_inc);
1864
1865         DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
1866                         offset0, offset1, row_inc, pix_inc);
1867
1868         _dispc_set_color_mode(plane, color_mode);
1869
1870         _dispc_set_plane_ba0(plane, paddr + offset0);
1871         _dispc_set_plane_ba1(plane, paddr + offset1);
1872
1873         if (OMAP_DSS_COLOR_NV12 == color_mode) {
1874                 _dispc_set_plane_ba0_uv(plane, puv_addr + offset0);
1875                 _dispc_set_plane_ba1_uv(plane, puv_addr + offset1);
1876         }
1877
1878
1879         _dispc_set_row_inc(plane, row_inc);
1880         _dispc_set_pix_inc(plane, pix_inc);
1881
1882         DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height,
1883                         out_width, out_height);
1884
1885         _dispc_set_plane_pos(plane, pos_x, pos_y);
1886
1887         _dispc_set_pic_size(plane, width, height);
1888
1889         if (plane != OMAP_DSS_GFX) {
1890                 _dispc_set_scaling(plane, width, height,
1891                                    out_width, out_height,
1892                                    ilace, five_taps, fieldmode,
1893                                    color_mode, rotation);
1894                 _dispc_set_vid_size(plane, out_width, out_height);
1895                 _dispc_set_vid_color_conv(plane, cconv);
1896         }
1897
1898         _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
1899
1900         _dispc_set_pre_mult_alpha(plane, pre_mult_alpha);
1901         _dispc_setup_global_alpha(plane, global_alpha);
1902
1903         return 0;
1904 }
1905
1906 static void _dispc_enable_plane(enum omap_plane plane, bool enable)
1907 {
1908         REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
1909 }
1910
1911 static void dispc_disable_isr(void *data, u32 mask)
1912 {
1913         struct completion *compl = data;
1914         complete(compl);
1915 }
1916
1917 static void _enable_lcd_out(enum omap_channel channel, bool enable)
1918 {
1919         if (channel == OMAP_DSS_CHANNEL_LCD2)
1920                 REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0);
1921         else
1922                 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
1923 }
1924
1925 static void dispc_enable_lcd_out(enum omap_channel channel, bool enable)
1926 {
1927         struct completion frame_done_completion;
1928         bool is_on;
1929         int r;
1930         u32 irq;
1931
1932         enable_clocks(1);
1933
1934         /* When we disable LCD output, we need to wait until frame is done.
1935          * Otherwise the DSS is still working, and turning off the clocks
1936          * prevents DSS from going to OFF mode */
1937         is_on = channel == OMAP_DSS_CHANNEL_LCD2 ?
1938                         REG_GET(DISPC_CONTROL2, 0, 0) :
1939                         REG_GET(DISPC_CONTROL, 0, 0);
1940
1941         irq = channel == OMAP_DSS_CHANNEL_LCD2 ? DISPC_IRQ_FRAMEDONE2 :
1942                         DISPC_IRQ_FRAMEDONE;
1943
1944         if (!enable && is_on) {
1945                 init_completion(&frame_done_completion);
1946
1947                 r = omap_dispc_register_isr(dispc_disable_isr,
1948                                 &frame_done_completion, irq);
1949
1950                 if (r)
1951                         DSSERR("failed to register FRAMEDONE isr\n");
1952         }
1953
1954         _enable_lcd_out(channel, enable);
1955
1956         if (!enable && is_on) {
1957                 if (!wait_for_completion_timeout(&frame_done_completion,
1958                                         msecs_to_jiffies(100)))
1959                         DSSERR("timeout waiting for FRAME DONE\n");
1960
1961                 r = omap_dispc_unregister_isr(dispc_disable_isr,
1962                                 &frame_done_completion, irq);
1963
1964                 if (r)
1965                         DSSERR("failed to unregister FRAMEDONE isr\n");
1966         }
1967
1968         enable_clocks(0);
1969 }
1970
1971 static void _enable_digit_out(bool enable)
1972 {
1973         REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
1974 }
1975
1976 static void dispc_enable_digit_out(bool enable)
1977 {
1978         struct completion frame_done_completion;
1979         int r;
1980
1981         enable_clocks(1);
1982
1983         if (REG_GET(DISPC_CONTROL, 1, 1) == enable) {
1984                 enable_clocks(0);
1985                 return;
1986         }
1987
1988         if (enable) {
1989                 unsigned long flags;
1990                 /* When we enable digit output, we'll get an extra digit
1991                  * sync lost interrupt, that we need to ignore */
1992                 spin_lock_irqsave(&dispc.irq_lock, flags);
1993                 dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
1994                 _omap_dispc_set_irqs();
1995                 spin_unlock_irqrestore(&dispc.irq_lock, flags);
1996         }
1997
1998         /* When we disable digit output, we need to wait until fields are done.
1999          * Otherwise the DSS is still working, and turning off the clocks
2000          * prevents DSS from going to OFF mode. And when enabling, we need to
2001          * wait for the extra sync losts */
2002         init_completion(&frame_done_completion);
2003
2004         r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion,
2005                         DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
2006         if (r)
2007                 DSSERR("failed to register EVSYNC isr\n");
2008
2009         _enable_digit_out(enable);
2010
2011         /* XXX I understand from TRM that we should only wait for the
2012          * current field to complete. But it seems we have to wait
2013          * for both fields */
2014         if (!wait_for_completion_timeout(&frame_done_completion,
2015                                 msecs_to_jiffies(100)))
2016                 DSSERR("timeout waiting for EVSYNC\n");
2017
2018         if (!wait_for_completion_timeout(&frame_done_completion,
2019                                 msecs_to_jiffies(100)))
2020                 DSSERR("timeout waiting for EVSYNC\n");
2021
2022         r = omap_dispc_unregister_isr(dispc_disable_isr,
2023                         &frame_done_completion,
2024                         DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
2025         if (r)
2026                 DSSERR("failed to unregister EVSYNC isr\n");
2027
2028         if (enable) {
2029                 unsigned long flags;
2030                 spin_lock_irqsave(&dispc.irq_lock, flags);
2031                 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
2032                 if (dss_has_feature(FEAT_MGR_LCD2))
2033                         dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
2034                 dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
2035                 _omap_dispc_set_irqs();
2036                 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2037         }
2038
2039         enable_clocks(0);
2040 }
2041
2042 bool dispc_is_channel_enabled(enum omap_channel channel)
2043 {
2044         if (channel == OMAP_DSS_CHANNEL_LCD)
2045                 return !!REG_GET(DISPC_CONTROL, 0, 0);
2046         else if (channel == OMAP_DSS_CHANNEL_DIGIT)
2047                 return !!REG_GET(DISPC_CONTROL, 1, 1);
2048         else if (channel == OMAP_DSS_CHANNEL_LCD2)
2049                 return !!REG_GET(DISPC_CONTROL2, 0, 0);
2050         else
2051                 BUG();
2052 }
2053
2054 void dispc_enable_channel(enum omap_channel channel, bool enable)
2055 {
2056         if (channel == OMAP_DSS_CHANNEL_LCD ||
2057                         channel == OMAP_DSS_CHANNEL_LCD2)
2058                 dispc_enable_lcd_out(channel, enable);
2059         else if (channel == OMAP_DSS_CHANNEL_DIGIT)
2060                 dispc_enable_digit_out(enable);
2061         else
2062                 BUG();
2063 }
2064
2065 void dispc_lcd_enable_signal_polarity(bool act_high)
2066 {
2067         if (!dss_has_feature(FEAT_LCDENABLEPOL))
2068                 return;
2069
2070         enable_clocks(1);
2071         REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
2072         enable_clocks(0);
2073 }
2074
2075 void dispc_lcd_enable_signal(bool enable)
2076 {
2077         if (!dss_has_feature(FEAT_LCDENABLESIGNAL))
2078                 return;
2079
2080         enable_clocks(1);
2081         REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
2082         enable_clocks(0);
2083 }
2084
2085 void dispc_pck_free_enable(bool enable)
2086 {
2087         if (!dss_has_feature(FEAT_PCKFREEENABLE))
2088                 return;
2089
2090         enable_clocks(1);
2091         REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
2092         enable_clocks(0);
2093 }
2094
2095 void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable)
2096 {
2097         enable_clocks(1);
2098         if (channel == OMAP_DSS_CHANNEL_LCD2)
2099                 REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16);
2100         else
2101                 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
2102         enable_clocks(0);
2103 }
2104
2105
2106 void dispc_set_lcd_display_type(enum omap_channel channel,
2107                 enum omap_lcd_display_type type)
2108 {
2109         int mode;
2110
2111         switch (type) {
2112         case OMAP_DSS_LCD_DISPLAY_STN:
2113                 mode = 0;
2114                 break;
2115
2116         case OMAP_DSS_LCD_DISPLAY_TFT:
2117                 mode = 1;
2118                 break;
2119
2120         default:
2121                 BUG();
2122                 return;
2123         }
2124
2125         enable_clocks(1);
2126         if (channel == OMAP_DSS_CHANNEL_LCD2)
2127                 REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3);
2128         else
2129                 REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
2130         enable_clocks(0);
2131 }
2132
2133 void dispc_set_loadmode(enum omap_dss_load_mode mode)
2134 {
2135         enable_clocks(1);
2136         REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
2137         enable_clocks(0);
2138 }
2139
2140
2141 void dispc_set_default_color(enum omap_channel channel, u32 color)
2142 {
2143         enable_clocks(1);
2144         dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
2145         enable_clocks(0);
2146 }
2147
2148 u32 dispc_get_default_color(enum omap_channel channel)
2149 {
2150         u32 l;
2151
2152         BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
2153                 channel != OMAP_DSS_CHANNEL_LCD &&
2154                 channel != OMAP_DSS_CHANNEL_LCD2);
2155
2156         enable_clocks(1);
2157         l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel));
2158         enable_clocks(0);
2159
2160         return l;
2161 }
2162
2163 void dispc_set_trans_key(enum omap_channel ch,
2164                 enum omap_dss_trans_key_type type,
2165                 u32 trans_key)
2166 {
2167         enable_clocks(1);
2168         if (ch == OMAP_DSS_CHANNEL_LCD)
2169                 REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
2170         else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2171                 REG_FLD_MOD(DISPC_CONFIG, type, 13, 13);
2172         else /* OMAP_DSS_CHANNEL_LCD2 */
2173                 REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11);
2174
2175         dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
2176         enable_clocks(0);
2177 }
2178
2179 void dispc_get_trans_key(enum omap_channel ch,
2180                 enum omap_dss_trans_key_type *type,
2181                 u32 *trans_key)
2182 {
2183         enable_clocks(1);
2184         if (type) {
2185                 if (ch == OMAP_DSS_CHANNEL_LCD)
2186                         *type = REG_GET(DISPC_CONFIG, 11, 11);
2187                 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2188                         *type = REG_GET(DISPC_CONFIG, 13, 13);
2189                 else if (ch == OMAP_DSS_CHANNEL_LCD2)
2190                         *type = REG_GET(DISPC_CONFIG2, 11, 11);
2191                 else
2192                         BUG();
2193         }
2194
2195         if (trans_key)
2196                 *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch));
2197         enable_clocks(0);
2198 }
2199
2200 void dispc_enable_trans_key(enum omap_channel ch, bool enable)
2201 {
2202         enable_clocks(1);
2203         if (ch == OMAP_DSS_CHANNEL_LCD)
2204                 REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
2205         else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2206                 REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
2207         else /* OMAP_DSS_CHANNEL_LCD2 */
2208                 REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10);
2209         enable_clocks(0);
2210 }
2211 void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
2212 {
2213         if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
2214                 return;
2215
2216         enable_clocks(1);
2217         if (ch == OMAP_DSS_CHANNEL_LCD)
2218                 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
2219         else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2220                 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
2221         else /* OMAP_DSS_CHANNEL_LCD2 */
2222                 REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18);
2223         enable_clocks(0);
2224 }
2225 bool dispc_alpha_blending_enabled(enum omap_channel ch)
2226 {
2227         bool enabled;
2228
2229         if (!dss_has_feature(FEAT_GLOBAL_ALPHA))
2230                 return false;
2231
2232         enable_clocks(1);
2233         if (ch == OMAP_DSS_CHANNEL_LCD)
2234                 enabled = REG_GET(DISPC_CONFIG, 18, 18);
2235         else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2236                 enabled = REG_GET(DISPC_CONFIG, 19, 19);
2237         else if (ch == OMAP_DSS_CHANNEL_LCD2)
2238                 enabled = REG_GET(DISPC_CONFIG2, 18, 18);
2239         else
2240                 BUG();
2241         enable_clocks(0);
2242
2243         return enabled;
2244 }
2245
2246
2247 bool dispc_trans_key_enabled(enum omap_channel ch)
2248 {
2249         bool enabled;
2250
2251         enable_clocks(1);
2252         if (ch == OMAP_DSS_CHANNEL_LCD)
2253                 enabled = REG_GET(DISPC_CONFIG, 10, 10);
2254         else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2255                 enabled = REG_GET(DISPC_CONFIG, 12, 12);
2256         else if (ch == OMAP_DSS_CHANNEL_LCD2)
2257                 enabled = REG_GET(DISPC_CONFIG2, 10, 10);
2258         else
2259                 BUG();
2260         enable_clocks(0);
2261
2262         return enabled;
2263 }
2264
2265
2266 void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
2267 {
2268         int code;
2269
2270         switch (data_lines) {
2271         case 12:
2272                 code = 0;
2273                 break;
2274         case 16:
2275                 code = 1;
2276                 break;
2277         case 18:
2278                 code = 2;
2279                 break;
2280         case 24:
2281                 code = 3;
2282                 break;
2283         default:
2284                 BUG();
2285                 return;
2286         }
2287
2288         enable_clocks(1);
2289         if (channel == OMAP_DSS_CHANNEL_LCD2)
2290                 REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8);
2291         else
2292                 REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
2293         enable_clocks(0);
2294 }
2295
2296 void dispc_set_parallel_interface_mode(enum omap_channel channel,
2297                 enum omap_parallel_interface_mode mode)
2298 {
2299         u32 l;
2300         int stallmode;
2301         int gpout0 = 1;
2302         int gpout1;
2303
2304         switch (mode) {
2305         case OMAP_DSS_PARALLELMODE_BYPASS:
2306                 stallmode = 0;
2307                 gpout1 = 1;
2308                 break;
2309
2310         case OMAP_DSS_PARALLELMODE_RFBI:
2311                 stallmode = 1;
2312                 gpout1 = 0;
2313                 break;
2314
2315         case OMAP_DSS_PARALLELMODE_DSI:
2316                 stallmode = 1;
2317                 gpout1 = 1;
2318                 break;
2319
2320         default:
2321                 BUG();
2322                 return;
2323         }
2324
2325         enable_clocks(1);
2326
2327         if (channel == OMAP_DSS_CHANNEL_LCD2) {
2328                 l = dispc_read_reg(DISPC_CONTROL2);
2329                 l = FLD_MOD(l, stallmode, 11, 11);
2330                 dispc_write_reg(DISPC_CONTROL2, l);
2331         } else {
2332                 l = dispc_read_reg(DISPC_CONTROL);
2333                 l = FLD_MOD(l, stallmode, 11, 11);
2334                 l = FLD_MOD(l, gpout0, 15, 15);
2335                 l = FLD_MOD(l, gpout1, 16, 16);
2336                 dispc_write_reg(DISPC_CONTROL, l);
2337         }
2338
2339         enable_clocks(0);
2340 }
2341
2342 static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
2343                 int vsw, int vfp, int vbp)
2344 {
2345         if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2346                 if (hsw < 1 || hsw > 64 ||
2347                                 hfp < 1 || hfp > 256 ||
2348                                 hbp < 1 || hbp > 256 ||
2349                                 vsw < 1 || vsw > 64 ||
2350                                 vfp < 0 || vfp > 255 ||
2351                                 vbp < 0 || vbp > 255)
2352                         return false;
2353         } else {
2354                 if (hsw < 1 || hsw > 256 ||
2355                                 hfp < 1 || hfp > 4096 ||
2356                                 hbp < 1 || hbp > 4096 ||
2357                                 vsw < 1 || vsw > 256 ||
2358                                 vfp < 0 || vfp > 4095 ||
2359                                 vbp < 0 || vbp > 4095)
2360                         return false;
2361         }
2362
2363         return true;
2364 }
2365
2366 bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
2367 {
2368         return _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2369                         timings->hbp, timings->vsw,
2370                         timings->vfp, timings->vbp);
2371 }
2372
2373 static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw,
2374                 int hfp, int hbp, int vsw, int vfp, int vbp)
2375 {
2376         u32 timing_h, timing_v;
2377
2378         if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2379                 timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
2380                         FLD_VAL(hbp-1, 27, 20);
2381
2382                 timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
2383                         FLD_VAL(vbp, 27, 20);
2384         } else {
2385                 timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
2386                         FLD_VAL(hbp-1, 31, 20);
2387
2388                 timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
2389                         FLD_VAL(vbp, 31, 20);
2390         }
2391
2392         enable_clocks(1);
2393         dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
2394         dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
2395         enable_clocks(0);
2396 }
2397
2398 /* change name to mode? */
2399 void dispc_set_lcd_timings(enum omap_channel channel,
2400                 struct omap_video_timings *timings)
2401 {
2402         unsigned xtot, ytot;
2403         unsigned long ht, vt;
2404
2405         if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2406                                 timings->hbp, timings->vsw,
2407                                 timings->vfp, timings->vbp))
2408                 BUG();
2409
2410         _dispc_set_lcd_timings(channel, timings->hsw, timings->hfp,
2411                         timings->hbp, timings->vsw, timings->vfp,
2412                         timings->vbp);
2413
2414         dispc_set_lcd_size(channel, timings->x_res, timings->y_res);
2415
2416         xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
2417         ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
2418
2419         ht = (timings->pixel_clock * 1000) / xtot;
2420         vt = (timings->pixel_clock * 1000) / xtot / ytot;
2421
2422         DSSDBG("channel %d xres %u yres %u\n", channel, timings->x_res,
2423                         timings->y_res);
2424         DSSDBG("pck %u\n", timings->pixel_clock);
2425         DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
2426                         timings->hsw, timings->hfp, timings->hbp,
2427                         timings->vsw, timings->vfp, timings->vbp);
2428
2429         DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
2430 }
2431
2432 static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
2433                 u16 pck_div)
2434 {
2435         BUG_ON(lck_div < 1);
2436         BUG_ON(pck_div < 2);
2437
2438         enable_clocks(1);
2439         dispc_write_reg(DISPC_DIVISORo(channel),
2440                         FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
2441         enable_clocks(0);
2442 }
2443
2444 static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div,
2445                 int *pck_div)
2446 {
2447         u32 l;
2448         l = dispc_read_reg(DISPC_DIVISORo(channel));
2449         *lck_div = FLD_GET(l, 23, 16);
2450         *pck_div = FLD_GET(l, 7, 0);
2451 }
2452
2453 unsigned long dispc_fclk_rate(void)
2454 {
2455         struct platform_device *dsidev;
2456         unsigned long r = 0;
2457
2458         switch (dss_get_dispc_clk_source()) {
2459         case OMAP_DSS_CLK_SRC_FCK:
2460                 r = dss_clk_get_rate(DSS_CLK_FCK);
2461                 break;
2462         case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
2463                 dsidev = dsi_get_dsidev_from_id(0);
2464                 r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
2465                 break;
2466         case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
2467                 dsidev = dsi_get_dsidev_from_id(1);
2468                 r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
2469                 break;
2470         default:
2471                 BUG();
2472         }
2473
2474         return r;
2475 }
2476
2477 unsigned long dispc_lclk_rate(enum omap_channel channel)
2478 {
2479         struct platform_device *dsidev;
2480         int lcd;
2481         unsigned long r;
2482         u32 l;
2483
2484         l = dispc_read_reg(DISPC_DIVISORo(channel));
2485
2486         lcd = FLD_GET(l, 23, 16);
2487
2488         switch (dss_get_lcd_clk_source(channel)) {
2489         case OMAP_DSS_CLK_SRC_FCK:
2490                 r = dss_clk_get_rate(DSS_CLK_FCK);
2491                 break;
2492         case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
2493                 dsidev = dsi_get_dsidev_from_id(0);
2494                 r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
2495                 break;
2496         case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
2497                 dsidev = dsi_get_dsidev_from_id(1);
2498                 r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
2499                 break;
2500         default:
2501                 BUG();
2502         }
2503
2504         return r / lcd;
2505 }
2506
2507 unsigned long dispc_pclk_rate(enum omap_channel channel)
2508 {
2509         int pcd;
2510         unsigned long r;
2511         u32 l;
2512
2513         l = dispc_read_reg(DISPC_DIVISORo(channel));
2514
2515         pcd = FLD_GET(l, 7, 0);
2516
2517         r = dispc_lclk_rate(channel);
2518
2519         return r / pcd;
2520 }
2521
2522 void dispc_dump_clocks(struct seq_file *s)
2523 {
2524         int lcd, pcd;
2525         u32 l;
2526         enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
2527         enum omap_dss_clk_source lcd_clk_src;
2528
2529         enable_clocks(1);
2530
2531         seq_printf(s, "- DISPC -\n");
2532
2533         seq_printf(s, "dispc fclk source = %s (%s)\n",
2534                         dss_get_generic_clk_source_name(dispc_clk_src),
2535                         dss_feat_get_clk_source_name(dispc_clk_src));
2536
2537         seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
2538
2539         if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
2540                 seq_printf(s, "- DISPC-CORE-CLK -\n");
2541                 l = dispc_read_reg(DISPC_DIVISOR);
2542                 lcd = FLD_GET(l, 23, 16);
2543
2544                 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
2545                                 (dispc_fclk_rate()/lcd), lcd);
2546         }
2547         seq_printf(s, "- LCD1 -\n");
2548
2549         lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD);
2550
2551         seq_printf(s, "lcd1_clk source = %s (%s)\n",
2552                 dss_get_generic_clk_source_name(lcd_clk_src),
2553                 dss_feat_get_clk_source_name(lcd_clk_src));
2554
2555         dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd);
2556
2557         seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
2558                         dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd);
2559         seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
2560                         dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd);
2561         if (dss_has_feature(FEAT_MGR_LCD2)) {
2562                 seq_printf(s, "- LCD2 -\n");
2563
2564                 lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD2);
2565
2566                 seq_printf(s, "lcd2_clk source = %s (%s)\n",
2567                         dss_get_generic_clk_source_name(lcd_clk_src),
2568                         dss_feat_get_clk_source_name(lcd_clk_src));
2569
2570                 dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd);
2571
2572                 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
2573                                 dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD2), lcd);
2574                 seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
2575                                 dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd);
2576         }
2577         enable_clocks(0);
2578 }
2579
2580 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2581 void dispc_dump_irqs(struct seq_file *s)
2582 {
2583         unsigned long flags;
2584         struct dispc_irq_stats stats;
2585
2586         spin_lock_irqsave(&dispc.irq_stats_lock, flags);
2587
2588         stats = dispc.irq_stats;
2589         memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats));
2590         dispc.irq_stats.last_reset = jiffies;
2591
2592         spin_unlock_irqrestore(&dispc.irq_stats_lock, flags);
2593
2594         seq_printf(s, "period %u ms\n",
2595                         jiffies_to_msecs(jiffies - stats.last_reset));
2596
2597         seq_printf(s, "irqs %d\n", stats.irq_count);
2598 #define PIS(x) \
2599         seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
2600
2601         PIS(FRAMEDONE);
2602         PIS(VSYNC);
2603         PIS(EVSYNC_EVEN);
2604         PIS(EVSYNC_ODD);
2605         PIS(ACBIAS_COUNT_STAT);
2606         PIS(PROG_LINE_NUM);
2607         PIS(GFX_FIFO_UNDERFLOW);
2608         PIS(GFX_END_WIN);
2609         PIS(PAL_GAMMA_MASK);
2610         PIS(OCP_ERR);
2611         PIS(VID1_FIFO_UNDERFLOW);
2612         PIS(VID1_END_WIN);
2613         PIS(VID2_FIFO_UNDERFLOW);
2614         PIS(VID2_END_WIN);
2615         PIS(SYNC_LOST);
2616         PIS(SYNC_LOST_DIGIT);
2617         PIS(WAKEUP);
2618         if (dss_has_feature(FEAT_MGR_LCD2)) {
2619                 PIS(FRAMEDONE2);
2620                 PIS(VSYNC2);
2621                 PIS(ACBIAS_COUNT_STAT2);
2622                 PIS(SYNC_LOST2);
2623         }
2624 #undef PIS
2625 }
2626 #endif
2627
2628 void dispc_dump_regs(struct seq_file *s)
2629 {
2630 #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
2631
2632         dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
2633
2634         DUMPREG(DISPC_REVISION);
2635         DUMPREG(DISPC_SYSCONFIG);
2636         DUMPREG(DISPC_SYSSTATUS);
2637         DUMPREG(DISPC_IRQSTATUS);
2638         DUMPREG(DISPC_IRQENABLE);
2639         DUMPREG(DISPC_CONTROL);
2640         DUMPREG(DISPC_CONFIG);
2641         DUMPREG(DISPC_CAPABLE);
2642         DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD));
2643         DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT));
2644         DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_LCD));
2645         DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT));
2646         DUMPREG(DISPC_LINE_STATUS);
2647         DUMPREG(DISPC_LINE_NUMBER);
2648         DUMPREG(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD));
2649         DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD));
2650         DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD));
2651         DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD));
2652         DUMPREG(DISPC_GLOBAL_ALPHA);
2653         DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
2654         DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
2655         if (dss_has_feature(FEAT_MGR_LCD2)) {
2656                 DUMPREG(DISPC_CONTROL2);
2657                 DUMPREG(DISPC_CONFIG2);
2658                 DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2));
2659                 DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2));
2660                 DUMPREG(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD2));
2661                 DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD2));
2662                 DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD2));
2663                 DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD2));
2664                 DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD2));
2665         }
2666
2667         DUMPREG(DISPC_OVL_BA0(OMAP_DSS_GFX));
2668         DUMPREG(DISPC_OVL_BA1(OMAP_DSS_GFX));
2669         DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_GFX));
2670         DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_GFX));
2671         DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_GFX));
2672         DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_GFX));
2673         DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_GFX));
2674         DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_GFX));
2675         DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_GFX));
2676         DUMPREG(DISPC_OVL_WINDOW_SKIP(OMAP_DSS_GFX));
2677         DUMPREG(DISPC_OVL_TABLE_BA(OMAP_DSS_GFX));
2678
2679         DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD));
2680         DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
2681         DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
2682
2683         DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
2684         DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
2685         DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
2686         if (dss_has_feature(FEAT_MGR_LCD2)) {
2687                 DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
2688                 DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
2689                 DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
2690
2691                 DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
2692                 DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
2693                 DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
2694         }
2695
2696         DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX));
2697
2698         DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1));
2699         DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO1));
2700         DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO1));
2701         DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO1));
2702         DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
2703         DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
2704         DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO1));
2705         DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO1));
2706         DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
2707         DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO1));
2708         DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
2709         DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO1));
2710         DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO1));
2711
2712         DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO2));
2713         DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO2));
2714         DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO2));
2715         DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO2));
2716         DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
2717         DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
2718         DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO2));
2719         DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO2));
2720         DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
2721         DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO2));
2722         DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
2723         DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO2));
2724         DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO2));
2725
2726         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 0));
2727         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 1));
2728         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 2));
2729         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 3));
2730         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 4));
2731         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 5));
2732         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 6));
2733         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 7));
2734         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 0));
2735         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 1));
2736         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 2));
2737         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 3));
2738         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 4));
2739         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 5));
2740         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 6));
2741         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 7));
2742         DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0));
2743         DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1));
2744         DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2));
2745         DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3));
2746         DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4));
2747         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0));
2748         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1));
2749         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2));
2750         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3));
2751         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4));
2752         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5));
2753         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6));
2754         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7));
2755
2756         if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
2757                 DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1));
2758                 DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO1));
2759                 DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO1));
2760                 DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO1));
2761                 DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO1));
2762
2763                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 0));
2764                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 1));
2765                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 2));
2766                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 3));
2767                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 4));
2768                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 5));
2769                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 6));
2770                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 7));
2771
2772                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 0));
2773                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 1));
2774                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 2));
2775                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 3));
2776                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 4));
2777                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 5));
2778                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 6));
2779                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 7));
2780
2781                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 0));
2782                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 1));
2783                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 2));
2784                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 3));
2785                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 4));
2786                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 5));
2787                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 6));
2788                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 7));
2789         }
2790         if (dss_has_feature(FEAT_ATTR2))
2791                 DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
2792
2793
2794         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 0));
2795         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 1));
2796         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 2));
2797         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 3));
2798         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 4));
2799         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 5));
2800         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 6));
2801         DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 7));
2802         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 0));
2803         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 1));
2804         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 2));
2805         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 3));
2806         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 4));
2807         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 5));
2808         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 6));
2809         DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 7));
2810         DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0));
2811         DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1));
2812         DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2));
2813         DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3));
2814         DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4));
2815         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0));
2816         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1));
2817         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2));
2818         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3));
2819         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4));
2820         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5));
2821         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6));
2822         DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7));
2823
2824         if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
2825                 DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2));
2826                 DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO2));
2827                 DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO2));
2828                 DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO2));
2829                 DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO2));
2830
2831                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 0));
2832                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 1));
2833                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 2));
2834                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 3));
2835                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 4));
2836                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 5));
2837                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 6));
2838                 DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 7));
2839
2840                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 0));
2841                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 1));
2842                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 2));
2843                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 3));
2844                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 4));
2845                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 5));
2846                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 6));
2847                 DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 7));
2848
2849                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 0));
2850                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 1));
2851                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 2));
2852                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 3));
2853                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 4));
2854                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 5));
2855                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 6));
2856                 DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 7));
2857         }
2858         if (dss_has_feature(FEAT_ATTR2))
2859                 DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
2860
2861         DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1));
2862         DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2));
2863
2864         dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
2865 #undef DUMPREG
2866 }
2867
2868 static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf,
2869                 bool ieo, bool ipc, bool ihs, bool ivs, u8 acbi, u8 acb)
2870 {
2871         u32 l = 0;
2872
2873         DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n",
2874                         onoff, rf, ieo, ipc, ihs, ivs, acbi, acb);
2875
2876         l |= FLD_VAL(onoff, 17, 17);
2877         l |= FLD_VAL(rf, 16, 16);
2878         l |= FLD_VAL(ieo, 15, 15);
2879         l |= FLD_VAL(ipc, 14, 14);
2880         l |= FLD_VAL(ihs, 13, 13);
2881         l |= FLD_VAL(ivs, 12, 12);
2882         l |= FLD_VAL(acbi, 11, 8);
2883         l |= FLD_VAL(acb, 7, 0);
2884
2885         enable_clocks(1);
2886         dispc_write_reg(DISPC_POL_FREQ(channel), l);
2887         enable_clocks(0);
2888 }
2889
2890 void dispc_set_pol_freq(enum omap_channel channel,
2891                 enum omap_panel_config config, u8 acbi, u8 acb)
2892 {
2893         _dispc_set_pol_freq(channel, (config & OMAP_DSS_LCD_ONOFF) != 0,
2894                         (config & OMAP_DSS_LCD_RF) != 0,
2895                         (config & OMAP_DSS_LCD_IEO) != 0,
2896                         (config & OMAP_DSS_LCD_IPC) != 0,
2897                         (config & OMAP_DSS_LCD_IHS) != 0,
2898                         (config & OMAP_DSS_LCD_IVS) != 0,
2899                         acbi, acb);
2900 }
2901
2902 /* with fck as input clock rate, find dispc dividers that produce req_pck */
2903 void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
2904                 struct dispc_clock_info *cinfo)
2905 {
2906         u16 pcd_min = is_tft ? 2 : 3;
2907         unsigned long best_pck;
2908         u16 best_ld, cur_ld;
2909         u16 best_pd, cur_pd;
2910
2911         best_pck = 0;
2912         best_ld = 0;
2913         best_pd = 0;
2914
2915         for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
2916                 unsigned long lck = fck / cur_ld;
2917
2918                 for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) {
2919                         unsigned long pck = lck / cur_pd;
2920                         long old_delta = abs(best_pck - req_pck);
2921                         long new_delta = abs(pck - req_pck);
2922
2923                         if (best_pck == 0 || new_delta < old_delta) {
2924                                 best_pck = pck;
2925                                 best_ld = cur_ld;
2926                                 best_pd = cur_pd;
2927
2928                                 if (pck == req_pck)
2929                                         goto found;
2930                         }
2931
2932                         if (pck < req_pck)
2933                                 break;
2934                 }
2935
2936                 if (lck / pcd_min < req_pck)
2937                         break;
2938         }
2939
2940 found:
2941         cinfo->lck_div = best_ld;
2942         cinfo->pck_div = best_pd;
2943         cinfo->lck = fck / cinfo->lck_div;
2944         cinfo->pck = cinfo->lck / cinfo->pck_div;
2945 }
2946
2947 /* calculate clock rates using dividers in cinfo */
2948 int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
2949                 struct dispc_clock_info *cinfo)
2950 {
2951         if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
2952                 return -EINVAL;
2953         if (cinfo->pck_div < 2 || cinfo->pck_div > 255)
2954                 return -EINVAL;
2955
2956         cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
2957         cinfo->pck = cinfo->lck / cinfo->pck_div;
2958
2959         return 0;
2960 }
2961
2962 int dispc_set_clock_div(enum omap_channel channel,
2963                 struct dispc_clock_info *cinfo)
2964 {
2965         DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
2966         DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
2967
2968         dispc_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
2969
2970         return 0;
2971 }
2972
2973 int dispc_get_clock_div(enum omap_channel channel,
2974                 struct dispc_clock_info *cinfo)
2975 {
2976         unsigned long fck;
2977
2978         fck = dispc_fclk_rate();
2979
2980         cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16);
2981         cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0);
2982
2983         cinfo->lck = fck / cinfo->lck_div;
2984         cinfo->pck = cinfo->lck / cinfo->pck_div;
2985
2986         return 0;
2987 }
2988
2989 /* dispc.irq_lock has to be locked by the caller */
2990 static void _omap_dispc_set_irqs(void)
2991 {
2992         u32 mask;
2993         u32 old_mask;
2994         int i;
2995         struct omap_dispc_isr_data *isr_data;
2996
2997         mask = dispc.irq_error_mask;
2998
2999         for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3000                 isr_data = &dispc.registered_isr[i];
3001
3002                 if (isr_data->isr == NULL)
3003                         continue;
3004
3005                 mask |= isr_data->mask;
3006         }
3007
3008         enable_clocks(1);
3009
3010         old_mask = dispc_read_reg(DISPC_IRQENABLE);
3011         /* clear the irqstatus for newly enabled irqs */
3012         dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
3013
3014         dispc_write_reg(DISPC_IRQENABLE, mask);
3015
3016         enable_clocks(0);
3017 }
3018
3019 int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
3020 {
3021         int i;
3022         int ret;
3023         unsigned long flags;
3024         struct omap_dispc_isr_data *isr_data;
3025
3026         if (isr == NULL)
3027                 return -EINVAL;
3028
3029         spin_lock_irqsave(&dispc.irq_lock, flags);
3030
3031         /* check for duplicate entry */
3032         for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3033                 isr_data = &dispc.registered_isr[i];
3034                 if (isr_data->isr == isr && isr_data->arg == arg &&
3035                                 isr_data->mask == mask) {
3036                         ret = -EINVAL;
3037                         goto err;
3038                 }
3039         }
3040
3041         isr_data = NULL;
3042         ret = -EBUSY;
3043
3044         for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3045                 isr_data = &dispc.registered_isr[i];
3046
3047                 if (isr_data->isr != NULL)
3048                         continue;
3049
3050                 isr_data->isr = isr;
3051                 isr_data->arg = arg;
3052                 isr_data->mask = mask;
3053                 ret = 0;
3054
3055                 break;
3056         }
3057
3058         if (ret)
3059                 goto err;
3060
3061         _omap_dispc_set_irqs();
3062
3063         spin_unlock_irqrestore(&dispc.irq_lock, flags);
3064
3065         return 0;
3066 err:
3067         spin_unlock_irqrestore(&dispc.irq_lock, flags);
3068
3069         return ret;
3070 }
3071 EXPORT_SYMBOL(omap_dispc_register_isr);
3072
3073 int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
3074 {
3075         int i;
3076         unsigned long flags;
3077         int ret = -EINVAL;
3078         struct omap_dispc_isr_data *isr_data;
3079
3080         spin_lock_irqsave(&dispc.irq_lock, flags);
3081
3082         for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3083                 isr_data = &dispc.registered_isr[i];
3084                 if (isr_data->isr != isr || isr_data->arg != arg ||
3085                                 isr_data->mask != mask)
3086                         continue;
3087
3088                 /* found the correct isr */
3089
3090                 isr_data->isr = NULL;
3091                 isr_data->arg = NULL;
3092                 isr_data->mask = 0;
3093
3094                 ret = 0;
3095                 break;
3096         }
3097
3098         if (ret == 0)
3099                 _omap_dispc_set_irqs();
3100
3101         spin_unlock_irqrestore(&dispc.irq_lock, flags);
3102
3103         return ret;
3104 }
3105 EXPORT_SYMBOL(omap_dispc_unregister_isr);
3106
3107 #ifdef DEBUG
3108 static void print_irq_status(u32 status)
3109 {
3110         if ((status & dispc.irq_error_mask) == 0)
3111                 return;
3112
3113         printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status);
3114
3115 #define PIS(x) \
3116         if (status & DISPC_IRQ_##x) \
3117                 printk(#x " ");
3118         PIS(GFX_FIFO_UNDERFLOW);
3119         PIS(OCP_ERR);
3120         PIS(VID1_FIFO_UNDERFLOW);
3121         PIS(VID2_FIFO_UNDERFLOW);
3122         PIS(SYNC_LOST);
3123         PIS(SYNC_LOST_DIGIT);
3124         if (dss_has_feature(FEAT_MGR_LCD2))
3125                 PIS(SYNC_LOST2);
3126 #undef PIS
3127
3128         printk("\n");
3129 }
3130 #endif
3131
3132 /* Called from dss.c. Note that we don't touch clocks here,
3133  * but we presume they are on because we got an IRQ. However,
3134  * an irq handler may turn the clocks off, so we may not have
3135  * clock later in the function. */
3136 static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
3137 {
3138         int i;
3139         u32 irqstatus, irqenable;
3140         u32 handledirqs = 0;
3141         u32 unhandled_errors;
3142         struct omap_dispc_isr_data *isr_data;
3143         struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
3144
3145         spin_lock(&dispc.irq_lock);
3146
3147         irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
3148         irqenable = dispc_read_reg(DISPC_IRQENABLE);
3149
3150         /* IRQ is not for us */
3151         if (!(irqstatus & irqenable)) {
3152                 spin_unlock(&dispc.irq_lock);
3153                 return IRQ_NONE;
3154         }
3155
3156 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3157         spin_lock(&dispc.irq_stats_lock);
3158         dispc.irq_stats.irq_count++;
3159         dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs);
3160         spin_unlock(&dispc.irq_stats_lock);
3161 #endif
3162
3163 #ifdef DEBUG
3164         if (dss_debug)
3165                 print_irq_status(irqstatus);
3166 #endif
3167         /* Ack the interrupt. Do it here before clocks are possibly turned
3168          * off */
3169         dispc_write_reg(DISPC_IRQSTATUS, irqstatus);
3170         /* flush posted write */
3171         dispc_read_reg(DISPC_IRQSTATUS);
3172
3173         /* make a copy and unlock, so that isrs can unregister
3174          * themselves */
3175         memcpy(registered_isr, dispc.registered_isr,
3176                         sizeof(registered_isr));
3177
3178         spin_unlock(&dispc.irq_lock);
3179
3180         for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3181                 isr_data = &registered_isr[i];
3182
3183                 if (!isr_data->isr)
3184                         continue;
3185
3186                 if (isr_data->mask & irqstatus) {
3187                         isr_data->isr(isr_data->arg, irqstatus);
3188                         handledirqs |= isr_data->mask;
3189                 }
3190         }
3191
3192         spin_lock(&dispc.irq_lock);
3193
3194         unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
3195
3196         if (unhandled_errors) {
3197                 dispc.error_irqs |= unhandled_errors;
3198
3199                 dispc.irq_error_mask &= ~unhandled_errors;
3200                 _omap_dispc_set_irqs();
3201
3202                 schedule_work(&dispc.error_work);
3203         }
3204
3205         spin_unlock(&dispc.irq_lock);
3206
3207         return IRQ_HANDLED;
3208 }
3209
3210 static void dispc_error_worker(struct work_struct *work)
3211 {
3212         int i;
3213         u32 errors;
3214         unsigned long flags;
3215
3216         spin_lock_irqsave(&dispc.irq_lock, flags);
3217         errors = dispc.error_irqs;
3218         dispc.error_irqs = 0;
3219         spin_unlock_irqrestore(&dispc.irq_lock, flags);
3220
3221         if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) {
3222                 DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n");
3223                 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
3224                         struct omap_overlay *ovl;
3225                         ovl = omap_dss_get_overlay(i);
3226
3227                         if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
3228                                 continue;
3229
3230                         if (ovl->id == 0) {
3231                                 dispc_enable_plane(ovl->id, 0);
3232                                 dispc_go(ovl->manager->id);
3233                                 mdelay(50);
3234                                 break;
3235                         }
3236                 }
3237         }
3238
3239         if (errors & DISPC_IRQ_VID1_FIFO_UNDERFLOW) {
3240                 DSSERR("VID1_FIFO_UNDERFLOW, disabling VID1\n");
3241                 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
3242                         struct omap_overlay *ovl;
3243                         ovl = omap_dss_get_overlay(i);
3244
3245                         if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
3246                                 continue;
3247
3248                         if (ovl->id == 1) {
3249                                 dispc_enable_plane(ovl->id, 0);
3250                                 dispc_go(ovl->manager->id);
3251                                 mdelay(50);
3252                                 break;
3253                         }
3254                 }
3255         }
3256
3257         if (errors & DISPC_IRQ_VID2_FIFO_UNDERFLOW) {
3258                 DSSERR("VID2_FIFO_UNDERFLOW, disabling VID2\n");
3259                 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
3260                         struct omap_overlay *ovl;
3261                         ovl = omap_dss_get_overlay(i);
3262
3263                         if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
3264                                 continue;
3265
3266                         if (ovl->id == 2) {
3267                                 dispc_enable_plane(ovl->id, 0);
3268                                 dispc_go(ovl->manager->id);
3269                                 mdelay(50);
3270                                 break;
3271                         }
3272                 }
3273         }
3274
3275         if (errors & DISPC_IRQ_SYNC_LOST) {
3276                 struct omap_overlay_manager *manager = NULL;
3277                 bool enable = false;
3278
3279                 DSSERR("SYNC_LOST, disabling LCD\n");
3280
3281                 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
3282                         struct omap_overlay_manager *mgr;
3283                         mgr = omap_dss_get_overlay_manager(i);
3284
3285                         if (mgr->id == OMAP_DSS_CHANNEL_LCD) {
3286                                 manager = mgr;
3287                                 enable = mgr->device->state ==
3288                                                 OMAP_DSS_DISPLAY_ACTIVE;
3289                                 mgr->device->driver->disable(mgr->device);
3290                                 break;
3291                         }
3292                 }
3293
3294                 if (manager) {
3295                         struct omap_dss_device *dssdev = manager->device;
3296                         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
3297                                 struct omap_overlay *ovl;
3298                                 ovl = omap_dss_get_overlay(i);
3299
3300                                 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
3301                                         continue;
3302
3303                                 if (ovl->id != 0 && ovl->manager == manager)
3304                                         dispc_enable_plane(ovl->id, 0);
3305                         }
3306
3307                         dispc_go(manager->id);
3308                         mdelay(50);
3309                         if (enable)
3310                                 dssdev->driver->enable(dssdev);
3311                 }
3312         }
3313
3314         if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) {
3315                 struct omap_overlay_manager *manager = NULL;
3316                 bool enable = false;
3317
3318                 DSSERR("SYNC_LOST_DIGIT, disabling TV\n");
3319
3320                 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
3321                         struct omap_overlay_manager *mgr;
3322                         mgr = omap_dss_get_overlay_manager(i);
3323
3324                         if (mgr->id == OMAP_DSS_CHANNEL_DIGIT) {
3325                                 manager = mgr;
3326                                 enable = mgr->device->state ==
3327                                                 OMAP_DSS_DISPLAY_ACTIVE;
3328                                 mgr->device->driver->disable(mgr->device);
3329                                 break;
3330                         }
3331                 }
3332
3333                 if (manager) {
3334                         struct omap_dss_device *dssdev = manager->device;
3335                         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
3336                                 struct omap_overlay *ovl;
3337                                 ovl = omap_dss_get_overlay(i);
3338
3339                                 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
3340                                         continue;
3341
3342                                 if (ovl->id != 0 && ovl->manager == manager)
3343                                         dispc_enable_plane(ovl->id, 0);
3344                         }
3345
3346                         dispc_go(manager->id);
3347                         mdelay(50);
3348                         if (enable)
3349                                 dssdev->driver->enable(dssdev);
3350                 }
3351         }
3352
3353         if (errors & DISPC_IRQ_SYNC_LOST2) {
3354                 struct omap_overlay_manager *manager = NULL;
3355                 bool enable = false;
3356
3357                 DSSERR("SYNC_LOST for LCD2, disabling LCD2\n");
3358
3359                 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
3360                         struct omap_overlay_manager *mgr;
3361                         mgr = omap_dss_get_overlay_manager(i);
3362
3363                         if (mgr->id == OMAP_DSS_CHANNEL_LCD2) {
3364                                 manager = mgr;
3365                                 enable = mgr->device->state ==
3366                                                 OMAP_DSS_DISPLAY_ACTIVE;
3367                                 mgr->device->driver->disable(mgr->device);
3368                                 break;
3369                         }
3370                 }
3371
3372                 if (manager) {
3373                         struct omap_dss_device *dssdev = manager->device;
3374                         for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
3375                                 struct omap_overlay *ovl;
3376                                 ovl = omap_dss_get_overlay(i);
3377
3378                                 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
3379                                         continue;
3380
3381                                 if (ovl->id != 0 && ovl->manager == manager)
3382                                         dispc_enable_plane(ovl->id, 0);
3383                         }
3384
3385                         dispc_go(manager->id);
3386                         mdelay(50);
3387                         if (enable)
3388                                 dssdev->driver->enable(dssdev);
3389                 }
3390         }
3391
3392         if (errors & DISPC_IRQ_OCP_ERR) {
3393                 DSSERR("OCP_ERR\n");
3394                 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
3395                         struct omap_overlay_manager *mgr;
3396                         mgr = omap_dss_get_overlay_manager(i);
3397
3398                         if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC)
3399                                 mgr->device->driver->disable(mgr->device);
3400                 }
3401         }
3402
3403         spin_lock_irqsave(&dispc.irq_lock, flags);
3404         dispc.irq_error_mask |= errors;
3405         _omap_dispc_set_irqs();
3406         spin_unlock_irqrestore(&dispc.irq_lock, flags);
3407 }
3408
3409 int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
3410 {
3411         void dispc_irq_wait_handler(void *data, u32 mask)
3412         {
3413                 complete((struct completion *)data);
3414         }
3415
3416         int r;
3417         DECLARE_COMPLETION_ONSTACK(completion);
3418
3419         r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
3420                         irqmask);
3421
3422         if (r)
3423                 return r;
3424
3425         timeout = wait_for_completion_timeout(&completion, timeout);
3426
3427         omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
3428
3429         if (timeout == 0)
3430                 return -ETIMEDOUT;
3431
3432         if (timeout == -ERESTARTSYS)
3433                 return -ERESTARTSYS;
3434
3435         return 0;
3436 }
3437
3438 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
3439                 unsigned long timeout)
3440 {
3441         void dispc_irq_wait_handler(void *data, u32 mask)
3442         {
3443                 complete((struct completion *)data);
3444         }
3445
3446         int r;
3447         DECLARE_COMPLETION_ONSTACK(completion);
3448
3449         r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
3450                         irqmask);
3451
3452         if (r)
3453                 return r;
3454
3455         timeout = wait_for_completion_interruptible_timeout(&completion,
3456                         timeout);
3457
3458         omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
3459
3460         if (timeout == 0)
3461                 return -ETIMEDOUT;
3462
3463         if (timeout == -ERESTARTSYS)
3464                 return -ERESTARTSYS;
3465
3466         return 0;
3467 }
3468
3469 #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
3470 void dispc_fake_vsync_irq(void)
3471 {
3472         u32 irqstatus = DISPC_IRQ_VSYNC;
3473         int i;
3474
3475         WARN_ON(!in_interrupt());
3476
3477         for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3478                 struct omap_dispc_isr_data *isr_data;
3479                 isr_data = &dispc.registered_isr[i];
3480
3481                 if (!isr_data->isr)
3482                         continue;
3483
3484                 if (isr_data->mask & irqstatus)
3485                         isr_data->isr(isr_data->arg, irqstatus);
3486         }
3487 }
3488 #endif
3489
3490 static void _omap_dispc_initialize_irq(void)
3491 {
3492         unsigned long flags;
3493
3494         spin_lock_irqsave(&dispc.irq_lock, flags);
3495
3496         memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
3497
3498         dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
3499         if (dss_has_feature(FEAT_MGR_LCD2))
3500                 dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
3501
3502         /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
3503          * so clear it */
3504         dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS));
3505
3506         _omap_dispc_set_irqs();
3507
3508         spin_unlock_irqrestore(&dispc.irq_lock, flags);
3509 }
3510
3511 void dispc_enable_sidle(void)
3512 {
3513         REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3);  /* SIDLEMODE: smart idle */
3514 }
3515
3516 void dispc_disable_sidle(void)
3517 {
3518         REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3);  /* SIDLEMODE: no idle */
3519 }
3520
3521 static void _omap_dispc_initial_config(void)
3522 {
3523         u32 l;
3524
3525         l = dispc_read_reg(DISPC_SYSCONFIG);
3526         l = FLD_MOD(l, 2, 13, 12);      /* MIDLEMODE: smart standby */
3527         l = FLD_MOD(l, 2, 4, 3);        /* SIDLEMODE: smart idle */
3528         l = FLD_MOD(l, 1, 2, 2);        /* ENWAKEUP */
3529         l = FLD_MOD(l, 1, 0, 0);        /* AUTOIDLE */
3530         dispc_write_reg(DISPC_SYSCONFIG, l);
3531
3532         /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
3533         if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
3534                 l = dispc_read_reg(DISPC_DIVISOR);
3535                 /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
3536                 l = FLD_MOD(l, 1, 0, 0);
3537                 l = FLD_MOD(l, 1, 23, 16);
3538                 dispc_write_reg(DISPC_DIVISOR, l);
3539         }
3540
3541         /* FUNCGATED */
3542         if (dss_has_feature(FEAT_FUNCGATED))
3543                 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
3544
3545         /* L3 firewall setting: enable access to OCM RAM */
3546         /* XXX this should be somewhere in plat-omap */
3547         if (cpu_is_omap24xx())
3548                 __raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0));
3549
3550         _dispc_setup_color_conv_coef();
3551
3552         dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3553
3554         dispc_read_plane_fifo_sizes();
3555 }
3556
3557 int dispc_enable_plane(enum omap_plane plane, bool enable)
3558 {
3559         DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
3560
3561         enable_clocks(1);
3562         _dispc_enable_plane(plane, enable);
3563         enable_clocks(0);
3564
3565         return 0;
3566 }
3567
3568 int dispc_setup_plane(enum omap_plane plane,
3569                        u32 paddr, u16 screen_width,
3570                        u16 pos_x, u16 pos_y,
3571                        u16 width, u16 height,
3572                        u16 out_width, u16 out_height,
3573                        enum omap_color_mode color_mode,
3574                        bool ilace,
3575                        enum omap_dss_rotation_type rotation_type,
3576                        u8 rotation, bool mirror, u8 global_alpha,
3577                        u8 pre_mult_alpha, enum omap_channel channel,
3578                        u32 puv_addr)
3579 {
3580         int r = 0;
3581
3582         DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d, %d, %dx%d -> "
3583                "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
3584                plane, paddr, screen_width, pos_x, pos_y,
3585                width, height,
3586                out_width, out_height,
3587                ilace, color_mode,
3588                rotation, mirror, channel);
3589
3590         enable_clocks(1);
3591
3592         r = _dispc_setup_plane(plane,
3593                            paddr, screen_width,
3594                            pos_x, pos_y,
3595                            width, height,
3596                            out_width, out_height,
3597                            color_mode, ilace,
3598                            rotation_type,
3599                            rotation, mirror,
3600                            global_alpha,
3601                            pre_mult_alpha,
3602                            channel, puv_addr);
3603
3604         enable_clocks(0);
3605
3606         return r;
3607 }
3608
3609 /* DISPC HW IP initialisation */
3610 static int omap_dispchw_probe(struct platform_device *pdev)
3611 {
3612         u32 rev;
3613         int r = 0;
3614         struct resource *dispc_mem;
3615
3616         dispc.pdev = pdev;
3617
3618         spin_lock_init(&dispc.irq_lock);
3619
3620 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3621         spin_lock_init(&dispc.irq_stats_lock);
3622         dispc.irq_stats.last_reset = jiffies;
3623 #endif
3624
3625         INIT_WORK(&dispc.error_work, dispc_error_worker);
3626
3627         dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
3628         if (!dispc_mem) {
3629                 DSSERR("can't get IORESOURCE_MEM DISPC\n");
3630                 r = -EINVAL;
3631                 goto fail0;
3632         }
3633         dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem));
3634         if (!dispc.base) {
3635                 DSSERR("can't ioremap DISPC\n");
3636                 r = -ENOMEM;
3637                 goto fail0;
3638         }
3639         dispc.irq = platform_get_irq(dispc.pdev, 0);
3640         if (dispc.irq < 0) {
3641                 DSSERR("platform_get_irq failed\n");
3642                 r = -ENODEV;
3643                 goto fail1;
3644         }
3645
3646         r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED,
3647                 "OMAP DISPC", dispc.pdev);
3648         if (r < 0) {
3649                 DSSERR("request_irq failed\n");
3650                 goto fail1;
3651         }
3652
3653         enable_clocks(1);
3654
3655         _omap_dispc_initial_config();
3656
3657         _omap_dispc_initialize_irq();
3658
3659         dispc_save_context();
3660
3661         rev = dispc_read_reg(DISPC_REVISION);
3662         dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
3663                FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
3664
3665         enable_clocks(0);
3666
3667         return 0;
3668 fail1:
3669         iounmap(dispc.base);
3670 fail0:
3671         return r;
3672 }
3673
3674 static int omap_dispchw_remove(struct platform_device *pdev)
3675 {
3676         free_irq(dispc.irq, dispc.pdev);
3677         iounmap(dispc.base);
3678         return 0;
3679 }
3680
3681 static struct platform_driver omap_dispchw_driver = {
3682         .probe          = omap_dispchw_probe,
3683         .remove         = omap_dispchw_remove,
3684         .driver         = {
3685                 .name   = "omapdss_dispc",
3686                 .owner  = THIS_MODULE,
3687         },
3688 };
3689
3690 int dispc_init_platform_driver(void)
3691 {
3692         return platform_driver_register(&omap_dispchw_driver);
3693 }
3694
3695 void dispc_uninit_platform_driver(void)
3696 {
3697         return platform_driver_unregister(&omap_dispchw_driver);
3698 }