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