OMAP: DSS2: fix irq-stats compilation
[linux/fpc-iii.git] / drivers / video / omap2 / dss / dispc.c
blob7781c65bbeba670d676422f1f2c3e607a8f3b2b7
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 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 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 void dispc_lcd_enable_signal_polarity(bool act_high)
1841 enable_clocks(1);
1842 REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
1843 enable_clocks(0);
1846 void dispc_lcd_enable_signal(bool enable)
1848 enable_clocks(1);
1849 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
1850 enable_clocks(0);
1853 void dispc_pck_free_enable(bool enable)
1855 enable_clocks(1);
1856 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
1857 enable_clocks(0);
1860 void dispc_enable_fifohandcheck(bool enable)
1862 enable_clocks(1);
1863 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
1864 enable_clocks(0);
1868 void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
1870 int mode;
1872 switch (type) {
1873 case OMAP_DSS_LCD_DISPLAY_STN:
1874 mode = 0;
1875 break;
1877 case OMAP_DSS_LCD_DISPLAY_TFT:
1878 mode = 1;
1879 break;
1881 default:
1882 BUG();
1883 return;
1886 enable_clocks(1);
1887 REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
1888 enable_clocks(0);
1891 void dispc_set_loadmode(enum omap_dss_load_mode mode)
1893 enable_clocks(1);
1894 REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
1895 enable_clocks(0);
1899 void dispc_set_default_color(enum omap_channel channel, u32 color)
1901 const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1902 DISPC_DEFAULT_COLOR1 };
1904 enable_clocks(1);
1905 dispc_write_reg(def_reg[channel], color);
1906 enable_clocks(0);
1909 u32 dispc_get_default_color(enum omap_channel channel)
1911 const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1912 DISPC_DEFAULT_COLOR1 };
1913 u32 l;
1915 BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
1916 channel != OMAP_DSS_CHANNEL_LCD);
1918 enable_clocks(1);
1919 l = dispc_read_reg(def_reg[channel]);
1920 enable_clocks(0);
1922 return l;
1925 void dispc_set_trans_key(enum omap_channel ch,
1926 enum omap_dss_trans_key_type type,
1927 u32 trans_key)
1929 const struct dispc_reg tr_reg[] = {
1930 DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1932 enable_clocks(1);
1933 if (ch == OMAP_DSS_CHANNEL_LCD)
1934 REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
1935 else /* OMAP_DSS_CHANNEL_DIGIT */
1936 REG_FLD_MOD(DISPC_CONFIG, type, 13, 13);
1938 dispc_write_reg(tr_reg[ch], trans_key);
1939 enable_clocks(0);
1942 void dispc_get_trans_key(enum omap_channel ch,
1943 enum omap_dss_trans_key_type *type,
1944 u32 *trans_key)
1946 const struct dispc_reg tr_reg[] = {
1947 DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1949 enable_clocks(1);
1950 if (type) {
1951 if (ch == OMAP_DSS_CHANNEL_LCD)
1952 *type = REG_GET(DISPC_CONFIG, 11, 11);
1953 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
1954 *type = REG_GET(DISPC_CONFIG, 13, 13);
1955 else
1956 BUG();
1959 if (trans_key)
1960 *trans_key = dispc_read_reg(tr_reg[ch]);
1961 enable_clocks(0);
1964 void dispc_enable_trans_key(enum omap_channel ch, bool enable)
1966 enable_clocks(1);
1967 if (ch == OMAP_DSS_CHANNEL_LCD)
1968 REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
1969 else /* OMAP_DSS_CHANNEL_DIGIT */
1970 REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
1971 enable_clocks(0);
1973 void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
1975 if (cpu_is_omap24xx())
1976 return;
1978 enable_clocks(1);
1979 if (ch == OMAP_DSS_CHANNEL_LCD)
1980 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
1981 else /* OMAP_DSS_CHANNEL_DIGIT */
1982 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
1983 enable_clocks(0);
1985 bool dispc_alpha_blending_enabled(enum omap_channel ch)
1987 bool enabled;
1989 if (cpu_is_omap24xx())
1990 return false;
1992 enable_clocks(1);
1993 if (ch == OMAP_DSS_CHANNEL_LCD)
1994 enabled = REG_GET(DISPC_CONFIG, 18, 18);
1995 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
1996 enabled = REG_GET(DISPC_CONFIG, 18, 18);
1997 else
1998 BUG();
1999 enable_clocks(0);
2001 return enabled;
2006 bool dispc_trans_key_enabled(enum omap_channel ch)
2008 bool enabled;
2010 enable_clocks(1);
2011 if (ch == OMAP_DSS_CHANNEL_LCD)
2012 enabled = REG_GET(DISPC_CONFIG, 10, 10);
2013 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2014 enabled = REG_GET(DISPC_CONFIG, 12, 12);
2015 else
2016 BUG();
2017 enable_clocks(0);
2019 return enabled;
2023 void dispc_set_tft_data_lines(u8 data_lines)
2025 int code;
2027 switch (data_lines) {
2028 case 12:
2029 code = 0;
2030 break;
2031 case 16:
2032 code = 1;
2033 break;
2034 case 18:
2035 code = 2;
2036 break;
2037 case 24:
2038 code = 3;
2039 break;
2040 default:
2041 BUG();
2042 return;
2045 enable_clocks(1);
2046 REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
2047 enable_clocks(0);
2050 void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
2052 u32 l;
2053 int stallmode;
2054 int gpout0 = 1;
2055 int gpout1;
2057 switch (mode) {
2058 case OMAP_DSS_PARALLELMODE_BYPASS:
2059 stallmode = 0;
2060 gpout1 = 1;
2061 break;
2063 case OMAP_DSS_PARALLELMODE_RFBI:
2064 stallmode = 1;
2065 gpout1 = 0;
2066 break;
2068 case OMAP_DSS_PARALLELMODE_DSI:
2069 stallmode = 1;
2070 gpout1 = 1;
2071 break;
2073 default:
2074 BUG();
2075 return;
2078 enable_clocks(1);
2080 l = dispc_read_reg(DISPC_CONTROL);
2082 l = FLD_MOD(l, stallmode, 11, 11);
2083 l = FLD_MOD(l, gpout0, 15, 15);
2084 l = FLD_MOD(l, gpout1, 16, 16);
2086 dispc_write_reg(DISPC_CONTROL, l);
2088 enable_clocks(0);
2091 static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
2092 int vsw, int vfp, int vbp)
2094 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2095 if (hsw < 1 || hsw > 64 ||
2096 hfp < 1 || hfp > 256 ||
2097 hbp < 1 || hbp > 256 ||
2098 vsw < 1 || vsw > 64 ||
2099 vfp < 0 || vfp > 255 ||
2100 vbp < 0 || vbp > 255)
2101 return false;
2102 } else {
2103 if (hsw < 1 || hsw > 256 ||
2104 hfp < 1 || hfp > 4096 ||
2105 hbp < 1 || hbp > 4096 ||
2106 vsw < 1 || vsw > 256 ||
2107 vfp < 0 || vfp > 4095 ||
2108 vbp < 0 || vbp > 4095)
2109 return false;
2112 return true;
2115 bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
2117 return _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2118 timings->hbp, timings->vsw,
2119 timings->vfp, timings->vbp);
2122 static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
2123 int vsw, int vfp, int vbp)
2125 u32 timing_h, timing_v;
2127 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2128 timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
2129 FLD_VAL(hbp-1, 27, 20);
2131 timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
2132 FLD_VAL(vbp, 27, 20);
2133 } else {
2134 timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
2135 FLD_VAL(hbp-1, 31, 20);
2137 timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
2138 FLD_VAL(vbp, 31, 20);
2141 enable_clocks(1);
2142 dispc_write_reg(DISPC_TIMING_H, timing_h);
2143 dispc_write_reg(DISPC_TIMING_V, timing_v);
2144 enable_clocks(0);
2147 /* change name to mode? */
2148 void dispc_set_lcd_timings(struct omap_video_timings *timings)
2150 unsigned xtot, ytot;
2151 unsigned long ht, vt;
2153 if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2154 timings->hbp, timings->vsw,
2155 timings->vfp, timings->vbp))
2156 BUG();
2158 _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp,
2159 timings->vsw, timings->vfp, timings->vbp);
2161 dispc_set_lcd_size(timings->x_res, timings->y_res);
2163 xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
2164 ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
2166 ht = (timings->pixel_clock * 1000) / xtot;
2167 vt = (timings->pixel_clock * 1000) / xtot / ytot;
2169 DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res);
2170 DSSDBG("pck %u\n", timings->pixel_clock);
2171 DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
2172 timings->hsw, timings->hfp, timings->hbp,
2173 timings->vsw, timings->vfp, timings->vbp);
2175 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
2178 static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div)
2180 BUG_ON(lck_div < 1);
2181 BUG_ON(pck_div < 2);
2183 enable_clocks(1);
2184 dispc_write_reg(DISPC_DIVISOR,
2185 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
2186 enable_clocks(0);
2189 static void dispc_get_lcd_divisor(int *lck_div, int *pck_div)
2191 u32 l;
2192 l = dispc_read_reg(DISPC_DIVISOR);
2193 *lck_div = FLD_GET(l, 23, 16);
2194 *pck_div = FLD_GET(l, 7, 0);
2197 unsigned long dispc_fclk_rate(void)
2199 unsigned long r = 0;
2201 if (dss_get_dispc_clk_source() == 0)
2202 r = dss_clk_get_rate(DSS_CLK_FCK1);
2203 else
2204 #ifdef CONFIG_OMAP2_DSS_DSI
2205 r = dsi_get_dsi1_pll_rate();
2206 #else
2207 BUG();
2208 #endif
2209 return r;
2212 unsigned long dispc_lclk_rate(void)
2214 int lcd;
2215 unsigned long r;
2216 u32 l;
2218 l = dispc_read_reg(DISPC_DIVISOR);
2220 lcd = FLD_GET(l, 23, 16);
2222 r = dispc_fclk_rate();
2224 return r / lcd;
2227 unsigned long dispc_pclk_rate(void)
2229 int lcd, pcd;
2230 unsigned long r;
2231 u32 l;
2233 l = dispc_read_reg(DISPC_DIVISOR);
2235 lcd = FLD_GET(l, 23, 16);
2236 pcd = FLD_GET(l, 7, 0);
2238 r = dispc_fclk_rate();
2240 return r / lcd / pcd;
2243 void dispc_dump_clocks(struct seq_file *s)
2245 int lcd, pcd;
2247 enable_clocks(1);
2249 dispc_get_lcd_divisor(&lcd, &pcd);
2251 seq_printf(s, "- DISPC -\n");
2253 seq_printf(s, "dispc fclk source = %s\n",
2254 dss_get_dispc_clk_source() == 0 ?
2255 "dss1_alwon_fclk" : "dsi1_pll_fclk");
2257 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
2258 seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd);
2259 seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd);
2261 enable_clocks(0);
2264 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2265 void dispc_dump_irqs(struct seq_file *s)
2267 unsigned long flags;
2268 struct dispc_irq_stats stats;
2270 spin_lock_irqsave(&dispc.irq_stats_lock, flags);
2272 stats = dispc.irq_stats;
2273 memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats));
2274 dispc.irq_stats.last_reset = jiffies;
2276 spin_unlock_irqrestore(&dispc.irq_stats_lock, flags);
2278 seq_printf(s, "period %u ms\n",
2279 jiffies_to_msecs(jiffies - stats.last_reset));
2281 seq_printf(s, "irqs %d\n", stats.irq_count);
2282 #define PIS(x) \
2283 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
2285 PIS(FRAMEDONE);
2286 PIS(VSYNC);
2287 PIS(EVSYNC_EVEN);
2288 PIS(EVSYNC_ODD);
2289 PIS(ACBIAS_COUNT_STAT);
2290 PIS(PROG_LINE_NUM);
2291 PIS(GFX_FIFO_UNDERFLOW);
2292 PIS(GFX_END_WIN);
2293 PIS(PAL_GAMMA_MASK);
2294 PIS(OCP_ERR);
2295 PIS(VID1_FIFO_UNDERFLOW);
2296 PIS(VID1_END_WIN);
2297 PIS(VID2_FIFO_UNDERFLOW);
2298 PIS(VID2_END_WIN);
2299 PIS(SYNC_LOST);
2300 PIS(SYNC_LOST_DIGIT);
2301 PIS(WAKEUP);
2302 #undef PIS
2304 #endif
2306 void dispc_dump_regs(struct seq_file *s)
2308 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
2310 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
2312 DUMPREG(DISPC_REVISION);
2313 DUMPREG(DISPC_SYSCONFIG);
2314 DUMPREG(DISPC_SYSSTATUS);
2315 DUMPREG(DISPC_IRQSTATUS);
2316 DUMPREG(DISPC_IRQENABLE);
2317 DUMPREG(DISPC_CONTROL);
2318 DUMPREG(DISPC_CONFIG);
2319 DUMPREG(DISPC_CAPABLE);
2320 DUMPREG(DISPC_DEFAULT_COLOR0);
2321 DUMPREG(DISPC_DEFAULT_COLOR1);
2322 DUMPREG(DISPC_TRANS_COLOR0);
2323 DUMPREG(DISPC_TRANS_COLOR1);
2324 DUMPREG(DISPC_LINE_STATUS);
2325 DUMPREG(DISPC_LINE_NUMBER);
2326 DUMPREG(DISPC_TIMING_H);
2327 DUMPREG(DISPC_TIMING_V);
2328 DUMPREG(DISPC_POL_FREQ);
2329 DUMPREG(DISPC_DIVISOR);
2330 DUMPREG(DISPC_GLOBAL_ALPHA);
2331 DUMPREG(DISPC_SIZE_DIG);
2332 DUMPREG(DISPC_SIZE_LCD);
2334 DUMPREG(DISPC_GFX_BA0);
2335 DUMPREG(DISPC_GFX_BA1);
2336 DUMPREG(DISPC_GFX_POSITION);
2337 DUMPREG(DISPC_GFX_SIZE);
2338 DUMPREG(DISPC_GFX_ATTRIBUTES);
2339 DUMPREG(DISPC_GFX_FIFO_THRESHOLD);
2340 DUMPREG(DISPC_GFX_FIFO_SIZE_STATUS);
2341 DUMPREG(DISPC_GFX_ROW_INC);
2342 DUMPREG(DISPC_GFX_PIXEL_INC);
2343 DUMPREG(DISPC_GFX_WINDOW_SKIP);
2344 DUMPREG(DISPC_GFX_TABLE_BA);
2346 DUMPREG(DISPC_DATA_CYCLE1);
2347 DUMPREG(DISPC_DATA_CYCLE2);
2348 DUMPREG(DISPC_DATA_CYCLE3);
2350 DUMPREG(DISPC_CPR_COEF_R);
2351 DUMPREG(DISPC_CPR_COEF_G);
2352 DUMPREG(DISPC_CPR_COEF_B);
2354 DUMPREG(DISPC_GFX_PRELOAD);
2356 DUMPREG(DISPC_VID_BA0(0));
2357 DUMPREG(DISPC_VID_BA1(0));
2358 DUMPREG(DISPC_VID_POSITION(0));
2359 DUMPREG(DISPC_VID_SIZE(0));
2360 DUMPREG(DISPC_VID_ATTRIBUTES(0));
2361 DUMPREG(DISPC_VID_FIFO_THRESHOLD(0));
2362 DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(0));
2363 DUMPREG(DISPC_VID_ROW_INC(0));
2364 DUMPREG(DISPC_VID_PIXEL_INC(0));
2365 DUMPREG(DISPC_VID_FIR(0));
2366 DUMPREG(DISPC_VID_PICTURE_SIZE(0));
2367 DUMPREG(DISPC_VID_ACCU0(0));
2368 DUMPREG(DISPC_VID_ACCU1(0));
2370 DUMPREG(DISPC_VID_BA0(1));
2371 DUMPREG(DISPC_VID_BA1(1));
2372 DUMPREG(DISPC_VID_POSITION(1));
2373 DUMPREG(DISPC_VID_SIZE(1));
2374 DUMPREG(DISPC_VID_ATTRIBUTES(1));
2375 DUMPREG(DISPC_VID_FIFO_THRESHOLD(1));
2376 DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(1));
2377 DUMPREG(DISPC_VID_ROW_INC(1));
2378 DUMPREG(DISPC_VID_PIXEL_INC(1));
2379 DUMPREG(DISPC_VID_FIR(1));
2380 DUMPREG(DISPC_VID_PICTURE_SIZE(1));
2381 DUMPREG(DISPC_VID_ACCU0(1));
2382 DUMPREG(DISPC_VID_ACCU1(1));
2384 DUMPREG(DISPC_VID_FIR_COEF_H(0, 0));
2385 DUMPREG(DISPC_VID_FIR_COEF_H(0, 1));
2386 DUMPREG(DISPC_VID_FIR_COEF_H(0, 2));
2387 DUMPREG(DISPC_VID_FIR_COEF_H(0, 3));
2388 DUMPREG(DISPC_VID_FIR_COEF_H(0, 4));
2389 DUMPREG(DISPC_VID_FIR_COEF_H(0, 5));
2390 DUMPREG(DISPC_VID_FIR_COEF_H(0, 6));
2391 DUMPREG(DISPC_VID_FIR_COEF_H(0, 7));
2392 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 0));
2393 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 1));
2394 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 2));
2395 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 3));
2396 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 4));
2397 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 5));
2398 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 6));
2399 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 7));
2400 DUMPREG(DISPC_VID_CONV_COEF(0, 0));
2401 DUMPREG(DISPC_VID_CONV_COEF(0, 1));
2402 DUMPREG(DISPC_VID_CONV_COEF(0, 2));
2403 DUMPREG(DISPC_VID_CONV_COEF(0, 3));
2404 DUMPREG(DISPC_VID_CONV_COEF(0, 4));
2405 DUMPREG(DISPC_VID_FIR_COEF_V(0, 0));
2406 DUMPREG(DISPC_VID_FIR_COEF_V(0, 1));
2407 DUMPREG(DISPC_VID_FIR_COEF_V(0, 2));
2408 DUMPREG(DISPC_VID_FIR_COEF_V(0, 3));
2409 DUMPREG(DISPC_VID_FIR_COEF_V(0, 4));
2410 DUMPREG(DISPC_VID_FIR_COEF_V(0, 5));
2411 DUMPREG(DISPC_VID_FIR_COEF_V(0, 6));
2412 DUMPREG(DISPC_VID_FIR_COEF_V(0, 7));
2414 DUMPREG(DISPC_VID_FIR_COEF_H(1, 0));
2415 DUMPREG(DISPC_VID_FIR_COEF_H(1, 1));
2416 DUMPREG(DISPC_VID_FIR_COEF_H(1, 2));
2417 DUMPREG(DISPC_VID_FIR_COEF_H(1, 3));
2418 DUMPREG(DISPC_VID_FIR_COEF_H(1, 4));
2419 DUMPREG(DISPC_VID_FIR_COEF_H(1, 5));
2420 DUMPREG(DISPC_VID_FIR_COEF_H(1, 6));
2421 DUMPREG(DISPC_VID_FIR_COEF_H(1, 7));
2422 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 0));
2423 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 1));
2424 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 2));
2425 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 3));
2426 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 4));
2427 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 5));
2428 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 6));
2429 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 7));
2430 DUMPREG(DISPC_VID_CONV_COEF(1, 0));
2431 DUMPREG(DISPC_VID_CONV_COEF(1, 1));
2432 DUMPREG(DISPC_VID_CONV_COEF(1, 2));
2433 DUMPREG(DISPC_VID_CONV_COEF(1, 3));
2434 DUMPREG(DISPC_VID_CONV_COEF(1, 4));
2435 DUMPREG(DISPC_VID_FIR_COEF_V(1, 0));
2436 DUMPREG(DISPC_VID_FIR_COEF_V(1, 1));
2437 DUMPREG(DISPC_VID_FIR_COEF_V(1, 2));
2438 DUMPREG(DISPC_VID_FIR_COEF_V(1, 3));
2439 DUMPREG(DISPC_VID_FIR_COEF_V(1, 4));
2440 DUMPREG(DISPC_VID_FIR_COEF_V(1, 5));
2441 DUMPREG(DISPC_VID_FIR_COEF_V(1, 6));
2442 DUMPREG(DISPC_VID_FIR_COEF_V(1, 7));
2444 DUMPREG(DISPC_VID_PRELOAD(0));
2445 DUMPREG(DISPC_VID_PRELOAD(1));
2447 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
2448 #undef DUMPREG
2451 static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
2452 bool ihs, bool ivs, u8 acbi, u8 acb)
2454 u32 l = 0;
2456 DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n",
2457 onoff, rf, ieo, ipc, ihs, ivs, acbi, acb);
2459 l |= FLD_VAL(onoff, 17, 17);
2460 l |= FLD_VAL(rf, 16, 16);
2461 l |= FLD_VAL(ieo, 15, 15);
2462 l |= FLD_VAL(ipc, 14, 14);
2463 l |= FLD_VAL(ihs, 13, 13);
2464 l |= FLD_VAL(ivs, 12, 12);
2465 l |= FLD_VAL(acbi, 11, 8);
2466 l |= FLD_VAL(acb, 7, 0);
2468 enable_clocks(1);
2469 dispc_write_reg(DISPC_POL_FREQ, l);
2470 enable_clocks(0);
2473 void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb)
2475 _dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0,
2476 (config & OMAP_DSS_LCD_RF) != 0,
2477 (config & OMAP_DSS_LCD_IEO) != 0,
2478 (config & OMAP_DSS_LCD_IPC) != 0,
2479 (config & OMAP_DSS_LCD_IHS) != 0,
2480 (config & OMAP_DSS_LCD_IVS) != 0,
2481 acbi, acb);
2484 /* with fck as input clock rate, find dispc dividers that produce req_pck */
2485 void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
2486 struct dispc_clock_info *cinfo)
2488 u16 pcd_min = is_tft ? 2 : 3;
2489 unsigned long best_pck;
2490 u16 best_ld, cur_ld;
2491 u16 best_pd, cur_pd;
2493 best_pck = 0;
2494 best_ld = 0;
2495 best_pd = 0;
2497 for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
2498 unsigned long lck = fck / cur_ld;
2500 for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) {
2501 unsigned long pck = lck / cur_pd;
2502 long old_delta = abs(best_pck - req_pck);
2503 long new_delta = abs(pck - req_pck);
2505 if (best_pck == 0 || new_delta < old_delta) {
2506 best_pck = pck;
2507 best_ld = cur_ld;
2508 best_pd = cur_pd;
2510 if (pck == req_pck)
2511 goto found;
2514 if (pck < req_pck)
2515 break;
2518 if (lck / pcd_min < req_pck)
2519 break;
2522 found:
2523 cinfo->lck_div = best_ld;
2524 cinfo->pck_div = best_pd;
2525 cinfo->lck = fck / cinfo->lck_div;
2526 cinfo->pck = cinfo->lck / cinfo->pck_div;
2529 /* calculate clock rates using dividers in cinfo */
2530 int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
2531 struct dispc_clock_info *cinfo)
2533 if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
2534 return -EINVAL;
2535 if (cinfo->pck_div < 2 || cinfo->pck_div > 255)
2536 return -EINVAL;
2538 cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
2539 cinfo->pck = cinfo->lck / cinfo->pck_div;
2541 return 0;
2544 int dispc_set_clock_div(struct dispc_clock_info *cinfo)
2546 DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
2547 DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
2549 dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div);
2551 return 0;
2554 int dispc_get_clock_div(struct dispc_clock_info *cinfo)
2556 unsigned long fck;
2558 fck = dispc_fclk_rate();
2560 cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
2561 cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
2563 cinfo->lck = fck / cinfo->lck_div;
2564 cinfo->pck = cinfo->lck / cinfo->pck_div;
2566 return 0;
2569 /* dispc.irq_lock has to be locked by the caller */
2570 static void _omap_dispc_set_irqs(void)
2572 u32 mask;
2573 u32 old_mask;
2574 int i;
2575 struct omap_dispc_isr_data *isr_data;
2577 mask = dispc.irq_error_mask;
2579 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2580 isr_data = &dispc.registered_isr[i];
2582 if (isr_data->isr == NULL)
2583 continue;
2585 mask |= isr_data->mask;
2588 enable_clocks(1);
2590 old_mask = dispc_read_reg(DISPC_IRQENABLE);
2591 /* clear the irqstatus for newly enabled irqs */
2592 dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
2594 dispc_write_reg(DISPC_IRQENABLE, mask);
2596 enable_clocks(0);
2599 int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2601 int i;
2602 int ret;
2603 unsigned long flags;
2604 struct omap_dispc_isr_data *isr_data;
2606 if (isr == NULL)
2607 return -EINVAL;
2609 spin_lock_irqsave(&dispc.irq_lock, flags);
2611 /* check for duplicate entry */
2612 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2613 isr_data = &dispc.registered_isr[i];
2614 if (isr_data->isr == isr && isr_data->arg == arg &&
2615 isr_data->mask == mask) {
2616 ret = -EINVAL;
2617 goto err;
2621 isr_data = NULL;
2622 ret = -EBUSY;
2624 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2625 isr_data = &dispc.registered_isr[i];
2627 if (isr_data->isr != NULL)
2628 continue;
2630 isr_data->isr = isr;
2631 isr_data->arg = arg;
2632 isr_data->mask = mask;
2633 ret = 0;
2635 break;
2638 _omap_dispc_set_irqs();
2640 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2642 return 0;
2643 err:
2644 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2646 return ret;
2648 EXPORT_SYMBOL(omap_dispc_register_isr);
2650 int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2652 int i;
2653 unsigned long flags;
2654 int ret = -EINVAL;
2655 struct omap_dispc_isr_data *isr_data;
2657 spin_lock_irqsave(&dispc.irq_lock, flags);
2659 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2660 isr_data = &dispc.registered_isr[i];
2661 if (isr_data->isr != isr || isr_data->arg != arg ||
2662 isr_data->mask != mask)
2663 continue;
2665 /* found the correct isr */
2667 isr_data->isr = NULL;
2668 isr_data->arg = NULL;
2669 isr_data->mask = 0;
2671 ret = 0;
2672 break;
2675 if (ret == 0)
2676 _omap_dispc_set_irqs();
2678 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2680 return ret;
2682 EXPORT_SYMBOL(omap_dispc_unregister_isr);
2684 #ifdef DEBUG
2685 static void print_irq_status(u32 status)
2687 if ((status & dispc.irq_error_mask) == 0)
2688 return;
2690 printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status);
2692 #define PIS(x) \
2693 if (status & DISPC_IRQ_##x) \
2694 printk(#x " ");
2695 PIS(GFX_FIFO_UNDERFLOW);
2696 PIS(OCP_ERR);
2697 PIS(VID1_FIFO_UNDERFLOW);
2698 PIS(VID2_FIFO_UNDERFLOW);
2699 PIS(SYNC_LOST);
2700 PIS(SYNC_LOST_DIGIT);
2701 #undef PIS
2703 printk("\n");
2705 #endif
2707 /* Called from dss.c. Note that we don't touch clocks here,
2708 * but we presume they are on because we got an IRQ. However,
2709 * an irq handler may turn the clocks off, so we may not have
2710 * clock later in the function. */
2711 void dispc_irq_handler(void)
2713 int i;
2714 u32 irqstatus;
2715 u32 handledirqs = 0;
2716 u32 unhandled_errors;
2717 struct omap_dispc_isr_data *isr_data;
2718 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
2720 spin_lock(&dispc.irq_lock);
2722 irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
2724 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2725 spin_lock(&dispc.irq_stats_lock);
2726 dispc.irq_stats.irq_count++;
2727 dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs);
2728 spin_unlock(&dispc.irq_stats_lock);
2729 #endif
2731 #ifdef DEBUG
2732 if (dss_debug)
2733 print_irq_status(irqstatus);
2734 #endif
2735 /* Ack the interrupt. Do it here before clocks are possibly turned
2736 * off */
2737 dispc_write_reg(DISPC_IRQSTATUS, irqstatus);
2738 /* flush posted write */
2739 dispc_read_reg(DISPC_IRQSTATUS);
2741 /* make a copy and unlock, so that isrs can unregister
2742 * themselves */
2743 memcpy(registered_isr, dispc.registered_isr,
2744 sizeof(registered_isr));
2746 spin_unlock(&dispc.irq_lock);
2748 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2749 isr_data = &registered_isr[i];
2751 if (!isr_data->isr)
2752 continue;
2754 if (isr_data->mask & irqstatus) {
2755 isr_data->isr(isr_data->arg, irqstatus);
2756 handledirqs |= isr_data->mask;
2760 spin_lock(&dispc.irq_lock);
2762 unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
2764 if (unhandled_errors) {
2765 dispc.error_irqs |= unhandled_errors;
2767 dispc.irq_error_mask &= ~unhandled_errors;
2768 _omap_dispc_set_irqs();
2770 schedule_work(&dispc.error_work);
2773 spin_unlock(&dispc.irq_lock);
2776 static void dispc_error_worker(struct work_struct *work)
2778 int i;
2779 u32 errors;
2780 unsigned long flags;
2782 spin_lock_irqsave(&dispc.irq_lock, flags);
2783 errors = dispc.error_irqs;
2784 dispc.error_irqs = 0;
2785 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2787 if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) {
2788 DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n");
2789 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2790 struct omap_overlay *ovl;
2791 ovl = omap_dss_get_overlay(i);
2793 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2794 continue;
2796 if (ovl->id == 0) {
2797 dispc_enable_plane(ovl->id, 0);
2798 dispc_go(ovl->manager->id);
2799 mdelay(50);
2800 break;
2805 if (errors & DISPC_IRQ_VID1_FIFO_UNDERFLOW) {
2806 DSSERR("VID1_FIFO_UNDERFLOW, disabling VID1\n");
2807 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2808 struct omap_overlay *ovl;
2809 ovl = omap_dss_get_overlay(i);
2811 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2812 continue;
2814 if (ovl->id == 1) {
2815 dispc_enable_plane(ovl->id, 0);
2816 dispc_go(ovl->manager->id);
2817 mdelay(50);
2818 break;
2823 if (errors & DISPC_IRQ_VID2_FIFO_UNDERFLOW) {
2824 DSSERR("VID2_FIFO_UNDERFLOW, disabling VID2\n");
2825 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2826 struct omap_overlay *ovl;
2827 ovl = omap_dss_get_overlay(i);
2829 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2830 continue;
2832 if (ovl->id == 2) {
2833 dispc_enable_plane(ovl->id, 0);
2834 dispc_go(ovl->manager->id);
2835 mdelay(50);
2836 break;
2841 if (errors & DISPC_IRQ_SYNC_LOST) {
2842 struct omap_overlay_manager *manager = NULL;
2843 bool enable = false;
2845 DSSERR("SYNC_LOST, disabling LCD\n");
2847 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2848 struct omap_overlay_manager *mgr;
2849 mgr = omap_dss_get_overlay_manager(i);
2851 if (mgr->id == OMAP_DSS_CHANNEL_LCD) {
2852 manager = mgr;
2853 enable = mgr->device->state ==
2854 OMAP_DSS_DISPLAY_ACTIVE;
2855 mgr->device->disable(mgr->device);
2856 break;
2860 if (manager) {
2861 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2862 struct omap_overlay *ovl;
2863 ovl = omap_dss_get_overlay(i);
2865 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2866 continue;
2868 if (ovl->id != 0 && ovl->manager == manager)
2869 dispc_enable_plane(ovl->id, 0);
2872 dispc_go(manager->id);
2873 mdelay(50);
2874 if (enable)
2875 manager->device->enable(manager->device);
2879 if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) {
2880 struct omap_overlay_manager *manager = NULL;
2881 bool enable = false;
2883 DSSERR("SYNC_LOST_DIGIT, disabling TV\n");
2885 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2886 struct omap_overlay_manager *mgr;
2887 mgr = omap_dss_get_overlay_manager(i);
2889 if (mgr->id == OMAP_DSS_CHANNEL_DIGIT) {
2890 manager = mgr;
2891 enable = mgr->device->state ==
2892 OMAP_DSS_DISPLAY_ACTIVE;
2893 mgr->device->disable(mgr->device);
2894 break;
2898 if (manager) {
2899 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2900 struct omap_overlay *ovl;
2901 ovl = omap_dss_get_overlay(i);
2903 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2904 continue;
2906 if (ovl->id != 0 && ovl->manager == manager)
2907 dispc_enable_plane(ovl->id, 0);
2910 dispc_go(manager->id);
2911 mdelay(50);
2912 if (enable)
2913 manager->device->enable(manager->device);
2917 if (errors & DISPC_IRQ_OCP_ERR) {
2918 DSSERR("OCP_ERR\n");
2919 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2920 struct omap_overlay_manager *mgr;
2921 mgr = omap_dss_get_overlay_manager(i);
2923 if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC)
2924 mgr->device->disable(mgr->device);
2928 spin_lock_irqsave(&dispc.irq_lock, flags);
2929 dispc.irq_error_mask |= errors;
2930 _omap_dispc_set_irqs();
2931 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2934 int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
2936 void dispc_irq_wait_handler(void *data, u32 mask)
2938 complete((struct completion *)data);
2941 int r;
2942 DECLARE_COMPLETION_ONSTACK(completion);
2944 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2945 irqmask);
2947 if (r)
2948 return r;
2950 timeout = wait_for_completion_timeout(&completion, timeout);
2952 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
2954 if (timeout == 0)
2955 return -ETIMEDOUT;
2957 if (timeout == -ERESTARTSYS)
2958 return -ERESTARTSYS;
2960 return 0;
2963 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
2964 unsigned long timeout)
2966 void dispc_irq_wait_handler(void *data, u32 mask)
2968 complete((struct completion *)data);
2971 int r;
2972 DECLARE_COMPLETION_ONSTACK(completion);
2974 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2975 irqmask);
2977 if (r)
2978 return r;
2980 timeout = wait_for_completion_interruptible_timeout(&completion,
2981 timeout);
2983 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
2985 if (timeout == 0)
2986 return -ETIMEDOUT;
2988 if (timeout == -ERESTARTSYS)
2989 return -ERESTARTSYS;
2991 return 0;
2994 #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
2995 void dispc_fake_vsync_irq(void)
2997 u32 irqstatus = DISPC_IRQ_VSYNC;
2998 int i;
3000 local_irq_disable();
3002 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3003 struct omap_dispc_isr_data *isr_data;
3004 isr_data = &dispc.registered_isr[i];
3006 if (!isr_data->isr)
3007 continue;
3009 if (isr_data->mask & irqstatus)
3010 isr_data->isr(isr_data->arg, irqstatus);
3013 local_irq_enable();
3015 #endif
3017 static void _omap_dispc_initialize_irq(void)
3019 unsigned long flags;
3021 spin_lock_irqsave(&dispc.irq_lock, flags);
3023 memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
3025 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
3027 /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
3028 * so clear it */
3029 dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS));
3031 _omap_dispc_set_irqs();
3033 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3036 void dispc_enable_sidle(void)
3038 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
3041 void dispc_disable_sidle(void)
3043 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
3046 static void _omap_dispc_initial_config(void)
3048 u32 l;
3050 l = dispc_read_reg(DISPC_SYSCONFIG);
3051 l = FLD_MOD(l, 2, 13, 12); /* MIDLEMODE: smart standby */
3052 l = FLD_MOD(l, 2, 4, 3); /* SIDLEMODE: smart idle */
3053 l = FLD_MOD(l, 1, 2, 2); /* ENWAKEUP */
3054 l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */
3055 dispc_write_reg(DISPC_SYSCONFIG, l);
3057 /* FUNCGATED */
3058 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
3060 /* L3 firewall setting: enable access to OCM RAM */
3061 /* XXX this should be somewhere in plat-omap */
3062 if (cpu_is_omap24xx())
3063 __raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0));
3065 _dispc_setup_color_conv_coef();
3067 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3069 dispc_read_plane_fifo_sizes();
3072 int dispc_init(void)
3074 u32 rev;
3076 spin_lock_init(&dispc.irq_lock);
3078 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3079 spin_lock_init(&dispc.irq_stats_lock);
3080 dispc.irq_stats.last_reset = jiffies;
3081 #endif
3083 INIT_WORK(&dispc.error_work, dispc_error_worker);
3085 dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
3086 if (!dispc.base) {
3087 DSSERR("can't ioremap DISPC\n");
3088 return -ENOMEM;
3091 enable_clocks(1);
3093 _omap_dispc_initial_config();
3095 _omap_dispc_initialize_irq();
3097 dispc_save_context();
3099 rev = dispc_read_reg(DISPC_REVISION);
3100 printk(KERN_INFO "OMAP DISPC rev %d.%d\n",
3101 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
3103 enable_clocks(0);
3105 return 0;
3108 void dispc_exit(void)
3110 iounmap(dispc.base);
3113 int dispc_enable_plane(enum omap_plane plane, bool enable)
3115 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
3117 enable_clocks(1);
3118 _dispc_enable_plane(plane, enable);
3119 enable_clocks(0);
3121 return 0;
3124 int dispc_setup_plane(enum omap_plane plane,
3125 u32 paddr, u16 screen_width,
3126 u16 pos_x, u16 pos_y,
3127 u16 width, u16 height,
3128 u16 out_width, u16 out_height,
3129 enum omap_color_mode color_mode,
3130 bool ilace,
3131 enum omap_dss_rotation_type rotation_type,
3132 u8 rotation, bool mirror, u8 global_alpha)
3134 int r = 0;
3136 DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
3137 "%dx%d, ilace %d, cmode %x, rot %d, mir %d\n",
3138 plane, paddr, screen_width, pos_x, pos_y,
3139 width, height,
3140 out_width, out_height,
3141 ilace, color_mode,
3142 rotation, mirror);
3144 enable_clocks(1);
3146 r = _dispc_setup_plane(plane,
3147 paddr, screen_width,
3148 pos_x, pos_y,
3149 width, height,
3150 out_width, out_height,
3151 color_mode, ilace,
3152 rotation_type,
3153 rotation, mirror,
3154 global_alpha);
3156 enable_clocks(0);
3158 return r;