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