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