Full support for Ginger Console
[linux-ginger.git] / drivers / video / omap2 / dss / dispc.c
blobadba0da44e551bb17567a78ac0c302992d4637c2
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 static struct {
152 void __iomem *base;
154 u32 fifo_size[3];
156 spinlock_t irq_lock;
157 u32 irq_error_mask;
158 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
159 u32 error_irqs;
160 struct work_struct error_work;
162 u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
163 } dispc;
165 static void _omap_dispc_set_irqs(void);
167 static inline void dispc_write_reg(const struct dispc_reg idx, u32 val)
169 __raw_writel(val, dispc.base + idx.idx);
172 static inline u32 dispc_read_reg(const struct dispc_reg idx)
174 return __raw_readl(dispc.base + idx.idx);
177 #define SR(reg) \
178 dispc.ctx[(DISPC_##reg).idx / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
179 #define RR(reg) \
180 dispc_write_reg(DISPC_##reg, dispc.ctx[(DISPC_##reg).idx / sizeof(u32)])
182 void dispc_save_context(void)
184 if (cpu_is_omap24xx())
185 return;
187 SR(SYSCONFIG);
188 SR(IRQENABLE);
189 SR(CONTROL);
190 SR(CONFIG);
191 SR(DEFAULT_COLOR0);
192 SR(DEFAULT_COLOR1);
193 SR(TRANS_COLOR0);
194 SR(TRANS_COLOR1);
195 SR(LINE_NUMBER);
196 SR(TIMING_H);
197 SR(TIMING_V);
198 SR(POL_FREQ);
199 SR(DIVISOR);
200 SR(GLOBAL_ALPHA);
201 SR(SIZE_DIG);
202 SR(SIZE_LCD);
204 SR(GFX_BA0);
205 SR(GFX_BA1);
206 SR(GFX_POSITION);
207 SR(GFX_SIZE);
208 SR(GFX_ATTRIBUTES);
209 SR(GFX_FIFO_THRESHOLD);
210 SR(GFX_ROW_INC);
211 SR(GFX_PIXEL_INC);
212 SR(GFX_WINDOW_SKIP);
213 SR(GFX_TABLE_BA);
215 SR(DATA_CYCLE1);
216 SR(DATA_CYCLE2);
217 SR(DATA_CYCLE3);
219 SR(CPR_COEF_R);
220 SR(CPR_COEF_G);
221 SR(CPR_COEF_B);
223 SR(GFX_PRELOAD);
225 /* VID1 */
226 SR(VID_BA0(0));
227 SR(VID_BA1(0));
228 SR(VID_POSITION(0));
229 SR(VID_SIZE(0));
230 SR(VID_ATTRIBUTES(0));
231 SR(VID_FIFO_THRESHOLD(0));
232 SR(VID_ROW_INC(0));
233 SR(VID_PIXEL_INC(0));
234 SR(VID_FIR(0));
235 SR(VID_PICTURE_SIZE(0));
236 SR(VID_ACCU0(0));
237 SR(VID_ACCU1(0));
239 SR(VID_FIR_COEF_H(0, 0));
240 SR(VID_FIR_COEF_H(0, 1));
241 SR(VID_FIR_COEF_H(0, 2));
242 SR(VID_FIR_COEF_H(0, 3));
243 SR(VID_FIR_COEF_H(0, 4));
244 SR(VID_FIR_COEF_H(0, 5));
245 SR(VID_FIR_COEF_H(0, 6));
246 SR(VID_FIR_COEF_H(0, 7));
248 SR(VID_FIR_COEF_HV(0, 0));
249 SR(VID_FIR_COEF_HV(0, 1));
250 SR(VID_FIR_COEF_HV(0, 2));
251 SR(VID_FIR_COEF_HV(0, 3));
252 SR(VID_FIR_COEF_HV(0, 4));
253 SR(VID_FIR_COEF_HV(0, 5));
254 SR(VID_FIR_COEF_HV(0, 6));
255 SR(VID_FIR_COEF_HV(0, 7));
257 SR(VID_CONV_COEF(0, 0));
258 SR(VID_CONV_COEF(0, 1));
259 SR(VID_CONV_COEF(0, 2));
260 SR(VID_CONV_COEF(0, 3));
261 SR(VID_CONV_COEF(0, 4));
263 SR(VID_FIR_COEF_V(0, 0));
264 SR(VID_FIR_COEF_V(0, 1));
265 SR(VID_FIR_COEF_V(0, 2));
266 SR(VID_FIR_COEF_V(0, 3));
267 SR(VID_FIR_COEF_V(0, 4));
268 SR(VID_FIR_COEF_V(0, 5));
269 SR(VID_FIR_COEF_V(0, 6));
270 SR(VID_FIR_COEF_V(0, 7));
272 SR(VID_PRELOAD(0));
274 /* VID2 */
275 SR(VID_BA0(1));
276 SR(VID_BA1(1));
277 SR(VID_POSITION(1));
278 SR(VID_SIZE(1));
279 SR(VID_ATTRIBUTES(1));
280 SR(VID_FIFO_THRESHOLD(1));
281 SR(VID_ROW_INC(1));
282 SR(VID_PIXEL_INC(1));
283 SR(VID_FIR(1));
284 SR(VID_PICTURE_SIZE(1));
285 SR(VID_ACCU0(1));
286 SR(VID_ACCU1(1));
288 SR(VID_FIR_COEF_H(1, 0));
289 SR(VID_FIR_COEF_H(1, 1));
290 SR(VID_FIR_COEF_H(1, 2));
291 SR(VID_FIR_COEF_H(1, 3));
292 SR(VID_FIR_COEF_H(1, 4));
293 SR(VID_FIR_COEF_H(1, 5));
294 SR(VID_FIR_COEF_H(1, 6));
295 SR(VID_FIR_COEF_H(1, 7));
297 SR(VID_FIR_COEF_HV(1, 0));
298 SR(VID_FIR_COEF_HV(1, 1));
299 SR(VID_FIR_COEF_HV(1, 2));
300 SR(VID_FIR_COEF_HV(1, 3));
301 SR(VID_FIR_COEF_HV(1, 4));
302 SR(VID_FIR_COEF_HV(1, 5));
303 SR(VID_FIR_COEF_HV(1, 6));
304 SR(VID_FIR_COEF_HV(1, 7));
306 SR(VID_CONV_COEF(1, 0));
307 SR(VID_CONV_COEF(1, 1));
308 SR(VID_CONV_COEF(1, 2));
309 SR(VID_CONV_COEF(1, 3));
310 SR(VID_CONV_COEF(1, 4));
312 SR(VID_FIR_COEF_V(1, 0));
313 SR(VID_FIR_COEF_V(1, 1));
314 SR(VID_FIR_COEF_V(1, 2));
315 SR(VID_FIR_COEF_V(1, 3));
316 SR(VID_FIR_COEF_V(1, 4));
317 SR(VID_FIR_COEF_V(1, 5));
318 SR(VID_FIR_COEF_V(1, 6));
319 SR(VID_FIR_COEF_V(1, 7));
321 SR(VID_PRELOAD(1));
324 void dispc_restore_context(void)
326 RR(SYSCONFIG);
327 RR(IRQENABLE);
328 /*RR(CONTROL);*/
329 RR(CONFIG);
330 RR(DEFAULT_COLOR0);
331 RR(DEFAULT_COLOR1);
332 RR(TRANS_COLOR0);
333 RR(TRANS_COLOR1);
334 RR(LINE_NUMBER);
335 RR(TIMING_H);
336 RR(TIMING_V);
337 RR(POL_FREQ);
338 RR(DIVISOR);
339 RR(GLOBAL_ALPHA);
340 RR(SIZE_DIG);
341 RR(SIZE_LCD);
343 RR(GFX_BA0);
344 RR(GFX_BA1);
345 RR(GFX_POSITION);
346 RR(GFX_SIZE);
347 RR(GFX_ATTRIBUTES);
348 RR(GFX_FIFO_THRESHOLD);
349 RR(GFX_ROW_INC);
350 RR(GFX_PIXEL_INC);
351 RR(GFX_WINDOW_SKIP);
352 RR(GFX_TABLE_BA);
354 RR(DATA_CYCLE1);
355 RR(DATA_CYCLE2);
356 RR(DATA_CYCLE3);
358 RR(CPR_COEF_R);
359 RR(CPR_COEF_G);
360 RR(CPR_COEF_B);
362 RR(GFX_PRELOAD);
364 /* VID1 */
365 RR(VID_BA0(0));
366 RR(VID_BA1(0));
367 RR(VID_POSITION(0));
368 RR(VID_SIZE(0));
369 RR(VID_ATTRIBUTES(0));
370 RR(VID_FIFO_THRESHOLD(0));
371 RR(VID_ROW_INC(0));
372 RR(VID_PIXEL_INC(0));
373 RR(VID_FIR(0));
374 RR(VID_PICTURE_SIZE(0));
375 RR(VID_ACCU0(0));
376 RR(VID_ACCU1(0));
378 RR(VID_FIR_COEF_H(0, 0));
379 RR(VID_FIR_COEF_H(0, 1));
380 RR(VID_FIR_COEF_H(0, 2));
381 RR(VID_FIR_COEF_H(0, 3));
382 RR(VID_FIR_COEF_H(0, 4));
383 RR(VID_FIR_COEF_H(0, 5));
384 RR(VID_FIR_COEF_H(0, 6));
385 RR(VID_FIR_COEF_H(0, 7));
387 RR(VID_FIR_COEF_HV(0, 0));
388 RR(VID_FIR_COEF_HV(0, 1));
389 RR(VID_FIR_COEF_HV(0, 2));
390 RR(VID_FIR_COEF_HV(0, 3));
391 RR(VID_FIR_COEF_HV(0, 4));
392 RR(VID_FIR_COEF_HV(0, 5));
393 RR(VID_FIR_COEF_HV(0, 6));
394 RR(VID_FIR_COEF_HV(0, 7));
396 RR(VID_CONV_COEF(0, 0));
397 RR(VID_CONV_COEF(0, 1));
398 RR(VID_CONV_COEF(0, 2));
399 RR(VID_CONV_COEF(0, 3));
400 RR(VID_CONV_COEF(0, 4));
402 RR(VID_FIR_COEF_V(0, 0));
403 RR(VID_FIR_COEF_V(0, 1));
404 RR(VID_FIR_COEF_V(0, 2));
405 RR(VID_FIR_COEF_V(0, 3));
406 RR(VID_FIR_COEF_V(0, 4));
407 RR(VID_FIR_COEF_V(0, 5));
408 RR(VID_FIR_COEF_V(0, 6));
409 RR(VID_FIR_COEF_V(0, 7));
411 RR(VID_PRELOAD(0));
413 /* VID2 */
414 RR(VID_BA0(1));
415 RR(VID_BA1(1));
416 RR(VID_POSITION(1));
417 RR(VID_SIZE(1));
418 RR(VID_ATTRIBUTES(1));
419 RR(VID_FIFO_THRESHOLD(1));
420 RR(VID_ROW_INC(1));
421 RR(VID_PIXEL_INC(1));
422 RR(VID_FIR(1));
423 RR(VID_PICTURE_SIZE(1));
424 RR(VID_ACCU0(1));
425 RR(VID_ACCU1(1));
427 RR(VID_FIR_COEF_H(1, 0));
428 RR(VID_FIR_COEF_H(1, 1));
429 RR(VID_FIR_COEF_H(1, 2));
430 RR(VID_FIR_COEF_H(1, 3));
431 RR(VID_FIR_COEF_H(1, 4));
432 RR(VID_FIR_COEF_H(1, 5));
433 RR(VID_FIR_COEF_H(1, 6));
434 RR(VID_FIR_COEF_H(1, 7));
436 RR(VID_FIR_COEF_HV(1, 0));
437 RR(VID_FIR_COEF_HV(1, 1));
438 RR(VID_FIR_COEF_HV(1, 2));
439 RR(VID_FIR_COEF_HV(1, 3));
440 RR(VID_FIR_COEF_HV(1, 4));
441 RR(VID_FIR_COEF_HV(1, 5));
442 RR(VID_FIR_COEF_HV(1, 6));
443 RR(VID_FIR_COEF_HV(1, 7));
445 RR(VID_CONV_COEF(1, 0));
446 RR(VID_CONV_COEF(1, 1));
447 RR(VID_CONV_COEF(1, 2));
448 RR(VID_CONV_COEF(1, 3));
449 RR(VID_CONV_COEF(1, 4));
451 RR(VID_FIR_COEF_V(1, 0));
452 RR(VID_FIR_COEF_V(1, 1));
453 RR(VID_FIR_COEF_V(1, 2));
454 RR(VID_FIR_COEF_V(1, 3));
455 RR(VID_FIR_COEF_V(1, 4));
456 RR(VID_FIR_COEF_V(1, 5));
457 RR(VID_FIR_COEF_V(1, 6));
458 RR(VID_FIR_COEF_V(1, 7));
460 RR(VID_PRELOAD(1));
462 /* enable last, because LCD & DIGIT enable are here */
463 RR(CONTROL);
466 #undef SR
467 #undef RR
469 static inline void enable_clocks(bool enable)
471 if (enable)
472 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
473 else
474 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
477 bool dispc_go_busy(enum omap_channel channel)
479 int bit;
481 if (channel == OMAP_DSS_CHANNEL_LCD)
482 bit = 5; /* GOLCD */
483 else
484 bit = 6; /* GODIGIT */
486 return REG_GET(DISPC_CONTROL, bit, bit) == 1;
489 void dispc_go(enum omap_channel channel)
491 int bit;
493 enable_clocks(1);
495 if (channel == OMAP_DSS_CHANNEL_LCD)
496 bit = 0; /* LCDENABLE */
497 else
498 bit = 1; /* DIGITALENABLE */
500 /* if the channel is not enabled, we don't need GO */
501 if (REG_GET(DISPC_CONTROL, bit, bit) == 0)
502 goto end;
504 if (channel == OMAP_DSS_CHANNEL_LCD)
505 bit = 5; /* GOLCD */
506 else
507 bit = 6; /* GODIGIT */
509 if (REG_GET(DISPC_CONTROL, bit, bit) == 1) {
510 DSSERR("GO bit not down for channel %d\n", channel);
511 goto end;
514 DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT");
516 REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
517 end:
518 enable_clocks(0);
521 static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
523 BUG_ON(plane == OMAP_DSS_GFX);
525 dispc_write_reg(DISPC_VID_FIR_COEF_H(plane-1, reg), value);
528 static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
530 BUG_ON(plane == OMAP_DSS_GFX);
532 dispc_write_reg(DISPC_VID_FIR_COEF_HV(plane-1, reg), value);
535 static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
537 BUG_ON(plane == OMAP_DSS_GFX);
539 dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
542 static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
543 int vscaleup, int five_taps)
545 /* Coefficients for horizontal up-sampling */
546 static const u32 coef_hup[8] = {
547 0x00800000,
548 0x0D7CF800,
549 0x1E70F5FF,
550 0x335FF5FE,
551 0xF74949F7,
552 0xF55F33FB,
553 0xF5701EFE,
554 0xF87C0DFF,
557 /* Coefficients for horizontal down-sampling */
558 static const u32 coef_hdown[8] = {
559 0x24382400,
560 0x28371FFE,
561 0x2C361BFB,
562 0x303516F9,
563 0x11343311,
564 0x1635300C,
565 0x1B362C08,
566 0x1F372804,
569 /* Coefficients for horizontal and vertical up-sampling */
570 static const u32 coef_hvup[2][8] = {
572 0x00800000,
573 0x037B02FF,
574 0x0C6F05FE,
575 0x205907FB,
576 0x00404000,
577 0x075920FE,
578 0x056F0CFF,
579 0x027B0300,
582 0x00800000,
583 0x0D7CF8FF,
584 0x1E70F5FE,
585 0x335FF5FB,
586 0xF7404000,
587 0xF55F33FE,
588 0xF5701EFF,
589 0xF87C0D00,
593 /* Coefficients for horizontal and vertical down-sampling */
594 static const u32 coef_hvdown[2][8] = {
596 0x24382400,
597 0x28391F04,
598 0x2D381B08,
599 0x3237170C,
600 0x123737F7,
601 0x173732F9,
602 0x1B382DFB,
603 0x1F3928FE,
606 0x24382400,
607 0x28371F04,
608 0x2C361B08,
609 0x3035160C,
610 0x113433F7,
611 0x163530F9,
612 0x1B362CFB,
613 0x1F3728FE,
617 /* Coefficients for vertical up-sampling */
618 static const u32 coef_vup[8] = {
619 0x00000000,
620 0x0000FF00,
621 0x0000FEFF,
622 0x0000FBFE,
623 0x000000F7,
624 0x0000FEFB,
625 0x0000FFFE,
626 0x000000FF,
630 /* Coefficients for vertical down-sampling */
631 static const u32 coef_vdown[8] = {
632 0x00000000,
633 0x000004FE,
634 0x000008FB,
635 0x00000CF9,
636 0x0000F711,
637 0x0000F90C,
638 0x0000FB08,
639 0x0000FE04,
642 const u32 *h_coef;
643 const u32 *hv_coef;
644 const u32 *hv_coef_mod;
645 const u32 *v_coef;
646 int i;
648 if (hscaleup)
649 h_coef = coef_hup;
650 else
651 h_coef = coef_hdown;
653 if (vscaleup) {
654 hv_coef = coef_hvup[five_taps];
655 v_coef = coef_vup;
657 if (hscaleup)
658 hv_coef_mod = NULL;
659 else
660 hv_coef_mod = coef_hvdown[five_taps];
661 } else {
662 hv_coef = coef_hvdown[five_taps];
663 v_coef = coef_vdown;
665 if (hscaleup)
666 hv_coef_mod = coef_hvup[five_taps];
667 else
668 hv_coef_mod = NULL;
671 for (i = 0; i < 8; i++) {
672 u32 h, hv;
674 h = h_coef[i];
676 hv = hv_coef[i];
678 if (hv_coef_mod) {
679 hv &= 0xffffff00;
680 hv |= (hv_coef_mod[i] & 0xff);
683 _dispc_write_firh_reg(plane, i, h);
684 _dispc_write_firhv_reg(plane, i, hv);
687 if (!five_taps)
688 return;
690 for (i = 0; i < 8; i++) {
691 u32 v;
692 v = v_coef[i];
693 _dispc_write_firv_reg(plane, i, v);
697 static void _dispc_setup_color_conv_coef(void)
699 const struct color_conv_coef {
700 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
701 int full_range;
702 } ctbl_bt601_5 = {
703 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
706 const struct color_conv_coef *ct;
708 #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
710 ct = &ctbl_bt601_5;
712 dispc_write_reg(DISPC_VID_CONV_COEF(0, 0), CVAL(ct->rcr, ct->ry));
713 dispc_write_reg(DISPC_VID_CONV_COEF(0, 1), CVAL(ct->gy, ct->rcb));
714 dispc_write_reg(DISPC_VID_CONV_COEF(0, 2), CVAL(ct->gcb, ct->gcr));
715 dispc_write_reg(DISPC_VID_CONV_COEF(0, 3), CVAL(ct->bcr, ct->by));
716 dispc_write_reg(DISPC_VID_CONV_COEF(0, 4), CVAL(0, ct->bcb));
718 dispc_write_reg(DISPC_VID_CONV_COEF(1, 0), CVAL(ct->rcr, ct->ry));
719 dispc_write_reg(DISPC_VID_CONV_COEF(1, 1), CVAL(ct->gy, ct->rcb));
720 dispc_write_reg(DISPC_VID_CONV_COEF(1, 2), CVAL(ct->gcb, ct->gcr));
721 dispc_write_reg(DISPC_VID_CONV_COEF(1, 3), CVAL(ct->bcr, ct->by));
722 dispc_write_reg(DISPC_VID_CONV_COEF(1, 4), CVAL(0, ct->bcb));
724 #undef CVAL
726 REG_FLD_MOD(DISPC_VID_ATTRIBUTES(0), ct->full_range, 11, 11);
727 REG_FLD_MOD(DISPC_VID_ATTRIBUTES(1), ct->full_range, 11, 11);
731 static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
733 const struct dispc_reg ba0_reg[] = { DISPC_GFX_BA0,
734 DISPC_VID_BA0(0),
735 DISPC_VID_BA0(1) };
737 dispc_write_reg(ba0_reg[plane], paddr);
740 static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr)
742 const struct dispc_reg ba1_reg[] = { DISPC_GFX_BA1,
743 DISPC_VID_BA1(0),
744 DISPC_VID_BA1(1) };
746 dispc_write_reg(ba1_reg[plane], paddr);
749 static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
751 const struct dispc_reg pos_reg[] = { DISPC_GFX_POSITION,
752 DISPC_VID_POSITION(0),
753 DISPC_VID_POSITION(1) };
755 u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
756 dispc_write_reg(pos_reg[plane], val);
759 static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
761 const struct dispc_reg siz_reg[] = { DISPC_GFX_SIZE,
762 DISPC_VID_PICTURE_SIZE(0),
763 DISPC_VID_PICTURE_SIZE(1) };
764 u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
765 dispc_write_reg(siz_reg[plane], val);
768 static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
770 u32 val;
771 const struct dispc_reg vsi_reg[] = { DISPC_VID_SIZE(0),
772 DISPC_VID_SIZE(1) };
774 BUG_ON(plane == OMAP_DSS_GFX);
776 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
777 dispc_write_reg(vsi_reg[plane-1], val);
780 static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
783 BUG_ON(plane == OMAP_DSS_VIDEO1);
785 if (cpu_is_omap24xx())
786 return;
788 if (plane == OMAP_DSS_GFX)
789 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
790 else if (plane == OMAP_DSS_VIDEO2)
791 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16);
794 static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
796 const struct dispc_reg ri_reg[] = { DISPC_GFX_PIXEL_INC,
797 DISPC_VID_PIXEL_INC(0),
798 DISPC_VID_PIXEL_INC(1) };
800 dispc_write_reg(ri_reg[plane], inc);
803 static void _dispc_set_row_inc(enum omap_plane plane, s32 inc)
805 const struct dispc_reg ri_reg[] = { DISPC_GFX_ROW_INC,
806 DISPC_VID_ROW_INC(0),
807 DISPC_VID_ROW_INC(1) };
809 dispc_write_reg(ri_reg[plane], inc);
812 static void _dispc_set_color_mode(enum omap_plane plane,
813 enum omap_color_mode color_mode)
815 u32 m = 0;
817 switch (color_mode) {
818 case OMAP_DSS_COLOR_CLUT1:
819 m = 0x0; break;
820 case OMAP_DSS_COLOR_CLUT2:
821 m = 0x1; break;
822 case OMAP_DSS_COLOR_CLUT4:
823 m = 0x2; break;
824 case OMAP_DSS_COLOR_CLUT8:
825 m = 0x3; break;
826 case OMAP_DSS_COLOR_RGB12U:
827 m = 0x4; break;
828 case OMAP_DSS_COLOR_ARGB16:
829 m = 0x5; break;
830 case OMAP_DSS_COLOR_RGB16:
831 m = 0x6; break;
832 case OMAP_DSS_COLOR_RGB24U:
833 m = 0x8; break;
834 case OMAP_DSS_COLOR_RGB24P:
835 m = 0x9; break;
836 case OMAP_DSS_COLOR_YUV2:
837 m = 0xa; break;
838 case OMAP_DSS_COLOR_UYVY:
839 m = 0xb; break;
840 case OMAP_DSS_COLOR_ARGB32:
841 m = 0xc; break;
842 case OMAP_DSS_COLOR_RGBA32:
843 m = 0xd; break;
844 case OMAP_DSS_COLOR_RGBX32:
845 m = 0xe; break;
846 default:
847 BUG(); break;
850 REG_FLD_MOD(dispc_reg_att[plane], m, 4, 1);
853 static void _dispc_set_channel_out(enum omap_plane plane,
854 enum omap_channel channel)
856 int shift;
857 u32 val;
859 switch (plane) {
860 case OMAP_DSS_GFX:
861 shift = 8;
862 break;
863 case OMAP_DSS_VIDEO1:
864 case OMAP_DSS_VIDEO2:
865 shift = 16;
866 break;
867 default:
868 BUG();
869 return;
872 val = dispc_read_reg(dispc_reg_att[plane]);
873 val = FLD_MOD(val, channel, shift, shift);
874 dispc_write_reg(dispc_reg_att[plane], val);
877 void dispc_set_burst_size(enum omap_plane plane,
878 enum omap_burst_size burst_size)
880 int shift;
881 u32 val;
883 enable_clocks(1);
885 switch (plane) {
886 case OMAP_DSS_GFX:
887 shift = 6;
888 break;
889 case OMAP_DSS_VIDEO1:
890 case OMAP_DSS_VIDEO2:
891 shift = 14;
892 break;
893 default:
894 BUG();
895 return;
898 val = dispc_read_reg(dispc_reg_att[plane]);
899 val = FLD_MOD(val, burst_size, shift+1, shift);
900 dispc_write_reg(dispc_reg_att[plane], val);
902 enable_clocks(0);
905 static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
907 u32 val;
909 BUG_ON(plane == OMAP_DSS_GFX);
911 val = dispc_read_reg(dispc_reg_att[plane]);
912 val = FLD_MOD(val, enable, 9, 9);
913 dispc_write_reg(dispc_reg_att[plane], val);
916 void dispc_enable_replication(enum omap_plane plane, bool enable)
918 int bit;
920 if (plane == OMAP_DSS_GFX)
921 bit = 5;
922 else
923 bit = 10;
925 enable_clocks(1);
926 REG_FLD_MOD(dispc_reg_att[plane], enable, bit, bit);
927 enable_clocks(0);
930 void dispc_set_lcd_size(u16 width, u16 height)
932 u32 val;
933 BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
934 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
935 enable_clocks(1);
936 dispc_write_reg(DISPC_SIZE_LCD, val);
937 enable_clocks(0);
940 void dispc_set_digit_size(u16 width, u16 height)
942 u32 val;
943 BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
944 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
945 enable_clocks(1);
946 dispc_write_reg(DISPC_SIZE_DIG, val);
947 enable_clocks(0);
950 static void dispc_read_plane_fifo_sizes(void)
952 const struct dispc_reg fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
953 DISPC_VID_FIFO_SIZE_STATUS(0),
954 DISPC_VID_FIFO_SIZE_STATUS(1) };
955 u32 size;
956 int plane;
958 enable_clocks(1);
960 for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
961 if (cpu_is_omap24xx())
962 size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 8, 0);
963 else if (cpu_is_omap34xx())
964 size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 10, 0);
965 else
966 BUG();
968 dispc.fifo_size[plane] = size;
971 enable_clocks(0);
974 u32 dispc_get_plane_fifo_size(enum omap_plane plane)
976 return dispc.fifo_size[plane];
979 void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
981 const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
982 DISPC_VID_FIFO_THRESHOLD(0),
983 DISPC_VID_FIFO_THRESHOLD(1) };
984 enable_clocks(1);
986 DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
987 plane,
988 REG_GET(ftrs_reg[plane], 11, 0),
989 REG_GET(ftrs_reg[plane], 27, 16),
990 low, high);
992 if (cpu_is_omap24xx())
993 dispc_write_reg(ftrs_reg[plane],
994 FLD_VAL(high, 24, 16) | FLD_VAL(low, 8, 0));
995 else
996 dispc_write_reg(ftrs_reg[plane],
997 FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0));
999 enable_clocks(0);
1002 void dispc_enable_fifomerge(bool enable)
1004 enable_clocks(1);
1006 DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1007 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
1009 enable_clocks(0);
1012 static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
1014 u32 val;
1015 const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0),
1016 DISPC_VID_FIR(1) };
1018 BUG_ON(plane == OMAP_DSS_GFX);
1020 if (cpu_is_omap24xx())
1021 val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0);
1022 else
1023 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1024 dispc_write_reg(fir_reg[plane-1], val);
1027 static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
1029 u32 val;
1030 const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
1031 DISPC_VID_ACCU0(1) };
1033 BUG_ON(plane == OMAP_DSS_GFX);
1035 val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
1036 dispc_write_reg(ac0_reg[plane-1], val);
1039 static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
1041 u32 val;
1042 const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
1043 DISPC_VID_ACCU1(1) };
1045 BUG_ON(plane == OMAP_DSS_GFX);
1047 val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
1048 dispc_write_reg(ac1_reg[plane-1], val);
1052 static void _dispc_set_scaling(enum omap_plane plane,
1053 u16 orig_width, u16 orig_height,
1054 u16 out_width, u16 out_height,
1055 bool ilace, bool five_taps,
1056 bool fieldmode)
1058 int fir_hinc;
1059 int fir_vinc;
1060 int hscaleup, vscaleup;
1061 int accu0 = 0;
1062 int accu1 = 0;
1063 u32 l;
1065 BUG_ON(plane == OMAP_DSS_GFX);
1067 hscaleup = orig_width <= out_width;
1068 vscaleup = orig_height <= out_height;
1070 _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps);
1072 if (!orig_width || orig_width == out_width)
1073 fir_hinc = 0;
1074 else
1075 fir_hinc = 1024 * orig_width / out_width;
1077 if (!orig_height || orig_height == out_height)
1078 fir_vinc = 0;
1079 else
1080 fir_vinc = 1024 * orig_height / out_height;
1082 _dispc_set_fir(plane, fir_hinc, fir_vinc);
1084 l = dispc_read_reg(dispc_reg_att[plane]);
1085 l &= ~((0x0f << 5) | (0x3 << 21));
1087 l |= fir_hinc ? (1 << 5) : 0;
1088 l |= fir_vinc ? (1 << 6) : 0;
1090 l |= hscaleup ? 0 : (1 << 7);
1091 l |= vscaleup ? 0 : (1 << 8);
1093 l |= five_taps ? (1 << 21) : 0;
1094 l |= five_taps ? (1 << 22) : 0;
1096 dispc_write_reg(dispc_reg_att[plane], l);
1099 * field 0 = even field = bottom field
1100 * field 1 = odd field = top field
1102 if (ilace && !fieldmode) {
1103 accu1 = 0;
1104 accu0 = (fir_vinc / 2) & 0x3ff;
1105 if (accu0 >= 1024/2) {
1106 accu1 = 1024/2;
1107 accu0 -= accu1;
1111 _dispc_set_vid_accu0(plane, 0, accu0);
1112 _dispc_set_vid_accu1(plane, 0, accu1);
1115 static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
1116 bool mirroring, enum omap_color_mode color_mode)
1118 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1119 color_mode == OMAP_DSS_COLOR_UYVY) {
1120 int vidrot = 0;
1122 if (mirroring) {
1123 switch (rotation) {
1124 case OMAP_DSS_ROT_0:
1125 vidrot = 2;
1126 break;
1127 case OMAP_DSS_ROT_90:
1128 vidrot = 1;
1129 break;
1130 case OMAP_DSS_ROT_180:
1131 vidrot = 0;
1132 break;
1133 case OMAP_DSS_ROT_270:
1134 vidrot = 3;
1135 break;
1137 } else {
1138 switch (rotation) {
1139 case OMAP_DSS_ROT_0:
1140 vidrot = 0;
1141 break;
1142 case OMAP_DSS_ROT_90:
1143 vidrot = 1;
1144 break;
1145 case OMAP_DSS_ROT_180:
1146 vidrot = 2;
1147 break;
1148 case OMAP_DSS_ROT_270:
1149 vidrot = 3;
1150 break;
1154 REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
1156 if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
1157 REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
1158 else
1159 REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
1160 } else {
1161 REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
1162 REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
1166 static int color_mode_to_bpp(enum omap_color_mode color_mode)
1168 switch (color_mode) {
1169 case OMAP_DSS_COLOR_CLUT1:
1170 return 1;
1171 case OMAP_DSS_COLOR_CLUT2:
1172 return 2;
1173 case OMAP_DSS_COLOR_CLUT4:
1174 return 4;
1175 case OMAP_DSS_COLOR_CLUT8:
1176 return 8;
1177 case OMAP_DSS_COLOR_RGB12U:
1178 case OMAP_DSS_COLOR_RGB16:
1179 case OMAP_DSS_COLOR_ARGB16:
1180 case OMAP_DSS_COLOR_YUV2:
1181 case OMAP_DSS_COLOR_UYVY:
1182 return 16;
1183 case OMAP_DSS_COLOR_RGB24P:
1184 return 24;
1185 case OMAP_DSS_COLOR_RGB24U:
1186 case OMAP_DSS_COLOR_ARGB32:
1187 case OMAP_DSS_COLOR_RGBA32:
1188 case OMAP_DSS_COLOR_RGBX32:
1189 return 32;
1190 default:
1191 BUG();
1195 static s32 pixinc(int pixels, u8 ps)
1197 if (pixels == 1)
1198 return 1;
1199 else if (pixels > 1)
1200 return 1 + (pixels - 1) * ps;
1201 else if (pixels < 0)
1202 return 1 - (-pixels + 1) * ps;
1203 else
1204 BUG();
1207 static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
1208 u16 screen_width,
1209 u16 width, u16 height,
1210 enum omap_color_mode color_mode, bool fieldmode,
1211 unsigned int field_offset,
1212 unsigned *offset0, unsigned *offset1,
1213 s32 *row_inc, s32 *pix_inc)
1215 u8 ps;
1217 /* FIXME CLUT formats */
1218 switch (color_mode) {
1219 case OMAP_DSS_COLOR_CLUT1:
1220 case OMAP_DSS_COLOR_CLUT2:
1221 case OMAP_DSS_COLOR_CLUT4:
1222 case OMAP_DSS_COLOR_CLUT8:
1223 BUG();
1224 return;
1225 case OMAP_DSS_COLOR_YUV2:
1226 case OMAP_DSS_COLOR_UYVY:
1227 ps = 4;
1228 break;
1229 default:
1230 ps = color_mode_to_bpp(color_mode) / 8;
1231 break;
1234 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1235 width, height);
1238 * field 0 = even field = bottom field
1239 * field 1 = odd field = top field
1241 switch (rotation + mirror * 4) {
1242 case OMAP_DSS_ROT_0:
1243 case OMAP_DSS_ROT_180:
1245 * If the pixel format is YUV or UYVY divide the width
1246 * of the image by 2 for 0 and 180 degree rotation.
1248 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1249 color_mode == OMAP_DSS_COLOR_UYVY)
1250 width = width >> 1;
1251 case OMAP_DSS_ROT_90:
1252 case OMAP_DSS_ROT_270:
1253 *offset1 = 0;
1254 if (field_offset)
1255 *offset0 = field_offset * screen_width * ps;
1256 else
1257 *offset0 = 0;
1259 *row_inc = pixinc(1 + (screen_width - width) +
1260 (fieldmode ? screen_width : 0),
1261 ps);
1262 *pix_inc = pixinc(1, ps);
1263 break;
1265 case OMAP_DSS_ROT_0 + 4:
1266 case OMAP_DSS_ROT_180 + 4:
1267 /* If the pixel format is YUV or UYVY divide the width
1268 * of the image by 2 for 0 degree and 180 degree
1270 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1271 color_mode == OMAP_DSS_COLOR_UYVY)
1272 width = width >> 1;
1273 case OMAP_DSS_ROT_90 + 4:
1274 case OMAP_DSS_ROT_270 + 4:
1275 *offset1 = 0;
1276 if (field_offset)
1277 *offset0 = field_offset * screen_width * ps;
1278 else
1279 *offset0 = 0;
1280 *row_inc = pixinc(1 - (screen_width + width) -
1281 (fieldmode ? screen_width : 0),
1282 ps);
1283 *pix_inc = pixinc(1, ps);
1284 break;
1286 default:
1287 BUG();
1291 static void calc_dma_rotation_offset(u8 rotation, bool mirror,
1292 u16 screen_width,
1293 u16 width, u16 height,
1294 enum omap_color_mode color_mode, bool fieldmode,
1295 unsigned int field_offset,
1296 unsigned *offset0, unsigned *offset1,
1297 s32 *row_inc, s32 *pix_inc)
1299 u8 ps;
1300 u16 fbw, fbh;
1302 /* FIXME CLUT formats */
1303 switch (color_mode) {
1304 case OMAP_DSS_COLOR_CLUT1:
1305 case OMAP_DSS_COLOR_CLUT2:
1306 case OMAP_DSS_COLOR_CLUT4:
1307 case OMAP_DSS_COLOR_CLUT8:
1308 BUG();
1309 return;
1310 default:
1311 ps = color_mode_to_bpp(color_mode) / 8;
1312 break;
1315 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1316 width, height);
1318 /* width & height are overlay sizes, convert to fb sizes */
1320 if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) {
1321 fbw = width;
1322 fbh = height;
1323 } else {
1324 fbw = height;
1325 fbh = width;
1329 * field 0 = even field = bottom field
1330 * field 1 = odd field = top field
1332 switch (rotation + mirror * 4) {
1333 case OMAP_DSS_ROT_0:
1334 *offset1 = 0;
1335 if (field_offset)
1336 *offset0 = *offset1 + field_offset * screen_width * ps;
1337 else
1338 *offset0 = *offset1;
1339 *row_inc = pixinc(1 + (screen_width - fbw) +
1340 (fieldmode ? screen_width : 0),
1341 ps);
1342 *pix_inc = pixinc(1, ps);
1343 break;
1344 case OMAP_DSS_ROT_90:
1345 *offset1 = screen_width * (fbh - 1) * ps;
1346 if (field_offset)
1347 *offset0 = *offset1 + field_offset * ps;
1348 else
1349 *offset0 = *offset1;
1350 *row_inc = pixinc(screen_width * (fbh - 1) + 1 +
1351 (fieldmode ? 1 : 0), ps);
1352 *pix_inc = pixinc(-screen_width, ps);
1353 break;
1354 case OMAP_DSS_ROT_180:
1355 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1356 if (field_offset)
1357 *offset0 = *offset1 - field_offset * screen_width * ps;
1358 else
1359 *offset0 = *offset1;
1360 *row_inc = pixinc(-1 -
1361 (screen_width - fbw) -
1362 (fieldmode ? screen_width : 0),
1363 ps);
1364 *pix_inc = pixinc(-1, ps);
1365 break;
1366 case OMAP_DSS_ROT_270:
1367 *offset1 = (fbw - 1) * ps;
1368 if (field_offset)
1369 *offset0 = *offset1 - field_offset * ps;
1370 else
1371 *offset0 = *offset1;
1372 *row_inc = pixinc(-screen_width * (fbh - 1) - 1 -
1373 (fieldmode ? 1 : 0), ps);
1374 *pix_inc = pixinc(screen_width, ps);
1375 break;
1377 /* mirroring */
1378 case OMAP_DSS_ROT_0 + 4:
1379 *offset1 = (fbw - 1) * ps;
1380 if (field_offset)
1381 *offset0 = *offset1 + field_offset * screen_width * ps;
1382 else
1383 *offset0 = *offset1;
1384 *row_inc = pixinc(screen_width * 2 - 1 +
1385 (fieldmode ? screen_width : 0),
1386 ps);
1387 *pix_inc = pixinc(-1, ps);
1388 break;
1390 case OMAP_DSS_ROT_90 + 4:
1391 *offset1 = 0;
1392 if (field_offset)
1393 *offset0 = *offset1 + field_offset * ps;
1394 else
1395 *offset0 = *offset1;
1396 *row_inc = pixinc(-screen_width * (fbh - 1) + 1 +
1397 (fieldmode ? 1 : 0),
1398 ps);
1399 *pix_inc = pixinc(screen_width, ps);
1400 break;
1402 case OMAP_DSS_ROT_180 + 4:
1403 *offset1 = screen_width * (fbh - 1) * ps;
1404 if (field_offset)
1405 *offset0 = *offset1 - field_offset * screen_width * ps;
1406 else
1407 *offset0 = *offset1;
1408 *row_inc = pixinc(1 - screen_width * 2 -
1409 (fieldmode ? screen_width : 0),
1410 ps);
1411 *pix_inc = pixinc(1, ps);
1412 break;
1414 case OMAP_DSS_ROT_270 + 4:
1415 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1416 if (field_offset)
1417 *offset0 = *offset1 - field_offset * ps;
1418 else
1419 *offset0 = *offset1;
1420 *row_inc = pixinc(screen_width * (fbh - 1) - 1 -
1421 (fieldmode ? 1 : 0),
1422 ps);
1423 *pix_inc = pixinc(-screen_width, ps);
1424 break;
1426 default:
1427 BUG();
1431 static unsigned long calc_fclk_five_taps(u16 width, u16 height,
1432 u16 out_width, u16 out_height, enum omap_color_mode color_mode)
1434 u32 fclk = 0;
1435 /* FIXME venc pclk? */
1436 u64 tmp, pclk = dispc_pclk_rate();
1438 if (height > out_height) {
1439 /* FIXME get real display PPL */
1440 unsigned int ppl = 800;
1442 tmp = pclk * height * out_width;
1443 do_div(tmp, 2 * out_height * ppl);
1444 fclk = tmp;
1446 if (height > 2 * out_height && ppl != out_width) {
1447 tmp = pclk * (height - 2 * out_height) * out_width;
1448 do_div(tmp, 2 * out_height * (ppl - out_width));
1449 fclk = max(fclk, (u32) tmp);
1453 if (width > out_width) {
1454 tmp = pclk * width;
1455 do_div(tmp, out_width);
1456 fclk = max(fclk, (u32) tmp);
1458 if (color_mode == OMAP_DSS_COLOR_RGB24U)
1459 fclk <<= 1;
1462 return fclk;
1465 static unsigned long calc_fclk(u16 width, u16 height,
1466 u16 out_width, u16 out_height)
1468 unsigned int hf, vf;
1471 * FIXME how to determine the 'A' factor
1472 * for the no downscaling case ?
1475 if (width > 3 * out_width)
1476 hf = 4;
1477 else if (width > 2 * out_width)
1478 hf = 3;
1479 else if (width > out_width)
1480 hf = 2;
1481 else
1482 hf = 1;
1484 if (height > out_height)
1485 vf = 2;
1486 else
1487 vf = 1;
1489 /* FIXME venc pclk? */
1490 return dispc_pclk_rate() * vf * hf;
1493 void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
1495 enable_clocks(1);
1496 _dispc_set_channel_out(plane, channel_out);
1497 enable_clocks(0);
1500 static int _dispc_setup_plane(enum omap_plane plane,
1501 u32 paddr, u16 screen_width,
1502 u16 pos_x, u16 pos_y,
1503 u16 width, u16 height,
1504 u16 out_width, u16 out_height,
1505 enum omap_color_mode color_mode,
1506 bool ilace,
1507 enum omap_dss_rotation_type rotation_type,
1508 u8 rotation, int mirror,
1509 u8 global_alpha)
1511 const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
1512 bool five_taps = 0;
1513 bool fieldmode = 0;
1514 int cconv = 0;
1515 unsigned offset0, offset1;
1516 s32 row_inc;
1517 s32 pix_inc;
1518 u16 frame_height = height;
1519 unsigned int field_offset = 0;
1521 if (paddr == 0)
1522 return -EINVAL;
1524 if (ilace && height == out_height)
1525 fieldmode = 1;
1527 if (ilace) {
1528 if (fieldmode)
1529 height /= 2;
1530 pos_y /= 2;
1531 out_height /= 2;
1533 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
1534 "out_height %d\n",
1535 height, pos_y, out_height);
1538 if (plane == OMAP_DSS_GFX) {
1539 if (width != out_width || height != out_height)
1540 return -EINVAL;
1542 switch (color_mode) {
1543 case OMAP_DSS_COLOR_ARGB16:
1544 case OMAP_DSS_COLOR_ARGB32:
1545 case OMAP_DSS_COLOR_RGBA32:
1546 case OMAP_DSS_COLOR_RGBX32:
1547 if (cpu_is_omap24xx())
1548 return -EINVAL;
1549 /* fall through */
1550 case OMAP_DSS_COLOR_RGB12U:
1551 case OMAP_DSS_COLOR_RGB16:
1552 case OMAP_DSS_COLOR_RGB24P:
1553 case OMAP_DSS_COLOR_RGB24U:
1554 break;
1556 default:
1557 return -EINVAL;
1559 } else {
1560 /* video plane */
1562 unsigned long fclk = 0;
1564 if (out_width < width / maxdownscale ||
1565 out_width > width * 8)
1566 return -EINVAL;
1568 if (out_height < height / maxdownscale ||
1569 out_height > height * 8)
1570 return -EINVAL;
1572 switch (color_mode) {
1573 case OMAP_DSS_COLOR_RGBX32:
1574 case OMAP_DSS_COLOR_RGB12U:
1575 if (cpu_is_omap24xx())
1576 return -EINVAL;
1577 /* fall through */
1578 case OMAP_DSS_COLOR_RGB16:
1579 case OMAP_DSS_COLOR_RGB24P:
1580 case OMAP_DSS_COLOR_RGB24U:
1581 break;
1583 case OMAP_DSS_COLOR_ARGB16:
1584 case OMAP_DSS_COLOR_ARGB32:
1585 case OMAP_DSS_COLOR_RGBA32:
1586 if (cpu_is_omap24xx())
1587 return -EINVAL;
1588 if (plane == OMAP_DSS_VIDEO1)
1589 return -EINVAL;
1590 break;
1592 case OMAP_DSS_COLOR_YUV2:
1593 case OMAP_DSS_COLOR_UYVY:
1594 cconv = 1;
1595 break;
1597 default:
1598 return -EINVAL;
1601 /* Must use 5-tap filter? */
1602 five_taps = height > out_height * 2;
1604 if (!five_taps) {
1605 fclk = calc_fclk(width, height,
1606 out_width, out_height);
1608 /* Try 5-tap filter if 3-tap fclk is too high */
1609 if (cpu_is_omap34xx() && height > out_height &&
1610 fclk > dispc_fclk_rate())
1611 five_taps = true;
1614 if (width > (2048 >> five_taps)) {
1615 DSSERR("failed to set up scaling, fclk too low\n");
1616 return -EINVAL;
1619 if (five_taps)
1620 fclk = calc_fclk_five_taps(width, height,
1621 out_width, out_height, color_mode);
1623 DSSDBG("required fclk rate = %lu Hz\n", fclk);
1624 DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
1626 if (fclk > dispc_fclk_rate()) {
1627 DSSERR("failed to set up scaling, "
1628 "required fclk rate = %lu Hz, "
1629 "current fclk rate = %lu Hz\n",
1630 fclk, dispc_fclk_rate());
1631 return -EINVAL;
1635 if (ilace && !fieldmode) {
1637 * when downscaling the bottom field may have to start several
1638 * source lines below the top field. Unfortunately ACCUI
1639 * registers will only hold the fractional part of the offset
1640 * so the integer part must be added to the base address of the
1641 * bottom field.
1643 if (!height || height == out_height)
1644 field_offset = 0;
1645 else
1646 field_offset = height / out_height / 2;
1649 /* Fields are independent but interleaved in memory. */
1650 if (fieldmode)
1651 field_offset = 1;
1653 if (rotation_type == OMAP_DSS_ROT_DMA)
1654 calc_dma_rotation_offset(rotation, mirror,
1655 screen_width, width, frame_height, color_mode,
1656 fieldmode, field_offset,
1657 &offset0, &offset1, &row_inc, &pix_inc);
1658 else
1659 calc_vrfb_rotation_offset(rotation, mirror,
1660 screen_width, width, frame_height, color_mode,
1661 fieldmode, field_offset,
1662 &offset0, &offset1, &row_inc, &pix_inc);
1664 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
1665 offset0, offset1, row_inc, pix_inc);
1667 _dispc_set_color_mode(plane, color_mode);
1669 _dispc_set_plane_ba0(plane, paddr + offset0);
1670 _dispc_set_plane_ba1(plane, paddr + offset1);
1672 _dispc_set_row_inc(plane, row_inc);
1673 _dispc_set_pix_inc(plane, pix_inc);
1675 DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height,
1676 out_width, out_height);
1678 _dispc_set_plane_pos(plane, pos_x, pos_y);
1680 _dispc_set_pic_size(plane, width, height);
1682 if (plane != OMAP_DSS_GFX) {
1683 _dispc_set_scaling(plane, width, height,
1684 out_width, out_height,
1685 ilace, five_taps, fieldmode);
1686 _dispc_set_vid_size(plane, out_width, out_height);
1687 _dispc_set_vid_color_conv(plane, cconv);
1690 _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
1692 if (plane != OMAP_DSS_VIDEO1)
1693 _dispc_setup_global_alpha(plane, global_alpha);
1695 return 0;
1698 static void _dispc_enable_plane(enum omap_plane plane, bool enable)
1700 REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 0, 0);
1703 static void dispc_disable_isr(void *data, u32 mask)
1705 struct completion *compl = data;
1706 complete(compl);
1709 static void _enable_lcd_out(bool enable)
1711 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
1714 void dispc_enable_lcd_out(bool enable)
1716 struct completion frame_done_completion;
1717 bool is_on;
1718 int r;
1720 enable_clocks(1);
1722 /* When we disable LCD output, we need to wait until frame is done.
1723 * Otherwise the DSS is still working, and turning off the clocks
1724 * prevents DSS from going to OFF mode */
1725 is_on = REG_GET(DISPC_CONTROL, 0, 0);
1727 if (!enable && is_on) {
1728 init_completion(&frame_done_completion);
1730 r = omap_dispc_register_isr(dispc_disable_isr,
1731 &frame_done_completion,
1732 DISPC_IRQ_FRAMEDONE);
1734 if (r)
1735 DSSERR("failed to register FRAMEDONE isr\n");
1738 _enable_lcd_out(enable);
1740 if (!enable && is_on) {
1741 if (!wait_for_completion_timeout(&frame_done_completion,
1742 msecs_to_jiffies(100)))
1743 DSSERR("timeout waiting for FRAME DONE\n");
1745 r = omap_dispc_unregister_isr(dispc_disable_isr,
1746 &frame_done_completion,
1747 DISPC_IRQ_FRAMEDONE);
1749 if (r)
1750 DSSERR("failed to unregister FRAMEDONE isr\n");
1753 enable_clocks(0);
1756 static void _enable_digit_out(bool enable)
1758 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
1761 void dispc_enable_digit_out(bool enable)
1763 struct completion frame_done_completion;
1764 int r;
1766 enable_clocks(1);
1768 if (REG_GET(DISPC_CONTROL, 1, 1) == enable) {
1769 enable_clocks(0);
1770 return;
1773 if (enable) {
1774 unsigned long flags;
1775 /* When we enable digit output, we'll get an extra digit
1776 * sync lost interrupt, that we need to ignore */
1777 spin_lock_irqsave(&dispc.irq_lock, flags);
1778 dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
1779 _omap_dispc_set_irqs();
1780 spin_unlock_irqrestore(&dispc.irq_lock, flags);
1783 /* When we disable digit output, we need to wait until fields are done.
1784 * Otherwise the DSS is still working, and turning off the clocks
1785 * prevents DSS from going to OFF mode. And when enabling, we need to
1786 * wait for the extra sync losts */
1787 init_completion(&frame_done_completion);
1789 r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion,
1790 DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
1791 if (r)
1792 DSSERR("failed to register EVSYNC isr\n");
1794 _enable_digit_out(enable);
1796 /* XXX I understand from TRM that we should only wait for the
1797 * current field to complete. But it seems we have to wait
1798 * for both fields */
1799 if (!wait_for_completion_timeout(&frame_done_completion,
1800 msecs_to_jiffies(100)))
1801 DSSERR("timeout waiting for EVSYNC\n");
1803 if (!wait_for_completion_timeout(&frame_done_completion,
1804 msecs_to_jiffies(100)))
1805 DSSERR("timeout waiting for EVSYNC\n");
1807 r = omap_dispc_unregister_isr(dispc_disable_isr,
1808 &frame_done_completion,
1809 DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
1810 if (r)
1811 DSSERR("failed to unregister EVSYNC isr\n");
1813 if (enable) {
1814 unsigned long flags;
1815 spin_lock_irqsave(&dispc.irq_lock, flags);
1816 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
1817 dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
1818 _omap_dispc_set_irqs();
1819 spin_unlock_irqrestore(&dispc.irq_lock, flags);
1822 enable_clocks(0);
1825 void dispc_lcd_enable_signal_polarity(bool act_high)
1827 enable_clocks(1);
1828 REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
1829 enable_clocks(0);
1832 void dispc_lcd_enable_signal(bool enable)
1834 enable_clocks(1);
1835 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
1836 enable_clocks(0);
1839 void dispc_pck_free_enable(bool enable)
1841 enable_clocks(1);
1842 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
1843 enable_clocks(0);
1846 void dispc_enable_fifohandcheck(bool enable)
1848 enable_clocks(1);
1849 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
1850 enable_clocks(0);
1854 void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
1856 int mode;
1858 switch (type) {
1859 case OMAP_DSS_LCD_DISPLAY_STN:
1860 mode = 0;
1861 break;
1863 case OMAP_DSS_LCD_DISPLAY_TFT:
1864 mode = 1;
1865 break;
1867 default:
1868 BUG();
1869 return;
1872 enable_clocks(1);
1873 REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
1874 enable_clocks(0);
1877 void dispc_set_loadmode(enum omap_dss_load_mode mode)
1879 enable_clocks(1);
1880 REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
1881 enable_clocks(0);
1885 void dispc_set_default_color(enum omap_channel channel, u32 color)
1887 const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1888 DISPC_DEFAULT_COLOR1 };
1890 enable_clocks(1);
1891 dispc_write_reg(def_reg[channel], color);
1892 enable_clocks(0);
1895 u32 dispc_get_default_color(enum omap_channel channel)
1897 const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1898 DISPC_DEFAULT_COLOR1 };
1899 u32 l;
1901 BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
1902 channel != OMAP_DSS_CHANNEL_LCD);
1904 enable_clocks(1);
1905 l = dispc_read_reg(def_reg[channel]);
1906 enable_clocks(0);
1908 return l;
1911 void dispc_set_trans_key(enum omap_channel ch,
1912 enum omap_dss_trans_key_type type,
1913 u32 trans_key)
1915 const struct dispc_reg tr_reg[] = {
1916 DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1918 enable_clocks(1);
1919 if (ch == OMAP_DSS_CHANNEL_LCD)
1920 REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
1921 else /* OMAP_DSS_CHANNEL_DIGIT */
1922 REG_FLD_MOD(DISPC_CONFIG, type, 13, 13);
1924 dispc_write_reg(tr_reg[ch], trans_key);
1925 enable_clocks(0);
1928 void dispc_get_trans_key(enum omap_channel ch,
1929 enum omap_dss_trans_key_type *type,
1930 u32 *trans_key)
1932 const struct dispc_reg tr_reg[] = {
1933 DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1935 enable_clocks(1);
1936 if (type) {
1937 if (ch == OMAP_DSS_CHANNEL_LCD)
1938 *type = REG_GET(DISPC_CONFIG, 11, 11);
1939 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
1940 *type = REG_GET(DISPC_CONFIG, 13, 13);
1941 else
1942 BUG();
1945 if (trans_key)
1946 *trans_key = dispc_read_reg(tr_reg[ch]);
1947 enable_clocks(0);
1950 void dispc_enable_trans_key(enum omap_channel ch, bool enable)
1952 enable_clocks(1);
1953 if (ch == OMAP_DSS_CHANNEL_LCD)
1954 REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
1955 else /* OMAP_DSS_CHANNEL_DIGIT */
1956 REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
1957 enable_clocks(0);
1959 void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
1961 if (cpu_is_omap24xx())
1962 return;
1964 enable_clocks(1);
1965 if (ch == OMAP_DSS_CHANNEL_LCD)
1966 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
1967 else /* OMAP_DSS_CHANNEL_DIGIT */
1968 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
1969 enable_clocks(0);
1971 bool dispc_alpha_blending_enabled(enum omap_channel ch)
1973 bool enabled;
1975 if (cpu_is_omap24xx())
1976 return false;
1978 enable_clocks(1);
1979 if (ch == OMAP_DSS_CHANNEL_LCD)
1980 enabled = REG_GET(DISPC_CONFIG, 18, 18);
1981 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
1982 enabled = REG_GET(DISPC_CONFIG, 18, 18);
1983 else
1984 BUG();
1985 enable_clocks(0);
1987 return enabled;
1992 bool dispc_trans_key_enabled(enum omap_channel ch)
1994 bool enabled;
1996 enable_clocks(1);
1997 if (ch == OMAP_DSS_CHANNEL_LCD)
1998 enabled = REG_GET(DISPC_CONFIG, 10, 10);
1999 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2000 enabled = REG_GET(DISPC_CONFIG, 12, 12);
2001 else
2002 BUG();
2003 enable_clocks(0);
2005 return enabled;
2009 void dispc_set_tft_data_lines(u8 data_lines)
2011 int code;
2013 switch (data_lines) {
2014 case 12:
2015 code = 0;
2016 break;
2017 case 16:
2018 code = 1;
2019 break;
2020 case 18:
2021 code = 2;
2022 break;
2023 case 24:
2024 code = 3;
2025 break;
2026 default:
2027 BUG();
2028 return;
2031 enable_clocks(1);
2032 REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
2033 enable_clocks(0);
2036 void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
2038 u32 l;
2039 int stallmode;
2040 int gpout0 = 1;
2041 int gpout1;
2043 switch (mode) {
2044 case OMAP_DSS_PARALLELMODE_BYPASS:
2045 stallmode = 0;
2046 gpout1 = 1;
2047 break;
2049 case OMAP_DSS_PARALLELMODE_RFBI:
2050 stallmode = 1;
2051 gpout1 = 0;
2052 break;
2054 case OMAP_DSS_PARALLELMODE_DSI:
2055 stallmode = 1;
2056 gpout1 = 1;
2057 break;
2059 default:
2060 BUG();
2061 return;
2064 enable_clocks(1);
2066 l = dispc_read_reg(DISPC_CONTROL);
2068 l = FLD_MOD(l, stallmode, 11, 11);
2069 l = FLD_MOD(l, gpout0, 15, 15);
2070 l = FLD_MOD(l, gpout1, 16, 16);
2072 dispc_write_reg(DISPC_CONTROL, l);
2074 enable_clocks(0);
2077 static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
2078 int vsw, int vfp, int vbp)
2080 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2081 if (hsw < 1 || hsw > 64 ||
2082 hfp < 1 || hfp > 256 ||
2083 hbp < 1 || hbp > 256 ||
2084 vsw < 1 || vsw > 64 ||
2085 vfp < 0 || vfp > 255 ||
2086 vbp < 0 || vbp > 255)
2087 return false;
2088 } else {
2089 if (hsw < 1 || hsw > 256 ||
2090 hfp < 1 || hfp > 4096 ||
2091 hbp < 1 || hbp > 4096 ||
2092 vsw < 1 || vsw > 256 ||
2093 vfp < 0 || vfp > 4095 ||
2094 vbp < 0 || vbp > 4095)
2095 return false;
2098 return true;
2101 bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
2103 return _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2104 timings->hbp, timings->vsw,
2105 timings->vfp, timings->vbp);
2108 static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
2109 int vsw, int vfp, int vbp)
2111 u32 timing_h, timing_v;
2113 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2114 timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
2115 FLD_VAL(hbp-1, 27, 20);
2117 timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
2118 FLD_VAL(vbp, 27, 20);
2119 } else {
2120 timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
2121 FLD_VAL(hbp-1, 31, 20);
2123 timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
2124 FLD_VAL(vbp, 31, 20);
2127 enable_clocks(1);
2128 dispc_write_reg(DISPC_TIMING_H, timing_h);
2129 dispc_write_reg(DISPC_TIMING_V, timing_v);
2130 enable_clocks(0);
2133 /* change name to mode? */
2134 void dispc_set_lcd_timings(struct omap_video_timings *timings)
2136 unsigned xtot, ytot;
2137 unsigned long ht, vt;
2139 if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2140 timings->hbp, timings->vsw,
2141 timings->vfp, timings->vbp))
2142 BUG();
2144 _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp,
2145 timings->vsw, timings->vfp, timings->vbp);
2147 dispc_set_lcd_size(timings->x_res, timings->y_res);
2149 xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
2150 ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
2152 ht = (timings->pixel_clock * 1000) / xtot;
2153 vt = (timings->pixel_clock * 1000) / xtot / ytot;
2155 DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res);
2156 DSSDBG("pck %u\n", timings->pixel_clock);
2157 DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
2158 timings->hsw, timings->hfp, timings->hbp,
2159 timings->vsw, timings->vfp, timings->vbp);
2161 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
2164 static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div)
2166 BUG_ON(lck_div < 1);
2167 BUG_ON(pck_div < 2);
2169 enable_clocks(1);
2170 dispc_write_reg(DISPC_DIVISOR,
2171 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
2172 enable_clocks(0);
2175 static void dispc_get_lcd_divisor(int *lck_div, int *pck_div)
2177 u32 l;
2178 l = dispc_read_reg(DISPC_DIVISOR);
2179 *lck_div = FLD_GET(l, 23, 16);
2180 *pck_div = FLD_GET(l, 7, 0);
2183 unsigned long dispc_fclk_rate(void)
2185 unsigned long r = 0;
2187 if (dss_get_dispc_clk_source() == 0)
2188 r = dss_clk_get_rate(DSS_CLK_FCK1);
2189 else
2190 #ifdef CONFIG_OMAP2_DSS_DSI
2191 r = dsi_get_dsi1_pll_rate();
2192 #else
2193 BUG();
2194 #endif
2195 return r;
2198 unsigned long dispc_lclk_rate(void)
2200 int lcd;
2201 unsigned long r;
2202 u32 l;
2204 l = dispc_read_reg(DISPC_DIVISOR);
2206 lcd = FLD_GET(l, 23, 16);
2208 r = dispc_fclk_rate();
2210 return r / lcd;
2213 unsigned long dispc_pclk_rate(void)
2215 int lcd, pcd;
2216 unsigned long r;
2217 u32 l;
2219 l = dispc_read_reg(DISPC_DIVISOR);
2221 lcd = FLD_GET(l, 23, 16);
2222 pcd = FLD_GET(l, 7, 0);
2224 r = dispc_fclk_rate();
2226 return r / lcd / pcd;
2229 void dispc_dump_clocks(struct seq_file *s)
2231 int lcd, pcd;
2233 enable_clocks(1);
2235 dispc_get_lcd_divisor(&lcd, &pcd);
2237 seq_printf(s, "- DISPC -\n");
2239 seq_printf(s, "dispc fclk source = %s\n",
2240 dss_get_dispc_clk_source() == 0 ?
2241 "dss1_alwon_fclk" : "dsi1_pll_fclk");
2243 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
2244 seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd);
2245 seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd);
2247 enable_clocks(0);
2250 void dispc_dump_regs(struct seq_file *s)
2252 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
2254 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
2256 DUMPREG(DISPC_REVISION);
2257 DUMPREG(DISPC_SYSCONFIG);
2258 DUMPREG(DISPC_SYSSTATUS);
2259 DUMPREG(DISPC_IRQSTATUS);
2260 DUMPREG(DISPC_IRQENABLE);
2261 DUMPREG(DISPC_CONTROL);
2262 DUMPREG(DISPC_CONFIG);
2263 DUMPREG(DISPC_CAPABLE);
2264 DUMPREG(DISPC_DEFAULT_COLOR0);
2265 DUMPREG(DISPC_DEFAULT_COLOR1);
2266 DUMPREG(DISPC_TRANS_COLOR0);
2267 DUMPREG(DISPC_TRANS_COLOR1);
2268 DUMPREG(DISPC_LINE_STATUS);
2269 DUMPREG(DISPC_LINE_NUMBER);
2270 DUMPREG(DISPC_TIMING_H);
2271 DUMPREG(DISPC_TIMING_V);
2272 DUMPREG(DISPC_POL_FREQ);
2273 DUMPREG(DISPC_DIVISOR);
2274 DUMPREG(DISPC_GLOBAL_ALPHA);
2275 DUMPREG(DISPC_SIZE_DIG);
2276 DUMPREG(DISPC_SIZE_LCD);
2278 DUMPREG(DISPC_GFX_BA0);
2279 DUMPREG(DISPC_GFX_BA1);
2280 DUMPREG(DISPC_GFX_POSITION);
2281 DUMPREG(DISPC_GFX_SIZE);
2282 DUMPREG(DISPC_GFX_ATTRIBUTES);
2283 DUMPREG(DISPC_GFX_FIFO_THRESHOLD);
2284 DUMPREG(DISPC_GFX_FIFO_SIZE_STATUS);
2285 DUMPREG(DISPC_GFX_ROW_INC);
2286 DUMPREG(DISPC_GFX_PIXEL_INC);
2287 DUMPREG(DISPC_GFX_WINDOW_SKIP);
2288 DUMPREG(DISPC_GFX_TABLE_BA);
2290 DUMPREG(DISPC_DATA_CYCLE1);
2291 DUMPREG(DISPC_DATA_CYCLE2);
2292 DUMPREG(DISPC_DATA_CYCLE3);
2294 DUMPREG(DISPC_CPR_COEF_R);
2295 DUMPREG(DISPC_CPR_COEF_G);
2296 DUMPREG(DISPC_CPR_COEF_B);
2298 DUMPREG(DISPC_GFX_PRELOAD);
2300 DUMPREG(DISPC_VID_BA0(0));
2301 DUMPREG(DISPC_VID_BA1(0));
2302 DUMPREG(DISPC_VID_POSITION(0));
2303 DUMPREG(DISPC_VID_SIZE(0));
2304 DUMPREG(DISPC_VID_ATTRIBUTES(0));
2305 DUMPREG(DISPC_VID_FIFO_THRESHOLD(0));
2306 DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(0));
2307 DUMPREG(DISPC_VID_ROW_INC(0));
2308 DUMPREG(DISPC_VID_PIXEL_INC(0));
2309 DUMPREG(DISPC_VID_FIR(0));
2310 DUMPREG(DISPC_VID_PICTURE_SIZE(0));
2311 DUMPREG(DISPC_VID_ACCU0(0));
2312 DUMPREG(DISPC_VID_ACCU1(0));
2314 DUMPREG(DISPC_VID_BA0(1));
2315 DUMPREG(DISPC_VID_BA1(1));
2316 DUMPREG(DISPC_VID_POSITION(1));
2317 DUMPREG(DISPC_VID_SIZE(1));
2318 DUMPREG(DISPC_VID_ATTRIBUTES(1));
2319 DUMPREG(DISPC_VID_FIFO_THRESHOLD(1));
2320 DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(1));
2321 DUMPREG(DISPC_VID_ROW_INC(1));
2322 DUMPREG(DISPC_VID_PIXEL_INC(1));
2323 DUMPREG(DISPC_VID_FIR(1));
2324 DUMPREG(DISPC_VID_PICTURE_SIZE(1));
2325 DUMPREG(DISPC_VID_ACCU0(1));
2326 DUMPREG(DISPC_VID_ACCU1(1));
2328 DUMPREG(DISPC_VID_FIR_COEF_H(0, 0));
2329 DUMPREG(DISPC_VID_FIR_COEF_H(0, 1));
2330 DUMPREG(DISPC_VID_FIR_COEF_H(0, 2));
2331 DUMPREG(DISPC_VID_FIR_COEF_H(0, 3));
2332 DUMPREG(DISPC_VID_FIR_COEF_H(0, 4));
2333 DUMPREG(DISPC_VID_FIR_COEF_H(0, 5));
2334 DUMPREG(DISPC_VID_FIR_COEF_H(0, 6));
2335 DUMPREG(DISPC_VID_FIR_COEF_H(0, 7));
2336 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 0));
2337 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 1));
2338 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 2));
2339 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 3));
2340 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 4));
2341 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 5));
2342 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 6));
2343 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 7));
2344 DUMPREG(DISPC_VID_CONV_COEF(0, 0));
2345 DUMPREG(DISPC_VID_CONV_COEF(0, 1));
2346 DUMPREG(DISPC_VID_CONV_COEF(0, 2));
2347 DUMPREG(DISPC_VID_CONV_COEF(0, 3));
2348 DUMPREG(DISPC_VID_CONV_COEF(0, 4));
2349 DUMPREG(DISPC_VID_FIR_COEF_V(0, 0));
2350 DUMPREG(DISPC_VID_FIR_COEF_V(0, 1));
2351 DUMPREG(DISPC_VID_FIR_COEF_V(0, 2));
2352 DUMPREG(DISPC_VID_FIR_COEF_V(0, 3));
2353 DUMPREG(DISPC_VID_FIR_COEF_V(0, 4));
2354 DUMPREG(DISPC_VID_FIR_COEF_V(0, 5));
2355 DUMPREG(DISPC_VID_FIR_COEF_V(0, 6));
2356 DUMPREG(DISPC_VID_FIR_COEF_V(0, 7));
2358 DUMPREG(DISPC_VID_FIR_COEF_H(1, 0));
2359 DUMPREG(DISPC_VID_FIR_COEF_H(1, 1));
2360 DUMPREG(DISPC_VID_FIR_COEF_H(1, 2));
2361 DUMPREG(DISPC_VID_FIR_COEF_H(1, 3));
2362 DUMPREG(DISPC_VID_FIR_COEF_H(1, 4));
2363 DUMPREG(DISPC_VID_FIR_COEF_H(1, 5));
2364 DUMPREG(DISPC_VID_FIR_COEF_H(1, 6));
2365 DUMPREG(DISPC_VID_FIR_COEF_H(1, 7));
2366 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 0));
2367 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 1));
2368 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 2));
2369 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 3));
2370 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 4));
2371 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 5));
2372 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 6));
2373 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 7));
2374 DUMPREG(DISPC_VID_CONV_COEF(1, 0));
2375 DUMPREG(DISPC_VID_CONV_COEF(1, 1));
2376 DUMPREG(DISPC_VID_CONV_COEF(1, 2));
2377 DUMPREG(DISPC_VID_CONV_COEF(1, 3));
2378 DUMPREG(DISPC_VID_CONV_COEF(1, 4));
2379 DUMPREG(DISPC_VID_FIR_COEF_V(1, 0));
2380 DUMPREG(DISPC_VID_FIR_COEF_V(1, 1));
2381 DUMPREG(DISPC_VID_FIR_COEF_V(1, 2));
2382 DUMPREG(DISPC_VID_FIR_COEF_V(1, 3));
2383 DUMPREG(DISPC_VID_FIR_COEF_V(1, 4));
2384 DUMPREG(DISPC_VID_FIR_COEF_V(1, 5));
2385 DUMPREG(DISPC_VID_FIR_COEF_V(1, 6));
2386 DUMPREG(DISPC_VID_FIR_COEF_V(1, 7));
2388 DUMPREG(DISPC_VID_PRELOAD(0));
2389 DUMPREG(DISPC_VID_PRELOAD(1));
2391 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
2392 #undef DUMPREG
2395 static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
2396 bool ihs, bool ivs, u8 acbi, u8 acb)
2398 u32 l = 0;
2400 DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n",
2401 onoff, rf, ieo, ipc, ihs, ivs, acbi, acb);
2403 l |= FLD_VAL(onoff, 17, 17);
2404 l |= FLD_VAL(rf, 16, 16);
2405 l |= FLD_VAL(ieo, 15, 15);
2406 l |= FLD_VAL(ipc, 14, 14);
2407 l |= FLD_VAL(ihs, 13, 13);
2408 l |= FLD_VAL(ivs, 12, 12);
2409 l |= FLD_VAL(acbi, 11, 8);
2410 l |= FLD_VAL(acb, 7, 0);
2412 enable_clocks(1);
2413 dispc_write_reg(DISPC_POL_FREQ, l);
2414 enable_clocks(0);
2417 void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb)
2419 _dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0,
2420 (config & OMAP_DSS_LCD_RF) != 0,
2421 (config & OMAP_DSS_LCD_IEO) != 0,
2422 (config & OMAP_DSS_LCD_IPC) != 0,
2423 (config & OMAP_DSS_LCD_IHS) != 0,
2424 (config & OMAP_DSS_LCD_IVS) != 0,
2425 acbi, acb);
2428 /* with fck as input clock rate, find dispc dividers that produce req_pck */
2429 void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
2430 struct dispc_clock_info *cinfo)
2432 u16 pcd_min = is_tft ? 2 : 3;
2433 unsigned long best_pck;
2434 u16 best_ld, cur_ld;
2435 u16 best_pd, cur_pd;
2437 best_pck = 0;
2438 best_ld = 0;
2439 best_pd = 0;
2441 for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
2442 unsigned long lck = fck / cur_ld;
2444 for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) {
2445 unsigned long pck = lck / cur_pd;
2446 long old_delta = abs(best_pck - req_pck);
2447 long new_delta = abs(pck - req_pck);
2449 if (best_pck == 0 || new_delta < old_delta) {
2450 best_pck = pck;
2451 best_ld = cur_ld;
2452 best_pd = cur_pd;
2454 if (pck == req_pck)
2455 goto found;
2458 if (pck < req_pck)
2459 break;
2462 if (lck / pcd_min < req_pck)
2463 break;
2466 found:
2467 cinfo->lck_div = best_ld;
2468 cinfo->pck_div = best_pd;
2469 cinfo->lck = fck / cinfo->lck_div;
2470 cinfo->pck = cinfo->lck / cinfo->pck_div;
2473 /* calculate clock rates using dividers in cinfo */
2474 int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
2475 struct dispc_clock_info *cinfo)
2477 if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
2478 return -EINVAL;
2479 if (cinfo->pck_div < 2 || cinfo->pck_div > 255)
2480 return -EINVAL;
2482 cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
2483 cinfo->pck = cinfo->lck / cinfo->pck_div;
2485 return 0;
2488 int dispc_set_clock_div(struct dispc_clock_info *cinfo)
2490 DSSDBG("lck = %ld (%d)\n", cinfo->lck, cinfo->lck_div);
2491 DSSDBG("pck = %ld (%d)\n", cinfo->pck, cinfo->pck_div);
2493 dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div);
2495 return 0;
2498 int dispc_get_clock_div(struct dispc_clock_info *cinfo)
2500 unsigned long fck;
2502 fck = dispc_fclk_rate();
2504 cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
2505 cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
2507 cinfo->lck = fck / cinfo->lck_div;
2508 cinfo->pck = cinfo->lck / cinfo->pck_div;
2510 return 0;
2513 /* dispc.irq_lock has to be locked by the caller */
2514 static void _omap_dispc_set_irqs(void)
2516 u32 mask;
2517 u32 old_mask;
2518 int i;
2519 struct omap_dispc_isr_data *isr_data;
2521 mask = dispc.irq_error_mask;
2523 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2524 isr_data = &dispc.registered_isr[i];
2526 if (isr_data->isr == NULL)
2527 continue;
2529 mask |= isr_data->mask;
2532 enable_clocks(1);
2534 old_mask = dispc_read_reg(DISPC_IRQENABLE);
2535 /* clear the irqstatus for newly enabled irqs */
2536 dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
2538 dispc_write_reg(DISPC_IRQENABLE, mask);
2540 enable_clocks(0);
2543 int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2545 int i;
2546 int ret;
2547 unsigned long flags;
2548 struct omap_dispc_isr_data *isr_data;
2550 if (isr == NULL)
2551 return -EINVAL;
2553 spin_lock_irqsave(&dispc.irq_lock, flags);
2555 /* check for duplicate entry */
2556 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2557 isr_data = &dispc.registered_isr[i];
2558 if (isr_data->isr == isr && isr_data->arg == arg &&
2559 isr_data->mask == mask) {
2560 ret = -EINVAL;
2561 goto err;
2565 isr_data = NULL;
2566 ret = -EBUSY;
2568 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2569 isr_data = &dispc.registered_isr[i];
2571 if (isr_data->isr != NULL)
2572 continue;
2574 isr_data->isr = isr;
2575 isr_data->arg = arg;
2576 isr_data->mask = mask;
2577 ret = 0;
2579 break;
2582 _omap_dispc_set_irqs();
2584 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2586 return 0;
2587 err:
2588 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2590 return ret;
2592 EXPORT_SYMBOL(omap_dispc_register_isr);
2594 int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2596 int i;
2597 unsigned long flags;
2598 int ret = -EINVAL;
2599 struct omap_dispc_isr_data *isr_data;
2601 spin_lock_irqsave(&dispc.irq_lock, flags);
2603 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2604 isr_data = &dispc.registered_isr[i];
2605 if (isr_data->isr != isr || isr_data->arg != arg ||
2606 isr_data->mask != mask)
2607 continue;
2609 /* found the correct isr */
2611 isr_data->isr = NULL;
2612 isr_data->arg = NULL;
2613 isr_data->mask = 0;
2615 ret = 0;
2616 break;
2619 if (ret == 0)
2620 _omap_dispc_set_irqs();
2622 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2624 return ret;
2626 EXPORT_SYMBOL(omap_dispc_unregister_isr);
2628 #ifdef DEBUG
2629 static void print_irq_status(u32 status)
2631 if ((status & dispc.irq_error_mask) == 0)
2632 return;
2634 printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status);
2636 #define PIS(x) \
2637 if (status & DISPC_IRQ_##x) \
2638 printk(#x " ");
2639 PIS(GFX_FIFO_UNDERFLOW);
2640 PIS(OCP_ERR);
2641 PIS(VID1_FIFO_UNDERFLOW);
2642 PIS(VID2_FIFO_UNDERFLOW);
2643 PIS(SYNC_LOST);
2644 PIS(SYNC_LOST_DIGIT);
2645 #undef PIS
2647 printk("\n");
2649 #endif
2651 /* Called from dss.c. Note that we don't touch clocks here,
2652 * but we presume they are on because we got an IRQ. However,
2653 * an irq handler may turn the clocks off, so we may not have
2654 * clock later in the function. */
2655 void dispc_irq_handler(void)
2657 int i;
2658 u32 irqstatus;
2659 u32 handledirqs = 0;
2660 u32 unhandled_errors;
2661 struct omap_dispc_isr_data *isr_data;
2662 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
2664 spin_lock(&dispc.irq_lock);
2666 irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
2668 #ifdef DEBUG
2669 if (dss_debug)
2670 print_irq_status(irqstatus);
2671 #endif
2672 /* Ack the interrupt. Do it here before clocks are possibly turned
2673 * off */
2674 dispc_write_reg(DISPC_IRQSTATUS, irqstatus);
2675 /* flush posted write */
2676 dispc_read_reg(DISPC_IRQSTATUS);
2678 /* make a copy and unlock, so that isrs can unregister
2679 * themselves */
2680 memcpy(registered_isr, dispc.registered_isr,
2681 sizeof(registered_isr));
2683 spin_unlock(&dispc.irq_lock);
2685 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2686 isr_data = &registered_isr[i];
2688 if (!isr_data->isr)
2689 continue;
2691 if (isr_data->mask & irqstatus) {
2692 isr_data->isr(isr_data->arg, irqstatus);
2693 handledirqs |= isr_data->mask;
2697 spin_lock(&dispc.irq_lock);
2699 unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
2701 if (unhandled_errors) {
2702 dispc.error_irqs |= unhandled_errors;
2704 dispc.irq_error_mask &= ~unhandled_errors;
2705 _omap_dispc_set_irqs();
2707 schedule_work(&dispc.error_work);
2710 spin_unlock(&dispc.irq_lock);
2713 static void dispc_error_worker(struct work_struct *work)
2715 int i;
2716 u32 errors;
2717 unsigned long flags;
2719 spin_lock_irqsave(&dispc.irq_lock, flags);
2720 errors = dispc.error_irqs;
2721 dispc.error_irqs = 0;
2722 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2724 if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) {
2725 DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n");
2726 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2727 struct omap_overlay *ovl;
2728 ovl = omap_dss_get_overlay(i);
2730 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2731 continue;
2733 if (ovl->id == 0) {
2734 dispc_enable_plane(ovl->id, 0);
2735 dispc_go(ovl->manager->id);
2736 mdelay(50);
2737 break;
2742 if (errors & DISPC_IRQ_VID1_FIFO_UNDERFLOW) {
2743 DSSERR("VID1_FIFO_UNDERFLOW, disabling VID1\n");
2744 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2745 struct omap_overlay *ovl;
2746 ovl = omap_dss_get_overlay(i);
2748 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2749 continue;
2751 if (ovl->id == 1) {
2752 dispc_enable_plane(ovl->id, 0);
2753 dispc_go(ovl->manager->id);
2754 mdelay(50);
2755 break;
2760 if (errors & DISPC_IRQ_VID2_FIFO_UNDERFLOW) {
2761 DSSERR("VID2_FIFO_UNDERFLOW, disabling VID2\n");
2762 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2763 struct omap_overlay *ovl;
2764 ovl = omap_dss_get_overlay(i);
2766 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2767 continue;
2769 if (ovl->id == 2) {
2770 dispc_enable_plane(ovl->id, 0);
2771 dispc_go(ovl->manager->id);
2772 mdelay(50);
2773 break;
2778 if (errors & DISPC_IRQ_SYNC_LOST) {
2779 struct omap_overlay_manager *manager = NULL;
2780 bool enable = false;
2782 DSSERR("SYNC_LOST, disabling LCD\n");
2784 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2785 struct omap_overlay_manager *mgr;
2786 mgr = omap_dss_get_overlay_manager(i);
2788 if (mgr->id == OMAP_DSS_CHANNEL_LCD) {
2789 manager = mgr;
2790 enable = mgr->device->state ==
2791 OMAP_DSS_DISPLAY_ACTIVE;
2792 mgr->device->disable(mgr->device);
2793 break;
2797 if (manager) {
2798 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2799 struct omap_overlay *ovl;
2800 ovl = omap_dss_get_overlay(i);
2802 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2803 continue;
2805 if (ovl->id != 0 && ovl->manager == manager)
2806 dispc_enable_plane(ovl->id, 0);
2809 dispc_go(manager->id);
2810 mdelay(50);
2811 if (enable)
2812 manager->device->enable(manager->device);
2816 if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) {
2817 struct omap_overlay_manager *manager = NULL;
2818 bool enable = false;
2820 DSSERR("SYNC_LOST_DIGIT, disabling TV\n");
2822 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2823 struct omap_overlay_manager *mgr;
2824 mgr = omap_dss_get_overlay_manager(i);
2826 if (mgr->id == OMAP_DSS_CHANNEL_DIGIT) {
2827 manager = mgr;
2828 enable = mgr->device->state ==
2829 OMAP_DSS_DISPLAY_ACTIVE;
2830 mgr->device->disable(mgr->device);
2831 break;
2835 if (manager) {
2836 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2837 struct omap_overlay *ovl;
2838 ovl = omap_dss_get_overlay(i);
2840 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2841 continue;
2843 if (ovl->id != 0 && ovl->manager == manager)
2844 dispc_enable_plane(ovl->id, 0);
2847 dispc_go(manager->id);
2848 mdelay(50);
2849 if (enable)
2850 manager->device->enable(manager->device);
2854 if (errors & DISPC_IRQ_OCP_ERR) {
2855 DSSERR("OCP_ERR\n");
2856 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2857 struct omap_overlay_manager *mgr;
2858 mgr = omap_dss_get_overlay_manager(i);
2860 if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC)
2861 mgr->device->disable(mgr->device);
2865 spin_lock_irqsave(&dispc.irq_lock, flags);
2866 dispc.irq_error_mask |= errors;
2867 _omap_dispc_set_irqs();
2868 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2871 int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
2873 void dispc_irq_wait_handler(void *data, u32 mask)
2875 complete((struct completion *)data);
2878 int r;
2879 DECLARE_COMPLETION_ONSTACK(completion);
2881 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2882 irqmask);
2884 if (r)
2885 return r;
2887 timeout = wait_for_completion_timeout(&completion, timeout);
2889 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
2891 if (timeout == 0)
2892 return -ETIMEDOUT;
2894 if (timeout == -ERESTARTSYS)
2895 return -ERESTARTSYS;
2897 return 0;
2900 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
2901 unsigned long timeout)
2903 void dispc_irq_wait_handler(void *data, u32 mask)
2905 complete((struct completion *)data);
2908 int r;
2909 DECLARE_COMPLETION_ONSTACK(completion);
2911 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2912 irqmask);
2914 if (r)
2915 return r;
2917 timeout = wait_for_completion_interruptible_timeout(&completion,
2918 timeout);
2920 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
2922 if (timeout == 0)
2923 return -ETIMEDOUT;
2925 if (timeout == -ERESTARTSYS)
2926 return -ERESTARTSYS;
2928 return 0;
2931 #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
2932 void dispc_fake_vsync_irq(void)
2934 u32 irqstatus = DISPC_IRQ_VSYNC;
2935 int i;
2937 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2938 struct omap_dispc_isr_data *isr_data;
2939 isr_data = &dispc.registered_isr[i];
2941 if (!isr_data->isr)
2942 continue;
2944 if (isr_data->mask & irqstatus)
2945 isr_data->isr(isr_data->arg, irqstatus);
2948 #endif
2950 static void _omap_dispc_initialize_irq(void)
2952 unsigned long flags;
2954 spin_lock_irqsave(&dispc.irq_lock, flags);
2956 memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
2958 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
2960 /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
2961 * so clear it */
2962 dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS));
2964 _omap_dispc_set_irqs();
2966 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2969 void dispc_enable_sidle(void)
2971 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
2974 void dispc_disable_sidle(void)
2976 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
2979 static void _omap_dispc_initial_config(void)
2981 u32 l;
2983 l = dispc_read_reg(DISPC_SYSCONFIG);
2984 l = FLD_MOD(l, 2, 13, 12); /* MIDLEMODE: smart standby */
2985 l = FLD_MOD(l, 2, 4, 3); /* SIDLEMODE: smart idle */
2986 l = FLD_MOD(l, 1, 2, 2); /* ENWAKEUP */
2987 l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */
2988 dispc_write_reg(DISPC_SYSCONFIG, l);
2990 /* FUNCGATED */
2991 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
2993 /* L3 firewall setting: enable access to OCM RAM */
2994 /* XXX this should be somewhere in plat-omap */
2995 if (cpu_is_omap24xx())
2996 __raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0));
2998 _dispc_setup_color_conv_coef();
3000 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3002 dispc_read_plane_fifo_sizes();
3005 int dispc_init(void)
3007 u32 rev;
3009 spin_lock_init(&dispc.irq_lock);
3011 INIT_WORK(&dispc.error_work, dispc_error_worker);
3013 dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
3014 if (!dispc.base) {
3015 DSSERR("can't ioremap DISPC\n");
3016 return -ENOMEM;
3019 enable_clocks(1);
3021 _omap_dispc_initial_config();
3023 _omap_dispc_initialize_irq();
3025 dispc_save_context();
3027 rev = dispc_read_reg(DISPC_REVISION);
3028 printk(KERN_INFO "OMAP DISPC rev %d.%d\n",
3029 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
3031 enable_clocks(0);
3033 return 0;
3036 void dispc_exit(void)
3038 iounmap(dispc.base);
3041 int dispc_enable_plane(enum omap_plane plane, bool enable)
3043 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
3045 enable_clocks(1);
3046 _dispc_enable_plane(plane, enable);
3047 enable_clocks(0);
3049 return 0;
3052 int dispc_setup_plane(enum omap_plane plane,
3053 u32 paddr, u16 screen_width,
3054 u16 pos_x, u16 pos_y,
3055 u16 width, u16 height,
3056 u16 out_width, u16 out_height,
3057 enum omap_color_mode color_mode,
3058 bool ilace,
3059 enum omap_dss_rotation_type rotation_type,
3060 u8 rotation, bool mirror, u8 global_alpha)
3062 int r = 0;
3064 DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
3065 "%dx%d, ilace %d, cmode %x, rot %d, mir %d\n",
3066 plane, paddr, screen_width, pos_x, pos_y,
3067 width, height,
3068 out_width, out_height,
3069 ilace, color_mode,
3070 rotation, mirror);
3072 enable_clocks(1);
3074 r = _dispc_setup_plane(plane,
3075 paddr, screen_width,
3076 pos_x, pos_y,
3077 width, height,
3078 out_width, out_height,
3079 color_mode, ilace,
3080 rotation_type,
3081 rotation, mirror,
3082 global_alpha);
3084 enable_clocks(0);
3086 return r;