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