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