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