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