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