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