Linux 2.6.34-rc3
[pohmelfs.git] / drivers / video / omap2 / dss / dispc.c
blobe777e352dbcd8f4050a202323fadfebe2828c4d7
1 /*
2 * linux/drivers/video/omap2/dss/dispc.c
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
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.
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.
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/>.
23 #define DSS_SUBSYS_NAME "DISPC"
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>
35 #include <plat/sram.h>
36 #include <plat/clock.h>
38 #include <plat/display.h>
40 #include "dss.h"
42 /* DISPC */
43 #define DISPC_BASE 0x48050400
45 #define DISPC_SZ_REGS SZ_1K
47 struct dispc_reg { u16 idx; };
49 #define DISPC_REG(idx) ((const struct dispc_reg) { idx })
51 /* DISPC common */
52 #define DISPC_REVISION DISPC_REG(0x0000)
53 #define DISPC_SYSCONFIG DISPC_REG(0x0010)
54 #define DISPC_SYSSTATUS DISPC_REG(0x0014)
55 #define DISPC_IRQSTATUS DISPC_REG(0x0018)
56 #define DISPC_IRQENABLE DISPC_REG(0x001C)
57 #define DISPC_CONTROL DISPC_REG(0x0040)
58 #define DISPC_CONFIG DISPC_REG(0x0044)
59 #define DISPC_CAPABLE DISPC_REG(0x0048)
60 #define DISPC_DEFAULT_COLOR0 DISPC_REG(0x004C)
61 #define DISPC_DEFAULT_COLOR1 DISPC_REG(0x0050)
62 #define DISPC_TRANS_COLOR0 DISPC_REG(0x0054)
63 #define DISPC_TRANS_COLOR1 DISPC_REG(0x0058)
64 #define DISPC_LINE_STATUS DISPC_REG(0x005C)
65 #define DISPC_LINE_NUMBER DISPC_REG(0x0060)
66 #define DISPC_TIMING_H DISPC_REG(0x0064)
67 #define DISPC_TIMING_V DISPC_REG(0x0068)
68 #define DISPC_POL_FREQ DISPC_REG(0x006C)
69 #define DISPC_DIVISOR DISPC_REG(0x0070)
70 #define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074)
71 #define DISPC_SIZE_DIG DISPC_REG(0x0078)
72 #define DISPC_SIZE_LCD DISPC_REG(0x007C)
74 /* DISPC GFX plane */
75 #define DISPC_GFX_BA0 DISPC_REG(0x0080)
76 #define DISPC_GFX_BA1 DISPC_REG(0x0084)
77 #define DISPC_GFX_POSITION DISPC_REG(0x0088)
78 #define DISPC_GFX_SIZE DISPC_REG(0x008C)
79 #define DISPC_GFX_ATTRIBUTES DISPC_REG(0x00A0)
80 #define DISPC_GFX_FIFO_THRESHOLD DISPC_REG(0x00A4)
81 #define DISPC_GFX_FIFO_SIZE_STATUS DISPC_REG(0x00A8)
82 #define DISPC_GFX_ROW_INC DISPC_REG(0x00AC)
83 #define DISPC_GFX_PIXEL_INC DISPC_REG(0x00B0)
84 #define DISPC_GFX_WINDOW_SKIP DISPC_REG(0x00B4)
85 #define DISPC_GFX_TABLE_BA DISPC_REG(0x00B8)
87 #define DISPC_DATA_CYCLE1 DISPC_REG(0x01D4)
88 #define DISPC_DATA_CYCLE2 DISPC_REG(0x01D8)
89 #define DISPC_DATA_CYCLE3 DISPC_REG(0x01DC)
91 #define DISPC_CPR_COEF_R DISPC_REG(0x0220)
92 #define DISPC_CPR_COEF_G DISPC_REG(0x0224)
93 #define DISPC_CPR_COEF_B DISPC_REG(0x0228)
95 #define DISPC_GFX_PRELOAD DISPC_REG(0x022C)
97 /* DISPC Video plane, n = 0 for VID1 and n = 1 for VID2 */
98 #define DISPC_VID_REG(n, idx) DISPC_REG(0x00BC + (n)*0x90 + idx)
100 #define DISPC_VID_BA0(n) DISPC_VID_REG(n, 0x0000)
101 #define DISPC_VID_BA1(n) DISPC_VID_REG(n, 0x0004)
102 #define DISPC_VID_POSITION(n) DISPC_VID_REG(n, 0x0008)
103 #define DISPC_VID_SIZE(n) DISPC_VID_REG(n, 0x000C)
104 #define DISPC_VID_ATTRIBUTES(n) DISPC_VID_REG(n, 0x0010)
105 #define DISPC_VID_FIFO_THRESHOLD(n) DISPC_VID_REG(n, 0x0014)
106 #define DISPC_VID_FIFO_SIZE_STATUS(n) DISPC_VID_REG(n, 0x0018)
107 #define DISPC_VID_ROW_INC(n) DISPC_VID_REG(n, 0x001C)
108 #define DISPC_VID_PIXEL_INC(n) DISPC_VID_REG(n, 0x0020)
109 #define DISPC_VID_FIR(n) DISPC_VID_REG(n, 0x0024)
110 #define DISPC_VID_PICTURE_SIZE(n) DISPC_VID_REG(n, 0x0028)
111 #define DISPC_VID_ACCU0(n) DISPC_VID_REG(n, 0x002C)
112 #define DISPC_VID_ACCU1(n) DISPC_VID_REG(n, 0x0030)
114 /* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
115 #define DISPC_VID_FIR_COEF_H(n, i) DISPC_REG(0x00F0 + (n)*0x90 + (i)*0x8)
116 /* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
117 #define DISPC_VID_FIR_COEF_HV(n, i) DISPC_REG(0x00F4 + (n)*0x90 + (i)*0x8)
118 /* coef index i = {0, 1, 2, 3, 4} */
119 #define DISPC_VID_CONV_COEF(n, i) DISPC_REG(0x0130 + (n)*0x90 + (i)*0x4)
120 /* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
121 #define DISPC_VID_FIR_COEF_V(n, i) DISPC_REG(0x01E0 + (n)*0x20 + (i)*0x4)
123 #define DISPC_VID_PRELOAD(n) DISPC_REG(0x230 + (n)*0x04)
126 #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
127 DISPC_IRQ_OCP_ERR | \
128 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
129 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
130 DISPC_IRQ_SYNC_LOST | \
131 DISPC_IRQ_SYNC_LOST_DIGIT)
133 #define DISPC_MAX_NR_ISRS 8
135 struct omap_dispc_isr_data {
136 omap_dispc_isr_t isr;
137 void *arg;
138 u32 mask;
141 #define REG_GET(idx, start, end) \
142 FLD_GET(dispc_read_reg(idx), start, end)
144 #define REG_FLD_MOD(idx, val, start, end) \
145 dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
147 static const struct dispc_reg dispc_reg_att[] = { DISPC_GFX_ATTRIBUTES,
148 DISPC_VID_ATTRIBUTES(0),
149 DISPC_VID_ATTRIBUTES(1) };
151 struct dispc_irq_stats {
152 unsigned long last_reset;
153 unsigned irq_count;
154 unsigned irqs[32];
157 static struct {
158 void __iomem *base;
160 u32 fifo_size[3];
162 spinlock_t irq_lock;
163 u32 irq_error_mask;
164 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
165 u32 error_irqs;
166 struct work_struct error_work;
168 u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
170 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
171 spinlock_t irq_stats_lock;
172 struct dispc_irq_stats irq_stats;
173 #endif
174 } dispc;
176 static void _omap_dispc_set_irqs(void);
178 static inline void dispc_write_reg(const struct dispc_reg idx, u32 val)
180 __raw_writel(val, dispc.base + idx.idx);
183 static inline u32 dispc_read_reg(const struct dispc_reg idx)
185 return __raw_readl(dispc.base + idx.idx);
188 #define SR(reg) \
189 dispc.ctx[(DISPC_##reg).idx / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
190 #define RR(reg) \
191 dispc_write_reg(DISPC_##reg, dispc.ctx[(DISPC_##reg).idx / sizeof(u32)])
193 void dispc_save_context(void)
195 if (cpu_is_omap24xx())
196 return;
198 SR(SYSCONFIG);
199 SR(IRQENABLE);
200 SR(CONTROL);
201 SR(CONFIG);
202 SR(DEFAULT_COLOR0);
203 SR(DEFAULT_COLOR1);
204 SR(TRANS_COLOR0);
205 SR(TRANS_COLOR1);
206 SR(LINE_NUMBER);
207 SR(TIMING_H);
208 SR(TIMING_V);
209 SR(POL_FREQ);
210 SR(DIVISOR);
211 SR(GLOBAL_ALPHA);
212 SR(SIZE_DIG);
213 SR(SIZE_LCD);
215 SR(GFX_BA0);
216 SR(GFX_BA1);
217 SR(GFX_POSITION);
218 SR(GFX_SIZE);
219 SR(GFX_ATTRIBUTES);
220 SR(GFX_FIFO_THRESHOLD);
221 SR(GFX_ROW_INC);
222 SR(GFX_PIXEL_INC);
223 SR(GFX_WINDOW_SKIP);
224 SR(GFX_TABLE_BA);
226 SR(DATA_CYCLE1);
227 SR(DATA_CYCLE2);
228 SR(DATA_CYCLE3);
230 SR(CPR_COEF_R);
231 SR(CPR_COEF_G);
232 SR(CPR_COEF_B);
234 SR(GFX_PRELOAD);
236 /* VID1 */
237 SR(VID_BA0(0));
238 SR(VID_BA1(0));
239 SR(VID_POSITION(0));
240 SR(VID_SIZE(0));
241 SR(VID_ATTRIBUTES(0));
242 SR(VID_FIFO_THRESHOLD(0));
243 SR(VID_ROW_INC(0));
244 SR(VID_PIXEL_INC(0));
245 SR(VID_FIR(0));
246 SR(VID_PICTURE_SIZE(0));
247 SR(VID_ACCU0(0));
248 SR(VID_ACCU1(0));
250 SR(VID_FIR_COEF_H(0, 0));
251 SR(VID_FIR_COEF_H(0, 1));
252 SR(VID_FIR_COEF_H(0, 2));
253 SR(VID_FIR_COEF_H(0, 3));
254 SR(VID_FIR_COEF_H(0, 4));
255 SR(VID_FIR_COEF_H(0, 5));
256 SR(VID_FIR_COEF_H(0, 6));
257 SR(VID_FIR_COEF_H(0, 7));
259 SR(VID_FIR_COEF_HV(0, 0));
260 SR(VID_FIR_COEF_HV(0, 1));
261 SR(VID_FIR_COEF_HV(0, 2));
262 SR(VID_FIR_COEF_HV(0, 3));
263 SR(VID_FIR_COEF_HV(0, 4));
264 SR(VID_FIR_COEF_HV(0, 5));
265 SR(VID_FIR_COEF_HV(0, 6));
266 SR(VID_FIR_COEF_HV(0, 7));
268 SR(VID_CONV_COEF(0, 0));
269 SR(VID_CONV_COEF(0, 1));
270 SR(VID_CONV_COEF(0, 2));
271 SR(VID_CONV_COEF(0, 3));
272 SR(VID_CONV_COEF(0, 4));
274 SR(VID_FIR_COEF_V(0, 0));
275 SR(VID_FIR_COEF_V(0, 1));
276 SR(VID_FIR_COEF_V(0, 2));
277 SR(VID_FIR_COEF_V(0, 3));
278 SR(VID_FIR_COEF_V(0, 4));
279 SR(VID_FIR_COEF_V(0, 5));
280 SR(VID_FIR_COEF_V(0, 6));
281 SR(VID_FIR_COEF_V(0, 7));
283 SR(VID_PRELOAD(0));
285 /* VID2 */
286 SR(VID_BA0(1));
287 SR(VID_BA1(1));
288 SR(VID_POSITION(1));
289 SR(VID_SIZE(1));
290 SR(VID_ATTRIBUTES(1));
291 SR(VID_FIFO_THRESHOLD(1));
292 SR(VID_ROW_INC(1));
293 SR(VID_PIXEL_INC(1));
294 SR(VID_FIR(1));
295 SR(VID_PICTURE_SIZE(1));
296 SR(VID_ACCU0(1));
297 SR(VID_ACCU1(1));
299 SR(VID_FIR_COEF_H(1, 0));
300 SR(VID_FIR_COEF_H(1, 1));
301 SR(VID_FIR_COEF_H(1, 2));
302 SR(VID_FIR_COEF_H(1, 3));
303 SR(VID_FIR_COEF_H(1, 4));
304 SR(VID_FIR_COEF_H(1, 5));
305 SR(VID_FIR_COEF_H(1, 6));
306 SR(VID_FIR_COEF_H(1, 7));
308 SR(VID_FIR_COEF_HV(1, 0));
309 SR(VID_FIR_COEF_HV(1, 1));
310 SR(VID_FIR_COEF_HV(1, 2));
311 SR(VID_FIR_COEF_HV(1, 3));
312 SR(VID_FIR_COEF_HV(1, 4));
313 SR(VID_FIR_COEF_HV(1, 5));
314 SR(VID_FIR_COEF_HV(1, 6));
315 SR(VID_FIR_COEF_HV(1, 7));
317 SR(VID_CONV_COEF(1, 0));
318 SR(VID_CONV_COEF(1, 1));
319 SR(VID_CONV_COEF(1, 2));
320 SR(VID_CONV_COEF(1, 3));
321 SR(VID_CONV_COEF(1, 4));
323 SR(VID_FIR_COEF_V(1, 0));
324 SR(VID_FIR_COEF_V(1, 1));
325 SR(VID_FIR_COEF_V(1, 2));
326 SR(VID_FIR_COEF_V(1, 3));
327 SR(VID_FIR_COEF_V(1, 4));
328 SR(VID_FIR_COEF_V(1, 5));
329 SR(VID_FIR_COEF_V(1, 6));
330 SR(VID_FIR_COEF_V(1, 7));
332 SR(VID_PRELOAD(1));
335 void dispc_restore_context(void)
337 RR(SYSCONFIG);
338 RR(IRQENABLE);
339 /*RR(CONTROL);*/
340 RR(CONFIG);
341 RR(DEFAULT_COLOR0);
342 RR(DEFAULT_COLOR1);
343 RR(TRANS_COLOR0);
344 RR(TRANS_COLOR1);
345 RR(LINE_NUMBER);
346 RR(TIMING_H);
347 RR(TIMING_V);
348 RR(POL_FREQ);
349 RR(DIVISOR);
350 RR(GLOBAL_ALPHA);
351 RR(SIZE_DIG);
352 RR(SIZE_LCD);
354 RR(GFX_BA0);
355 RR(GFX_BA1);
356 RR(GFX_POSITION);
357 RR(GFX_SIZE);
358 RR(GFX_ATTRIBUTES);
359 RR(GFX_FIFO_THRESHOLD);
360 RR(GFX_ROW_INC);
361 RR(GFX_PIXEL_INC);
362 RR(GFX_WINDOW_SKIP);
363 RR(GFX_TABLE_BA);
365 RR(DATA_CYCLE1);
366 RR(DATA_CYCLE2);
367 RR(DATA_CYCLE3);
369 RR(CPR_COEF_R);
370 RR(CPR_COEF_G);
371 RR(CPR_COEF_B);
373 RR(GFX_PRELOAD);
375 /* VID1 */
376 RR(VID_BA0(0));
377 RR(VID_BA1(0));
378 RR(VID_POSITION(0));
379 RR(VID_SIZE(0));
380 RR(VID_ATTRIBUTES(0));
381 RR(VID_FIFO_THRESHOLD(0));
382 RR(VID_ROW_INC(0));
383 RR(VID_PIXEL_INC(0));
384 RR(VID_FIR(0));
385 RR(VID_PICTURE_SIZE(0));
386 RR(VID_ACCU0(0));
387 RR(VID_ACCU1(0));
389 RR(VID_FIR_COEF_H(0, 0));
390 RR(VID_FIR_COEF_H(0, 1));
391 RR(VID_FIR_COEF_H(0, 2));
392 RR(VID_FIR_COEF_H(0, 3));
393 RR(VID_FIR_COEF_H(0, 4));
394 RR(VID_FIR_COEF_H(0, 5));
395 RR(VID_FIR_COEF_H(0, 6));
396 RR(VID_FIR_COEF_H(0, 7));
398 RR(VID_FIR_COEF_HV(0, 0));
399 RR(VID_FIR_COEF_HV(0, 1));
400 RR(VID_FIR_COEF_HV(0, 2));
401 RR(VID_FIR_COEF_HV(0, 3));
402 RR(VID_FIR_COEF_HV(0, 4));
403 RR(VID_FIR_COEF_HV(0, 5));
404 RR(VID_FIR_COEF_HV(0, 6));
405 RR(VID_FIR_COEF_HV(0, 7));
407 RR(VID_CONV_COEF(0, 0));
408 RR(VID_CONV_COEF(0, 1));
409 RR(VID_CONV_COEF(0, 2));
410 RR(VID_CONV_COEF(0, 3));
411 RR(VID_CONV_COEF(0, 4));
413 RR(VID_FIR_COEF_V(0, 0));
414 RR(VID_FIR_COEF_V(0, 1));
415 RR(VID_FIR_COEF_V(0, 2));
416 RR(VID_FIR_COEF_V(0, 3));
417 RR(VID_FIR_COEF_V(0, 4));
418 RR(VID_FIR_COEF_V(0, 5));
419 RR(VID_FIR_COEF_V(0, 6));
420 RR(VID_FIR_COEF_V(0, 7));
422 RR(VID_PRELOAD(0));
424 /* VID2 */
425 RR(VID_BA0(1));
426 RR(VID_BA1(1));
427 RR(VID_POSITION(1));
428 RR(VID_SIZE(1));
429 RR(VID_ATTRIBUTES(1));
430 RR(VID_FIFO_THRESHOLD(1));
431 RR(VID_ROW_INC(1));
432 RR(VID_PIXEL_INC(1));
433 RR(VID_FIR(1));
434 RR(VID_PICTURE_SIZE(1));
435 RR(VID_ACCU0(1));
436 RR(VID_ACCU1(1));
438 RR(VID_FIR_COEF_H(1, 0));
439 RR(VID_FIR_COEF_H(1, 1));
440 RR(VID_FIR_COEF_H(1, 2));
441 RR(VID_FIR_COEF_H(1, 3));
442 RR(VID_FIR_COEF_H(1, 4));
443 RR(VID_FIR_COEF_H(1, 5));
444 RR(VID_FIR_COEF_H(1, 6));
445 RR(VID_FIR_COEF_H(1, 7));
447 RR(VID_FIR_COEF_HV(1, 0));
448 RR(VID_FIR_COEF_HV(1, 1));
449 RR(VID_FIR_COEF_HV(1, 2));
450 RR(VID_FIR_COEF_HV(1, 3));
451 RR(VID_FIR_COEF_HV(1, 4));
452 RR(VID_FIR_COEF_HV(1, 5));
453 RR(VID_FIR_COEF_HV(1, 6));
454 RR(VID_FIR_COEF_HV(1, 7));
456 RR(VID_CONV_COEF(1, 0));
457 RR(VID_CONV_COEF(1, 1));
458 RR(VID_CONV_COEF(1, 2));
459 RR(VID_CONV_COEF(1, 3));
460 RR(VID_CONV_COEF(1, 4));
462 RR(VID_FIR_COEF_V(1, 0));
463 RR(VID_FIR_COEF_V(1, 1));
464 RR(VID_FIR_COEF_V(1, 2));
465 RR(VID_FIR_COEF_V(1, 3));
466 RR(VID_FIR_COEF_V(1, 4));
467 RR(VID_FIR_COEF_V(1, 5));
468 RR(VID_FIR_COEF_V(1, 6));
469 RR(VID_FIR_COEF_V(1, 7));
471 RR(VID_PRELOAD(1));
473 /* enable last, because LCD & DIGIT enable are here */
474 RR(CONTROL);
477 #undef SR
478 #undef RR
480 static inline void enable_clocks(bool enable)
482 if (enable)
483 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
484 else
485 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
488 bool dispc_go_busy(enum omap_channel channel)
490 int bit;
492 if (channel == OMAP_DSS_CHANNEL_LCD)
493 bit = 5; /* GOLCD */
494 else
495 bit = 6; /* GODIGIT */
497 return REG_GET(DISPC_CONTROL, bit, bit) == 1;
500 void dispc_go(enum omap_channel channel)
502 int bit;
504 enable_clocks(1);
506 if (channel == OMAP_DSS_CHANNEL_LCD)
507 bit = 0; /* LCDENABLE */
508 else
509 bit = 1; /* DIGITALENABLE */
511 /* if the channel is not enabled, we don't need GO */
512 if (REG_GET(DISPC_CONTROL, bit, bit) == 0)
513 goto end;
515 if (channel == OMAP_DSS_CHANNEL_LCD)
516 bit = 5; /* GOLCD */
517 else
518 bit = 6; /* GODIGIT */
520 if (REG_GET(DISPC_CONTROL, bit, bit) == 1) {
521 DSSERR("GO bit not down for channel %d\n", channel);
522 goto end;
525 DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT");
527 REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
528 end:
529 enable_clocks(0);
532 static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
534 BUG_ON(plane == OMAP_DSS_GFX);
536 dispc_write_reg(DISPC_VID_FIR_COEF_H(plane-1, reg), value);
539 static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
541 BUG_ON(plane == OMAP_DSS_GFX);
543 dispc_write_reg(DISPC_VID_FIR_COEF_HV(plane-1, reg), value);
546 static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
548 BUG_ON(plane == OMAP_DSS_GFX);
550 dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
553 static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
554 int vscaleup, int five_taps)
556 /* Coefficients for horizontal up-sampling */
557 static const u32 coef_hup[8] = {
558 0x00800000,
559 0x0D7CF800,
560 0x1E70F5FF,
561 0x335FF5FE,
562 0xF74949F7,
563 0xF55F33FB,
564 0xF5701EFE,
565 0xF87C0DFF,
568 /* Coefficients for horizontal down-sampling */
569 static const u32 coef_hdown[8] = {
570 0x24382400,
571 0x28371FFE,
572 0x2C361BFB,
573 0x303516F9,
574 0x11343311,
575 0x1635300C,
576 0x1B362C08,
577 0x1F372804,
580 /* Coefficients for horizontal and vertical up-sampling */
581 static const u32 coef_hvup[2][8] = {
583 0x00800000,
584 0x037B02FF,
585 0x0C6F05FE,
586 0x205907FB,
587 0x00404000,
588 0x075920FE,
589 0x056F0CFF,
590 0x027B0300,
593 0x00800000,
594 0x0D7CF8FF,
595 0x1E70F5FE,
596 0x335FF5FB,
597 0xF7404000,
598 0xF55F33FE,
599 0xF5701EFF,
600 0xF87C0D00,
604 /* Coefficients for horizontal and vertical down-sampling */
605 static const u32 coef_hvdown[2][8] = {
607 0x24382400,
608 0x28391F04,
609 0x2D381B08,
610 0x3237170C,
611 0x123737F7,
612 0x173732F9,
613 0x1B382DFB,
614 0x1F3928FE,
617 0x24382400,
618 0x28371F04,
619 0x2C361B08,
620 0x3035160C,
621 0x113433F7,
622 0x163530F9,
623 0x1B362CFB,
624 0x1F3728FE,
628 /* Coefficients for vertical up-sampling */
629 static const u32 coef_vup[8] = {
630 0x00000000,
631 0x0000FF00,
632 0x0000FEFF,
633 0x0000FBFE,
634 0x000000F7,
635 0x0000FEFB,
636 0x0000FFFE,
637 0x000000FF,
641 /* Coefficients for vertical down-sampling */
642 static const u32 coef_vdown[8] = {
643 0x00000000,
644 0x000004FE,
645 0x000008FB,
646 0x00000CF9,
647 0x0000F711,
648 0x0000F90C,
649 0x0000FB08,
650 0x0000FE04,
653 const u32 *h_coef;
654 const u32 *hv_coef;
655 const u32 *hv_coef_mod;
656 const u32 *v_coef;
657 int i;
659 if (hscaleup)
660 h_coef = coef_hup;
661 else
662 h_coef = coef_hdown;
664 if (vscaleup) {
665 hv_coef = coef_hvup[five_taps];
666 v_coef = coef_vup;
668 if (hscaleup)
669 hv_coef_mod = NULL;
670 else
671 hv_coef_mod = coef_hvdown[five_taps];
672 } else {
673 hv_coef = coef_hvdown[five_taps];
674 v_coef = coef_vdown;
676 if (hscaleup)
677 hv_coef_mod = coef_hvup[five_taps];
678 else
679 hv_coef_mod = NULL;
682 for (i = 0; i < 8; i++) {
683 u32 h, hv;
685 h = h_coef[i];
687 hv = hv_coef[i];
689 if (hv_coef_mod) {
690 hv &= 0xffffff00;
691 hv |= (hv_coef_mod[i] & 0xff);
694 _dispc_write_firh_reg(plane, i, h);
695 _dispc_write_firhv_reg(plane, i, hv);
698 if (!five_taps)
699 return;
701 for (i = 0; i < 8; i++) {
702 u32 v;
703 v = v_coef[i];
704 _dispc_write_firv_reg(plane, i, v);
708 static void _dispc_setup_color_conv_coef(void)
710 const struct color_conv_coef {
711 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
712 int full_range;
713 } ctbl_bt601_5 = {
714 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
717 const struct color_conv_coef *ct;
719 #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
721 ct = &ctbl_bt601_5;
723 dispc_write_reg(DISPC_VID_CONV_COEF(0, 0), CVAL(ct->rcr, ct->ry));
724 dispc_write_reg(DISPC_VID_CONV_COEF(0, 1), CVAL(ct->gy, ct->rcb));
725 dispc_write_reg(DISPC_VID_CONV_COEF(0, 2), CVAL(ct->gcb, ct->gcr));
726 dispc_write_reg(DISPC_VID_CONV_COEF(0, 3), CVAL(ct->bcr, ct->by));
727 dispc_write_reg(DISPC_VID_CONV_COEF(0, 4), CVAL(0, ct->bcb));
729 dispc_write_reg(DISPC_VID_CONV_COEF(1, 0), CVAL(ct->rcr, ct->ry));
730 dispc_write_reg(DISPC_VID_CONV_COEF(1, 1), CVAL(ct->gy, ct->rcb));
731 dispc_write_reg(DISPC_VID_CONV_COEF(1, 2), CVAL(ct->gcb, ct->gcr));
732 dispc_write_reg(DISPC_VID_CONV_COEF(1, 3), CVAL(ct->bcr, ct->by));
733 dispc_write_reg(DISPC_VID_CONV_COEF(1, 4), CVAL(0, ct->bcb));
735 #undef CVAL
737 REG_FLD_MOD(DISPC_VID_ATTRIBUTES(0), ct->full_range, 11, 11);
738 REG_FLD_MOD(DISPC_VID_ATTRIBUTES(1), ct->full_range, 11, 11);
742 static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
744 const struct dispc_reg ba0_reg[] = { DISPC_GFX_BA0,
745 DISPC_VID_BA0(0),
746 DISPC_VID_BA0(1) };
748 dispc_write_reg(ba0_reg[plane], paddr);
751 static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr)
753 const struct dispc_reg ba1_reg[] = { DISPC_GFX_BA1,
754 DISPC_VID_BA1(0),
755 DISPC_VID_BA1(1) };
757 dispc_write_reg(ba1_reg[plane], paddr);
760 static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
762 const struct dispc_reg pos_reg[] = { DISPC_GFX_POSITION,
763 DISPC_VID_POSITION(0),
764 DISPC_VID_POSITION(1) };
766 u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
767 dispc_write_reg(pos_reg[plane], val);
770 static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
772 const struct dispc_reg siz_reg[] = { DISPC_GFX_SIZE,
773 DISPC_VID_PICTURE_SIZE(0),
774 DISPC_VID_PICTURE_SIZE(1) };
775 u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
776 dispc_write_reg(siz_reg[plane], val);
779 static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
781 u32 val;
782 const struct dispc_reg vsi_reg[] = { DISPC_VID_SIZE(0),
783 DISPC_VID_SIZE(1) };
785 BUG_ON(plane == OMAP_DSS_GFX);
787 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
788 dispc_write_reg(vsi_reg[plane-1], val);
791 static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
794 BUG_ON(plane == OMAP_DSS_VIDEO1);
796 if (cpu_is_omap24xx())
797 return;
799 if (plane == OMAP_DSS_GFX)
800 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
801 else if (plane == OMAP_DSS_VIDEO2)
802 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16);
805 static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
807 const struct dispc_reg ri_reg[] = { DISPC_GFX_PIXEL_INC,
808 DISPC_VID_PIXEL_INC(0),
809 DISPC_VID_PIXEL_INC(1) };
811 dispc_write_reg(ri_reg[plane], inc);
814 static void _dispc_set_row_inc(enum omap_plane plane, s32 inc)
816 const struct dispc_reg ri_reg[] = { DISPC_GFX_ROW_INC,
817 DISPC_VID_ROW_INC(0),
818 DISPC_VID_ROW_INC(1) };
820 dispc_write_reg(ri_reg[plane], inc);
823 static void _dispc_set_color_mode(enum omap_plane plane,
824 enum omap_color_mode color_mode)
826 u32 m = 0;
828 switch (color_mode) {
829 case OMAP_DSS_COLOR_CLUT1:
830 m = 0x0; break;
831 case OMAP_DSS_COLOR_CLUT2:
832 m = 0x1; break;
833 case OMAP_DSS_COLOR_CLUT4:
834 m = 0x2; break;
835 case OMAP_DSS_COLOR_CLUT8:
836 m = 0x3; break;
837 case OMAP_DSS_COLOR_RGB12U:
838 m = 0x4; break;
839 case OMAP_DSS_COLOR_ARGB16:
840 m = 0x5; break;
841 case OMAP_DSS_COLOR_RGB16:
842 m = 0x6; break;
843 case OMAP_DSS_COLOR_RGB24U:
844 m = 0x8; break;
845 case OMAP_DSS_COLOR_RGB24P:
846 m = 0x9; break;
847 case OMAP_DSS_COLOR_YUV2:
848 m = 0xa; break;
849 case OMAP_DSS_COLOR_UYVY:
850 m = 0xb; break;
851 case OMAP_DSS_COLOR_ARGB32:
852 m = 0xc; break;
853 case OMAP_DSS_COLOR_RGBA32:
854 m = 0xd; break;
855 case OMAP_DSS_COLOR_RGBX32:
856 m = 0xe; break;
857 default:
858 BUG(); break;
861 REG_FLD_MOD(dispc_reg_att[plane], m, 4, 1);
864 static void _dispc_set_channel_out(enum omap_plane plane,
865 enum omap_channel channel)
867 int shift;
868 u32 val;
870 switch (plane) {
871 case OMAP_DSS_GFX:
872 shift = 8;
873 break;
874 case OMAP_DSS_VIDEO1:
875 case OMAP_DSS_VIDEO2:
876 shift = 16;
877 break;
878 default:
879 BUG();
880 return;
883 val = dispc_read_reg(dispc_reg_att[plane]);
884 val = FLD_MOD(val, channel, shift, shift);
885 dispc_write_reg(dispc_reg_att[plane], val);
888 void dispc_set_burst_size(enum omap_plane plane,
889 enum omap_burst_size burst_size)
891 int shift;
892 u32 val;
894 enable_clocks(1);
896 switch (plane) {
897 case OMAP_DSS_GFX:
898 shift = 6;
899 break;
900 case OMAP_DSS_VIDEO1:
901 case OMAP_DSS_VIDEO2:
902 shift = 14;
903 break;
904 default:
905 BUG();
906 return;
909 val = dispc_read_reg(dispc_reg_att[plane]);
910 val = FLD_MOD(val, burst_size, shift+1, shift);
911 dispc_write_reg(dispc_reg_att[plane], val);
913 enable_clocks(0);
916 static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
918 u32 val;
920 BUG_ON(plane == OMAP_DSS_GFX);
922 val = dispc_read_reg(dispc_reg_att[plane]);
923 val = FLD_MOD(val, enable, 9, 9);
924 dispc_write_reg(dispc_reg_att[plane], val);
927 void dispc_enable_replication(enum omap_plane plane, bool enable)
929 int bit;
931 if (plane == OMAP_DSS_GFX)
932 bit = 5;
933 else
934 bit = 10;
936 enable_clocks(1);
937 REG_FLD_MOD(dispc_reg_att[plane], enable, bit, bit);
938 enable_clocks(0);
941 void dispc_set_lcd_size(u16 width, u16 height)
943 u32 val;
944 BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
945 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
946 enable_clocks(1);
947 dispc_write_reg(DISPC_SIZE_LCD, val);
948 enable_clocks(0);
951 void dispc_set_digit_size(u16 width, u16 height)
953 u32 val;
954 BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
955 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
956 enable_clocks(1);
957 dispc_write_reg(DISPC_SIZE_DIG, val);
958 enable_clocks(0);
961 static void dispc_read_plane_fifo_sizes(void)
963 const struct dispc_reg fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
964 DISPC_VID_FIFO_SIZE_STATUS(0),
965 DISPC_VID_FIFO_SIZE_STATUS(1) };
966 u32 size;
967 int plane;
969 enable_clocks(1);
971 for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
972 if (cpu_is_omap24xx())
973 size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 8, 0);
974 else if (cpu_is_omap34xx())
975 size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 10, 0);
976 else
977 BUG();
979 dispc.fifo_size[plane] = size;
982 enable_clocks(0);
985 u32 dispc_get_plane_fifo_size(enum omap_plane plane)
987 return dispc.fifo_size[plane];
990 void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
992 const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
993 DISPC_VID_FIFO_THRESHOLD(0),
994 DISPC_VID_FIFO_THRESHOLD(1) };
995 enable_clocks(1);
997 DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
998 plane,
999 REG_GET(ftrs_reg[plane], 11, 0),
1000 REG_GET(ftrs_reg[plane], 27, 16),
1001 low, high);
1003 if (cpu_is_omap24xx())
1004 dispc_write_reg(ftrs_reg[plane],
1005 FLD_VAL(high, 24, 16) | FLD_VAL(low, 8, 0));
1006 else
1007 dispc_write_reg(ftrs_reg[plane],
1008 FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0));
1010 enable_clocks(0);
1013 void dispc_enable_fifomerge(bool enable)
1015 enable_clocks(1);
1017 DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1018 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
1020 enable_clocks(0);
1023 static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
1025 u32 val;
1026 const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0),
1027 DISPC_VID_FIR(1) };
1029 BUG_ON(plane == OMAP_DSS_GFX);
1031 if (cpu_is_omap24xx())
1032 val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0);
1033 else
1034 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1035 dispc_write_reg(fir_reg[plane-1], val);
1038 static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
1040 u32 val;
1041 const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
1042 DISPC_VID_ACCU0(1) };
1044 BUG_ON(plane == OMAP_DSS_GFX);
1046 val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
1047 dispc_write_reg(ac0_reg[plane-1], val);
1050 static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
1052 u32 val;
1053 const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
1054 DISPC_VID_ACCU1(1) };
1056 BUG_ON(plane == OMAP_DSS_GFX);
1058 val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
1059 dispc_write_reg(ac1_reg[plane-1], val);
1063 static void _dispc_set_scaling(enum omap_plane plane,
1064 u16 orig_width, u16 orig_height,
1065 u16 out_width, u16 out_height,
1066 bool ilace, bool five_taps,
1067 bool fieldmode)
1069 int fir_hinc;
1070 int fir_vinc;
1071 int hscaleup, vscaleup;
1072 int accu0 = 0;
1073 int accu1 = 0;
1074 u32 l;
1076 BUG_ON(plane == OMAP_DSS_GFX);
1078 hscaleup = orig_width <= out_width;
1079 vscaleup = orig_height <= out_height;
1081 _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps);
1083 if (!orig_width || orig_width == out_width)
1084 fir_hinc = 0;
1085 else
1086 fir_hinc = 1024 * orig_width / out_width;
1088 if (!orig_height || orig_height == out_height)
1089 fir_vinc = 0;
1090 else
1091 fir_vinc = 1024 * orig_height / out_height;
1093 _dispc_set_fir(plane, fir_hinc, fir_vinc);
1095 l = dispc_read_reg(dispc_reg_att[plane]);
1096 l &= ~((0x0f << 5) | (0x3 << 21));
1098 l |= fir_hinc ? (1 << 5) : 0;
1099 l |= fir_vinc ? (1 << 6) : 0;
1101 l |= hscaleup ? 0 : (1 << 7);
1102 l |= vscaleup ? 0 : (1 << 8);
1104 l |= five_taps ? (1 << 21) : 0;
1105 l |= five_taps ? (1 << 22) : 0;
1107 dispc_write_reg(dispc_reg_att[plane], l);
1110 * field 0 = even field = bottom field
1111 * field 1 = odd field = top field
1113 if (ilace && !fieldmode) {
1114 accu1 = 0;
1115 accu0 = (fir_vinc / 2) & 0x3ff;
1116 if (accu0 >= 1024/2) {
1117 accu1 = 1024/2;
1118 accu0 -= accu1;
1122 _dispc_set_vid_accu0(plane, 0, accu0);
1123 _dispc_set_vid_accu1(plane, 0, accu1);
1126 static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
1127 bool mirroring, enum omap_color_mode color_mode)
1129 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1130 color_mode == OMAP_DSS_COLOR_UYVY) {
1131 int vidrot = 0;
1133 if (mirroring) {
1134 switch (rotation) {
1135 case OMAP_DSS_ROT_0:
1136 vidrot = 2;
1137 break;
1138 case OMAP_DSS_ROT_90:
1139 vidrot = 1;
1140 break;
1141 case OMAP_DSS_ROT_180:
1142 vidrot = 0;
1143 break;
1144 case OMAP_DSS_ROT_270:
1145 vidrot = 3;
1146 break;
1148 } else {
1149 switch (rotation) {
1150 case OMAP_DSS_ROT_0:
1151 vidrot = 0;
1152 break;
1153 case OMAP_DSS_ROT_90:
1154 vidrot = 1;
1155 break;
1156 case OMAP_DSS_ROT_180:
1157 vidrot = 2;
1158 break;
1159 case OMAP_DSS_ROT_270:
1160 vidrot = 3;
1161 break;
1165 REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
1167 if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
1168 REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
1169 else
1170 REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
1171 } else {
1172 REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
1173 REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
1177 static int color_mode_to_bpp(enum omap_color_mode color_mode)
1179 switch (color_mode) {
1180 case OMAP_DSS_COLOR_CLUT1:
1181 return 1;
1182 case OMAP_DSS_COLOR_CLUT2:
1183 return 2;
1184 case OMAP_DSS_COLOR_CLUT4:
1185 return 4;
1186 case OMAP_DSS_COLOR_CLUT8:
1187 return 8;
1188 case OMAP_DSS_COLOR_RGB12U:
1189 case OMAP_DSS_COLOR_RGB16:
1190 case OMAP_DSS_COLOR_ARGB16:
1191 case OMAP_DSS_COLOR_YUV2:
1192 case OMAP_DSS_COLOR_UYVY:
1193 return 16;
1194 case OMAP_DSS_COLOR_RGB24P:
1195 return 24;
1196 case OMAP_DSS_COLOR_RGB24U:
1197 case OMAP_DSS_COLOR_ARGB32:
1198 case OMAP_DSS_COLOR_RGBA32:
1199 case OMAP_DSS_COLOR_RGBX32:
1200 return 32;
1201 default:
1202 BUG();
1206 static s32 pixinc(int pixels, u8 ps)
1208 if (pixels == 1)
1209 return 1;
1210 else if (pixels > 1)
1211 return 1 + (pixels - 1) * ps;
1212 else if (pixels < 0)
1213 return 1 - (-pixels + 1) * ps;
1214 else
1215 BUG();
1218 static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
1219 u16 screen_width,
1220 u16 width, u16 height,
1221 enum omap_color_mode color_mode, bool fieldmode,
1222 unsigned int field_offset,
1223 unsigned *offset0, unsigned *offset1,
1224 s32 *row_inc, s32 *pix_inc)
1226 u8 ps;
1228 /* FIXME CLUT formats */
1229 switch (color_mode) {
1230 case OMAP_DSS_COLOR_CLUT1:
1231 case OMAP_DSS_COLOR_CLUT2:
1232 case OMAP_DSS_COLOR_CLUT4:
1233 case OMAP_DSS_COLOR_CLUT8:
1234 BUG();
1235 return;
1236 case OMAP_DSS_COLOR_YUV2:
1237 case OMAP_DSS_COLOR_UYVY:
1238 ps = 4;
1239 break;
1240 default:
1241 ps = color_mode_to_bpp(color_mode) / 8;
1242 break;
1245 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1246 width, height);
1249 * field 0 = even field = bottom field
1250 * field 1 = odd field = top field
1252 switch (rotation + mirror * 4) {
1253 case OMAP_DSS_ROT_0:
1254 case OMAP_DSS_ROT_180:
1256 * If the pixel format is YUV or UYVY divide the width
1257 * of the image by 2 for 0 and 180 degree rotation.
1259 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1260 color_mode == OMAP_DSS_COLOR_UYVY)
1261 width = width >> 1;
1262 case OMAP_DSS_ROT_90:
1263 case OMAP_DSS_ROT_270:
1264 *offset1 = 0;
1265 if (field_offset)
1266 *offset0 = field_offset * screen_width * ps;
1267 else
1268 *offset0 = 0;
1270 *row_inc = pixinc(1 + (screen_width - width) +
1271 (fieldmode ? screen_width : 0),
1272 ps);
1273 *pix_inc = pixinc(1, ps);
1274 break;
1276 case OMAP_DSS_ROT_0 + 4:
1277 case OMAP_DSS_ROT_180 + 4:
1278 /* If the pixel format is YUV or UYVY divide the width
1279 * of the image by 2 for 0 degree and 180 degree
1281 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1282 color_mode == OMAP_DSS_COLOR_UYVY)
1283 width = width >> 1;
1284 case OMAP_DSS_ROT_90 + 4:
1285 case OMAP_DSS_ROT_270 + 4:
1286 *offset1 = 0;
1287 if (field_offset)
1288 *offset0 = field_offset * screen_width * ps;
1289 else
1290 *offset0 = 0;
1291 *row_inc = pixinc(1 - (screen_width + width) -
1292 (fieldmode ? screen_width : 0),
1293 ps);
1294 *pix_inc = pixinc(1, ps);
1295 break;
1297 default:
1298 BUG();
1302 static void calc_dma_rotation_offset(u8 rotation, bool mirror,
1303 u16 screen_width,
1304 u16 width, u16 height,
1305 enum omap_color_mode color_mode, bool fieldmode,
1306 unsigned int field_offset,
1307 unsigned *offset0, unsigned *offset1,
1308 s32 *row_inc, s32 *pix_inc)
1310 u8 ps;
1311 u16 fbw, fbh;
1313 /* FIXME CLUT formats */
1314 switch (color_mode) {
1315 case OMAP_DSS_COLOR_CLUT1:
1316 case OMAP_DSS_COLOR_CLUT2:
1317 case OMAP_DSS_COLOR_CLUT4:
1318 case OMAP_DSS_COLOR_CLUT8:
1319 BUG();
1320 return;
1321 default:
1322 ps = color_mode_to_bpp(color_mode) / 8;
1323 break;
1326 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1327 width, height);
1329 /* width & height are overlay sizes, convert to fb sizes */
1331 if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) {
1332 fbw = width;
1333 fbh = height;
1334 } else {
1335 fbw = height;
1336 fbh = width;
1340 * field 0 = even field = bottom field
1341 * field 1 = odd field = top field
1343 switch (rotation + mirror * 4) {
1344 case OMAP_DSS_ROT_0:
1345 *offset1 = 0;
1346 if (field_offset)
1347 *offset0 = *offset1 + field_offset * screen_width * ps;
1348 else
1349 *offset0 = *offset1;
1350 *row_inc = pixinc(1 + (screen_width - fbw) +
1351 (fieldmode ? screen_width : 0),
1352 ps);
1353 *pix_inc = pixinc(1, ps);
1354 break;
1355 case OMAP_DSS_ROT_90:
1356 *offset1 = screen_width * (fbh - 1) * ps;
1357 if (field_offset)
1358 *offset0 = *offset1 + field_offset * ps;
1359 else
1360 *offset0 = *offset1;
1361 *row_inc = pixinc(screen_width * (fbh - 1) + 1 +
1362 (fieldmode ? 1 : 0), ps);
1363 *pix_inc = pixinc(-screen_width, ps);
1364 break;
1365 case OMAP_DSS_ROT_180:
1366 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1367 if (field_offset)
1368 *offset0 = *offset1 - field_offset * screen_width * ps;
1369 else
1370 *offset0 = *offset1;
1371 *row_inc = pixinc(-1 -
1372 (screen_width - fbw) -
1373 (fieldmode ? screen_width : 0),
1374 ps);
1375 *pix_inc = pixinc(-1, ps);
1376 break;
1377 case OMAP_DSS_ROT_270:
1378 *offset1 = (fbw - 1) * ps;
1379 if (field_offset)
1380 *offset0 = *offset1 - field_offset * ps;
1381 else
1382 *offset0 = *offset1;
1383 *row_inc = pixinc(-screen_width * (fbh - 1) - 1 -
1384 (fieldmode ? 1 : 0), ps);
1385 *pix_inc = pixinc(screen_width, ps);
1386 break;
1388 /* mirroring */
1389 case OMAP_DSS_ROT_0 + 4:
1390 *offset1 = (fbw - 1) * ps;
1391 if (field_offset)
1392 *offset0 = *offset1 + field_offset * screen_width * ps;
1393 else
1394 *offset0 = *offset1;
1395 *row_inc = pixinc(screen_width * 2 - 1 +
1396 (fieldmode ? screen_width : 0),
1397 ps);
1398 *pix_inc = pixinc(-1, ps);
1399 break;
1401 case OMAP_DSS_ROT_90 + 4:
1402 *offset1 = 0;
1403 if (field_offset)
1404 *offset0 = *offset1 + field_offset * ps;
1405 else
1406 *offset0 = *offset1;
1407 *row_inc = pixinc(-screen_width * (fbh - 1) + 1 +
1408 (fieldmode ? 1 : 0),
1409 ps);
1410 *pix_inc = pixinc(screen_width, ps);
1411 break;
1413 case OMAP_DSS_ROT_180 + 4:
1414 *offset1 = screen_width * (fbh - 1) * ps;
1415 if (field_offset)
1416 *offset0 = *offset1 - field_offset * screen_width * ps;
1417 else
1418 *offset0 = *offset1;
1419 *row_inc = pixinc(1 - screen_width * 2 -
1420 (fieldmode ? screen_width : 0),
1421 ps);
1422 *pix_inc = pixinc(1, ps);
1423 break;
1425 case OMAP_DSS_ROT_270 + 4:
1426 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1427 if (field_offset)
1428 *offset0 = *offset1 - field_offset * ps;
1429 else
1430 *offset0 = *offset1;
1431 *row_inc = pixinc(screen_width * (fbh - 1) - 1 -
1432 (fieldmode ? 1 : 0),
1433 ps);
1434 *pix_inc = pixinc(-screen_width, ps);
1435 break;
1437 default:
1438 BUG();
1442 static unsigned long calc_fclk_five_taps(u16 width, u16 height,
1443 u16 out_width, u16 out_height, enum omap_color_mode color_mode)
1445 u32 fclk = 0;
1446 /* FIXME venc pclk? */
1447 u64 tmp, pclk = dispc_pclk_rate();
1449 if (height > out_height) {
1450 /* FIXME get real display PPL */
1451 unsigned int ppl = 800;
1453 tmp = pclk * height * out_width;
1454 do_div(tmp, 2 * out_height * ppl);
1455 fclk = tmp;
1457 if (height > 2 * out_height) {
1458 if (ppl == out_width)
1459 return 0;
1461 tmp = pclk * (height - 2 * out_height) * out_width;
1462 do_div(tmp, 2 * out_height * (ppl - out_width));
1463 fclk = max(fclk, (u32) tmp);
1467 if (width > out_width) {
1468 tmp = pclk * width;
1469 do_div(tmp, out_width);
1470 fclk = max(fclk, (u32) tmp);
1472 if (color_mode == OMAP_DSS_COLOR_RGB24U)
1473 fclk <<= 1;
1476 return fclk;
1479 static unsigned long calc_fclk(u16 width, u16 height,
1480 u16 out_width, u16 out_height)
1482 unsigned int hf, vf;
1485 * FIXME how to determine the 'A' factor
1486 * for the no downscaling case ?
1489 if (width > 3 * out_width)
1490 hf = 4;
1491 else if (width > 2 * out_width)
1492 hf = 3;
1493 else if (width > out_width)
1494 hf = 2;
1495 else
1496 hf = 1;
1498 if (height > out_height)
1499 vf = 2;
1500 else
1501 vf = 1;
1503 /* FIXME venc pclk? */
1504 return dispc_pclk_rate() * vf * hf;
1507 void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
1509 enable_clocks(1);
1510 _dispc_set_channel_out(plane, channel_out);
1511 enable_clocks(0);
1514 static int _dispc_setup_plane(enum omap_plane plane,
1515 u32 paddr, u16 screen_width,
1516 u16 pos_x, u16 pos_y,
1517 u16 width, u16 height,
1518 u16 out_width, u16 out_height,
1519 enum omap_color_mode color_mode,
1520 bool ilace,
1521 enum omap_dss_rotation_type rotation_type,
1522 u8 rotation, int mirror,
1523 u8 global_alpha)
1525 const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
1526 bool five_taps = 0;
1527 bool fieldmode = 0;
1528 int cconv = 0;
1529 unsigned offset0, offset1;
1530 s32 row_inc;
1531 s32 pix_inc;
1532 u16 frame_height = height;
1533 unsigned int field_offset = 0;
1535 if (paddr == 0)
1536 return -EINVAL;
1538 if (ilace && height == out_height)
1539 fieldmode = 1;
1541 if (ilace) {
1542 if (fieldmode)
1543 height /= 2;
1544 pos_y /= 2;
1545 out_height /= 2;
1547 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
1548 "out_height %d\n",
1549 height, pos_y, out_height);
1552 if (plane == OMAP_DSS_GFX) {
1553 if (width != out_width || height != out_height)
1554 return -EINVAL;
1556 switch (color_mode) {
1557 case OMAP_DSS_COLOR_ARGB16:
1558 case OMAP_DSS_COLOR_ARGB32:
1559 case OMAP_DSS_COLOR_RGBA32:
1560 case OMAP_DSS_COLOR_RGBX32:
1561 if (cpu_is_omap24xx())
1562 return -EINVAL;
1563 /* fall through */
1564 case OMAP_DSS_COLOR_RGB12U:
1565 case OMAP_DSS_COLOR_RGB16:
1566 case OMAP_DSS_COLOR_RGB24P:
1567 case OMAP_DSS_COLOR_RGB24U:
1568 break;
1570 default:
1571 return -EINVAL;
1573 } else {
1574 /* video plane */
1576 unsigned long fclk = 0;
1578 if (out_width < width / maxdownscale ||
1579 out_width > width * 8)
1580 return -EINVAL;
1582 if (out_height < height / maxdownscale ||
1583 out_height > height * 8)
1584 return -EINVAL;
1586 switch (color_mode) {
1587 case OMAP_DSS_COLOR_RGBX32:
1588 case OMAP_DSS_COLOR_RGB12U:
1589 if (cpu_is_omap24xx())
1590 return -EINVAL;
1591 /* fall through */
1592 case OMAP_DSS_COLOR_RGB16:
1593 case OMAP_DSS_COLOR_RGB24P:
1594 case OMAP_DSS_COLOR_RGB24U:
1595 break;
1597 case OMAP_DSS_COLOR_ARGB16:
1598 case OMAP_DSS_COLOR_ARGB32:
1599 case OMAP_DSS_COLOR_RGBA32:
1600 if (cpu_is_omap24xx())
1601 return -EINVAL;
1602 if (plane == OMAP_DSS_VIDEO1)
1603 return -EINVAL;
1604 break;
1606 case OMAP_DSS_COLOR_YUV2:
1607 case OMAP_DSS_COLOR_UYVY:
1608 cconv = 1;
1609 break;
1611 default:
1612 return -EINVAL;
1615 /* Must use 5-tap filter? */
1616 five_taps = height > out_height * 2;
1618 if (!five_taps) {
1619 fclk = calc_fclk(width, height,
1620 out_width, out_height);
1622 /* Try 5-tap filter if 3-tap fclk is too high */
1623 if (cpu_is_omap34xx() && height > out_height &&
1624 fclk > dispc_fclk_rate())
1625 five_taps = true;
1628 if (width > (2048 >> five_taps)) {
1629 DSSERR("failed to set up scaling, fclk too low\n");
1630 return -EINVAL;
1633 if (five_taps)
1634 fclk = calc_fclk_five_taps(width, height,
1635 out_width, out_height, color_mode);
1637 DSSDBG("required fclk rate = %lu Hz\n", fclk);
1638 DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
1640 if (!fclk || fclk > dispc_fclk_rate()) {
1641 DSSERR("failed to set up scaling, "
1642 "required fclk rate = %lu Hz, "
1643 "current fclk rate = %lu Hz\n",
1644 fclk, dispc_fclk_rate());
1645 return -EINVAL;
1649 if (ilace && !fieldmode) {
1651 * when downscaling the bottom field may have to start several
1652 * source lines below the top field. Unfortunately ACCUI
1653 * registers will only hold the fractional part of the offset
1654 * so the integer part must be added to the base address of the
1655 * bottom field.
1657 if (!height || height == out_height)
1658 field_offset = 0;
1659 else
1660 field_offset = height / out_height / 2;
1663 /* Fields are independent but interleaved in memory. */
1664 if (fieldmode)
1665 field_offset = 1;
1667 if (rotation_type == OMAP_DSS_ROT_DMA)
1668 calc_dma_rotation_offset(rotation, mirror,
1669 screen_width, width, frame_height, color_mode,
1670 fieldmode, field_offset,
1671 &offset0, &offset1, &row_inc, &pix_inc);
1672 else
1673 calc_vrfb_rotation_offset(rotation, mirror,
1674 screen_width, width, frame_height, color_mode,
1675 fieldmode, field_offset,
1676 &offset0, &offset1, &row_inc, &pix_inc);
1678 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
1679 offset0, offset1, row_inc, pix_inc);
1681 _dispc_set_color_mode(plane, color_mode);
1683 _dispc_set_plane_ba0(plane, paddr + offset0);
1684 _dispc_set_plane_ba1(plane, paddr + offset1);
1686 _dispc_set_row_inc(plane, row_inc);
1687 _dispc_set_pix_inc(plane, pix_inc);
1689 DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height,
1690 out_width, out_height);
1692 _dispc_set_plane_pos(plane, pos_x, pos_y);
1694 _dispc_set_pic_size(plane, width, height);
1696 if (plane != OMAP_DSS_GFX) {
1697 _dispc_set_scaling(plane, width, height,
1698 out_width, out_height,
1699 ilace, five_taps, fieldmode);
1700 _dispc_set_vid_size(plane, out_width, out_height);
1701 _dispc_set_vid_color_conv(plane, cconv);
1704 _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
1706 if (plane != OMAP_DSS_VIDEO1)
1707 _dispc_setup_global_alpha(plane, global_alpha);
1709 return 0;
1712 static void _dispc_enable_plane(enum omap_plane plane, bool enable)
1714 REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 0, 0);
1717 static void dispc_disable_isr(void *data, u32 mask)
1719 struct completion *compl = data;
1720 complete(compl);
1723 static void _enable_lcd_out(bool enable)
1725 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
1728 static void dispc_enable_lcd_out(bool enable)
1730 struct completion frame_done_completion;
1731 bool is_on;
1732 int r;
1734 enable_clocks(1);
1736 /* When we disable LCD output, we need to wait until frame is done.
1737 * Otherwise the DSS is still working, and turning off the clocks
1738 * prevents DSS from going to OFF mode */
1739 is_on = REG_GET(DISPC_CONTROL, 0, 0);
1741 if (!enable && is_on) {
1742 init_completion(&frame_done_completion);
1744 r = omap_dispc_register_isr(dispc_disable_isr,
1745 &frame_done_completion,
1746 DISPC_IRQ_FRAMEDONE);
1748 if (r)
1749 DSSERR("failed to register FRAMEDONE isr\n");
1752 _enable_lcd_out(enable);
1754 if (!enable && is_on) {
1755 if (!wait_for_completion_timeout(&frame_done_completion,
1756 msecs_to_jiffies(100)))
1757 DSSERR("timeout waiting for FRAME DONE\n");
1759 r = omap_dispc_unregister_isr(dispc_disable_isr,
1760 &frame_done_completion,
1761 DISPC_IRQ_FRAMEDONE);
1763 if (r)
1764 DSSERR("failed to unregister FRAMEDONE isr\n");
1767 enable_clocks(0);
1770 static void _enable_digit_out(bool enable)
1772 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
1775 static void dispc_enable_digit_out(bool enable)
1777 struct completion frame_done_completion;
1778 int r;
1780 enable_clocks(1);
1782 if (REG_GET(DISPC_CONTROL, 1, 1) == enable) {
1783 enable_clocks(0);
1784 return;
1787 if (enable) {
1788 unsigned long flags;
1789 /* When we enable digit output, we'll get an extra digit
1790 * sync lost interrupt, that we need to ignore */
1791 spin_lock_irqsave(&dispc.irq_lock, flags);
1792 dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
1793 _omap_dispc_set_irqs();
1794 spin_unlock_irqrestore(&dispc.irq_lock, flags);
1797 /* When we disable digit output, we need to wait until fields are done.
1798 * Otherwise the DSS is still working, and turning off the clocks
1799 * prevents DSS from going to OFF mode. And when enabling, we need to
1800 * wait for the extra sync losts */
1801 init_completion(&frame_done_completion);
1803 r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion,
1804 DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
1805 if (r)
1806 DSSERR("failed to register EVSYNC isr\n");
1808 _enable_digit_out(enable);
1810 /* XXX I understand from TRM that we should only wait for the
1811 * current field to complete. But it seems we have to wait
1812 * for both fields */
1813 if (!wait_for_completion_timeout(&frame_done_completion,
1814 msecs_to_jiffies(100)))
1815 DSSERR("timeout waiting for EVSYNC\n");
1817 if (!wait_for_completion_timeout(&frame_done_completion,
1818 msecs_to_jiffies(100)))
1819 DSSERR("timeout waiting for EVSYNC\n");
1821 r = omap_dispc_unregister_isr(dispc_disable_isr,
1822 &frame_done_completion,
1823 DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
1824 if (r)
1825 DSSERR("failed to unregister EVSYNC isr\n");
1827 if (enable) {
1828 unsigned long flags;
1829 spin_lock_irqsave(&dispc.irq_lock, flags);
1830 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
1831 dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
1832 _omap_dispc_set_irqs();
1833 spin_unlock_irqrestore(&dispc.irq_lock, flags);
1836 enable_clocks(0);
1839 bool dispc_is_channel_enabled(enum omap_channel channel)
1841 if (channel == OMAP_DSS_CHANNEL_LCD)
1842 return !!REG_GET(DISPC_CONTROL, 0, 0);
1843 else if (channel == OMAP_DSS_CHANNEL_DIGIT)
1844 return !!REG_GET(DISPC_CONTROL, 1, 1);
1845 else
1846 BUG();
1849 void dispc_enable_channel(enum omap_channel channel, bool enable)
1851 if (channel == OMAP_DSS_CHANNEL_LCD)
1852 dispc_enable_lcd_out(enable);
1853 else if (channel == OMAP_DSS_CHANNEL_DIGIT)
1854 dispc_enable_digit_out(enable);
1855 else
1856 BUG();
1859 void dispc_lcd_enable_signal_polarity(bool act_high)
1861 enable_clocks(1);
1862 REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
1863 enable_clocks(0);
1866 void dispc_lcd_enable_signal(bool enable)
1868 enable_clocks(1);
1869 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
1870 enable_clocks(0);
1873 void dispc_pck_free_enable(bool enable)
1875 enable_clocks(1);
1876 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
1877 enable_clocks(0);
1880 void dispc_enable_fifohandcheck(bool enable)
1882 enable_clocks(1);
1883 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
1884 enable_clocks(0);
1888 void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
1890 int mode;
1892 switch (type) {
1893 case OMAP_DSS_LCD_DISPLAY_STN:
1894 mode = 0;
1895 break;
1897 case OMAP_DSS_LCD_DISPLAY_TFT:
1898 mode = 1;
1899 break;
1901 default:
1902 BUG();
1903 return;
1906 enable_clocks(1);
1907 REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
1908 enable_clocks(0);
1911 void dispc_set_loadmode(enum omap_dss_load_mode mode)
1913 enable_clocks(1);
1914 REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
1915 enable_clocks(0);
1919 void dispc_set_default_color(enum omap_channel channel, u32 color)
1921 const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1922 DISPC_DEFAULT_COLOR1 };
1924 enable_clocks(1);
1925 dispc_write_reg(def_reg[channel], color);
1926 enable_clocks(0);
1929 u32 dispc_get_default_color(enum omap_channel channel)
1931 const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1932 DISPC_DEFAULT_COLOR1 };
1933 u32 l;
1935 BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
1936 channel != OMAP_DSS_CHANNEL_LCD);
1938 enable_clocks(1);
1939 l = dispc_read_reg(def_reg[channel]);
1940 enable_clocks(0);
1942 return l;
1945 void dispc_set_trans_key(enum omap_channel ch,
1946 enum omap_dss_trans_key_type type,
1947 u32 trans_key)
1949 const struct dispc_reg tr_reg[] = {
1950 DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1952 enable_clocks(1);
1953 if (ch == OMAP_DSS_CHANNEL_LCD)
1954 REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
1955 else /* OMAP_DSS_CHANNEL_DIGIT */
1956 REG_FLD_MOD(DISPC_CONFIG, type, 13, 13);
1958 dispc_write_reg(tr_reg[ch], trans_key);
1959 enable_clocks(0);
1962 void dispc_get_trans_key(enum omap_channel ch,
1963 enum omap_dss_trans_key_type *type,
1964 u32 *trans_key)
1966 const struct dispc_reg tr_reg[] = {
1967 DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1969 enable_clocks(1);
1970 if (type) {
1971 if (ch == OMAP_DSS_CHANNEL_LCD)
1972 *type = REG_GET(DISPC_CONFIG, 11, 11);
1973 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
1974 *type = REG_GET(DISPC_CONFIG, 13, 13);
1975 else
1976 BUG();
1979 if (trans_key)
1980 *trans_key = dispc_read_reg(tr_reg[ch]);
1981 enable_clocks(0);
1984 void dispc_enable_trans_key(enum omap_channel ch, bool enable)
1986 enable_clocks(1);
1987 if (ch == OMAP_DSS_CHANNEL_LCD)
1988 REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
1989 else /* OMAP_DSS_CHANNEL_DIGIT */
1990 REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
1991 enable_clocks(0);
1993 void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
1995 if (cpu_is_omap24xx())
1996 return;
1998 enable_clocks(1);
1999 if (ch == OMAP_DSS_CHANNEL_LCD)
2000 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
2001 else /* OMAP_DSS_CHANNEL_DIGIT */
2002 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
2003 enable_clocks(0);
2005 bool dispc_alpha_blending_enabled(enum omap_channel ch)
2007 bool enabled;
2009 if (cpu_is_omap24xx())
2010 return false;
2012 enable_clocks(1);
2013 if (ch == OMAP_DSS_CHANNEL_LCD)
2014 enabled = REG_GET(DISPC_CONFIG, 18, 18);
2015 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2016 enabled = REG_GET(DISPC_CONFIG, 18, 18);
2017 else
2018 BUG();
2019 enable_clocks(0);
2021 return enabled;
2026 bool dispc_trans_key_enabled(enum omap_channel ch)
2028 bool enabled;
2030 enable_clocks(1);
2031 if (ch == OMAP_DSS_CHANNEL_LCD)
2032 enabled = REG_GET(DISPC_CONFIG, 10, 10);
2033 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2034 enabled = REG_GET(DISPC_CONFIG, 12, 12);
2035 else
2036 BUG();
2037 enable_clocks(0);
2039 return enabled;
2043 void dispc_set_tft_data_lines(u8 data_lines)
2045 int code;
2047 switch (data_lines) {
2048 case 12:
2049 code = 0;
2050 break;
2051 case 16:
2052 code = 1;
2053 break;
2054 case 18:
2055 code = 2;
2056 break;
2057 case 24:
2058 code = 3;
2059 break;
2060 default:
2061 BUG();
2062 return;
2065 enable_clocks(1);
2066 REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
2067 enable_clocks(0);
2070 void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
2072 u32 l;
2073 int stallmode;
2074 int gpout0 = 1;
2075 int gpout1;
2077 switch (mode) {
2078 case OMAP_DSS_PARALLELMODE_BYPASS:
2079 stallmode = 0;
2080 gpout1 = 1;
2081 break;
2083 case OMAP_DSS_PARALLELMODE_RFBI:
2084 stallmode = 1;
2085 gpout1 = 0;
2086 break;
2088 case OMAP_DSS_PARALLELMODE_DSI:
2089 stallmode = 1;
2090 gpout1 = 1;
2091 break;
2093 default:
2094 BUG();
2095 return;
2098 enable_clocks(1);
2100 l = dispc_read_reg(DISPC_CONTROL);
2102 l = FLD_MOD(l, stallmode, 11, 11);
2103 l = FLD_MOD(l, gpout0, 15, 15);
2104 l = FLD_MOD(l, gpout1, 16, 16);
2106 dispc_write_reg(DISPC_CONTROL, l);
2108 enable_clocks(0);
2111 static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
2112 int vsw, int vfp, int vbp)
2114 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2115 if (hsw < 1 || hsw > 64 ||
2116 hfp < 1 || hfp > 256 ||
2117 hbp < 1 || hbp > 256 ||
2118 vsw < 1 || vsw > 64 ||
2119 vfp < 0 || vfp > 255 ||
2120 vbp < 0 || vbp > 255)
2121 return false;
2122 } else {
2123 if (hsw < 1 || hsw > 256 ||
2124 hfp < 1 || hfp > 4096 ||
2125 hbp < 1 || hbp > 4096 ||
2126 vsw < 1 || vsw > 256 ||
2127 vfp < 0 || vfp > 4095 ||
2128 vbp < 0 || vbp > 4095)
2129 return false;
2132 return true;
2135 bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
2137 return _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2138 timings->hbp, timings->vsw,
2139 timings->vfp, timings->vbp);
2142 static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
2143 int vsw, int vfp, int vbp)
2145 u32 timing_h, timing_v;
2147 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2148 timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
2149 FLD_VAL(hbp-1, 27, 20);
2151 timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
2152 FLD_VAL(vbp, 27, 20);
2153 } else {
2154 timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
2155 FLD_VAL(hbp-1, 31, 20);
2157 timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
2158 FLD_VAL(vbp, 31, 20);
2161 enable_clocks(1);
2162 dispc_write_reg(DISPC_TIMING_H, timing_h);
2163 dispc_write_reg(DISPC_TIMING_V, timing_v);
2164 enable_clocks(0);
2167 /* change name to mode? */
2168 void dispc_set_lcd_timings(struct omap_video_timings *timings)
2170 unsigned xtot, ytot;
2171 unsigned long ht, vt;
2173 if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2174 timings->hbp, timings->vsw,
2175 timings->vfp, timings->vbp))
2176 BUG();
2178 _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp,
2179 timings->vsw, timings->vfp, timings->vbp);
2181 dispc_set_lcd_size(timings->x_res, timings->y_res);
2183 xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
2184 ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
2186 ht = (timings->pixel_clock * 1000) / xtot;
2187 vt = (timings->pixel_clock * 1000) / xtot / ytot;
2189 DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res);
2190 DSSDBG("pck %u\n", timings->pixel_clock);
2191 DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
2192 timings->hsw, timings->hfp, timings->hbp,
2193 timings->vsw, timings->vfp, timings->vbp);
2195 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
2198 static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div)
2200 BUG_ON(lck_div < 1);
2201 BUG_ON(pck_div < 2);
2203 enable_clocks(1);
2204 dispc_write_reg(DISPC_DIVISOR,
2205 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
2206 enable_clocks(0);
2209 static void dispc_get_lcd_divisor(int *lck_div, int *pck_div)
2211 u32 l;
2212 l = dispc_read_reg(DISPC_DIVISOR);
2213 *lck_div = FLD_GET(l, 23, 16);
2214 *pck_div = FLD_GET(l, 7, 0);
2217 unsigned long dispc_fclk_rate(void)
2219 unsigned long r = 0;
2221 if (dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK)
2222 r = dss_clk_get_rate(DSS_CLK_FCK1);
2223 else
2224 #ifdef CONFIG_OMAP2_DSS_DSI
2225 r = dsi_get_dsi1_pll_rate();
2226 #else
2227 BUG();
2228 #endif
2229 return r;
2232 unsigned long dispc_lclk_rate(void)
2234 int lcd;
2235 unsigned long r;
2236 u32 l;
2238 l = dispc_read_reg(DISPC_DIVISOR);
2240 lcd = FLD_GET(l, 23, 16);
2242 r = dispc_fclk_rate();
2244 return r / lcd;
2247 unsigned long dispc_pclk_rate(void)
2249 int lcd, pcd;
2250 unsigned long r;
2251 u32 l;
2253 l = dispc_read_reg(DISPC_DIVISOR);
2255 lcd = FLD_GET(l, 23, 16);
2256 pcd = FLD_GET(l, 7, 0);
2258 r = dispc_fclk_rate();
2260 return r / lcd / pcd;
2263 void dispc_dump_clocks(struct seq_file *s)
2265 int lcd, pcd;
2267 enable_clocks(1);
2269 dispc_get_lcd_divisor(&lcd, &pcd);
2271 seq_printf(s, "- DISPC -\n");
2273 seq_printf(s, "dispc fclk source = %s\n",
2274 dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
2275 "dss1_alwon_fclk" : "dsi1_pll_fclk");
2277 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
2278 seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd);
2279 seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd);
2281 enable_clocks(0);
2284 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2285 void dispc_dump_irqs(struct seq_file *s)
2287 unsigned long flags;
2288 struct dispc_irq_stats stats;
2290 spin_lock_irqsave(&dispc.irq_stats_lock, flags);
2292 stats = dispc.irq_stats;
2293 memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats));
2294 dispc.irq_stats.last_reset = jiffies;
2296 spin_unlock_irqrestore(&dispc.irq_stats_lock, flags);
2298 seq_printf(s, "period %u ms\n",
2299 jiffies_to_msecs(jiffies - stats.last_reset));
2301 seq_printf(s, "irqs %d\n", stats.irq_count);
2302 #define PIS(x) \
2303 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
2305 PIS(FRAMEDONE);
2306 PIS(VSYNC);
2307 PIS(EVSYNC_EVEN);
2308 PIS(EVSYNC_ODD);
2309 PIS(ACBIAS_COUNT_STAT);
2310 PIS(PROG_LINE_NUM);
2311 PIS(GFX_FIFO_UNDERFLOW);
2312 PIS(GFX_END_WIN);
2313 PIS(PAL_GAMMA_MASK);
2314 PIS(OCP_ERR);
2315 PIS(VID1_FIFO_UNDERFLOW);
2316 PIS(VID1_END_WIN);
2317 PIS(VID2_FIFO_UNDERFLOW);
2318 PIS(VID2_END_WIN);
2319 PIS(SYNC_LOST);
2320 PIS(SYNC_LOST_DIGIT);
2321 PIS(WAKEUP);
2322 #undef PIS
2324 #endif
2326 void dispc_dump_regs(struct seq_file *s)
2328 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
2330 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
2332 DUMPREG(DISPC_REVISION);
2333 DUMPREG(DISPC_SYSCONFIG);
2334 DUMPREG(DISPC_SYSSTATUS);
2335 DUMPREG(DISPC_IRQSTATUS);
2336 DUMPREG(DISPC_IRQENABLE);
2337 DUMPREG(DISPC_CONTROL);
2338 DUMPREG(DISPC_CONFIG);
2339 DUMPREG(DISPC_CAPABLE);
2340 DUMPREG(DISPC_DEFAULT_COLOR0);
2341 DUMPREG(DISPC_DEFAULT_COLOR1);
2342 DUMPREG(DISPC_TRANS_COLOR0);
2343 DUMPREG(DISPC_TRANS_COLOR1);
2344 DUMPREG(DISPC_LINE_STATUS);
2345 DUMPREG(DISPC_LINE_NUMBER);
2346 DUMPREG(DISPC_TIMING_H);
2347 DUMPREG(DISPC_TIMING_V);
2348 DUMPREG(DISPC_POL_FREQ);
2349 DUMPREG(DISPC_DIVISOR);
2350 DUMPREG(DISPC_GLOBAL_ALPHA);
2351 DUMPREG(DISPC_SIZE_DIG);
2352 DUMPREG(DISPC_SIZE_LCD);
2354 DUMPREG(DISPC_GFX_BA0);
2355 DUMPREG(DISPC_GFX_BA1);
2356 DUMPREG(DISPC_GFX_POSITION);
2357 DUMPREG(DISPC_GFX_SIZE);
2358 DUMPREG(DISPC_GFX_ATTRIBUTES);
2359 DUMPREG(DISPC_GFX_FIFO_THRESHOLD);
2360 DUMPREG(DISPC_GFX_FIFO_SIZE_STATUS);
2361 DUMPREG(DISPC_GFX_ROW_INC);
2362 DUMPREG(DISPC_GFX_PIXEL_INC);
2363 DUMPREG(DISPC_GFX_WINDOW_SKIP);
2364 DUMPREG(DISPC_GFX_TABLE_BA);
2366 DUMPREG(DISPC_DATA_CYCLE1);
2367 DUMPREG(DISPC_DATA_CYCLE2);
2368 DUMPREG(DISPC_DATA_CYCLE3);
2370 DUMPREG(DISPC_CPR_COEF_R);
2371 DUMPREG(DISPC_CPR_COEF_G);
2372 DUMPREG(DISPC_CPR_COEF_B);
2374 DUMPREG(DISPC_GFX_PRELOAD);
2376 DUMPREG(DISPC_VID_BA0(0));
2377 DUMPREG(DISPC_VID_BA1(0));
2378 DUMPREG(DISPC_VID_POSITION(0));
2379 DUMPREG(DISPC_VID_SIZE(0));
2380 DUMPREG(DISPC_VID_ATTRIBUTES(0));
2381 DUMPREG(DISPC_VID_FIFO_THRESHOLD(0));
2382 DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(0));
2383 DUMPREG(DISPC_VID_ROW_INC(0));
2384 DUMPREG(DISPC_VID_PIXEL_INC(0));
2385 DUMPREG(DISPC_VID_FIR(0));
2386 DUMPREG(DISPC_VID_PICTURE_SIZE(0));
2387 DUMPREG(DISPC_VID_ACCU0(0));
2388 DUMPREG(DISPC_VID_ACCU1(0));
2390 DUMPREG(DISPC_VID_BA0(1));
2391 DUMPREG(DISPC_VID_BA1(1));
2392 DUMPREG(DISPC_VID_POSITION(1));
2393 DUMPREG(DISPC_VID_SIZE(1));
2394 DUMPREG(DISPC_VID_ATTRIBUTES(1));
2395 DUMPREG(DISPC_VID_FIFO_THRESHOLD(1));
2396 DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(1));
2397 DUMPREG(DISPC_VID_ROW_INC(1));
2398 DUMPREG(DISPC_VID_PIXEL_INC(1));
2399 DUMPREG(DISPC_VID_FIR(1));
2400 DUMPREG(DISPC_VID_PICTURE_SIZE(1));
2401 DUMPREG(DISPC_VID_ACCU0(1));
2402 DUMPREG(DISPC_VID_ACCU1(1));
2404 DUMPREG(DISPC_VID_FIR_COEF_H(0, 0));
2405 DUMPREG(DISPC_VID_FIR_COEF_H(0, 1));
2406 DUMPREG(DISPC_VID_FIR_COEF_H(0, 2));
2407 DUMPREG(DISPC_VID_FIR_COEF_H(0, 3));
2408 DUMPREG(DISPC_VID_FIR_COEF_H(0, 4));
2409 DUMPREG(DISPC_VID_FIR_COEF_H(0, 5));
2410 DUMPREG(DISPC_VID_FIR_COEF_H(0, 6));
2411 DUMPREG(DISPC_VID_FIR_COEF_H(0, 7));
2412 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 0));
2413 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 1));
2414 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 2));
2415 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 3));
2416 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 4));
2417 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 5));
2418 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 6));
2419 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 7));
2420 DUMPREG(DISPC_VID_CONV_COEF(0, 0));
2421 DUMPREG(DISPC_VID_CONV_COEF(0, 1));
2422 DUMPREG(DISPC_VID_CONV_COEF(0, 2));
2423 DUMPREG(DISPC_VID_CONV_COEF(0, 3));
2424 DUMPREG(DISPC_VID_CONV_COEF(0, 4));
2425 DUMPREG(DISPC_VID_FIR_COEF_V(0, 0));
2426 DUMPREG(DISPC_VID_FIR_COEF_V(0, 1));
2427 DUMPREG(DISPC_VID_FIR_COEF_V(0, 2));
2428 DUMPREG(DISPC_VID_FIR_COEF_V(0, 3));
2429 DUMPREG(DISPC_VID_FIR_COEF_V(0, 4));
2430 DUMPREG(DISPC_VID_FIR_COEF_V(0, 5));
2431 DUMPREG(DISPC_VID_FIR_COEF_V(0, 6));
2432 DUMPREG(DISPC_VID_FIR_COEF_V(0, 7));
2434 DUMPREG(DISPC_VID_FIR_COEF_H(1, 0));
2435 DUMPREG(DISPC_VID_FIR_COEF_H(1, 1));
2436 DUMPREG(DISPC_VID_FIR_COEF_H(1, 2));
2437 DUMPREG(DISPC_VID_FIR_COEF_H(1, 3));
2438 DUMPREG(DISPC_VID_FIR_COEF_H(1, 4));
2439 DUMPREG(DISPC_VID_FIR_COEF_H(1, 5));
2440 DUMPREG(DISPC_VID_FIR_COEF_H(1, 6));
2441 DUMPREG(DISPC_VID_FIR_COEF_H(1, 7));
2442 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 0));
2443 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 1));
2444 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 2));
2445 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 3));
2446 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 4));
2447 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 5));
2448 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 6));
2449 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 7));
2450 DUMPREG(DISPC_VID_CONV_COEF(1, 0));
2451 DUMPREG(DISPC_VID_CONV_COEF(1, 1));
2452 DUMPREG(DISPC_VID_CONV_COEF(1, 2));
2453 DUMPREG(DISPC_VID_CONV_COEF(1, 3));
2454 DUMPREG(DISPC_VID_CONV_COEF(1, 4));
2455 DUMPREG(DISPC_VID_FIR_COEF_V(1, 0));
2456 DUMPREG(DISPC_VID_FIR_COEF_V(1, 1));
2457 DUMPREG(DISPC_VID_FIR_COEF_V(1, 2));
2458 DUMPREG(DISPC_VID_FIR_COEF_V(1, 3));
2459 DUMPREG(DISPC_VID_FIR_COEF_V(1, 4));
2460 DUMPREG(DISPC_VID_FIR_COEF_V(1, 5));
2461 DUMPREG(DISPC_VID_FIR_COEF_V(1, 6));
2462 DUMPREG(DISPC_VID_FIR_COEF_V(1, 7));
2464 DUMPREG(DISPC_VID_PRELOAD(0));
2465 DUMPREG(DISPC_VID_PRELOAD(1));
2467 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
2468 #undef DUMPREG
2471 static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
2472 bool ihs, bool ivs, u8 acbi, u8 acb)
2474 u32 l = 0;
2476 DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n",
2477 onoff, rf, ieo, ipc, ihs, ivs, acbi, acb);
2479 l |= FLD_VAL(onoff, 17, 17);
2480 l |= FLD_VAL(rf, 16, 16);
2481 l |= FLD_VAL(ieo, 15, 15);
2482 l |= FLD_VAL(ipc, 14, 14);
2483 l |= FLD_VAL(ihs, 13, 13);
2484 l |= FLD_VAL(ivs, 12, 12);
2485 l |= FLD_VAL(acbi, 11, 8);
2486 l |= FLD_VAL(acb, 7, 0);
2488 enable_clocks(1);
2489 dispc_write_reg(DISPC_POL_FREQ, l);
2490 enable_clocks(0);
2493 void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb)
2495 _dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0,
2496 (config & OMAP_DSS_LCD_RF) != 0,
2497 (config & OMAP_DSS_LCD_IEO) != 0,
2498 (config & OMAP_DSS_LCD_IPC) != 0,
2499 (config & OMAP_DSS_LCD_IHS) != 0,
2500 (config & OMAP_DSS_LCD_IVS) != 0,
2501 acbi, acb);
2504 /* with fck as input clock rate, find dispc dividers that produce req_pck */
2505 void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
2506 struct dispc_clock_info *cinfo)
2508 u16 pcd_min = is_tft ? 2 : 3;
2509 unsigned long best_pck;
2510 u16 best_ld, cur_ld;
2511 u16 best_pd, cur_pd;
2513 best_pck = 0;
2514 best_ld = 0;
2515 best_pd = 0;
2517 for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
2518 unsigned long lck = fck / cur_ld;
2520 for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) {
2521 unsigned long pck = lck / cur_pd;
2522 long old_delta = abs(best_pck - req_pck);
2523 long new_delta = abs(pck - req_pck);
2525 if (best_pck == 0 || new_delta < old_delta) {
2526 best_pck = pck;
2527 best_ld = cur_ld;
2528 best_pd = cur_pd;
2530 if (pck == req_pck)
2531 goto found;
2534 if (pck < req_pck)
2535 break;
2538 if (lck / pcd_min < req_pck)
2539 break;
2542 found:
2543 cinfo->lck_div = best_ld;
2544 cinfo->pck_div = best_pd;
2545 cinfo->lck = fck / cinfo->lck_div;
2546 cinfo->pck = cinfo->lck / cinfo->pck_div;
2549 /* calculate clock rates using dividers in cinfo */
2550 int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
2551 struct dispc_clock_info *cinfo)
2553 if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
2554 return -EINVAL;
2555 if (cinfo->pck_div < 2 || cinfo->pck_div > 255)
2556 return -EINVAL;
2558 cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
2559 cinfo->pck = cinfo->lck / cinfo->pck_div;
2561 return 0;
2564 int dispc_set_clock_div(struct dispc_clock_info *cinfo)
2566 DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
2567 DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
2569 dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div);
2571 return 0;
2574 int dispc_get_clock_div(struct dispc_clock_info *cinfo)
2576 unsigned long fck;
2578 fck = dispc_fclk_rate();
2580 cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
2581 cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
2583 cinfo->lck = fck / cinfo->lck_div;
2584 cinfo->pck = cinfo->lck / cinfo->pck_div;
2586 return 0;
2589 /* dispc.irq_lock has to be locked by the caller */
2590 static void _omap_dispc_set_irqs(void)
2592 u32 mask;
2593 u32 old_mask;
2594 int i;
2595 struct omap_dispc_isr_data *isr_data;
2597 mask = dispc.irq_error_mask;
2599 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2600 isr_data = &dispc.registered_isr[i];
2602 if (isr_data->isr == NULL)
2603 continue;
2605 mask |= isr_data->mask;
2608 enable_clocks(1);
2610 old_mask = dispc_read_reg(DISPC_IRQENABLE);
2611 /* clear the irqstatus for newly enabled irqs */
2612 dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
2614 dispc_write_reg(DISPC_IRQENABLE, mask);
2616 enable_clocks(0);
2619 int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2621 int i;
2622 int ret;
2623 unsigned long flags;
2624 struct omap_dispc_isr_data *isr_data;
2626 if (isr == NULL)
2627 return -EINVAL;
2629 spin_lock_irqsave(&dispc.irq_lock, flags);
2631 /* check for duplicate entry */
2632 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2633 isr_data = &dispc.registered_isr[i];
2634 if (isr_data->isr == isr && isr_data->arg == arg &&
2635 isr_data->mask == mask) {
2636 ret = -EINVAL;
2637 goto err;
2641 isr_data = NULL;
2642 ret = -EBUSY;
2644 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2645 isr_data = &dispc.registered_isr[i];
2647 if (isr_data->isr != NULL)
2648 continue;
2650 isr_data->isr = isr;
2651 isr_data->arg = arg;
2652 isr_data->mask = mask;
2653 ret = 0;
2655 break;
2658 _omap_dispc_set_irqs();
2660 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2662 return 0;
2663 err:
2664 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2666 return ret;
2668 EXPORT_SYMBOL(omap_dispc_register_isr);
2670 int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2672 int i;
2673 unsigned long flags;
2674 int ret = -EINVAL;
2675 struct omap_dispc_isr_data *isr_data;
2677 spin_lock_irqsave(&dispc.irq_lock, flags);
2679 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2680 isr_data = &dispc.registered_isr[i];
2681 if (isr_data->isr != isr || isr_data->arg != arg ||
2682 isr_data->mask != mask)
2683 continue;
2685 /* found the correct isr */
2687 isr_data->isr = NULL;
2688 isr_data->arg = NULL;
2689 isr_data->mask = 0;
2691 ret = 0;
2692 break;
2695 if (ret == 0)
2696 _omap_dispc_set_irqs();
2698 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2700 return ret;
2702 EXPORT_SYMBOL(omap_dispc_unregister_isr);
2704 #ifdef DEBUG
2705 static void print_irq_status(u32 status)
2707 if ((status & dispc.irq_error_mask) == 0)
2708 return;
2710 printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status);
2712 #define PIS(x) \
2713 if (status & DISPC_IRQ_##x) \
2714 printk(#x " ");
2715 PIS(GFX_FIFO_UNDERFLOW);
2716 PIS(OCP_ERR);
2717 PIS(VID1_FIFO_UNDERFLOW);
2718 PIS(VID2_FIFO_UNDERFLOW);
2719 PIS(SYNC_LOST);
2720 PIS(SYNC_LOST_DIGIT);
2721 #undef PIS
2723 printk("\n");
2725 #endif
2727 /* Called from dss.c. Note that we don't touch clocks here,
2728 * but we presume they are on because we got an IRQ. However,
2729 * an irq handler may turn the clocks off, so we may not have
2730 * clock later in the function. */
2731 void dispc_irq_handler(void)
2733 int i;
2734 u32 irqstatus;
2735 u32 handledirqs = 0;
2736 u32 unhandled_errors;
2737 struct omap_dispc_isr_data *isr_data;
2738 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
2740 spin_lock(&dispc.irq_lock);
2742 irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
2744 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2745 spin_lock(&dispc.irq_stats_lock);
2746 dispc.irq_stats.irq_count++;
2747 dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs);
2748 spin_unlock(&dispc.irq_stats_lock);
2749 #endif
2751 #ifdef DEBUG
2752 if (dss_debug)
2753 print_irq_status(irqstatus);
2754 #endif
2755 /* Ack the interrupt. Do it here before clocks are possibly turned
2756 * off */
2757 dispc_write_reg(DISPC_IRQSTATUS, irqstatus);
2758 /* flush posted write */
2759 dispc_read_reg(DISPC_IRQSTATUS);
2761 /* make a copy and unlock, so that isrs can unregister
2762 * themselves */
2763 memcpy(registered_isr, dispc.registered_isr,
2764 sizeof(registered_isr));
2766 spin_unlock(&dispc.irq_lock);
2768 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2769 isr_data = &registered_isr[i];
2771 if (!isr_data->isr)
2772 continue;
2774 if (isr_data->mask & irqstatus) {
2775 isr_data->isr(isr_data->arg, irqstatus);
2776 handledirqs |= isr_data->mask;
2780 spin_lock(&dispc.irq_lock);
2782 unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
2784 if (unhandled_errors) {
2785 dispc.error_irqs |= unhandled_errors;
2787 dispc.irq_error_mask &= ~unhandled_errors;
2788 _omap_dispc_set_irqs();
2790 schedule_work(&dispc.error_work);
2793 spin_unlock(&dispc.irq_lock);
2796 static void dispc_error_worker(struct work_struct *work)
2798 int i;
2799 u32 errors;
2800 unsigned long flags;
2802 spin_lock_irqsave(&dispc.irq_lock, flags);
2803 errors = dispc.error_irqs;
2804 dispc.error_irqs = 0;
2805 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2807 if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) {
2808 DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n");
2809 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2810 struct omap_overlay *ovl;
2811 ovl = omap_dss_get_overlay(i);
2813 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2814 continue;
2816 if (ovl->id == 0) {
2817 dispc_enable_plane(ovl->id, 0);
2818 dispc_go(ovl->manager->id);
2819 mdelay(50);
2820 break;
2825 if (errors & DISPC_IRQ_VID1_FIFO_UNDERFLOW) {
2826 DSSERR("VID1_FIFO_UNDERFLOW, disabling VID1\n");
2827 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2828 struct omap_overlay *ovl;
2829 ovl = omap_dss_get_overlay(i);
2831 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2832 continue;
2834 if (ovl->id == 1) {
2835 dispc_enable_plane(ovl->id, 0);
2836 dispc_go(ovl->manager->id);
2837 mdelay(50);
2838 break;
2843 if (errors & DISPC_IRQ_VID2_FIFO_UNDERFLOW) {
2844 DSSERR("VID2_FIFO_UNDERFLOW, disabling VID2\n");
2845 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2846 struct omap_overlay *ovl;
2847 ovl = omap_dss_get_overlay(i);
2849 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2850 continue;
2852 if (ovl->id == 2) {
2853 dispc_enable_plane(ovl->id, 0);
2854 dispc_go(ovl->manager->id);
2855 mdelay(50);
2856 break;
2861 if (errors & DISPC_IRQ_SYNC_LOST) {
2862 struct omap_overlay_manager *manager = NULL;
2863 bool enable = false;
2865 DSSERR("SYNC_LOST, disabling LCD\n");
2867 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2868 struct omap_overlay_manager *mgr;
2869 mgr = omap_dss_get_overlay_manager(i);
2871 if (mgr->id == OMAP_DSS_CHANNEL_LCD) {
2872 manager = mgr;
2873 enable = mgr->device->state ==
2874 OMAP_DSS_DISPLAY_ACTIVE;
2875 mgr->device->driver->disable(mgr->device);
2876 break;
2880 if (manager) {
2881 struct omap_dss_device *dssdev = manager->device;
2882 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2883 struct omap_overlay *ovl;
2884 ovl = omap_dss_get_overlay(i);
2886 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2887 continue;
2889 if (ovl->id != 0 && ovl->manager == manager)
2890 dispc_enable_plane(ovl->id, 0);
2893 dispc_go(manager->id);
2894 mdelay(50);
2895 if (enable)
2896 dssdev->driver->enable(dssdev);
2900 if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) {
2901 struct omap_overlay_manager *manager = NULL;
2902 bool enable = false;
2904 DSSERR("SYNC_LOST_DIGIT, disabling TV\n");
2906 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2907 struct omap_overlay_manager *mgr;
2908 mgr = omap_dss_get_overlay_manager(i);
2910 if (mgr->id == OMAP_DSS_CHANNEL_DIGIT) {
2911 manager = mgr;
2912 enable = mgr->device->state ==
2913 OMAP_DSS_DISPLAY_ACTIVE;
2914 mgr->device->driver->disable(mgr->device);
2915 break;
2919 if (manager) {
2920 struct omap_dss_device *dssdev = manager->device;
2921 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2922 struct omap_overlay *ovl;
2923 ovl = omap_dss_get_overlay(i);
2925 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2926 continue;
2928 if (ovl->id != 0 && ovl->manager == manager)
2929 dispc_enable_plane(ovl->id, 0);
2932 dispc_go(manager->id);
2933 mdelay(50);
2934 if (enable)
2935 dssdev->driver->enable(dssdev);
2939 if (errors & DISPC_IRQ_OCP_ERR) {
2940 DSSERR("OCP_ERR\n");
2941 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2942 struct omap_overlay_manager *mgr;
2943 mgr = omap_dss_get_overlay_manager(i);
2945 if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC)
2946 mgr->device->driver->disable(mgr->device);
2950 spin_lock_irqsave(&dispc.irq_lock, flags);
2951 dispc.irq_error_mask |= errors;
2952 _omap_dispc_set_irqs();
2953 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2956 int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
2958 void dispc_irq_wait_handler(void *data, u32 mask)
2960 complete((struct completion *)data);
2963 int r;
2964 DECLARE_COMPLETION_ONSTACK(completion);
2966 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2967 irqmask);
2969 if (r)
2970 return r;
2972 timeout = wait_for_completion_timeout(&completion, timeout);
2974 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
2976 if (timeout == 0)
2977 return -ETIMEDOUT;
2979 if (timeout == -ERESTARTSYS)
2980 return -ERESTARTSYS;
2982 return 0;
2985 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
2986 unsigned long timeout)
2988 void dispc_irq_wait_handler(void *data, u32 mask)
2990 complete((struct completion *)data);
2993 int r;
2994 DECLARE_COMPLETION_ONSTACK(completion);
2996 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2997 irqmask);
2999 if (r)
3000 return r;
3002 timeout = wait_for_completion_interruptible_timeout(&completion,
3003 timeout);
3005 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
3007 if (timeout == 0)
3008 return -ETIMEDOUT;
3010 if (timeout == -ERESTARTSYS)
3011 return -ERESTARTSYS;
3013 return 0;
3016 #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
3017 void dispc_fake_vsync_irq(void)
3019 u32 irqstatus = DISPC_IRQ_VSYNC;
3020 int i;
3022 local_irq_disable();
3024 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3025 struct omap_dispc_isr_data *isr_data;
3026 isr_data = &dispc.registered_isr[i];
3028 if (!isr_data->isr)
3029 continue;
3031 if (isr_data->mask & irqstatus)
3032 isr_data->isr(isr_data->arg, irqstatus);
3035 local_irq_enable();
3037 #endif
3039 static void _omap_dispc_initialize_irq(void)
3041 unsigned long flags;
3043 spin_lock_irqsave(&dispc.irq_lock, flags);
3045 memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
3047 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
3049 /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
3050 * so clear it */
3051 dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS));
3053 _omap_dispc_set_irqs();
3055 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3058 void dispc_enable_sidle(void)
3060 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
3063 void dispc_disable_sidle(void)
3065 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
3068 static void _omap_dispc_initial_config(void)
3070 u32 l;
3072 l = dispc_read_reg(DISPC_SYSCONFIG);
3073 l = FLD_MOD(l, 2, 13, 12); /* MIDLEMODE: smart standby */
3074 l = FLD_MOD(l, 2, 4, 3); /* SIDLEMODE: smart idle */
3075 l = FLD_MOD(l, 1, 2, 2); /* ENWAKEUP */
3076 l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */
3077 dispc_write_reg(DISPC_SYSCONFIG, l);
3079 /* FUNCGATED */
3080 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
3082 /* L3 firewall setting: enable access to OCM RAM */
3083 /* XXX this should be somewhere in plat-omap */
3084 if (cpu_is_omap24xx())
3085 __raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0));
3087 _dispc_setup_color_conv_coef();
3089 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3091 dispc_read_plane_fifo_sizes();
3094 int dispc_init(void)
3096 u32 rev;
3098 spin_lock_init(&dispc.irq_lock);
3100 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3101 spin_lock_init(&dispc.irq_stats_lock);
3102 dispc.irq_stats.last_reset = jiffies;
3103 #endif
3105 INIT_WORK(&dispc.error_work, dispc_error_worker);
3107 dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
3108 if (!dispc.base) {
3109 DSSERR("can't ioremap DISPC\n");
3110 return -ENOMEM;
3113 enable_clocks(1);
3115 _omap_dispc_initial_config();
3117 _omap_dispc_initialize_irq();
3119 dispc_save_context();
3121 rev = dispc_read_reg(DISPC_REVISION);
3122 printk(KERN_INFO "OMAP DISPC rev %d.%d\n",
3123 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
3125 enable_clocks(0);
3127 return 0;
3130 void dispc_exit(void)
3132 iounmap(dispc.base);
3135 int dispc_enable_plane(enum omap_plane plane, bool enable)
3137 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
3139 enable_clocks(1);
3140 _dispc_enable_plane(plane, enable);
3141 enable_clocks(0);
3143 return 0;
3146 int dispc_setup_plane(enum omap_plane plane,
3147 u32 paddr, u16 screen_width,
3148 u16 pos_x, u16 pos_y,
3149 u16 width, u16 height,
3150 u16 out_width, u16 out_height,
3151 enum omap_color_mode color_mode,
3152 bool ilace,
3153 enum omap_dss_rotation_type rotation_type,
3154 u8 rotation, bool mirror, u8 global_alpha)
3156 int r = 0;
3158 DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
3159 "%dx%d, ilace %d, cmode %x, rot %d, mir %d\n",
3160 plane, paddr, screen_width, pos_x, pos_y,
3161 width, height,
3162 out_width, out_height,
3163 ilace, color_mode,
3164 rotation, mirror);
3166 enable_clocks(1);
3168 r = _dispc_setup_plane(plane,
3169 paddr, screen_width,
3170 pos_x, pos_y,
3171 width, height,
3172 out_width, out_height,
3173 color_mode, ilace,
3174 rotation_type,
3175 rotation, mirror,
3176 global_alpha);
3178 enable_clocks(0);
3180 return r;