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