blob: dc0f372c6b226e248e5d924f5046ecdf83507a95 [file] [log] [blame]
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001/*
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>
Paul Gortmakera8a35932011-07-10 13:20:26 -040028#include <linux/export.h>
Tomi Valkeinen80c39712009-11-12 11:41:42 +020029#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>
Tomi Valkeinenab83b142010-06-09 15:31:01 +030035#include <linux/hardirq.h>
archit tanejaaffe3602011-02-23 08:41:03 +000036#include <linux/interrupt.h>
Tomi Valkeinen24e62892011-05-23 11:51:18 +030037#include <linux/platform_device.h>
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +030038#include <linux/pm_runtime.h>
Tomi Valkeinen80c39712009-11-12 11:41:42 +020039
Tomi Valkeinena0b38cc2011-05-11 14:05:07 +030040#include <video/omapdss.h>
Tomi Valkeinen80c39712009-11-12 11:41:42 +020041
42#include "dss.h"
Archit Tanejaa0acb552010-09-15 19:20:00 +053043#include "dss_features.h"
Archit Taneja9b372c22011-05-06 11:45:49 +053044#include "dispc.h"
Tomi Valkeinen80c39712009-11-12 11:41:42 +020045
46/* DISPC */
Sumit Semwal8613b002010-12-02 11:27:09 +000047#define DISPC_SZ_REGS SZ_4K
Tomi Valkeinen80c39712009-11-12 11:41:42 +020048
Tomi Valkeinen80c39712009-11-12 11:41:42 +020049#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
50 DISPC_IRQ_OCP_ERR | \
51 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
52 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
53 DISPC_IRQ_SYNC_LOST | \
54 DISPC_IRQ_SYNC_LOST_DIGIT)
55
56#define DISPC_MAX_NR_ISRS 8
57
58struct omap_dispc_isr_data {
59 omap_dispc_isr_t isr;
60 void *arg;
61 u32 mask;
62};
63
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +030064enum omap_burst_size {
65 BURST_SIZE_X2 = 0,
66 BURST_SIZE_X4 = 1,
67 BURST_SIZE_X8 = 2,
68};
69
Tomi Valkeinen80c39712009-11-12 11:41:42 +020070#define REG_GET(idx, start, end) \
71 FLD_GET(dispc_read_reg(idx), start, end)
72
73#define REG_FLD_MOD(idx, val, start, end) \
74 dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
75
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +020076struct dispc_irq_stats {
77 unsigned long last_reset;
78 unsigned irq_count;
79 unsigned irqs[32];
80};
81
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +053082struct dispc_features {
83 u8 sw_start;
84 u8 fp_start;
85 u8 bp_start;
86 u16 sw_max;
87 u16 vp_max;
88 u16 hp_max;
89 int (*calc_scaling) (enum omap_channel channel,
90 const struct omap_video_timings *mgr_timings,
91 u16 width, u16 height, u16 out_width, u16 out_height,
92 enum omap_color_mode color_mode, bool *five_taps,
93 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
94 u16 pos_x, unsigned long *core_clk);
95 unsigned long (*calc_core_clk) (enum omap_channel channel,
96 u16 width, u16 height, u16 out_width, u16 out_height);
Tomi Valkeinen42a69612012-08-22 16:56:57 +030097 u8 num_fifos;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +053098};
99
Tomi Valkeinen42a69612012-08-22 16:56:57 +0300100#define DISPC_MAX_NR_FIFOS 5
101
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200102static struct {
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +0000103 struct platform_device *pdev;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200104 void __iomem *base;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300105
106 int ctx_loss_cnt;
107
archit tanejaaffe3602011-02-23 08:41:03 +0000108 int irq;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300109 struct clk *dss_clk;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200110
Tomi Valkeinen42a69612012-08-22 16:56:57 +0300111 u32 fifo_size[DISPC_MAX_NR_FIFOS];
112 /* maps which plane is using a fifo. fifo-id -> plane-id */
113 int fifo_assignment[DISPC_MAX_NR_FIFOS];
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200114
115 spinlock_t irq_lock;
116 u32 irq_error_mask;
117 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
118 u32 error_irqs;
119 struct work_struct error_work;
120
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300121 bool ctx_valid;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200122 u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +0200123
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +0530124 const struct dispc_features *feat;
125
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +0200126#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
127 spinlock_t irq_stats_lock;
128 struct dispc_irq_stats irq_stats;
129#endif
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200130} dispc;
131
Amber Jain0d66cbb2011-05-19 19:47:54 +0530132enum omap_color_component {
133 /* used for all color formats for OMAP3 and earlier
134 * and for RGB and Y color component on OMAP4
135 */
136 DISPC_COLOR_COMPONENT_RGB_Y = 1 << 0,
137 /* used for UV component for
138 * OMAP_DSS_COLOR_YUV2, OMAP_DSS_COLOR_UYVY, OMAP_DSS_COLOR_NV12
139 * color formats on OMAP4
140 */
141 DISPC_COLOR_COMPONENT_UV = 1 << 1,
142};
143
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530144enum mgr_reg_fields {
145 DISPC_MGR_FLD_ENABLE,
146 DISPC_MGR_FLD_STNTFT,
147 DISPC_MGR_FLD_GO,
148 DISPC_MGR_FLD_TFTDATALINES,
149 DISPC_MGR_FLD_STALLMODE,
150 DISPC_MGR_FLD_TCKENABLE,
151 DISPC_MGR_FLD_TCKSELECTION,
152 DISPC_MGR_FLD_CPR,
153 DISPC_MGR_FLD_FIFOHANDCHECK,
154 /* used to maintain a count of the above fields */
155 DISPC_MGR_FLD_NUM,
156};
157
158static const struct {
159 const char *name;
160 u32 vsync_irq;
161 u32 framedone_irq;
162 u32 sync_lost_irq;
163 struct reg_field reg_desc[DISPC_MGR_FLD_NUM];
164} mgr_desc[] = {
165 [OMAP_DSS_CHANNEL_LCD] = {
166 .name = "LCD",
167 .vsync_irq = DISPC_IRQ_VSYNC,
168 .framedone_irq = DISPC_IRQ_FRAMEDONE,
169 .sync_lost_irq = DISPC_IRQ_SYNC_LOST,
170 .reg_desc = {
171 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 },
172 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 },
173 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 5, 5 },
174 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL, 9, 8 },
175 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL, 11, 11 },
176 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 10, 10 },
177 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 11, 11 },
178 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG, 15, 15 },
179 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
180 },
181 },
182 [OMAP_DSS_CHANNEL_DIGIT] = {
183 .name = "DIGIT",
184 .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN,
185 .framedone_irq = 0,
186 .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT,
187 .reg_desc = {
188 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 },
189 [DISPC_MGR_FLD_STNTFT] = { },
190 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 6, 6 },
191 [DISPC_MGR_FLD_TFTDATALINES] = { },
192 [DISPC_MGR_FLD_STALLMODE] = { },
193 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 12, 12 },
194 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 13, 13 },
195 [DISPC_MGR_FLD_CPR] = { },
196 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
197 },
198 },
199 [OMAP_DSS_CHANNEL_LCD2] = {
200 .name = "LCD2",
201 .vsync_irq = DISPC_IRQ_VSYNC2,
202 .framedone_irq = DISPC_IRQ_FRAMEDONE2,
203 .sync_lost_irq = DISPC_IRQ_SYNC_LOST2,
204 .reg_desc = {
205 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 },
206 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 },
207 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL2, 5, 5 },
208 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL2, 9, 8 },
209 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL2, 11, 11 },
210 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG2, 10, 10 },
211 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG2, 11, 11 },
212 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG2, 15, 15 },
213 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG2, 16, 16 },
214 },
215 },
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530216 [OMAP_DSS_CHANNEL_LCD3] = {
217 .name = "LCD3",
218 .vsync_irq = DISPC_IRQ_VSYNC3,
219 .framedone_irq = DISPC_IRQ_FRAMEDONE3,
220 .sync_lost_irq = DISPC_IRQ_SYNC_LOST3,
221 .reg_desc = {
222 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 },
223 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 },
224 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL3, 5, 5 },
225 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL3, 9, 8 },
226 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL3, 11, 11 },
227 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG3, 10, 10 },
228 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG3, 11, 11 },
229 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG3, 15, 15 },
230 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG3, 16, 16 },
231 },
232 },
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530233};
234
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200235static void _omap_dispc_set_irqs(void);
236
Archit Taneja55978cc2011-05-06 11:45:51 +0530237static inline void dispc_write_reg(const u16 idx, u32 val)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200238{
Archit Taneja55978cc2011-05-06 11:45:51 +0530239 __raw_writel(val, dispc.base + idx);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200240}
241
Archit Taneja55978cc2011-05-06 11:45:51 +0530242static inline u32 dispc_read_reg(const u16 idx)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200243{
Archit Taneja55978cc2011-05-06 11:45:51 +0530244 return __raw_readl(dispc.base + idx);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200245}
246
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530247static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld)
248{
249 const struct reg_field rfld = mgr_desc[channel].reg_desc[regfld];
250 return REG_GET(rfld.reg, rfld.high, rfld.low);
251}
252
253static void mgr_fld_write(enum omap_channel channel,
254 enum mgr_reg_fields regfld, int val) {
255 const struct reg_field rfld = mgr_desc[channel].reg_desc[regfld];
256 REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low);
257}
258
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200259#define SR(reg) \
Archit Taneja55978cc2011-05-06 11:45:51 +0530260 dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200261#define RR(reg) \
Archit Taneja55978cc2011-05-06 11:45:51 +0530262 dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200263
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300264static void dispc_save_context(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200265{
Archit Tanejac6104b82011-08-05 19:06:02 +0530266 int i, j;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200267
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300268 DSSDBG("dispc_save_context\n");
269
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200270 SR(IRQENABLE);
271 SR(CONTROL);
272 SR(CONFIG);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200273 SR(LINE_NUMBER);
Archit Taneja11354dd2011-09-26 11:47:29 +0530274 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
275 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300276 SR(GLOBAL_ALPHA);
Sumit Semwal2a205f32010-12-02 11:27:12 +0000277 if (dss_has_feature(FEAT_MGR_LCD2)) {
278 SR(CONTROL2);
Sumit Semwal2a205f32010-12-02 11:27:12 +0000279 SR(CONFIG2);
280 }
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530281 if (dss_has_feature(FEAT_MGR_LCD3)) {
282 SR(CONTROL3);
283 SR(CONFIG3);
284 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200285
Archit Tanejac6104b82011-08-05 19:06:02 +0530286 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
287 SR(DEFAULT_COLOR(i));
288 SR(TRANS_COLOR(i));
289 SR(SIZE_MGR(i));
290 if (i == OMAP_DSS_CHANNEL_DIGIT)
291 continue;
292 SR(TIMING_H(i));
293 SR(TIMING_V(i));
294 SR(POL_FREQ(i));
295 SR(DIVISORo(i));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200296
Archit Tanejac6104b82011-08-05 19:06:02 +0530297 SR(DATA_CYCLE1(i));
298 SR(DATA_CYCLE2(i));
299 SR(DATA_CYCLE3(i));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200300
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300301 if (dss_has_feature(FEAT_CPR)) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530302 SR(CPR_COEF_R(i));
303 SR(CPR_COEF_G(i));
304 SR(CPR_COEF_B(i));
305 }
306 }
307
308 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
309 SR(OVL_BA0(i));
310 SR(OVL_BA1(i));
311 SR(OVL_POSITION(i));
312 SR(OVL_SIZE(i));
313 SR(OVL_ATTRIBUTES(i));
314 SR(OVL_FIFO_THRESHOLD(i));
315 SR(OVL_ROW_INC(i));
316 SR(OVL_PIXEL_INC(i));
317 if (dss_has_feature(FEAT_PRELOAD))
318 SR(OVL_PRELOAD(i));
319 if (i == OMAP_DSS_GFX) {
320 SR(OVL_WINDOW_SKIP(i));
321 SR(OVL_TABLE_BA(i));
322 continue;
323 }
324 SR(OVL_FIR(i));
325 SR(OVL_PICTURE_SIZE(i));
326 SR(OVL_ACCU0(i));
327 SR(OVL_ACCU1(i));
328
329 for (j = 0; j < 8; j++)
330 SR(OVL_FIR_COEF_H(i, j));
331
332 for (j = 0; j < 8; j++)
333 SR(OVL_FIR_COEF_HV(i, j));
334
335 for (j = 0; j < 5; j++)
336 SR(OVL_CONV_COEF(i, j));
337
338 if (dss_has_feature(FEAT_FIR_COEF_V)) {
339 for (j = 0; j < 8; j++)
340 SR(OVL_FIR_COEF_V(i, j));
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300341 }
Sumit Semwal2a205f32010-12-02 11:27:12 +0000342
Archit Tanejac6104b82011-08-05 19:06:02 +0530343 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
344 SR(OVL_BA0_UV(i));
345 SR(OVL_BA1_UV(i));
346 SR(OVL_FIR2(i));
347 SR(OVL_ACCU2_0(i));
348 SR(OVL_ACCU2_1(i));
349
350 for (j = 0; j < 8; j++)
351 SR(OVL_FIR_COEF_H2(i, j));
352
353 for (j = 0; j < 8; j++)
354 SR(OVL_FIR_COEF_HV2(i, j));
355
356 for (j = 0; j < 8; j++)
357 SR(OVL_FIR_COEF_V2(i, j));
358 }
359 if (dss_has_feature(FEAT_ATTR2))
360 SR(OVL_ATTRIBUTES2(i));
Sumit Semwal2a205f32010-12-02 11:27:12 +0000361 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200362
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -0600363 if (dss_has_feature(FEAT_CORE_CLK_DIV))
364 SR(DIVISOR);
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300365
Tomi Valkeinen00928ea2012-02-20 11:50:06 +0200366 dispc.ctx_loss_cnt = dss_get_ctx_loss_count(&dispc.pdev->dev);
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300367 dispc.ctx_valid = true;
368
369 DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200370}
371
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300372static void dispc_restore_context(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200373{
Archit Tanejac6104b82011-08-05 19:06:02 +0530374 int i, j, ctx;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300375
376 DSSDBG("dispc_restore_context\n");
377
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300378 if (!dispc.ctx_valid)
379 return;
380
Tomi Valkeinen00928ea2012-02-20 11:50:06 +0200381 ctx = dss_get_ctx_loss_count(&dispc.pdev->dev);
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300382
383 if (ctx >= 0 && ctx == dispc.ctx_loss_cnt)
384 return;
385
386 DSSDBG("ctx_loss_count: saved %d, current %d\n",
387 dispc.ctx_loss_cnt, ctx);
388
Ville Syrjälä75c7d592010-03-05 01:13:11 +0200389 /*RR(IRQENABLE);*/
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200390 /*RR(CONTROL);*/
391 RR(CONFIG);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200392 RR(LINE_NUMBER);
Archit Taneja11354dd2011-09-26 11:47:29 +0530393 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
394 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300395 RR(GLOBAL_ALPHA);
Archit Tanejac6104b82011-08-05 19:06:02 +0530396 if (dss_has_feature(FEAT_MGR_LCD2))
Sumit Semwal2a205f32010-12-02 11:27:12 +0000397 RR(CONFIG2);
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530398 if (dss_has_feature(FEAT_MGR_LCD3))
399 RR(CONFIG3);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200400
Archit Tanejac6104b82011-08-05 19:06:02 +0530401 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
402 RR(DEFAULT_COLOR(i));
403 RR(TRANS_COLOR(i));
404 RR(SIZE_MGR(i));
405 if (i == OMAP_DSS_CHANNEL_DIGIT)
406 continue;
407 RR(TIMING_H(i));
408 RR(TIMING_V(i));
409 RR(POL_FREQ(i));
410 RR(DIVISORo(i));
Archit Taneja9b372c22011-05-06 11:45:49 +0530411
Archit Tanejac6104b82011-08-05 19:06:02 +0530412 RR(DATA_CYCLE1(i));
413 RR(DATA_CYCLE2(i));
414 RR(DATA_CYCLE3(i));
Sumit Semwal2a205f32010-12-02 11:27:12 +0000415
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300416 if (dss_has_feature(FEAT_CPR)) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530417 RR(CPR_COEF_R(i));
418 RR(CPR_COEF_G(i));
419 RR(CPR_COEF_B(i));
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300420 }
Sumit Semwal2a205f32010-12-02 11:27:12 +0000421 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200422
Archit Tanejac6104b82011-08-05 19:06:02 +0530423 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
424 RR(OVL_BA0(i));
425 RR(OVL_BA1(i));
426 RR(OVL_POSITION(i));
427 RR(OVL_SIZE(i));
428 RR(OVL_ATTRIBUTES(i));
429 RR(OVL_FIFO_THRESHOLD(i));
430 RR(OVL_ROW_INC(i));
431 RR(OVL_PIXEL_INC(i));
432 if (dss_has_feature(FEAT_PRELOAD))
433 RR(OVL_PRELOAD(i));
434 if (i == OMAP_DSS_GFX) {
435 RR(OVL_WINDOW_SKIP(i));
436 RR(OVL_TABLE_BA(i));
437 continue;
438 }
439 RR(OVL_FIR(i));
440 RR(OVL_PICTURE_SIZE(i));
441 RR(OVL_ACCU0(i));
442 RR(OVL_ACCU1(i));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200443
Archit Tanejac6104b82011-08-05 19:06:02 +0530444 for (j = 0; j < 8; j++)
445 RR(OVL_FIR_COEF_H(i, j));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200446
Archit Tanejac6104b82011-08-05 19:06:02 +0530447 for (j = 0; j < 8; j++)
448 RR(OVL_FIR_COEF_HV(i, j));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200449
Archit Tanejac6104b82011-08-05 19:06:02 +0530450 for (j = 0; j < 5; j++)
451 RR(OVL_CONV_COEF(i, j));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200452
Archit Tanejac6104b82011-08-05 19:06:02 +0530453 if (dss_has_feature(FEAT_FIR_COEF_V)) {
454 for (j = 0; j < 8; j++)
455 RR(OVL_FIR_COEF_V(i, j));
456 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200457
Archit Tanejac6104b82011-08-05 19:06:02 +0530458 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
459 RR(OVL_BA0_UV(i));
460 RR(OVL_BA1_UV(i));
461 RR(OVL_FIR2(i));
462 RR(OVL_ACCU2_0(i));
463 RR(OVL_ACCU2_1(i));
464
465 for (j = 0; j < 8; j++)
466 RR(OVL_FIR_COEF_H2(i, j));
467
468 for (j = 0; j < 8; j++)
469 RR(OVL_FIR_COEF_HV2(i, j));
470
471 for (j = 0; j < 8; j++)
472 RR(OVL_FIR_COEF_V2(i, j));
473 }
474 if (dss_has_feature(FEAT_ATTR2))
475 RR(OVL_ATTRIBUTES2(i));
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300476 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200477
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -0600478 if (dss_has_feature(FEAT_CORE_CLK_DIV))
479 RR(DIVISOR);
480
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200481 /* enable last, because LCD & DIGIT enable are here */
482 RR(CONTROL);
Sumit Semwal2a205f32010-12-02 11:27:12 +0000483 if (dss_has_feature(FEAT_MGR_LCD2))
484 RR(CONTROL2);
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530485 if (dss_has_feature(FEAT_MGR_LCD3))
486 RR(CONTROL3);
Ville Syrjälä75c7d592010-03-05 01:13:11 +0200487 /* clear spurious SYNC_LOST_DIGIT interrupts */
488 dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
489
490 /*
491 * enable last so IRQs won't trigger before
492 * the context is fully restored
493 */
494 RR(IRQENABLE);
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300495
496 DSSDBG("context restored\n");
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200497}
498
499#undef SR
500#undef RR
501
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300502int dispc_runtime_get(void)
503{
504 int r;
505
506 DSSDBG("dispc_runtime_get\n");
507
508 r = pm_runtime_get_sync(&dispc.pdev->dev);
509 WARN_ON(r < 0);
510 return r < 0 ? r : 0;
511}
512
513void dispc_runtime_put(void)
514{
515 int r;
516
517 DSSDBG("dispc_runtime_put\n");
518
Tomi Valkeinen0eaf9f52012-01-23 13:23:08 +0200519 r = pm_runtime_put_sync(&dispc.pdev->dev);
Tomi Valkeinen5be3aeb2012-06-27 16:37:18 +0300520 WARN_ON(r < 0 && r != -ENOSYS);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300521}
522
Tomi Valkeinen3dcec4d2011-11-07 15:50:09 +0200523u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)
524{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530525 return mgr_desc[channel].vsync_irq;
Tomi Valkeinen3dcec4d2011-11-07 15:50:09 +0200526}
527
Tomi Valkeinen7d1365c2011-11-18 15:39:52 +0200528u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
529{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530530 return mgr_desc[channel].framedone_irq;
Tomi Valkeinen7d1365c2011-11-18 15:39:52 +0200531}
532
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +0300533bool dispc_mgr_go_busy(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200534{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530535 return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200536}
537
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +0300538void dispc_mgr_go(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200539{
Sumit Semwal2a205f32010-12-02 11:27:12 +0000540 bool enable_bit, go_bit;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200541
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200542 /* if the channel is not enabled, we don't need GO */
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530543 enable_bit = mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE) == 1;
Sumit Semwal2a205f32010-12-02 11:27:12 +0000544
545 if (!enable_bit)
Tomi Valkeinene6d80f92011-05-19 14:12:26 +0300546 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200547
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530548 go_bit = mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
Sumit Semwal2a205f32010-12-02 11:27:12 +0000549
550 if (go_bit) {
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200551 DSSERR("GO bit not down for channel %d\n", channel);
Tomi Valkeinene6d80f92011-05-19 14:12:26 +0300552 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200553 }
554
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530555 DSSDBG("GO %s\n", mgr_desc[channel].name);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200556
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530557 mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200558}
559
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300560static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200561{
Archit Taneja9b372c22011-05-06 11:45:49 +0530562 dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200563}
564
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300565static void dispc_ovl_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200566{
Archit Taneja9b372c22011-05-06 11:45:49 +0530567 dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200568}
569
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300570static void dispc_ovl_write_firv_reg(enum omap_plane plane, int reg, u32 value)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200571{
Archit Taneja9b372c22011-05-06 11:45:49 +0530572 dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200573}
574
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300575static void dispc_ovl_write_firh2_reg(enum omap_plane plane, int reg, u32 value)
Amber Jainab5ca072011-05-19 19:47:53 +0530576{
577 BUG_ON(plane == OMAP_DSS_GFX);
578
579 dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value);
580}
581
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300582static void dispc_ovl_write_firhv2_reg(enum omap_plane plane, int reg,
583 u32 value)
Amber Jainab5ca072011-05-19 19:47:53 +0530584{
585 BUG_ON(plane == OMAP_DSS_GFX);
586
587 dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
588}
589
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300590static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
Amber Jainab5ca072011-05-19 19:47:53 +0530591{
592 BUG_ON(plane == OMAP_DSS_GFX);
593
594 dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
595}
596
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530597static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc,
598 int fir_vinc, int five_taps,
599 enum omap_color_component color_comp)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200600{
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530601 const struct dispc_coef *h_coef, *v_coef;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200602 int i;
603
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530604 h_coef = dispc_ovl_get_scale_coef(fir_hinc, true);
605 v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200606
607 for (i = 0; i < 8; i++) {
608 u32 h, hv;
609
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530610 h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0)
611 | FLD_VAL(h_coef[i].hc1_vc0, 15, 8)
612 | FLD_VAL(h_coef[i].hc2_vc1, 23, 16)
613 | FLD_VAL(h_coef[i].hc3_vc2, 31, 24);
614 hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0)
615 | FLD_VAL(v_coef[i].hc1_vc0, 15, 8)
616 | FLD_VAL(v_coef[i].hc2_vc1, 23, 16)
617 | FLD_VAL(v_coef[i].hc3_vc2, 31, 24);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200618
Amber Jain0d66cbb2011-05-19 19:47:54 +0530619 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300620 dispc_ovl_write_firh_reg(plane, i, h);
621 dispc_ovl_write_firhv_reg(plane, i, hv);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530622 } else {
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300623 dispc_ovl_write_firh2_reg(plane, i, h);
624 dispc_ovl_write_firhv2_reg(plane, i, hv);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530625 }
626
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200627 }
628
Grazvydas Ignotas66be8f62010-08-24 15:18:43 +0200629 if (five_taps) {
630 for (i = 0; i < 8; i++) {
631 u32 v;
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530632 v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0)
633 | FLD_VAL(v_coef[i].hc4_vc22, 15, 8);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530634 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300635 dispc_ovl_write_firv_reg(plane, i, v);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530636 else
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300637 dispc_ovl_write_firv2_reg(plane, i, v);
Grazvydas Ignotas66be8f62010-08-24 15:18:43 +0200638 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200639 }
640}
641
642static void _dispc_setup_color_conv_coef(void)
643{
Archit Tanejaac01c292011-08-05 19:06:03 +0530644 int i;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200645 const struct color_conv_coef {
646 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
647 int full_range;
648 } ctbl_bt601_5 = {
649 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
650 };
651
652 const struct color_conv_coef *ct;
653
654#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
655
656 ct = &ctbl_bt601_5;
657
Archit Tanejaac01c292011-08-05 19:06:03 +0530658 for (i = 1; i < dss_feat_get_num_ovls(); i++) {
659 dispc_write_reg(DISPC_OVL_CONV_COEF(i, 0),
660 CVAL(ct->rcr, ct->ry));
661 dispc_write_reg(DISPC_OVL_CONV_COEF(i, 1),
662 CVAL(ct->gy, ct->rcb));
663 dispc_write_reg(DISPC_OVL_CONV_COEF(i, 2),
664 CVAL(ct->gcb, ct->gcr));
665 dispc_write_reg(DISPC_OVL_CONV_COEF(i, 3),
666 CVAL(ct->bcr, ct->by));
667 dispc_write_reg(DISPC_OVL_CONV_COEF(i, 4),
668 CVAL(0, ct->bcb));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200669
Archit Tanejaac01c292011-08-05 19:06:03 +0530670 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), ct->full_range,
671 11, 11);
672 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200673
674#undef CVAL
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200675}
676
677
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300678static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200679{
Archit Taneja9b372c22011-05-06 11:45:49 +0530680 dispc_write_reg(DISPC_OVL_BA0(plane), paddr);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200681}
682
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300683static void dispc_ovl_set_ba1(enum omap_plane plane, u32 paddr)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200684{
Archit Taneja9b372c22011-05-06 11:45:49 +0530685 dispc_write_reg(DISPC_OVL_BA1(plane), paddr);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200686}
687
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300688static void dispc_ovl_set_ba0_uv(enum omap_plane plane, u32 paddr)
Amber Jainab5ca072011-05-19 19:47:53 +0530689{
690 dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr);
691}
692
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300693static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr)
Amber Jainab5ca072011-05-19 19:47:53 +0530694{
695 dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
696}
697
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300698static void dispc_ovl_set_pos(enum omap_plane plane, int x, int y)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200699{
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200700 u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
Archit Taneja9b372c22011-05-06 11:45:49 +0530701
702 dispc_write_reg(DISPC_OVL_POSITION(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200703}
704
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300705static void dispc_ovl_set_pic_size(enum omap_plane plane, int width, int height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200706{
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200707 u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
Archit Taneja9b372c22011-05-06 11:45:49 +0530708
709 if (plane == OMAP_DSS_GFX)
710 dispc_write_reg(DISPC_OVL_SIZE(plane), val);
711 else
712 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200713}
714
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300715static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200716{
717 u32 val;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200718
719 BUG_ON(plane == OMAP_DSS_GFX);
720
721 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
Archit Taneja9b372c22011-05-06 11:45:49 +0530722
723 dispc_write_reg(DISPC_OVL_SIZE(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200724}
725
Archit Taneja54128702011-09-08 11:29:17 +0530726static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder)
727{
728 struct omap_overlay *ovl = omap_dss_get_overlay(plane);
729
730 if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
731 return;
732
733 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
734}
735
736static void dispc_ovl_enable_zorder_planes(void)
737{
738 int i;
739
740 if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
741 return;
742
743 for (i = 0; i < dss_feat_get_num_ovls(); i++)
744 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
745}
746
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300747static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable)
Rajkumar Nfd28a392010-11-04 12:28:42 +0100748{
Tomi Valkeinenf6dc8152011-08-15 15:18:20 +0300749 struct omap_overlay *ovl = omap_dss_get_overlay(plane);
Rajkumar Nfd28a392010-11-04 12:28:42 +0100750
Tomi Valkeinenf6dc8152011-08-15 15:18:20 +0300751 if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
Rajkumar Nfd28a392010-11-04 12:28:42 +0100752 return;
753
Archit Taneja9b372c22011-05-06 11:45:49 +0530754 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
Rajkumar Nfd28a392010-11-04 12:28:42 +0100755}
756
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300757static void dispc_ovl_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200758{
Archit Tanejab8c095b2011-09-13 18:20:33 +0530759 static const unsigned shifts[] = { 0, 8, 16, 24, };
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +0300760 int shift;
Tomi Valkeinenf6dc8152011-08-15 15:18:20 +0300761 struct omap_overlay *ovl = omap_dss_get_overlay(plane);
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +0300762
Tomi Valkeinenf6dc8152011-08-15 15:18:20 +0300763 if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
Rajkumar Nfd28a392010-11-04 12:28:42 +0100764 return;
Archit Tanejaa0acb552010-09-15 19:20:00 +0530765
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +0300766 shift = shifts[plane];
767 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200768}
769
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300770static void dispc_ovl_set_pix_inc(enum omap_plane plane, s32 inc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200771{
Archit Taneja9b372c22011-05-06 11:45:49 +0530772 dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200773}
774
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300775static void dispc_ovl_set_row_inc(enum omap_plane plane, s32 inc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200776{
Archit Taneja9b372c22011-05-06 11:45:49 +0530777 dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200778}
779
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300780static void dispc_ovl_set_color_mode(enum omap_plane plane,
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200781 enum omap_color_mode color_mode)
782{
783 u32 m = 0;
Amber Jainf20e4222011-05-19 19:47:50 +0530784 if (plane != OMAP_DSS_GFX) {
785 switch (color_mode) {
786 case OMAP_DSS_COLOR_NV12:
787 m = 0x0; break;
Lajos Molnar08f32672012-02-21 19:36:30 +0530788 case OMAP_DSS_COLOR_RGBX16:
Amber Jainf20e4222011-05-19 19:47:50 +0530789 m = 0x1; break;
790 case OMAP_DSS_COLOR_RGBA16:
791 m = 0x2; break;
Lajos Molnar08f32672012-02-21 19:36:30 +0530792 case OMAP_DSS_COLOR_RGB12U:
Amber Jainf20e4222011-05-19 19:47:50 +0530793 m = 0x4; break;
794 case OMAP_DSS_COLOR_ARGB16:
795 m = 0x5; break;
796 case OMAP_DSS_COLOR_RGB16:
797 m = 0x6; break;
798 case OMAP_DSS_COLOR_ARGB16_1555:
799 m = 0x7; break;
800 case OMAP_DSS_COLOR_RGB24U:
801 m = 0x8; break;
802 case OMAP_DSS_COLOR_RGB24P:
803 m = 0x9; break;
804 case OMAP_DSS_COLOR_YUV2:
805 m = 0xa; break;
806 case OMAP_DSS_COLOR_UYVY:
807 m = 0xb; break;
808 case OMAP_DSS_COLOR_ARGB32:
809 m = 0xc; break;
810 case OMAP_DSS_COLOR_RGBA32:
811 m = 0xd; break;
812 case OMAP_DSS_COLOR_RGBX32:
813 m = 0xe; break;
814 case OMAP_DSS_COLOR_XRGB16_1555:
815 m = 0xf; break;
816 default:
Tomi Valkeinenc6eee962012-05-18 11:47:02 +0300817 BUG(); return;
Amber Jainf20e4222011-05-19 19:47:50 +0530818 }
819 } else {
820 switch (color_mode) {
821 case OMAP_DSS_COLOR_CLUT1:
822 m = 0x0; break;
823 case OMAP_DSS_COLOR_CLUT2:
824 m = 0x1; break;
825 case OMAP_DSS_COLOR_CLUT4:
826 m = 0x2; break;
827 case OMAP_DSS_COLOR_CLUT8:
828 m = 0x3; break;
829 case OMAP_DSS_COLOR_RGB12U:
830 m = 0x4; break;
831 case OMAP_DSS_COLOR_ARGB16:
832 m = 0x5; break;
833 case OMAP_DSS_COLOR_RGB16:
834 m = 0x6; break;
835 case OMAP_DSS_COLOR_ARGB16_1555:
836 m = 0x7; break;
837 case OMAP_DSS_COLOR_RGB24U:
838 m = 0x8; break;
839 case OMAP_DSS_COLOR_RGB24P:
840 m = 0x9; break;
Lajos Molnar08f32672012-02-21 19:36:30 +0530841 case OMAP_DSS_COLOR_RGBX16:
Amber Jainf20e4222011-05-19 19:47:50 +0530842 m = 0xa; break;
Lajos Molnar08f32672012-02-21 19:36:30 +0530843 case OMAP_DSS_COLOR_RGBA16:
Amber Jainf20e4222011-05-19 19:47:50 +0530844 m = 0xb; break;
845 case OMAP_DSS_COLOR_ARGB32:
846 m = 0xc; break;
847 case OMAP_DSS_COLOR_RGBA32:
848 m = 0xd; break;
849 case OMAP_DSS_COLOR_RGBX32:
850 m = 0xe; break;
851 case OMAP_DSS_COLOR_XRGB16_1555:
852 m = 0xf; break;
853 default:
Tomi Valkeinenc6eee962012-05-18 11:47:02 +0300854 BUG(); return;
Amber Jainf20e4222011-05-19 19:47:50 +0530855 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200856 }
857
Archit Taneja9b372c22011-05-06 11:45:49 +0530858 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200859}
860
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +0530861static void dispc_ovl_configure_burst_type(enum omap_plane plane,
862 enum omap_dss_rotation_type rotation_type)
863{
864 if (dss_has_feature(FEAT_BURST_2D) == 0)
865 return;
866
867 if (rotation_type == OMAP_DSS_ROT_TILER)
868 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29);
869 else
870 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29);
871}
872
Tomi Valkeinenf4279842011-10-28 15:26:26 +0300873void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200874{
875 int shift;
876 u32 val;
Sumit Semwal2a205f32010-12-02 11:27:12 +0000877 int chan = 0, chan2 = 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200878
879 switch (plane) {
880 case OMAP_DSS_GFX:
881 shift = 8;
882 break;
883 case OMAP_DSS_VIDEO1:
884 case OMAP_DSS_VIDEO2:
Archit Tanejab8c095b2011-09-13 18:20:33 +0530885 case OMAP_DSS_VIDEO3:
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200886 shift = 16;
887 break;
888 default:
889 BUG();
890 return;
891 }
892
Archit Taneja9b372c22011-05-06 11:45:49 +0530893 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
Sumit Semwal2a205f32010-12-02 11:27:12 +0000894 if (dss_has_feature(FEAT_MGR_LCD2)) {
895 switch (channel) {
896 case OMAP_DSS_CHANNEL_LCD:
897 chan = 0;
898 chan2 = 0;
899 break;
900 case OMAP_DSS_CHANNEL_DIGIT:
901 chan = 1;
902 chan2 = 0;
903 break;
904 case OMAP_DSS_CHANNEL_LCD2:
905 chan = 0;
906 chan2 = 1;
907 break;
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530908 case OMAP_DSS_CHANNEL_LCD3:
909 if (dss_has_feature(FEAT_MGR_LCD3)) {
910 chan = 0;
911 chan2 = 2;
912 } else {
913 BUG();
914 return;
915 }
916 break;
Sumit Semwal2a205f32010-12-02 11:27:12 +0000917 default:
918 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +0300919 return;
Sumit Semwal2a205f32010-12-02 11:27:12 +0000920 }
921
922 val = FLD_MOD(val, chan, shift, shift);
923 val = FLD_MOD(val, chan2, 31, 30);
924 } else {
925 val = FLD_MOD(val, channel, shift, shift);
926 }
Archit Taneja9b372c22011-05-06 11:45:49 +0530927 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200928}
929
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +0200930static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
931{
932 int shift;
933 u32 val;
934 enum omap_channel channel;
935
936 switch (plane) {
937 case OMAP_DSS_GFX:
938 shift = 8;
939 break;
940 case OMAP_DSS_VIDEO1:
941 case OMAP_DSS_VIDEO2:
942 case OMAP_DSS_VIDEO3:
943 shift = 16;
944 break;
945 default:
946 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +0300947 return 0;
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +0200948 }
949
950 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
951
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530952 if (dss_has_feature(FEAT_MGR_LCD3)) {
953 if (FLD_GET(val, 31, 30) == 0)
954 channel = FLD_GET(val, shift, shift);
955 else if (FLD_GET(val, 31, 30) == 1)
956 channel = OMAP_DSS_CHANNEL_LCD2;
957 else
958 channel = OMAP_DSS_CHANNEL_LCD3;
959 } else if (dss_has_feature(FEAT_MGR_LCD2)) {
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +0200960 if (FLD_GET(val, 31, 30) == 0)
961 channel = FLD_GET(val, shift, shift);
962 else
963 channel = OMAP_DSS_CHANNEL_LCD2;
964 } else {
965 channel = FLD_GET(val, shift, shift);
966 }
967
968 return channel;
969}
970
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300971static void dispc_ovl_set_burst_size(enum omap_plane plane,
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200972 enum omap_burst_size burst_size)
973{
Archit Tanejab8c095b2011-09-13 18:20:33 +0530974 static const unsigned shifts[] = { 6, 14, 14, 14, };
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200975 int shift;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200976
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +0300977 shift = shifts[plane];
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +0300978 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200979}
980
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +0300981static void dispc_configure_burst_sizes(void)
982{
983 int i;
984 const int burst_size = BURST_SIZE_X8;
985
986 /* Configure burst size always to maximum size */
987 for (i = 0; i < omap_dss_get_num_overlays(); ++i)
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300988 dispc_ovl_set_burst_size(i, burst_size);
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +0300989}
990
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +0200991static u32 dispc_ovl_get_burst_size(enum omap_plane plane)
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +0300992{
993 unsigned unit = dss_feat_get_burst_size_unit();
994 /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
995 return unit * 8;
996}
997
Mythri P Kd3862612011-03-11 18:02:49 +0530998void dispc_enable_gamma_table(bool enable)
999{
1000 /*
1001 * This is partially implemented to support only disabling of
1002 * the gamma table.
1003 */
1004 if (enable) {
1005 DSSWARN("Gamma table enabling for TV not yet supported");
1006 return;
1007 }
1008
1009 REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
1010}
1011
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02001012static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001013{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05301014 if (channel == OMAP_DSS_CHANNEL_DIGIT)
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001015 return;
1016
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05301017 mgr_fld_write(channel, DISPC_MGR_FLD_CPR, enable);
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001018}
1019
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02001020static void dispc_mgr_set_cpr_coef(enum omap_channel channel,
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001021 struct omap_dss_cpr_coefs *coefs)
1022{
1023 u32 coef_r, coef_g, coef_b;
1024
Archit Tanejadd88b7a2012-06-29 14:41:30 +05301025 if (!dss_mgr_is_lcd(channel))
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001026 return;
1027
1028 coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
1029 FLD_VAL(coefs->rb, 9, 0);
1030 coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) |
1031 FLD_VAL(coefs->gb, 9, 0);
1032 coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) |
1033 FLD_VAL(coefs->bb, 9, 0);
1034
1035 dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r);
1036 dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g);
1037 dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b);
1038}
1039
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001040static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001041{
1042 u32 val;
1043
1044 BUG_ON(plane == OMAP_DSS_GFX);
1045
Archit Taneja9b372c22011-05-06 11:45:49 +05301046 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001047 val = FLD_MOD(val, enable, 9, 9);
Archit Taneja9b372c22011-05-06 11:45:49 +05301048 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001049}
1050
Archit Tanejac3d925292011-09-14 11:52:54 +05301051static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001052{
Archit Tanejab8c095b2011-09-13 18:20:33 +05301053 static const unsigned shifts[] = { 5, 10, 10, 10 };
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03001054 int shift;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001055
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03001056 shift = shifts[plane];
1057 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001058}
1059
Archit Taneja8f366162012-04-16 12:53:44 +05301060static void dispc_mgr_set_size(enum omap_channel channel, u16 width,
Archit Tanejae5c09e02012-04-16 12:53:42 +05301061 u16 height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001062{
1063 u32 val;
Archit Taneja8f366162012-04-16 12:53:44 +05301064
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001065 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
Archit Taneja702d1442011-05-06 11:45:50 +05301066 dispc_write_reg(DISPC_SIZE_MGR(channel), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001067}
1068
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001069static void dispc_init_fifos(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001070{
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001071 u32 size;
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001072 int fifo;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301073 u8 start, end;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001074 u32 unit;
1075
1076 unit = dss_feat_get_buffer_size_unit();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001077
Archit Tanejaa0acb552010-09-15 19:20:00 +05301078 dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001079
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001080 for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1081 size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end);
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001082 size *= unit;
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001083 dispc.fifo_size[fifo] = size;
1084
1085 /*
1086 * By default fifos are mapped directly to overlays, fifo 0 to
1087 * ovl 0, fifo 1 to ovl 1, etc.
1088 */
1089 dispc.fifo_assignment[fifo] = fifo;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001090 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001091}
1092
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001093static u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001094{
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001095 int fifo;
1096 u32 size = 0;
1097
1098 for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1099 if (dispc.fifo_assignment[fifo] == plane)
1100 size += dispc.fifo_size[fifo];
1101 }
1102
1103 return size;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001104}
1105
Tomi Valkeinen6f04e1b2011-10-31 08:58:52 +02001106void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001107{
Archit Tanejaa0acb552010-09-15 19:20:00 +05301108 u8 hi_start, hi_end, lo_start, lo_end;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001109 u32 unit;
1110
1111 unit = dss_feat_get_buffer_size_unit();
1112
1113 WARN_ON(low % unit != 0);
1114 WARN_ON(high % unit != 0);
1115
1116 low /= unit;
1117 high /= unit;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301118
Archit Taneja9b372c22011-05-06 11:45:49 +05301119 dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
1120 dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
1121
Tomi Valkeinen3cb5d962012-01-13 13:14:57 +02001122 DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n",
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001123 plane,
Archit Taneja9b372c22011-05-06 11:45:49 +05301124 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
Tomi Valkeinen3cb5d962012-01-13 13:14:57 +02001125 lo_start, lo_end) * unit,
Archit Taneja9b372c22011-05-06 11:45:49 +05301126 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
Tomi Valkeinen3cb5d962012-01-13 13:14:57 +02001127 hi_start, hi_end) * unit,
1128 low * unit, high * unit);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001129
Archit Taneja9b372c22011-05-06 11:45:49 +05301130 dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
Archit Tanejaa0acb552010-09-15 19:20:00 +05301131 FLD_VAL(high, hi_start, hi_end) |
1132 FLD_VAL(low, lo_start, lo_end));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001133}
1134
1135void dispc_enable_fifomerge(bool enable)
1136{
Tomi Valkeinene6b0f882012-01-13 13:24:04 +02001137 if (!dss_has_feature(FEAT_FIFO_MERGE)) {
1138 WARN_ON(enable);
1139 return;
1140 }
1141
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001142 DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1143 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001144}
1145
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001146void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
Tomi Valkeinen3568f2a2012-05-15 15:31:01 +03001147 u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
1148 bool manual_update)
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001149{
1150 /*
1151 * All sizes are in bytes. Both the buffer and burst are made of
1152 * buffer_units, and the fifo thresholds must be buffer_unit aligned.
1153 */
1154
1155 unsigned buf_unit = dss_feat_get_buffer_size_unit();
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001156 unsigned ovl_fifo_size, total_fifo_size, burst_size;
1157 int i;
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001158
1159 burst_size = dispc_ovl_get_burst_size(plane);
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001160 ovl_fifo_size = dispc_ovl_get_fifo_size(plane);
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001161
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001162 if (use_fifomerge) {
1163 total_fifo_size = 0;
1164 for (i = 0; i < omap_dss_get_num_overlays(); ++i)
1165 total_fifo_size += dispc_ovl_get_fifo_size(i);
1166 } else {
1167 total_fifo_size = ovl_fifo_size;
1168 }
1169
1170 /*
1171 * We use the same low threshold for both fifomerge and non-fifomerge
1172 * cases, but for fifomerge we calculate the high threshold using the
1173 * combined fifo size
1174 */
1175
Tomi Valkeinen3568f2a2012-05-15 15:31:01 +03001176 if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001177 *fifo_low = ovl_fifo_size - burst_size * 2;
1178 *fifo_high = total_fifo_size - burst_size;
1179 } else {
1180 *fifo_low = ovl_fifo_size - burst_size;
1181 *fifo_high = total_fifo_size - buf_unit;
1182 }
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001183}
1184
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001185static void dispc_ovl_set_fir(enum omap_plane plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301186 int hinc, int vinc,
1187 enum omap_color_component color_comp)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001188{
1189 u32 val;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001190
Amber Jain0d66cbb2011-05-19 19:47:54 +05301191 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
1192 u8 hinc_start, hinc_end, vinc_start, vinc_end;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301193
Amber Jain0d66cbb2011-05-19 19:47:54 +05301194 dss_feat_get_reg_field(FEAT_REG_FIRHINC,
1195 &hinc_start, &hinc_end);
1196 dss_feat_get_reg_field(FEAT_REG_FIRVINC,
1197 &vinc_start, &vinc_end);
1198 val = FLD_VAL(vinc, vinc_start, vinc_end) |
1199 FLD_VAL(hinc, hinc_start, hinc_end);
Archit Tanejaa0acb552010-09-15 19:20:00 +05301200
Amber Jain0d66cbb2011-05-19 19:47:54 +05301201 dispc_write_reg(DISPC_OVL_FIR(plane), val);
1202 } else {
1203 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1204 dispc_write_reg(DISPC_OVL_FIR2(plane), val);
1205 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001206}
1207
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001208static void dispc_ovl_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001209{
1210 u32 val;
Archit Taneja87a74842011-03-02 11:19:50 +05301211 u8 hor_start, hor_end, vert_start, vert_end;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001212
Archit Taneja87a74842011-03-02 11:19:50 +05301213 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1214 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1215
1216 val = FLD_VAL(vaccu, vert_start, vert_end) |
1217 FLD_VAL(haccu, hor_start, hor_end);
1218
Archit Taneja9b372c22011-05-06 11:45:49 +05301219 dispc_write_reg(DISPC_OVL_ACCU0(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001220}
1221
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001222static void dispc_ovl_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001223{
1224 u32 val;
Archit Taneja87a74842011-03-02 11:19:50 +05301225 u8 hor_start, hor_end, vert_start, vert_end;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001226
Archit Taneja87a74842011-03-02 11:19:50 +05301227 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1228 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1229
1230 val = FLD_VAL(vaccu, vert_start, vert_end) |
1231 FLD_VAL(haccu, hor_start, hor_end);
1232
Archit Taneja9b372c22011-05-06 11:45:49 +05301233 dispc_write_reg(DISPC_OVL_ACCU1(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001234}
1235
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001236static void dispc_ovl_set_vid_accu2_0(enum omap_plane plane, int haccu,
1237 int vaccu)
Amber Jainab5ca072011-05-19 19:47:53 +05301238{
1239 u32 val;
1240
1241 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1242 dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val);
1243}
1244
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001245static void dispc_ovl_set_vid_accu2_1(enum omap_plane plane, int haccu,
1246 int vaccu)
Amber Jainab5ca072011-05-19 19:47:53 +05301247{
1248 u32 val;
1249
1250 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1251 dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val);
1252}
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001253
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001254static void dispc_ovl_set_scale_param(enum omap_plane plane,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001255 u16 orig_width, u16 orig_height,
1256 u16 out_width, u16 out_height,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301257 bool five_taps, u8 rotation,
1258 enum omap_color_component color_comp)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001259{
Amber Jain0d66cbb2011-05-19 19:47:54 +05301260 int fir_hinc, fir_vinc;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001261
Amber Jained14a3c2011-05-19 19:47:51 +05301262 fir_hinc = 1024 * orig_width / out_width;
1263 fir_vinc = 1024 * orig_height / out_height;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001264
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +05301265 dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps,
1266 color_comp);
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001267 dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301268}
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001269
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301270static void dispc_ovl_set_accu_uv(enum omap_plane plane,
1271 u16 orig_width, u16 orig_height, u16 out_width, u16 out_height,
1272 bool ilace, enum omap_color_mode color_mode, u8 rotation)
1273{
1274 int h_accu2_0, h_accu2_1;
1275 int v_accu2_0, v_accu2_1;
1276 int chroma_hinc, chroma_vinc;
1277 int idx;
1278
1279 struct accu {
1280 s8 h0_m, h0_n;
1281 s8 h1_m, h1_n;
1282 s8 v0_m, v0_n;
1283 s8 v1_m, v1_n;
1284 };
1285
1286 const struct accu *accu_table;
1287 const struct accu *accu_val;
1288
1289 static const struct accu accu_nv12[4] = {
1290 { 0, 1, 0, 1 , -1, 2, 0, 1 },
1291 { 1, 2, -3, 4 , 0, 1, 0, 1 },
1292 { -1, 1, 0, 1 , -1, 2, 0, 1 },
1293 { -1, 2, -1, 2 , -1, 1, 0, 1 },
1294 };
1295
1296 static const struct accu accu_nv12_ilace[4] = {
1297 { 0, 1, 0, 1 , -3, 4, -1, 4 },
1298 { -1, 4, -3, 4 , 0, 1, 0, 1 },
1299 { -1, 1, 0, 1 , -1, 4, -3, 4 },
1300 { -3, 4, -3, 4 , -1, 1, 0, 1 },
1301 };
1302
1303 static const struct accu accu_yuv[4] = {
1304 { 0, 1, 0, 1, 0, 1, 0, 1 },
1305 { 0, 1, 0, 1, 0, 1, 0, 1 },
1306 { -1, 1, 0, 1, 0, 1, 0, 1 },
1307 { 0, 1, 0, 1, -1, 1, 0, 1 },
1308 };
1309
1310 switch (rotation) {
1311 case OMAP_DSS_ROT_0:
1312 idx = 0;
1313 break;
1314 case OMAP_DSS_ROT_90:
1315 idx = 1;
1316 break;
1317 case OMAP_DSS_ROT_180:
1318 idx = 2;
1319 break;
1320 case OMAP_DSS_ROT_270:
1321 idx = 3;
1322 break;
1323 default:
1324 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001325 return;
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301326 }
1327
1328 switch (color_mode) {
1329 case OMAP_DSS_COLOR_NV12:
1330 if (ilace)
1331 accu_table = accu_nv12_ilace;
1332 else
1333 accu_table = accu_nv12;
1334 break;
1335 case OMAP_DSS_COLOR_YUV2:
1336 case OMAP_DSS_COLOR_UYVY:
1337 accu_table = accu_yuv;
1338 break;
1339 default:
1340 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001341 return;
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301342 }
1343
1344 accu_val = &accu_table[idx];
1345
1346 chroma_hinc = 1024 * orig_width / out_width;
1347 chroma_vinc = 1024 * orig_height / out_height;
1348
1349 h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024;
1350 h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024;
1351 v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024;
1352 v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024;
1353
1354 dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0);
1355 dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1);
1356}
1357
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001358static void dispc_ovl_set_scaling_common(enum omap_plane plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301359 u16 orig_width, u16 orig_height,
1360 u16 out_width, u16 out_height,
1361 bool ilace, bool five_taps,
1362 bool fieldmode, enum omap_color_mode color_mode,
1363 u8 rotation)
1364{
1365 int accu0 = 0;
1366 int accu1 = 0;
1367 u32 l;
1368
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001369 dispc_ovl_set_scale_param(plane, orig_width, orig_height,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301370 out_width, out_height, five_taps,
1371 rotation, DISPC_COLOR_COMPONENT_RGB_Y);
Archit Taneja9b372c22011-05-06 11:45:49 +05301372 l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001373
Archit Taneja87a74842011-03-02 11:19:50 +05301374 /* RESIZEENABLE and VERTICALTAPS */
1375 l &= ~((0x3 << 5) | (0x1 << 21));
Amber Jained14a3c2011-05-19 19:47:51 +05301376 l |= (orig_width != out_width) ? (1 << 5) : 0;
1377 l |= (orig_height != out_height) ? (1 << 6) : 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001378 l |= five_taps ? (1 << 21) : 0;
Archit Taneja87a74842011-03-02 11:19:50 +05301379
1380 /* VRESIZECONF and HRESIZECONF */
1381 if (dss_has_feature(FEAT_RESIZECONF)) {
1382 l &= ~(0x3 << 7);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301383 l |= (orig_width <= out_width) ? 0 : (1 << 7);
1384 l |= (orig_height <= out_height) ? 0 : (1 << 8);
Archit Taneja87a74842011-03-02 11:19:50 +05301385 }
1386
1387 /* LINEBUFFERSPLIT */
1388 if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) {
1389 l &= ~(0x1 << 22);
1390 l |= five_taps ? (1 << 22) : 0;
1391 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001392
Archit Taneja9b372c22011-05-06 11:45:49 +05301393 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001394
1395 /*
1396 * field 0 = even field = bottom field
1397 * field 1 = odd field = top field
1398 */
1399 if (ilace && !fieldmode) {
1400 accu1 = 0;
Amber Jain0d66cbb2011-05-19 19:47:54 +05301401 accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001402 if (accu0 >= 1024/2) {
1403 accu1 = 1024/2;
1404 accu0 -= accu1;
1405 }
1406 }
1407
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001408 dispc_ovl_set_vid_accu0(plane, 0, accu0);
1409 dispc_ovl_set_vid_accu1(plane, 0, accu1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001410}
1411
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001412static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301413 u16 orig_width, u16 orig_height,
1414 u16 out_width, u16 out_height,
1415 bool ilace, bool five_taps,
1416 bool fieldmode, enum omap_color_mode color_mode,
1417 u8 rotation)
1418{
1419 int scale_x = out_width != orig_width;
1420 int scale_y = out_height != orig_height;
1421
1422 if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE))
1423 return;
1424 if ((color_mode != OMAP_DSS_COLOR_YUV2 &&
1425 color_mode != OMAP_DSS_COLOR_UYVY &&
1426 color_mode != OMAP_DSS_COLOR_NV12)) {
1427 /* reset chroma resampling for RGB formats */
1428 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
1429 return;
1430 }
Tomi Valkeinen36377352012-05-15 15:54:15 +03001431
1432 dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width,
1433 out_height, ilace, color_mode, rotation);
1434
Amber Jain0d66cbb2011-05-19 19:47:54 +05301435 switch (color_mode) {
1436 case OMAP_DSS_COLOR_NV12:
1437 /* UV is subsampled by 2 vertically*/
1438 orig_height >>= 1;
1439 /* UV is subsampled by 2 horz.*/
1440 orig_width >>= 1;
1441 break;
1442 case OMAP_DSS_COLOR_YUV2:
1443 case OMAP_DSS_COLOR_UYVY:
1444 /*For YUV422 with 90/270 rotation,
1445 *we don't upsample chroma
1446 */
1447 if (rotation == OMAP_DSS_ROT_0 ||
1448 rotation == OMAP_DSS_ROT_180)
1449 /* UV is subsampled by 2 hrz*/
1450 orig_width >>= 1;
1451 /* must use FIR for YUV422 if rotated */
1452 if (rotation != OMAP_DSS_ROT_0)
1453 scale_x = scale_y = true;
1454 break;
1455 default:
1456 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001457 return;
Amber Jain0d66cbb2011-05-19 19:47:54 +05301458 }
1459
1460 if (out_width != orig_width)
1461 scale_x = true;
1462 if (out_height != orig_height)
1463 scale_y = true;
1464
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001465 dispc_ovl_set_scale_param(plane, orig_width, orig_height,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301466 out_width, out_height, five_taps,
1467 rotation, DISPC_COLOR_COMPONENT_UV);
1468
1469 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane),
1470 (scale_x || scale_y) ? 1 : 0, 8, 8);
1471 /* set H scaling */
1472 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
1473 /* set V scaling */
1474 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301475}
1476
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001477static void dispc_ovl_set_scaling(enum omap_plane plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301478 u16 orig_width, u16 orig_height,
1479 u16 out_width, u16 out_height,
1480 bool ilace, bool five_taps,
1481 bool fieldmode, enum omap_color_mode color_mode,
1482 u8 rotation)
1483{
1484 BUG_ON(plane == OMAP_DSS_GFX);
1485
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001486 dispc_ovl_set_scaling_common(plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301487 orig_width, orig_height,
1488 out_width, out_height,
1489 ilace, five_taps,
1490 fieldmode, color_mode,
1491 rotation);
1492
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001493 dispc_ovl_set_scaling_uv(plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301494 orig_width, orig_height,
1495 out_width, out_height,
1496 ilace, five_taps,
1497 fieldmode, color_mode,
1498 rotation);
1499}
1500
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001501static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001502 bool mirroring, enum omap_color_mode color_mode)
1503{
Archit Taneja87a74842011-03-02 11:19:50 +05301504 bool row_repeat = false;
1505 int vidrot = 0;
1506
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001507 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1508 color_mode == OMAP_DSS_COLOR_UYVY) {
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001509
1510 if (mirroring) {
1511 switch (rotation) {
1512 case OMAP_DSS_ROT_0:
1513 vidrot = 2;
1514 break;
1515 case OMAP_DSS_ROT_90:
1516 vidrot = 1;
1517 break;
1518 case OMAP_DSS_ROT_180:
1519 vidrot = 0;
1520 break;
1521 case OMAP_DSS_ROT_270:
1522 vidrot = 3;
1523 break;
1524 }
1525 } else {
1526 switch (rotation) {
1527 case OMAP_DSS_ROT_0:
1528 vidrot = 0;
1529 break;
1530 case OMAP_DSS_ROT_90:
1531 vidrot = 1;
1532 break;
1533 case OMAP_DSS_ROT_180:
1534 vidrot = 2;
1535 break;
1536 case OMAP_DSS_ROT_270:
1537 vidrot = 3;
1538 break;
1539 }
1540 }
1541
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001542 if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
Archit Taneja87a74842011-03-02 11:19:50 +05301543 row_repeat = true;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001544 else
Archit Taneja87a74842011-03-02 11:19:50 +05301545 row_repeat = false;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001546 }
Archit Taneja87a74842011-03-02 11:19:50 +05301547
Archit Taneja9b372c22011-05-06 11:45:49 +05301548 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
Archit Taneja87a74842011-03-02 11:19:50 +05301549 if (dss_has_feature(FEAT_ROWREPEATENABLE))
Archit Taneja9b372c22011-05-06 11:45:49 +05301550 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
1551 row_repeat ? 1 : 0, 18, 18);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001552}
1553
1554static int color_mode_to_bpp(enum omap_color_mode color_mode)
1555{
1556 switch (color_mode) {
1557 case OMAP_DSS_COLOR_CLUT1:
1558 return 1;
1559 case OMAP_DSS_COLOR_CLUT2:
1560 return 2;
1561 case OMAP_DSS_COLOR_CLUT4:
1562 return 4;
1563 case OMAP_DSS_COLOR_CLUT8:
Amber Jainf20e4222011-05-19 19:47:50 +05301564 case OMAP_DSS_COLOR_NV12:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001565 return 8;
1566 case OMAP_DSS_COLOR_RGB12U:
1567 case OMAP_DSS_COLOR_RGB16:
1568 case OMAP_DSS_COLOR_ARGB16:
1569 case OMAP_DSS_COLOR_YUV2:
1570 case OMAP_DSS_COLOR_UYVY:
Amber Jainf20e4222011-05-19 19:47:50 +05301571 case OMAP_DSS_COLOR_RGBA16:
1572 case OMAP_DSS_COLOR_RGBX16:
1573 case OMAP_DSS_COLOR_ARGB16_1555:
1574 case OMAP_DSS_COLOR_XRGB16_1555:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001575 return 16;
1576 case OMAP_DSS_COLOR_RGB24P:
1577 return 24;
1578 case OMAP_DSS_COLOR_RGB24U:
1579 case OMAP_DSS_COLOR_ARGB32:
1580 case OMAP_DSS_COLOR_RGBA32:
1581 case OMAP_DSS_COLOR_RGBX32:
1582 return 32;
1583 default:
1584 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001585 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001586 }
1587}
1588
1589static s32 pixinc(int pixels, u8 ps)
1590{
1591 if (pixels == 1)
1592 return 1;
1593 else if (pixels > 1)
1594 return 1 + (pixels - 1) * ps;
1595 else if (pixels < 0)
1596 return 1 - (-pixels + 1) * ps;
1597 else
1598 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001599 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001600}
1601
1602static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
1603 u16 screen_width,
1604 u16 width, u16 height,
1605 enum omap_color_mode color_mode, bool fieldmode,
1606 unsigned int field_offset,
1607 unsigned *offset0, unsigned *offset1,
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301608 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001609{
1610 u8 ps;
1611
1612 /* FIXME CLUT formats */
1613 switch (color_mode) {
1614 case OMAP_DSS_COLOR_CLUT1:
1615 case OMAP_DSS_COLOR_CLUT2:
1616 case OMAP_DSS_COLOR_CLUT4:
1617 case OMAP_DSS_COLOR_CLUT8:
1618 BUG();
1619 return;
1620 case OMAP_DSS_COLOR_YUV2:
1621 case OMAP_DSS_COLOR_UYVY:
1622 ps = 4;
1623 break;
1624 default:
1625 ps = color_mode_to_bpp(color_mode) / 8;
1626 break;
1627 }
1628
1629 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1630 width, height);
1631
1632 /*
1633 * field 0 = even field = bottom field
1634 * field 1 = odd field = top field
1635 */
1636 switch (rotation + mirror * 4) {
1637 case OMAP_DSS_ROT_0:
1638 case OMAP_DSS_ROT_180:
1639 /*
1640 * If the pixel format is YUV or UYVY divide the width
1641 * of the image by 2 for 0 and 180 degree rotation.
1642 */
1643 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1644 color_mode == OMAP_DSS_COLOR_UYVY)
1645 width = width >> 1;
1646 case OMAP_DSS_ROT_90:
1647 case OMAP_DSS_ROT_270:
1648 *offset1 = 0;
1649 if (field_offset)
1650 *offset0 = field_offset * screen_width * ps;
1651 else
1652 *offset0 = 0;
1653
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301654 *row_inc = pixinc(1 +
1655 (y_predecim * screen_width - x_predecim * width) +
1656 (fieldmode ? screen_width : 0), ps);
1657 *pix_inc = pixinc(x_predecim, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001658 break;
1659
1660 case OMAP_DSS_ROT_0 + 4:
1661 case OMAP_DSS_ROT_180 + 4:
1662 /* If the pixel format is YUV or UYVY divide the width
1663 * of the image by 2 for 0 degree and 180 degree
1664 */
1665 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1666 color_mode == OMAP_DSS_COLOR_UYVY)
1667 width = width >> 1;
1668 case OMAP_DSS_ROT_90 + 4:
1669 case OMAP_DSS_ROT_270 + 4:
1670 *offset1 = 0;
1671 if (field_offset)
1672 *offset0 = field_offset * screen_width * ps;
1673 else
1674 *offset0 = 0;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301675 *row_inc = pixinc(1 -
1676 (y_predecim * screen_width + x_predecim * width) -
1677 (fieldmode ? screen_width : 0), ps);
1678 *pix_inc = pixinc(x_predecim, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001679 break;
1680
1681 default:
1682 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001683 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001684 }
1685}
1686
1687static void calc_dma_rotation_offset(u8 rotation, bool mirror,
1688 u16 screen_width,
1689 u16 width, u16 height,
1690 enum omap_color_mode color_mode, bool fieldmode,
1691 unsigned int field_offset,
1692 unsigned *offset0, unsigned *offset1,
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301693 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001694{
1695 u8 ps;
1696 u16 fbw, fbh;
1697
1698 /* FIXME CLUT formats */
1699 switch (color_mode) {
1700 case OMAP_DSS_COLOR_CLUT1:
1701 case OMAP_DSS_COLOR_CLUT2:
1702 case OMAP_DSS_COLOR_CLUT4:
1703 case OMAP_DSS_COLOR_CLUT8:
1704 BUG();
1705 return;
1706 default:
1707 ps = color_mode_to_bpp(color_mode) / 8;
1708 break;
1709 }
1710
1711 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1712 width, height);
1713
1714 /* width & height are overlay sizes, convert to fb sizes */
1715
1716 if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) {
1717 fbw = width;
1718 fbh = height;
1719 } else {
1720 fbw = height;
1721 fbh = width;
1722 }
1723
1724 /*
1725 * field 0 = even field = bottom field
1726 * field 1 = odd field = top field
1727 */
1728 switch (rotation + mirror * 4) {
1729 case OMAP_DSS_ROT_0:
1730 *offset1 = 0;
1731 if (field_offset)
1732 *offset0 = *offset1 + field_offset * screen_width * ps;
1733 else
1734 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301735 *row_inc = pixinc(1 +
1736 (y_predecim * screen_width - fbw * x_predecim) +
1737 (fieldmode ? screen_width : 0), ps);
1738 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1739 color_mode == OMAP_DSS_COLOR_UYVY)
1740 *pix_inc = pixinc(x_predecim, 2 * ps);
1741 else
1742 *pix_inc = pixinc(x_predecim, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001743 break;
1744 case OMAP_DSS_ROT_90:
1745 *offset1 = screen_width * (fbh - 1) * ps;
1746 if (field_offset)
1747 *offset0 = *offset1 + field_offset * ps;
1748 else
1749 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301750 *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) +
1751 y_predecim + (fieldmode ? 1 : 0), ps);
1752 *pix_inc = pixinc(-x_predecim * screen_width, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001753 break;
1754 case OMAP_DSS_ROT_180:
1755 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1756 if (field_offset)
1757 *offset0 = *offset1 - field_offset * screen_width * ps;
1758 else
1759 *offset0 = *offset1;
1760 *row_inc = pixinc(-1 -
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301761 (y_predecim * screen_width - fbw * x_predecim) -
1762 (fieldmode ? screen_width : 0), ps);
1763 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1764 color_mode == OMAP_DSS_COLOR_UYVY)
1765 *pix_inc = pixinc(-x_predecim, 2 * ps);
1766 else
1767 *pix_inc = pixinc(-x_predecim, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001768 break;
1769 case OMAP_DSS_ROT_270:
1770 *offset1 = (fbw - 1) * ps;
1771 if (field_offset)
1772 *offset0 = *offset1 - field_offset * ps;
1773 else
1774 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301775 *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) -
1776 y_predecim - (fieldmode ? 1 : 0), ps);
1777 *pix_inc = pixinc(x_predecim * screen_width, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001778 break;
1779
1780 /* mirroring */
1781 case OMAP_DSS_ROT_0 + 4:
1782 *offset1 = (fbw - 1) * ps;
1783 if (field_offset)
1784 *offset0 = *offset1 + field_offset * screen_width * ps;
1785 else
1786 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301787 *row_inc = pixinc(y_predecim * screen_width * 2 - 1 +
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001788 (fieldmode ? screen_width : 0),
1789 ps);
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301790 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1791 color_mode == OMAP_DSS_COLOR_UYVY)
1792 *pix_inc = pixinc(-x_predecim, 2 * ps);
1793 else
1794 *pix_inc = pixinc(-x_predecim, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001795 break;
1796
1797 case OMAP_DSS_ROT_90 + 4:
1798 *offset1 = 0;
1799 if (field_offset)
1800 *offset0 = *offset1 + field_offset * ps;
1801 else
1802 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301803 *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) +
1804 y_predecim + (fieldmode ? 1 : 0),
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001805 ps);
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301806 *pix_inc = pixinc(x_predecim * screen_width, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001807 break;
1808
1809 case OMAP_DSS_ROT_180 + 4:
1810 *offset1 = screen_width * (fbh - 1) * ps;
1811 if (field_offset)
1812 *offset0 = *offset1 - field_offset * screen_width * ps;
1813 else
1814 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301815 *row_inc = pixinc(1 - y_predecim * screen_width * 2 -
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001816 (fieldmode ? screen_width : 0),
1817 ps);
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301818 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1819 color_mode == OMAP_DSS_COLOR_UYVY)
1820 *pix_inc = pixinc(x_predecim, 2 * ps);
1821 else
1822 *pix_inc = pixinc(x_predecim, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001823 break;
1824
1825 case OMAP_DSS_ROT_270 + 4:
1826 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1827 if (field_offset)
1828 *offset0 = *offset1 - field_offset * ps;
1829 else
1830 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301831 *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) -
1832 y_predecim - (fieldmode ? 1 : 0),
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001833 ps);
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05301834 *pix_inc = pixinc(-x_predecim * screen_width, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001835 break;
1836
1837 default:
1838 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001839 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001840 }
1841}
1842
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05301843static void calc_tiler_rotation_offset(u16 screen_width, u16 width,
1844 enum omap_color_mode color_mode, bool fieldmode,
1845 unsigned int field_offset, unsigned *offset0, unsigned *offset1,
1846 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
1847{
1848 u8 ps;
1849
1850 switch (color_mode) {
1851 case OMAP_DSS_COLOR_CLUT1:
1852 case OMAP_DSS_COLOR_CLUT2:
1853 case OMAP_DSS_COLOR_CLUT4:
1854 case OMAP_DSS_COLOR_CLUT8:
1855 BUG();
1856 return;
1857 default:
1858 ps = color_mode_to_bpp(color_mode) / 8;
1859 break;
1860 }
1861
1862 DSSDBG("scrw %d, width %d\n", screen_width, width);
1863
1864 /*
1865 * field 0 = even field = bottom field
1866 * field 1 = odd field = top field
1867 */
1868 *offset1 = 0;
1869 if (field_offset)
1870 *offset0 = *offset1 + field_offset * screen_width * ps;
1871 else
1872 *offset0 = *offset1;
1873 *row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) +
1874 (fieldmode ? screen_width : 0), ps);
1875 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1876 color_mode == OMAP_DSS_COLOR_UYVY)
1877 *pix_inc = pixinc(x_predecim, 2 * ps);
1878 else
1879 *pix_inc = pixinc(x_predecim, ps);
1880}
1881
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301882/*
1883 * This function is used to avoid synclosts in OMAP3, because of some
1884 * undocumented horizontal position and timing related limitations.
1885 */
Archit Taneja81ab95b2012-05-08 15:53:20 +05301886static int check_horiz_timing_omap3(enum omap_channel channel,
1887 const struct omap_video_timings *t, u16 pos_x,
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301888 u16 width, u16 height, u16 out_width, u16 out_height)
1889{
1890 int DS = DIV_ROUND_UP(height, out_height);
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301891 unsigned long nonactive, lclk, pclk;
1892 static const u8 limits[3] = { 8, 10, 20 };
1893 u64 val, blank;
1894 int i;
1895
Archit Taneja81ab95b2012-05-08 15:53:20 +05301896 nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width;
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301897 pclk = dispc_mgr_pclk_rate(channel);
Archit Tanejadd88b7a2012-06-29 14:41:30 +05301898 if (dss_mgr_is_lcd(channel))
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301899 lclk = dispc_mgr_lclk_rate(channel);
1900 else
1901 lclk = dispc_fclk_rate();
1902
1903 i = 0;
1904 if (out_height < height)
1905 i++;
1906 if (out_width < width)
1907 i++;
Archit Taneja81ab95b2012-05-08 15:53:20 +05301908 blank = div_u64((u64)(t->hbp + t->hsw + t->hfp) * lclk, pclk);
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301909 DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]);
1910 if (blank <= limits[i])
1911 return -EINVAL;
1912
1913 /*
1914 * Pixel data should be prepared before visible display point starts.
1915 * So, atleast DS-2 lines must have already been fetched by DISPC
1916 * during nonactive - pos_x period.
1917 */
1918 val = div_u64((u64)(nonactive - pos_x) * lclk, pclk);
1919 DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n",
1920 val, max(0, DS - 2) * width);
1921 if (val < max(0, DS - 2) * width)
1922 return -EINVAL;
1923
1924 /*
1925 * All lines need to be refilled during the nonactive period of which
1926 * only one line can be loaded during the active period. So, atleast
1927 * DS - 1 lines should be loaded during nonactive period.
1928 */
1929 val = div_u64((u64)nonactive * lclk, pclk);
1930 DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n",
1931 val, max(0, DS - 1) * width);
1932 if (val < max(0, DS - 1) * width)
1933 return -EINVAL;
1934
1935 return 0;
1936}
1937
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05301938static unsigned long calc_core_clk_five_taps(enum omap_channel channel,
Archit Taneja81ab95b2012-05-08 15:53:20 +05301939 const struct omap_video_timings *mgr_timings, u16 width,
1940 u16 height, u16 out_width, u16 out_height,
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00001941 enum omap_color_mode color_mode)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001942{
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05301943 u32 core_clk = 0;
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03001944 u64 tmp, pclk = dispc_mgr_pclk_rate(channel);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001945
Chandrabhanu Mahapatra7282f1b2011-12-19 14:03:56 +05301946 if (height <= out_height && width <= out_width)
1947 return (unsigned long) pclk;
1948
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001949 if (height > out_height) {
Archit Taneja81ab95b2012-05-08 15:53:20 +05301950 unsigned int ppl = mgr_timings->x_res;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001951
1952 tmp = pclk * height * out_width;
1953 do_div(tmp, 2 * out_height * ppl);
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05301954 core_clk = tmp;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001955
Ville Syrjälä2d9c5592010-01-08 11:56:41 +02001956 if (height > 2 * out_height) {
1957 if (ppl == out_width)
1958 return 0;
1959
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001960 tmp = pclk * (height - 2 * out_height) * out_width;
1961 do_div(tmp, 2 * out_height * (ppl - out_width));
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05301962 core_clk = max_t(u32, core_clk, tmp);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001963 }
1964 }
1965
1966 if (width > out_width) {
1967 tmp = pclk * width;
1968 do_div(tmp, out_width);
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05301969 core_clk = max_t(u32, core_clk, tmp);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001970
1971 if (color_mode == OMAP_DSS_COLOR_RGB24U)
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05301972 core_clk <<= 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001973 }
1974
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05301975 return core_clk;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001976}
1977
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05301978static unsigned long calc_core_clk_24xx(enum omap_channel channel, u16 width,
1979 u16 height, u16 out_width, u16 out_height)
1980{
1981 unsigned long pclk = dispc_mgr_pclk_rate(channel);
1982
1983 if (height > out_height && width > out_width)
1984 return pclk * 4;
1985 else
1986 return pclk * 2;
1987}
1988
1989static unsigned long calc_core_clk_34xx(enum omap_channel channel, u16 width,
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00001990 u16 height, u16 out_width, u16 out_height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001991{
1992 unsigned int hf, vf;
Archit Taneja79ee89c2012-01-30 10:54:17 +05301993 unsigned long pclk = dispc_mgr_pclk_rate(channel);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001994
1995 /*
1996 * FIXME how to determine the 'A' factor
1997 * for the no downscaling case ?
1998 */
1999
2000 if (width > 3 * out_width)
2001 hf = 4;
2002 else if (width > 2 * out_width)
2003 hf = 3;
2004 else if (width > out_width)
2005 hf = 2;
2006 else
2007 hf = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002008 if (height > out_height)
2009 vf = 2;
2010 else
2011 vf = 1;
2012
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302013 return pclk * vf * hf;
2014}
2015
2016static unsigned long calc_core_clk_44xx(enum omap_channel channel, u16 width,
2017 u16 height, u16 out_width, u16 out_height)
2018{
2019 unsigned long pclk = dispc_mgr_pclk_rate(channel);
2020
2021 if (width > out_width)
2022 return DIV_ROUND_UP(pclk, out_width) * width;
2023 else
2024 return pclk;
2025}
2026
2027static int dispc_ovl_calc_scaling_24xx(enum omap_channel channel,
2028 const struct omap_video_timings *mgr_timings,
2029 u16 width, u16 height, u16 out_width, u16 out_height,
2030 enum omap_color_mode color_mode, bool *five_taps,
2031 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
2032 u16 pos_x, unsigned long *core_clk)
2033{
2034 int error;
2035 u16 in_width, in_height;
2036 int min_factor = min(*decim_x, *decim_y);
2037 const int maxsinglelinewidth =
2038 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
2039 *five_taps = false;
2040
2041 do {
2042 in_height = DIV_ROUND_UP(height, *decim_y);
2043 in_width = DIV_ROUND_UP(width, *decim_x);
2044 *core_clk = dispc.feat->calc_core_clk(channel, in_width,
2045 in_height, out_width, out_height);
2046 error = (in_width > maxsinglelinewidth || !*core_clk ||
2047 *core_clk > dispc_core_clk_rate());
2048 if (error) {
2049 if (*decim_x == *decim_y) {
2050 *decim_x = min_factor;
2051 ++*decim_y;
2052 } else {
2053 swap(*decim_x, *decim_y);
2054 if (*decim_x < *decim_y)
2055 ++*decim_x;
2056 }
2057 }
2058 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2059
2060 if (in_width > maxsinglelinewidth) {
2061 DSSERR("Cannot scale max input width exceeded");
2062 return -EINVAL;
Chandrabhanu Mahapatra7282f1b2011-12-19 14:03:56 +05302063 }
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302064 return 0;
2065}
2066
2067static int dispc_ovl_calc_scaling_34xx(enum omap_channel channel,
2068 const struct omap_video_timings *mgr_timings,
2069 u16 width, u16 height, u16 out_width, u16 out_height,
2070 enum omap_color_mode color_mode, bool *five_taps,
2071 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
2072 u16 pos_x, unsigned long *core_clk)
2073{
2074 int error;
2075 u16 in_width, in_height;
2076 int min_factor = min(*decim_x, *decim_y);
2077 const int maxsinglelinewidth =
2078 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
2079
2080 do {
2081 in_height = DIV_ROUND_UP(height, *decim_y);
2082 in_width = DIV_ROUND_UP(width, *decim_x);
2083 *core_clk = calc_core_clk_five_taps(channel, mgr_timings,
2084 in_width, in_height, out_width, out_height, color_mode);
2085
2086 error = check_horiz_timing_omap3(channel, mgr_timings, pos_x,
2087 in_width, in_height, out_width, out_height);
2088
2089 if (in_width > maxsinglelinewidth)
2090 if (in_height > out_height &&
2091 in_height < out_height * 2)
2092 *five_taps = false;
2093 if (!*five_taps)
2094 *core_clk = dispc.feat->calc_core_clk(channel, in_width,
2095 in_height, out_width, out_height);
2096
2097 error = (error || in_width > maxsinglelinewidth * 2 ||
2098 (in_width > maxsinglelinewidth && *five_taps) ||
2099 !*core_clk || *core_clk > dispc_core_clk_rate());
2100 if (error) {
2101 if (*decim_x == *decim_y) {
2102 *decim_x = min_factor;
2103 ++*decim_y;
2104 } else {
2105 swap(*decim_x, *decim_y);
2106 if (*decim_x < *decim_y)
2107 ++*decim_x;
2108 }
2109 }
2110 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2111
2112 if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width, height,
2113 out_width, out_height)){
2114 DSSERR("horizontal timing too tight\n");
2115 return -EINVAL;
2116 }
2117
2118 if (in_width > (maxsinglelinewidth * 2)) {
2119 DSSERR("Cannot setup scaling");
2120 DSSERR("width exceeds maximum width possible");
2121 return -EINVAL;
2122 }
2123
2124 if (in_width > maxsinglelinewidth && *five_taps) {
2125 DSSERR("cannot setup scaling with five taps");
2126 return -EINVAL;
2127 }
2128 return 0;
2129}
2130
2131static int dispc_ovl_calc_scaling_44xx(enum omap_channel channel,
2132 const struct omap_video_timings *mgr_timings,
2133 u16 width, u16 height, u16 out_width, u16 out_height,
2134 enum omap_color_mode color_mode, bool *five_taps,
2135 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
2136 u16 pos_x, unsigned long *core_clk)
2137{
2138 u16 in_width, in_width_max;
2139 int decim_x_min = *decim_x;
2140 u16 in_height = DIV_ROUND_UP(height, *decim_y);
2141 const int maxsinglelinewidth =
2142 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
2143
2144 in_width_max = dispc_core_clk_rate() /
2145 DIV_ROUND_UP(dispc_mgr_pclk_rate(channel), out_width);
2146 *decim_x = DIV_ROUND_UP(width, in_width_max);
2147
2148 *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
2149 if (*decim_x > *x_predecim)
2150 return -EINVAL;
2151
2152 do {
2153 in_width = DIV_ROUND_UP(width, *decim_x);
2154 } while (*decim_x <= *x_predecim &&
2155 in_width > maxsinglelinewidth && ++*decim_x);
2156
2157 if (in_width > maxsinglelinewidth) {
2158 DSSERR("Cannot scale width exceeds max line width");
2159 return -EINVAL;
2160 }
2161
2162 *core_clk = dispc.feat->calc_core_clk(channel, in_width, in_height,
2163 out_width, out_height);
2164 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002165}
2166
Archit Taneja79ad75f2011-09-08 13:15:11 +05302167static int dispc_ovl_calc_scaling(enum omap_plane plane,
Archit Taneja81ab95b2012-05-08 15:53:20 +05302168 enum omap_channel channel,
2169 const struct omap_video_timings *mgr_timings,
2170 u16 width, u16 height, u16 out_width, u16 out_height,
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302171 enum omap_color_mode color_mode, bool *five_taps,
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302172 int *x_predecim, int *y_predecim, u16 pos_x)
Archit Taneja79ad75f2011-09-08 13:15:11 +05302173{
2174 struct omap_overlay *ovl = omap_dss_get_overlay(plane);
Archit Taneja0373cac2011-09-08 13:25:17 +05302175 const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302176 const int max_decim_limit = 16;
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302177 unsigned long core_clk = 0;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302178 int decim_x, decim_y, ret;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302179
Tomi Valkeinenf95cb5e2011-11-01 10:50:45 +02002180 if (width == out_width && height == out_height)
2181 return 0;
2182
2183 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
2184 return -EINVAL;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302185
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302186 *x_predecim = max_decim_limit;
2187 *y_predecim = max_decim_limit;
2188
2189 if (color_mode == OMAP_DSS_COLOR_CLUT1 ||
2190 color_mode == OMAP_DSS_COLOR_CLUT2 ||
2191 color_mode == OMAP_DSS_COLOR_CLUT4 ||
2192 color_mode == OMAP_DSS_COLOR_CLUT8) {
2193 *x_predecim = 1;
2194 *y_predecim = 1;
2195 *five_taps = false;
2196 return 0;
2197 }
2198
2199 decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
2200 decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
2201
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302202 if (decim_x > *x_predecim || out_width > width * 8)
Archit Taneja79ad75f2011-09-08 13:15:11 +05302203 return -EINVAL;
2204
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302205 if (decim_y > *y_predecim || out_height > height * 8)
Archit Taneja79ad75f2011-09-08 13:15:11 +05302206 return -EINVAL;
2207
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302208 ret = dispc.feat->calc_scaling(channel, mgr_timings, width, height,
2209 out_width, out_height, color_mode, five_taps, x_predecim,
2210 y_predecim, &decim_x, &decim_y, pos_x, &core_clk);
2211 if (ret)
2212 return ret;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302213
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302214 DSSDBG("required core clk rate = %lu Hz\n", core_clk);
2215 DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate());
Archit Taneja79ad75f2011-09-08 13:15:11 +05302216
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302217 if (!core_clk || core_clk > dispc_core_clk_rate()) {
Archit Taneja79ad75f2011-09-08 13:15:11 +05302218 DSSERR("failed to set up scaling, "
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302219 "required core clk rate = %lu Hz, "
2220 "current core clk rate = %lu Hz\n",
2221 core_clk, dispc_core_clk_rate());
Archit Taneja79ad75f2011-09-08 13:15:11 +05302222 return -EINVAL;
2223 }
2224
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302225 *x_predecim = decim_x;
2226 *y_predecim = decim_y;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302227 return 0;
2228}
2229
Archit Tanejaa4273b72011-09-14 11:10:10 +05302230int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi,
Archit Taneja8050cbe2012-06-06 16:25:52 +05302231 bool replication, const struct omap_video_timings *mgr_timings)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002232{
Archit Taneja79ad75f2011-09-08 13:15:11 +05302233 struct omap_overlay *ovl = omap_dss_get_overlay(plane);
Chandrabhanu Mahapatra7282f1b2011-12-19 14:03:56 +05302234 bool five_taps = true;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002235 bool fieldmode = 0;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302236 int r, cconv = 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002237 unsigned offset0, offset1;
2238 s32 row_inc;
2239 s32 pix_inc;
Archit Tanejaa4273b72011-09-14 11:10:10 +05302240 u16 frame_height = oi->height;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002241 unsigned int field_offset = 0;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302242 u16 in_height = oi->height;
2243 u16 in_width = oi->width;
2244 u16 out_width, out_height;
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02002245 enum omap_channel channel;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302246 int x_predecim = 1, y_predecim = 1;
Archit Taneja8050cbe2012-06-06 16:25:52 +05302247 bool ilace = mgr_timings->interlace;
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02002248
2249 channel = dispc_ovl_get_channel_out(plane);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002250
Archit Tanejaa4273b72011-09-14 11:10:10 +05302251 DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
Tomi Valkeinenf38545d2011-11-03 17:00:07 +02002252 "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n",
2253 plane, oi->paddr, oi->p_uv_addr,
Archit Tanejac3d925292011-09-14 11:52:54 +05302254 oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
2255 oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
Tomi Valkeinenf38545d2011-11-03 17:00:07 +02002256 oi->mirror, ilace, channel, replication);
Tomi Valkeinene6d80f92011-05-19 14:12:26 +03002257
Archit Tanejaa4273b72011-09-14 11:10:10 +05302258 if (oi->paddr == 0)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002259 return -EINVAL;
2260
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302261 out_width = oi->out_width == 0 ? oi->width : oi->out_width;
2262 out_height = oi->out_height == 0 ? oi->height : oi->out_height;
Tomi Valkeinencf073662011-11-03 16:08:27 +02002263
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302264 if (ilace && oi->height == out_height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002265 fieldmode = 1;
2266
2267 if (ilace) {
2268 if (fieldmode)
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302269 in_height /= 2;
Archit Tanejaa4273b72011-09-14 11:10:10 +05302270 oi->pos_y /= 2;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302271 out_height /= 2;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002272
2273 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
2274 "out_height %d\n",
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302275 in_height, oi->pos_y, out_height);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002276 }
2277
Archit Tanejaa4273b72011-09-14 11:10:10 +05302278 if (!dss_feat_color_mode_supported(plane, oi->color_mode))
Archit Taneja8dad2ab2010-11-25 17:58:10 +05302279 return -EINVAL;
2280
Archit Taneja81ab95b2012-05-08 15:53:20 +05302281 r = dispc_ovl_calc_scaling(plane, channel, mgr_timings, in_width,
2282 in_height, out_width, out_height, oi->color_mode,
2283 &five_taps, &x_predecim, &y_predecim, oi->pos_x);
Archit Taneja79ad75f2011-09-08 13:15:11 +05302284 if (r)
2285 return r;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002286
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302287 in_width = DIV_ROUND_UP(in_width, x_predecim);
2288 in_height = DIV_ROUND_UP(in_height, y_predecim);
2289
Archit Taneja79ad75f2011-09-08 13:15:11 +05302290 if (oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
2291 oi->color_mode == OMAP_DSS_COLOR_UYVY ||
2292 oi->color_mode == OMAP_DSS_COLOR_NV12)
2293 cconv = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002294
2295 if (ilace && !fieldmode) {
2296 /*
2297 * when downscaling the bottom field may have to start several
2298 * source lines below the top field. Unfortunately ACCUI
2299 * registers will only hold the fractional part of the offset
2300 * so the integer part must be added to the base address of the
2301 * bottom field.
2302 */
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302303 if (!in_height || in_height == out_height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002304 field_offset = 0;
2305 else
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302306 field_offset = in_height / out_height / 2;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002307 }
2308
2309 /* Fields are independent but interleaved in memory. */
2310 if (fieldmode)
2311 field_offset = 1;
2312
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002313 offset0 = 0;
2314 offset1 = 0;
2315 row_inc = 0;
2316 pix_inc = 0;
2317
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05302318 if (oi->rotation_type == OMAP_DSS_ROT_TILER)
2319 calc_tiler_rotation_offset(oi->screen_width, in_width,
2320 oi->color_mode, fieldmode, field_offset,
2321 &offset0, &offset1, &row_inc, &pix_inc,
2322 x_predecim, y_predecim);
2323 else if (oi->rotation_type == OMAP_DSS_ROT_DMA)
Archit Tanejaa4273b72011-09-14 11:10:10 +05302324 calc_dma_rotation_offset(oi->rotation, oi->mirror,
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302325 oi->screen_width, in_width, frame_height,
Archit Tanejaa4273b72011-09-14 11:10:10 +05302326 oi->color_mode, fieldmode, field_offset,
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302327 &offset0, &offset1, &row_inc, &pix_inc,
2328 x_predecim, y_predecim);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002329 else
Archit Tanejaa4273b72011-09-14 11:10:10 +05302330 calc_vrfb_rotation_offset(oi->rotation, oi->mirror,
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302331 oi->screen_width, in_width, frame_height,
Archit Tanejaa4273b72011-09-14 11:10:10 +05302332 oi->color_mode, fieldmode, field_offset,
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302333 &offset0, &offset1, &row_inc, &pix_inc,
2334 x_predecim, y_predecim);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002335
2336 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
2337 offset0, offset1, row_inc, pix_inc);
2338
Archit Tanejaa4273b72011-09-14 11:10:10 +05302339 dispc_ovl_set_color_mode(plane, oi->color_mode);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002340
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05302341 dispc_ovl_configure_burst_type(plane, oi->rotation_type);
2342
Archit Tanejaa4273b72011-09-14 11:10:10 +05302343 dispc_ovl_set_ba0(plane, oi->paddr + offset0);
2344 dispc_ovl_set_ba1(plane, oi->paddr + offset1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002345
Archit Tanejaa4273b72011-09-14 11:10:10 +05302346 if (OMAP_DSS_COLOR_NV12 == oi->color_mode) {
2347 dispc_ovl_set_ba0_uv(plane, oi->p_uv_addr + offset0);
2348 dispc_ovl_set_ba1_uv(plane, oi->p_uv_addr + offset1);
Amber Jain0d66cbb2011-05-19 19:47:54 +05302349 }
2350
2351
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03002352 dispc_ovl_set_row_inc(plane, row_inc);
2353 dispc_ovl_set_pix_inc(plane, pix_inc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002354
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302355 DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, in_width,
2356 in_height, out_width, out_height);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002357
Archit Tanejaa4273b72011-09-14 11:10:10 +05302358 dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002359
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302360 dispc_ovl_set_pic_size(plane, in_width, in_height);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002361
Archit Taneja79ad75f2011-09-08 13:15:11 +05302362 if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) {
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302363 dispc_ovl_set_scaling(plane, in_width, in_height, out_width,
2364 out_height, ilace, five_taps, fieldmode,
Archit Tanejaa4273b72011-09-14 11:10:10 +05302365 oi->color_mode, oi->rotation);
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302366 dispc_ovl_set_vid_size(plane, out_width, out_height);
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03002367 dispc_ovl_set_vid_color_conv(plane, cconv);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002368 }
2369
Archit Tanejaa4273b72011-09-14 11:10:10 +05302370 dispc_ovl_set_rotation_attrs(plane, oi->rotation, oi->mirror,
2371 oi->color_mode);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002372
Archit Taneja54128702011-09-08 11:29:17 +05302373 dispc_ovl_set_zorder(plane, oi->zorder);
Archit Tanejaa4273b72011-09-14 11:10:10 +05302374 dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha);
2375 dispc_ovl_setup_global_alpha(plane, oi->global_alpha);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002376
Archit Tanejac3d925292011-09-14 11:52:54 +05302377 dispc_ovl_enable_replication(plane, replication);
Archit Tanejac3d925292011-09-14 11:52:54 +05302378
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002379 return 0;
2380}
2381
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03002382int dispc_ovl_enable(enum omap_plane plane, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002383{
Tomi Valkeinene6d80f92011-05-19 14:12:26 +03002384 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
2385
Archit Taneja9b372c22011-05-06 11:45:49 +05302386 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
Tomi Valkeinene6d80f92011-05-19 14:12:26 +03002387
2388 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002389}
2390
2391static void dispc_disable_isr(void *data, u32 mask)
2392{
2393 struct completion *compl = data;
2394 complete(compl);
2395}
2396
Sumit Semwal2a205f32010-12-02 11:27:12 +00002397static void _enable_lcd_out(enum omap_channel channel, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002398{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302399 mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable);
2400 /* flush posted write */
2401 mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002402}
2403
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002404static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002405{
2406 struct completion frame_done_completion;
2407 bool is_on;
2408 int r;
Sumit Semwal2a205f32010-12-02 11:27:12 +00002409 u32 irq;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002410
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002411 /* When we disable LCD output, we need to wait until frame is done.
2412 * Otherwise the DSS is still working, and turning off the clocks
2413 * prevents DSS from going to OFF mode */
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302414 is_on = mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
Sumit Semwal2a205f32010-12-02 11:27:12 +00002415
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302416 irq = mgr_desc[channel].framedone_irq;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002417
2418 if (!enable && is_on) {
2419 init_completion(&frame_done_completion);
2420
2421 r = omap_dispc_register_isr(dispc_disable_isr,
Sumit Semwal2a205f32010-12-02 11:27:12 +00002422 &frame_done_completion, irq);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002423
2424 if (r)
2425 DSSERR("failed to register FRAMEDONE isr\n");
2426 }
2427
Sumit Semwal2a205f32010-12-02 11:27:12 +00002428 _enable_lcd_out(channel, enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002429
2430 if (!enable && is_on) {
2431 if (!wait_for_completion_timeout(&frame_done_completion,
2432 msecs_to_jiffies(100)))
2433 DSSERR("timeout waiting for FRAME DONE\n");
2434
2435 r = omap_dispc_unregister_isr(dispc_disable_isr,
Sumit Semwal2a205f32010-12-02 11:27:12 +00002436 &frame_done_completion, irq);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002437
2438 if (r)
2439 DSSERR("failed to unregister FRAMEDONE isr\n");
2440 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002441}
2442
2443static void _enable_digit_out(bool enable)
2444{
2445 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
Tomi Valkeinenb6a44e72011-10-12 10:17:02 +03002446 /* flush posted write */
2447 dispc_read_reg(DISPC_CONTROL);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002448}
2449
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002450static void dispc_mgr_enable_digit_out(bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002451{
2452 struct completion frame_done_completion;
Tomi Valkeinene82b0902011-08-31 14:42:49 +03002453 enum dss_hdmi_venc_clk_source_select src;
2454 int r, i;
2455 u32 irq_mask;
2456 int num_irqs;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002457
Tomi Valkeinene6d80f92011-05-19 14:12:26 +03002458 if (REG_GET(DISPC_CONTROL, 1, 1) == enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002459 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002460
Tomi Valkeinene82b0902011-08-31 14:42:49 +03002461 src = dss_get_hdmi_venc_clk_source();
2462
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002463 if (enable) {
2464 unsigned long flags;
2465 /* When we enable digit output, we'll get an extra digit
2466 * sync lost interrupt, that we need to ignore */
2467 spin_lock_irqsave(&dispc.irq_lock, flags);
2468 dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
2469 _omap_dispc_set_irqs();
2470 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2471 }
2472
2473 /* When we disable digit output, we need to wait until fields are done.
2474 * Otherwise the DSS is still working, and turning off the clocks
2475 * prevents DSS from going to OFF mode. And when enabling, we need to
2476 * wait for the extra sync losts */
2477 init_completion(&frame_done_completion);
2478
Tomi Valkeinene82b0902011-08-31 14:42:49 +03002479 if (src == DSS_HDMI_M_PCLK && enable == false) {
2480 irq_mask = DISPC_IRQ_FRAMEDONETV;
2481 num_irqs = 1;
2482 } else {
2483 irq_mask = DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD;
2484 /* XXX I understand from TRM that we should only wait for the
2485 * current field to complete. But it seems we have to wait for
2486 * both fields */
2487 num_irqs = 2;
2488 }
2489
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002490 r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion,
Tomi Valkeinene82b0902011-08-31 14:42:49 +03002491 irq_mask);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002492 if (r)
Tomi Valkeinene82b0902011-08-31 14:42:49 +03002493 DSSERR("failed to register %x isr\n", irq_mask);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002494
2495 _enable_digit_out(enable);
2496
Tomi Valkeinene82b0902011-08-31 14:42:49 +03002497 for (i = 0; i < num_irqs; ++i) {
2498 if (!wait_for_completion_timeout(&frame_done_completion,
2499 msecs_to_jiffies(100)))
2500 DSSERR("timeout waiting for digit out to %s\n",
2501 enable ? "start" : "stop");
2502 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002503
Tomi Valkeinene82b0902011-08-31 14:42:49 +03002504 r = omap_dispc_unregister_isr(dispc_disable_isr, &frame_done_completion,
2505 irq_mask);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002506 if (r)
Tomi Valkeinene82b0902011-08-31 14:42:49 +03002507 DSSERR("failed to unregister %x isr\n", irq_mask);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002508
2509 if (enable) {
2510 unsigned long flags;
2511 spin_lock_irqsave(&dispc.irq_lock, flags);
Tomi Valkeinene82b0902011-08-31 14:42:49 +03002512 dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST_DIGIT;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002513 dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
2514 _omap_dispc_set_irqs();
2515 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2516 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002517}
2518
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002519bool dispc_mgr_is_enabled(enum omap_channel channel)
Tomi Valkeinena2faee82010-01-08 17:14:53 +02002520{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302521 return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
Tomi Valkeinena2faee82010-01-08 17:14:53 +02002522}
2523
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002524void dispc_mgr_enable(enum omap_channel channel, bool enable)
Tomi Valkeinena2faee82010-01-08 17:14:53 +02002525{
Archit Tanejadd88b7a2012-06-29 14:41:30 +05302526 if (dss_mgr_is_lcd(channel))
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002527 dispc_mgr_enable_lcd_out(channel, enable);
Tomi Valkeinena2faee82010-01-08 17:14:53 +02002528 else if (channel == OMAP_DSS_CHANNEL_DIGIT)
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002529 dispc_mgr_enable_digit_out(enable);
Tomi Valkeinena2faee82010-01-08 17:14:53 +02002530 else
2531 BUG();
2532}
2533
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002534void dispc_lcd_enable_signal_polarity(bool act_high)
2535{
Archit Taneja6ced40b2010-12-02 11:27:13 +00002536 if (!dss_has_feature(FEAT_LCDENABLEPOL))
2537 return;
2538
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002539 REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002540}
2541
2542void dispc_lcd_enable_signal(bool enable)
2543{
Archit Taneja6ced40b2010-12-02 11:27:13 +00002544 if (!dss_has_feature(FEAT_LCDENABLESIGNAL))
2545 return;
2546
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002547 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002548}
2549
2550void dispc_pck_free_enable(bool enable)
2551{
Archit Taneja6ced40b2010-12-02 11:27:13 +00002552 if (!dss_has_feature(FEAT_PCKFREEENABLE))
2553 return;
2554
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002555 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002556}
2557
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002558void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002559{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302560 mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002561}
2562
2563
Archit Tanejad21f43b2012-06-21 09:45:11 +05302564void dispc_mgr_set_lcd_type_tft(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002565{
Archit Tanejad21f43b2012-06-21 09:45:11 +05302566 mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002567}
2568
2569void dispc_set_loadmode(enum omap_dss_load_mode mode)
2570{
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002571 REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002572}
2573
2574
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002575static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002576{
Sumit Semwal8613b002010-12-02 11:27:09 +00002577 dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002578}
2579
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002580static void dispc_mgr_set_trans_key(enum omap_channel ch,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002581 enum omap_dss_trans_key_type type,
2582 u32 trans_key)
2583{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302584 mgr_fld_write(ch, DISPC_MGR_FLD_TCKSELECTION, type);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002585
Sumit Semwal8613b002010-12-02 11:27:09 +00002586 dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002587}
2588
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002589static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002590{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302591 mgr_fld_write(ch, DISPC_MGR_FLD_TCKENABLE, enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002592}
Archit Taneja11354dd2011-09-26 11:47:29 +05302593
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002594static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch,
2595 bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002596{
Archit Taneja11354dd2011-09-26 11:47:29 +05302597 if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002598 return;
2599
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002600 if (ch == OMAP_DSS_CHANNEL_LCD)
2601 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
Sumit Semwal2a205f32010-12-02 11:27:12 +00002602 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002603 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002604}
Archit Taneja11354dd2011-09-26 11:47:29 +05302605
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002606void dispc_mgr_setup(enum omap_channel channel,
2607 struct omap_overlay_manager_info *info)
2608{
2609 dispc_mgr_set_default_color(channel, info->default_color);
2610 dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key);
2611 dispc_mgr_enable_trans_key(channel, info->trans_enabled);
2612 dispc_mgr_enable_alpha_fixed_zorder(channel,
2613 info->partial_alpha_enabled);
2614 if (dss_has_feature(FEAT_CPR)) {
2615 dispc_mgr_enable_cpr(channel, info->cpr_enable);
2616 dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs);
2617 }
2618}
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002619
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002620void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002621{
2622 int code;
2623
2624 switch (data_lines) {
2625 case 12:
2626 code = 0;
2627 break;
2628 case 16:
2629 code = 1;
2630 break;
2631 case 18:
2632 code = 2;
2633 break;
2634 case 24:
2635 code = 3;
2636 break;
2637 default:
2638 BUG();
2639 return;
2640 }
2641
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302642 mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002643}
2644
Archit Taneja569969d2011-08-22 17:41:57 +05302645void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002646{
2647 u32 l;
Archit Taneja569969d2011-08-22 17:41:57 +05302648 int gpout0, gpout1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002649
2650 switch (mode) {
Archit Taneja569969d2011-08-22 17:41:57 +05302651 case DSS_IO_PAD_MODE_RESET:
2652 gpout0 = 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002653 gpout1 = 0;
2654 break;
Archit Taneja569969d2011-08-22 17:41:57 +05302655 case DSS_IO_PAD_MODE_RFBI:
2656 gpout0 = 1;
2657 gpout1 = 0;
2658 break;
2659 case DSS_IO_PAD_MODE_BYPASS:
2660 gpout0 = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002661 gpout1 = 1;
2662 break;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002663 default:
2664 BUG();
2665 return;
2666 }
2667
Archit Taneja569969d2011-08-22 17:41:57 +05302668 l = dispc_read_reg(DISPC_CONTROL);
2669 l = FLD_MOD(l, gpout0, 15, 15);
2670 l = FLD_MOD(l, gpout1, 16, 16);
2671 dispc_write_reg(DISPC_CONTROL, l);
2672}
2673
2674void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable)
2675{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302676 mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002677}
2678
Archit Taneja8f366162012-04-16 12:53:44 +05302679static bool _dispc_mgr_size_ok(u16 width, u16 height)
2680{
2681 return width <= dss_feat_get_param_max(FEAT_PARAM_MGR_WIDTH) &&
2682 height <= dss_feat_get_param_max(FEAT_PARAM_MGR_HEIGHT);
2683}
2684
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002685static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
2686 int vsw, int vfp, int vbp)
2687{
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302688 if (hsw < 1 || hsw > dispc.feat->sw_max ||
2689 hfp < 1 || hfp > dispc.feat->hp_max ||
2690 hbp < 1 || hbp > dispc.feat->hp_max ||
2691 vsw < 1 || vsw > dispc.feat->sw_max ||
2692 vfp < 0 || vfp > dispc.feat->vp_max ||
2693 vbp < 0 || vbp > dispc.feat->vp_max)
2694 return false;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002695 return true;
2696}
2697
Archit Taneja8f366162012-04-16 12:53:44 +05302698bool dispc_mgr_timings_ok(enum omap_channel channel,
Archit Tanejab917fa32012-04-27 01:07:28 +05302699 const struct omap_video_timings *timings)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002700{
Archit Taneja8f366162012-04-16 12:53:44 +05302701 bool timings_ok;
2702
2703 timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res);
2704
Archit Tanejadd88b7a2012-06-29 14:41:30 +05302705 if (dss_mgr_is_lcd(channel))
Archit Taneja8f366162012-04-16 12:53:44 +05302706 timings_ok = timings_ok && _dispc_lcd_timings_ok(timings->hsw,
2707 timings->hfp, timings->hbp,
2708 timings->vsw, timings->vfp,
2709 timings->vbp);
2710
2711 return timings_ok;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002712}
2713
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002714static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
Archit Taneja655e2942012-06-21 10:37:43 +05302715 int hfp, int hbp, int vsw, int vfp, int vbp,
2716 enum omap_dss_signal_level vsync_level,
2717 enum omap_dss_signal_level hsync_level,
2718 enum omap_dss_signal_edge data_pclk_edge,
2719 enum omap_dss_signal_level de_level,
2720 enum omap_dss_signal_edge sync_pclk_edge)
2721
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002722{
Archit Taneja655e2942012-06-21 10:37:43 +05302723 u32 timing_h, timing_v, l;
2724 bool onoff, rf, ipc;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002725
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302726 timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) |
2727 FLD_VAL(hfp-1, dispc.feat->fp_start, 8) |
2728 FLD_VAL(hbp-1, dispc.feat->bp_start, 20);
2729 timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) |
2730 FLD_VAL(vfp, dispc.feat->fp_start, 8) |
2731 FLD_VAL(vbp, dispc.feat->bp_start, 20);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002732
Sumit Semwal64ba4f72010-12-02 11:27:10 +00002733 dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
2734 dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
Archit Taneja655e2942012-06-21 10:37:43 +05302735
2736 switch (data_pclk_edge) {
2737 case OMAPDSS_DRIVE_SIG_RISING_EDGE:
2738 ipc = false;
2739 break;
2740 case OMAPDSS_DRIVE_SIG_FALLING_EDGE:
2741 ipc = true;
2742 break;
2743 case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES:
2744 default:
2745 BUG();
2746 }
2747
2748 switch (sync_pclk_edge) {
2749 case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES:
2750 onoff = false;
2751 rf = false;
2752 break;
2753 case OMAPDSS_DRIVE_SIG_FALLING_EDGE:
2754 onoff = true;
2755 rf = false;
2756 break;
2757 case OMAPDSS_DRIVE_SIG_RISING_EDGE:
2758 onoff = true;
2759 rf = true;
2760 break;
2761 default:
2762 BUG();
2763 };
2764
2765 l = dispc_read_reg(DISPC_POL_FREQ(channel));
2766 l |= FLD_VAL(onoff, 17, 17);
2767 l |= FLD_VAL(rf, 16, 16);
2768 l |= FLD_VAL(de_level, 15, 15);
2769 l |= FLD_VAL(ipc, 14, 14);
2770 l |= FLD_VAL(hsync_level, 13, 13);
2771 l |= FLD_VAL(vsync_level, 12, 12);
2772 dispc_write_reg(DISPC_POL_FREQ(channel), l);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002773}
2774
2775/* change name to mode? */
Archit Tanejac51d9212012-04-16 12:53:43 +05302776void dispc_mgr_set_timings(enum omap_channel channel,
Sumit Semwal64ba4f72010-12-02 11:27:10 +00002777 struct omap_video_timings *timings)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002778{
2779 unsigned xtot, ytot;
2780 unsigned long ht, vt;
Archit Taneja2aefad42012-05-18 14:36:54 +05302781 struct omap_video_timings t = *timings;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002782
Archit Taneja2aefad42012-05-18 14:36:54 +05302783 DSSDBG("channel %d xres %u yres %u\n", channel, t.x_res, t.y_res);
Archit Tanejac51d9212012-04-16 12:53:43 +05302784
Archit Taneja2aefad42012-05-18 14:36:54 +05302785 if (!dispc_mgr_timings_ok(channel, &t)) {
Archit Taneja8f366162012-04-16 12:53:44 +05302786 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002787 return;
2788 }
Archit Tanejac51d9212012-04-16 12:53:43 +05302789
Archit Tanejadd88b7a2012-06-29 14:41:30 +05302790 if (dss_mgr_is_lcd(channel)) {
Archit Taneja2aefad42012-05-18 14:36:54 +05302791 _dispc_mgr_set_lcd_timings(channel, t.hsw, t.hfp, t.hbp, t.vsw,
Archit Taneja655e2942012-06-21 10:37:43 +05302792 t.vfp, t.vbp, t.vsync_level, t.hsync_level,
2793 t.data_pclk_edge, t.de_level, t.sync_pclk_edge);
Archit Tanejac51d9212012-04-16 12:53:43 +05302794
Archit Taneja2aefad42012-05-18 14:36:54 +05302795 xtot = t.x_res + t.hfp + t.hsw + t.hbp;
2796 ytot = t.y_res + t.vfp + t.vsw + t.vbp;
Archit Tanejac51d9212012-04-16 12:53:43 +05302797
2798 ht = (timings->pixel_clock * 1000) / xtot;
2799 vt = (timings->pixel_clock * 1000) / xtot / ytot;
2800
2801 DSSDBG("pck %u\n", timings->pixel_clock);
2802 DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
Archit Taneja2aefad42012-05-18 14:36:54 +05302803 t.hsw, t.hfp, t.hbp, t.vsw, t.vfp, t.vbp);
Archit Taneja655e2942012-06-21 10:37:43 +05302804 DSSDBG("vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d\n",
2805 t.vsync_level, t.hsync_level, t.data_pclk_edge,
2806 t.de_level, t.sync_pclk_edge);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002807
Archit Tanejac51d9212012-04-16 12:53:43 +05302808 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
Archit Taneja2aefad42012-05-18 14:36:54 +05302809 } else {
Archit Taneja23c8f882012-06-28 11:15:51 +05302810 if (t.interlace == true)
Archit Taneja2aefad42012-05-18 14:36:54 +05302811 t.y_res /= 2;
Archit Tanejac51d9212012-04-16 12:53:43 +05302812 }
Archit Taneja8f366162012-04-16 12:53:44 +05302813
Archit Taneja2aefad42012-05-18 14:36:54 +05302814 dispc_mgr_set_size(channel, t.x_res, t.y_res);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002815}
2816
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002817static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00002818 u16 pck_div)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002819{
2820 BUG_ON(lck_div < 1);
Tomi Valkeinen9eaaf202011-08-29 15:56:04 +03002821 BUG_ON(pck_div < 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002822
Murthy, Raghuveerce7fa5e2011-03-03 09:27:59 -06002823 dispc_write_reg(DISPC_DIVISORo(channel),
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002824 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002825}
2826
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002827static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
Sumit Semwal2a205f32010-12-02 11:27:12 +00002828 int *pck_div)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002829{
2830 u32 l;
Murthy, Raghuveerce7fa5e2011-03-03 09:27:59 -06002831 l = dispc_read_reg(DISPC_DIVISORo(channel));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002832 *lck_div = FLD_GET(l, 23, 16);
2833 *pck_div = FLD_GET(l, 7, 0);
2834}
2835
2836unsigned long dispc_fclk_rate(void)
2837{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302838 struct platform_device *dsidev;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002839 unsigned long r = 0;
2840
Taneja, Archit66534e82011-03-08 05:50:34 -06002841 switch (dss_get_dispc_clk_source()) {
Archit Taneja89a35e52011-04-12 13:52:23 +05302842 case OMAP_DSS_CLK_SRC_FCK:
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03002843 r = clk_get_rate(dispc.dss_clk);
Taneja, Archit66534e82011-03-08 05:50:34 -06002844 break;
Archit Taneja89a35e52011-04-12 13:52:23 +05302845 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302846 dsidev = dsi_get_dsidev_from_id(0);
2847 r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
Taneja, Archit66534e82011-03-08 05:50:34 -06002848 break;
Archit Taneja5a8b5722011-05-12 17:26:29 +05302849 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
2850 dsidev = dsi_get_dsidev_from_id(1);
2851 r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
2852 break;
Taneja, Archit66534e82011-03-08 05:50:34 -06002853 default:
2854 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002855 return 0;
Taneja, Archit66534e82011-03-08 05:50:34 -06002856 }
2857
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002858 return r;
2859}
2860
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002861unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002862{
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302863 struct platform_device *dsidev;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002864 int lcd;
2865 unsigned long r;
2866 u32 l;
2867
Murthy, Raghuveerce7fa5e2011-03-03 09:27:59 -06002868 l = dispc_read_reg(DISPC_DIVISORo(channel));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002869
2870 lcd = FLD_GET(l, 23, 16);
2871
Taneja, Architea751592011-03-08 05:50:35 -06002872 switch (dss_get_lcd_clk_source(channel)) {
Archit Taneja89a35e52011-04-12 13:52:23 +05302873 case OMAP_DSS_CLK_SRC_FCK:
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03002874 r = clk_get_rate(dispc.dss_clk);
Taneja, Architea751592011-03-08 05:50:35 -06002875 break;
Archit Taneja89a35e52011-04-12 13:52:23 +05302876 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
Archit Tanejaa72b64b2011-05-12 17:26:26 +05302877 dsidev = dsi_get_dsidev_from_id(0);
2878 r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
Taneja, Architea751592011-03-08 05:50:35 -06002879 break;
Archit Taneja5a8b5722011-05-12 17:26:29 +05302880 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
2881 dsidev = dsi_get_dsidev_from_id(1);
2882 r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
2883 break;
Taneja, Architea751592011-03-08 05:50:35 -06002884 default:
2885 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002886 return 0;
Taneja, Architea751592011-03-08 05:50:35 -06002887 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002888
2889 return r / lcd;
2890}
2891
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002892unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002893{
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002894 unsigned long r;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002895
Archit Tanejadd88b7a2012-06-29 14:41:30 +05302896 if (dss_mgr_is_lcd(channel)) {
Archit Tanejac3dc6a72011-09-13 18:28:41 +05302897 int pcd;
2898 u32 l;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002899
Archit Tanejac3dc6a72011-09-13 18:28:41 +05302900 l = dispc_read_reg(DISPC_DIVISORo(channel));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002901
Archit Tanejac3dc6a72011-09-13 18:28:41 +05302902 pcd = FLD_GET(l, 7, 0);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002903
Archit Tanejac3dc6a72011-09-13 18:28:41 +05302904 r = dispc_mgr_lclk_rate(channel);
2905
2906 return r / pcd;
2907 } else {
Archit Taneja3fa03ba2012-04-09 15:06:41 +05302908 enum dss_hdmi_venc_clk_source_select source;
Archit Tanejac3dc6a72011-09-13 18:28:41 +05302909
Archit Taneja3fa03ba2012-04-09 15:06:41 +05302910 source = dss_get_hdmi_venc_clk_source();
2911
2912 switch (source) {
2913 case DSS_VENC_TV_CLK:
Archit Tanejac3dc6a72011-09-13 18:28:41 +05302914 return venc_get_pixel_clock();
Archit Taneja3fa03ba2012-04-09 15:06:41 +05302915 case DSS_HDMI_M_PCLK:
Archit Tanejac3dc6a72011-09-13 18:28:41 +05302916 return hdmi_get_pixel_clock();
2917 default:
2918 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002919 return 0;
Archit Tanejac3dc6a72011-09-13 18:28:41 +05302920 }
2921 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002922}
2923
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302924unsigned long dispc_core_clk_rate(void)
2925{
2926 int lcd;
2927 unsigned long fclk = dispc_fclk_rate();
2928
2929 if (dss_has_feature(FEAT_CORE_CLK_DIV))
2930 lcd = REG_GET(DISPC_DIVISOR, 23, 16);
2931 else
2932 lcd = REG_GET(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD), 23, 16);
2933
2934 return fclk / lcd;
2935}
2936
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05302937static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002938{
2939 int lcd, pcd;
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05302940 enum omap_dss_clk_source lcd_clk_src;
2941
2942 seq_printf(s, "- %s -\n", mgr_desc[channel].name);
2943
2944 lcd_clk_src = dss_get_lcd_clk_source(channel);
2945
2946 seq_printf(s, "%s clk source = %s (%s)\n", mgr_desc[channel].name,
2947 dss_get_generic_clk_source_name(lcd_clk_src),
2948 dss_feat_get_clk_source_name(lcd_clk_src));
2949
2950 dispc_mgr_get_lcd_divisor(channel, &lcd, &pcd);
2951
2952 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
2953 dispc_mgr_lclk_rate(channel), lcd);
2954 seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
2955 dispc_mgr_pclk_rate(channel), pcd);
2956}
2957
2958void dispc_dump_clocks(struct seq_file *s)
2959{
2960 int lcd;
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06002961 u32 l;
Archit Taneja89a35e52011-04-12 13:52:23 +05302962 enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002963
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03002964 if (dispc_runtime_get())
2965 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002966
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002967 seq_printf(s, "- DISPC -\n");
2968
Archit Taneja067a57e2011-03-02 11:57:25 +05302969 seq_printf(s, "dispc fclk source = %s (%s)\n",
2970 dss_get_generic_clk_source_name(dispc_clk_src),
2971 dss_feat_get_clk_source_name(dispc_clk_src));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002972
2973 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
Sumit Semwal2a205f32010-12-02 11:27:12 +00002974
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06002975 if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
2976 seq_printf(s, "- DISPC-CORE-CLK -\n");
2977 l = dispc_read_reg(DISPC_DIVISOR);
2978 lcd = FLD_GET(l, 23, 16);
2979
2980 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
2981 (dispc_fclk_rate()/lcd), lcd);
2982 }
Sumit Semwal2a205f32010-12-02 11:27:12 +00002983
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05302984 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD);
Taneja, Architea751592011-03-08 05:50:35 -06002985
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05302986 if (dss_has_feature(FEAT_MGR_LCD2))
2987 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD2);
2988 if (dss_has_feature(FEAT_MGR_LCD3))
2989 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03002990
2991 dispc_runtime_put();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002992}
2993
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02002994#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2995void dispc_dump_irqs(struct seq_file *s)
2996{
2997 unsigned long flags;
2998 struct dispc_irq_stats stats;
2999
3000 spin_lock_irqsave(&dispc.irq_stats_lock, flags);
3001
3002 stats = dispc.irq_stats;
3003 memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats));
3004 dispc.irq_stats.last_reset = jiffies;
3005
3006 spin_unlock_irqrestore(&dispc.irq_stats_lock, flags);
3007
3008 seq_printf(s, "period %u ms\n",
3009 jiffies_to_msecs(jiffies - stats.last_reset));
3010
3011 seq_printf(s, "irqs %d\n", stats.irq_count);
3012#define PIS(x) \
3013 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
3014
3015 PIS(FRAMEDONE);
3016 PIS(VSYNC);
3017 PIS(EVSYNC_EVEN);
3018 PIS(EVSYNC_ODD);
3019 PIS(ACBIAS_COUNT_STAT);
3020 PIS(PROG_LINE_NUM);
3021 PIS(GFX_FIFO_UNDERFLOW);
3022 PIS(GFX_END_WIN);
3023 PIS(PAL_GAMMA_MASK);
3024 PIS(OCP_ERR);
3025 PIS(VID1_FIFO_UNDERFLOW);
3026 PIS(VID1_END_WIN);
3027 PIS(VID2_FIFO_UNDERFLOW);
3028 PIS(VID2_END_WIN);
Archit Tanejab8c095b2011-09-13 18:20:33 +05303029 if (dss_feat_get_num_ovls() > 3) {
3030 PIS(VID3_FIFO_UNDERFLOW);
3031 PIS(VID3_END_WIN);
3032 }
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02003033 PIS(SYNC_LOST);
3034 PIS(SYNC_LOST_DIGIT);
3035 PIS(WAKEUP);
Sumit Semwal2a205f32010-12-02 11:27:12 +00003036 if (dss_has_feature(FEAT_MGR_LCD2)) {
3037 PIS(FRAMEDONE2);
3038 PIS(VSYNC2);
3039 PIS(ACBIAS_COUNT_STAT2);
3040 PIS(SYNC_LOST2);
3041 }
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303042 if (dss_has_feature(FEAT_MGR_LCD3)) {
3043 PIS(FRAMEDONE3);
3044 PIS(VSYNC3);
3045 PIS(ACBIAS_COUNT_STAT3);
3046 PIS(SYNC_LOST3);
3047 }
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02003048#undef PIS
3049}
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02003050#endif
3051
Tomi Valkeinene40402c2012-03-02 18:01:07 +02003052static void dispc_dump_regs(struct seq_file *s)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003053{
Archit Taneja4dd2da12011-08-05 19:06:01 +05303054 int i, j;
3055 const char *mgr_names[] = {
3056 [OMAP_DSS_CHANNEL_LCD] = "LCD",
3057 [OMAP_DSS_CHANNEL_DIGIT] = "TV",
3058 [OMAP_DSS_CHANNEL_LCD2] = "LCD2",
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303059 [OMAP_DSS_CHANNEL_LCD3] = "LCD3",
Archit Taneja4dd2da12011-08-05 19:06:01 +05303060 };
3061 const char *ovl_names[] = {
3062 [OMAP_DSS_GFX] = "GFX",
3063 [OMAP_DSS_VIDEO1] = "VID1",
3064 [OMAP_DSS_VIDEO2] = "VID2",
Archit Tanejab8c095b2011-09-13 18:20:33 +05303065 [OMAP_DSS_VIDEO3] = "VID3",
Archit Taneja4dd2da12011-08-05 19:06:01 +05303066 };
3067 const char **p_names;
3068
Archit Taneja9b372c22011-05-06 11:45:49 +05303069#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003070
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003071 if (dispc_runtime_get())
3072 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003073
Archit Taneja5010be82011-08-05 19:06:00 +05303074 /* DISPC common registers */
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003075 DUMPREG(DISPC_REVISION);
3076 DUMPREG(DISPC_SYSCONFIG);
3077 DUMPREG(DISPC_SYSSTATUS);
3078 DUMPREG(DISPC_IRQSTATUS);
3079 DUMPREG(DISPC_IRQENABLE);
3080 DUMPREG(DISPC_CONTROL);
3081 DUMPREG(DISPC_CONFIG);
3082 DUMPREG(DISPC_CAPABLE);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003083 DUMPREG(DISPC_LINE_STATUS);
3084 DUMPREG(DISPC_LINE_NUMBER);
Archit Taneja11354dd2011-09-26 11:47:29 +05303085 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
3086 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003087 DUMPREG(DISPC_GLOBAL_ALPHA);
Sumit Semwal2a205f32010-12-02 11:27:12 +00003088 if (dss_has_feature(FEAT_MGR_LCD2)) {
3089 DUMPREG(DISPC_CONTROL2);
3090 DUMPREG(DISPC_CONFIG2);
Sumit Semwal2a205f32010-12-02 11:27:12 +00003091 }
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303092 if (dss_has_feature(FEAT_MGR_LCD3)) {
3093 DUMPREG(DISPC_CONTROL3);
3094 DUMPREG(DISPC_CONFIG3);
3095 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003096
Archit Taneja5010be82011-08-05 19:06:00 +05303097#undef DUMPREG
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003098
Archit Taneja5010be82011-08-05 19:06:00 +05303099#define DISPC_REG(i, name) name(i)
Archit Taneja4dd2da12011-08-05 19:06:01 +05303100#define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
3101 48 - strlen(#r) - strlen(p_names[i]), " ", \
Archit Taneja5010be82011-08-05 19:06:00 +05303102 dispc_read_reg(DISPC_REG(i, r)))
3103
Archit Taneja4dd2da12011-08-05 19:06:01 +05303104 p_names = mgr_names;
Archit Taneja5010be82011-08-05 19:06:00 +05303105
Archit Taneja4dd2da12011-08-05 19:06:01 +05303106 /* DISPC channel specific registers */
3107 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
3108 DUMPREG(i, DISPC_DEFAULT_COLOR);
3109 DUMPREG(i, DISPC_TRANS_COLOR);
3110 DUMPREG(i, DISPC_SIZE_MGR);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003111
Archit Taneja4dd2da12011-08-05 19:06:01 +05303112 if (i == OMAP_DSS_CHANNEL_DIGIT)
3113 continue;
Archit Taneja5010be82011-08-05 19:06:00 +05303114
Archit Taneja4dd2da12011-08-05 19:06:01 +05303115 DUMPREG(i, DISPC_DEFAULT_COLOR);
3116 DUMPREG(i, DISPC_TRANS_COLOR);
3117 DUMPREG(i, DISPC_TIMING_H);
3118 DUMPREG(i, DISPC_TIMING_V);
3119 DUMPREG(i, DISPC_POL_FREQ);
3120 DUMPREG(i, DISPC_DIVISORo);
3121 DUMPREG(i, DISPC_SIZE_MGR);
Archit Taneja5010be82011-08-05 19:06:00 +05303122
Archit Taneja4dd2da12011-08-05 19:06:01 +05303123 DUMPREG(i, DISPC_DATA_CYCLE1);
3124 DUMPREG(i, DISPC_DATA_CYCLE2);
3125 DUMPREG(i, DISPC_DATA_CYCLE3);
Sumit Semwal2a205f32010-12-02 11:27:12 +00003126
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003127 if (dss_has_feature(FEAT_CPR)) {
Archit Taneja4dd2da12011-08-05 19:06:01 +05303128 DUMPREG(i, DISPC_CPR_COEF_R);
3129 DUMPREG(i, DISPC_CPR_COEF_G);
3130 DUMPREG(i, DISPC_CPR_COEF_B);
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003131 }
Sumit Semwal2a205f32010-12-02 11:27:12 +00003132 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003133
Archit Taneja4dd2da12011-08-05 19:06:01 +05303134 p_names = ovl_names;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003135
Archit Taneja4dd2da12011-08-05 19:06:01 +05303136 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
3137 DUMPREG(i, DISPC_OVL_BA0);
3138 DUMPREG(i, DISPC_OVL_BA1);
3139 DUMPREG(i, DISPC_OVL_POSITION);
3140 DUMPREG(i, DISPC_OVL_SIZE);
3141 DUMPREG(i, DISPC_OVL_ATTRIBUTES);
3142 DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
3143 DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
3144 DUMPREG(i, DISPC_OVL_ROW_INC);
3145 DUMPREG(i, DISPC_OVL_PIXEL_INC);
3146 if (dss_has_feature(FEAT_PRELOAD))
3147 DUMPREG(i, DISPC_OVL_PRELOAD);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003148
Archit Taneja4dd2da12011-08-05 19:06:01 +05303149 if (i == OMAP_DSS_GFX) {
3150 DUMPREG(i, DISPC_OVL_WINDOW_SKIP);
3151 DUMPREG(i, DISPC_OVL_TABLE_BA);
3152 continue;
3153 }
3154
3155 DUMPREG(i, DISPC_OVL_FIR);
3156 DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
3157 DUMPREG(i, DISPC_OVL_ACCU0);
3158 DUMPREG(i, DISPC_OVL_ACCU1);
3159 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
3160 DUMPREG(i, DISPC_OVL_BA0_UV);
3161 DUMPREG(i, DISPC_OVL_BA1_UV);
3162 DUMPREG(i, DISPC_OVL_FIR2);
3163 DUMPREG(i, DISPC_OVL_ACCU2_0);
3164 DUMPREG(i, DISPC_OVL_ACCU2_1);
3165 }
3166 if (dss_has_feature(FEAT_ATTR2))
3167 DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
3168 if (dss_has_feature(FEAT_PRELOAD))
3169 DUMPREG(i, DISPC_OVL_PRELOAD);
Archit Taneja5010be82011-08-05 19:06:00 +05303170 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003171
Archit Taneja5010be82011-08-05 19:06:00 +05303172#undef DISPC_REG
3173#undef DUMPREG
3174
3175#define DISPC_REG(plane, name, i) name(plane, i)
3176#define DUMPREG(plane, name, i) \
Archit Taneja4dd2da12011-08-05 19:06:01 +05303177 seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \
3178 46 - strlen(#name) - strlen(p_names[plane]), " ", \
Archit Taneja5010be82011-08-05 19:06:00 +05303179 dispc_read_reg(DISPC_REG(plane, name, i)))
3180
Archit Taneja4dd2da12011-08-05 19:06:01 +05303181 /* Video pipeline coefficient registers */
Archit Taneja5010be82011-08-05 19:06:00 +05303182
Archit Taneja4dd2da12011-08-05 19:06:01 +05303183 /* start from OMAP_DSS_VIDEO1 */
3184 for (i = 1; i < dss_feat_get_num_ovls(); i++) {
3185 for (j = 0; j < 8; j++)
3186 DUMPREG(i, DISPC_OVL_FIR_COEF_H, j);
Archit Taneja5010be82011-08-05 19:06:00 +05303187
Archit Taneja4dd2da12011-08-05 19:06:01 +05303188 for (j = 0; j < 8; j++)
3189 DUMPREG(i, DISPC_OVL_FIR_COEF_HV, j);
Archit Taneja5010be82011-08-05 19:06:00 +05303190
Archit Taneja4dd2da12011-08-05 19:06:01 +05303191 for (j = 0; j < 5; j++)
3192 DUMPREG(i, DISPC_OVL_CONV_COEF, j);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003193
Archit Taneja4dd2da12011-08-05 19:06:01 +05303194 if (dss_has_feature(FEAT_FIR_COEF_V)) {
3195 for (j = 0; j < 8; j++)
3196 DUMPREG(i, DISPC_OVL_FIR_COEF_V, j);
3197 }
Amber Jainab5ca072011-05-19 19:47:53 +05303198
Archit Taneja4dd2da12011-08-05 19:06:01 +05303199 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
3200 for (j = 0; j < 8; j++)
3201 DUMPREG(i, DISPC_OVL_FIR_COEF_H2, j);
Amber Jainab5ca072011-05-19 19:47:53 +05303202
Archit Taneja4dd2da12011-08-05 19:06:01 +05303203 for (j = 0; j < 8; j++)
3204 DUMPREG(i, DISPC_OVL_FIR_COEF_HV2, j);
Amber Jainab5ca072011-05-19 19:47:53 +05303205
Archit Taneja4dd2da12011-08-05 19:06:01 +05303206 for (j = 0; j < 8; j++)
3207 DUMPREG(i, DISPC_OVL_FIR_COEF_V2, j);
3208 }
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003209 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003210
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003211 dispc_runtime_put();
Archit Taneja5010be82011-08-05 19:06:00 +05303212
3213#undef DISPC_REG
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003214#undef DUMPREG
3215}
3216
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003217/* with fck as input clock rate, find dispc dividers that produce req_pck */
Archit Taneja6d523e72012-06-21 09:33:55 +05303218void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003219 struct dispc_clock_info *cinfo)
3220{
Tomi Valkeinen9eaaf202011-08-29 15:56:04 +03003221 u16 pcd_min, pcd_max;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003222 unsigned long best_pck;
3223 u16 best_ld, cur_ld;
3224 u16 best_pd, cur_pd;
3225
Tomi Valkeinen9eaaf202011-08-29 15:56:04 +03003226 pcd_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);
3227 pcd_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD);
3228
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003229 best_pck = 0;
3230 best_ld = 0;
3231 best_pd = 0;
3232
3233 for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
3234 unsigned long lck = fck / cur_ld;
3235
Tomi Valkeinen9eaaf202011-08-29 15:56:04 +03003236 for (cur_pd = pcd_min; cur_pd <= pcd_max; ++cur_pd) {
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003237 unsigned long pck = lck / cur_pd;
3238 long old_delta = abs(best_pck - req_pck);
3239 long new_delta = abs(pck - req_pck);
3240
3241 if (best_pck == 0 || new_delta < old_delta) {
3242 best_pck = pck;
3243 best_ld = cur_ld;
3244 best_pd = cur_pd;
3245
3246 if (pck == req_pck)
3247 goto found;
3248 }
3249
3250 if (pck < req_pck)
3251 break;
3252 }
3253
3254 if (lck / pcd_min < req_pck)
3255 break;
3256 }
3257
3258found:
3259 cinfo->lck_div = best_ld;
3260 cinfo->pck_div = best_pd;
3261 cinfo->lck = fck / cinfo->lck_div;
3262 cinfo->pck = cinfo->lck / cinfo->pck_div;
3263}
3264
3265/* calculate clock rates using dividers in cinfo */
3266int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
3267 struct dispc_clock_info *cinfo)
3268{
3269 if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
3270 return -EINVAL;
Tomi Valkeinen9eaaf202011-08-29 15:56:04 +03003271 if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003272 return -EINVAL;
3273
3274 cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
3275 cinfo->pck = cinfo->lck / cinfo->pck_div;
3276
3277 return 0;
3278}
3279
Archit Tanejaf0d08f82012-06-29 14:00:54 +05303280void dispc_mgr_set_clock_div(enum omap_channel channel,
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00003281 struct dispc_clock_info *cinfo)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003282{
3283 DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
3284 DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
3285
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003286 dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003287}
3288
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003289int dispc_mgr_get_clock_div(enum omap_channel channel,
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00003290 struct dispc_clock_info *cinfo)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003291{
3292 unsigned long fck;
3293
3294 fck = dispc_fclk_rate();
3295
Murthy, Raghuveerce7fa5e2011-03-03 09:27:59 -06003296 cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16);
3297 cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003298
3299 cinfo->lck = fck / cinfo->lck_div;
3300 cinfo->pck = cinfo->lck / cinfo->pck_div;
3301
3302 return 0;
3303}
3304
3305/* dispc.irq_lock has to be locked by the caller */
3306static void _omap_dispc_set_irqs(void)
3307{
3308 u32 mask;
3309 u32 old_mask;
3310 int i;
3311 struct omap_dispc_isr_data *isr_data;
3312
3313 mask = dispc.irq_error_mask;
3314
3315 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3316 isr_data = &dispc.registered_isr[i];
3317
3318 if (isr_data->isr == NULL)
3319 continue;
3320
3321 mask |= isr_data->mask;
3322 }
3323
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003324 old_mask = dispc_read_reg(DISPC_IRQENABLE);
3325 /* clear the irqstatus for newly enabled irqs */
3326 dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
3327
3328 dispc_write_reg(DISPC_IRQENABLE, mask);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003329}
3330
3331int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
3332{
3333 int i;
3334 int ret;
3335 unsigned long flags;
3336 struct omap_dispc_isr_data *isr_data;
3337
3338 if (isr == NULL)
3339 return -EINVAL;
3340
3341 spin_lock_irqsave(&dispc.irq_lock, flags);
3342
3343 /* check for duplicate entry */
3344 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3345 isr_data = &dispc.registered_isr[i];
3346 if (isr_data->isr == isr && isr_data->arg == arg &&
3347 isr_data->mask == mask) {
3348 ret = -EINVAL;
3349 goto err;
3350 }
3351 }
3352
3353 isr_data = NULL;
3354 ret = -EBUSY;
3355
3356 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3357 isr_data = &dispc.registered_isr[i];
3358
3359 if (isr_data->isr != NULL)
3360 continue;
3361
3362 isr_data->isr = isr;
3363 isr_data->arg = arg;
3364 isr_data->mask = mask;
3365 ret = 0;
3366
3367 break;
3368 }
3369
Tomi Valkeinenb9cb0982011-03-04 18:19:54 +02003370 if (ret)
3371 goto err;
3372
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003373 _omap_dispc_set_irqs();
3374
3375 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3376
3377 return 0;
3378err:
3379 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3380
3381 return ret;
3382}
3383EXPORT_SYMBOL(omap_dispc_register_isr);
3384
3385int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
3386{
3387 int i;
3388 unsigned long flags;
3389 int ret = -EINVAL;
3390 struct omap_dispc_isr_data *isr_data;
3391
3392 spin_lock_irqsave(&dispc.irq_lock, flags);
3393
3394 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3395 isr_data = &dispc.registered_isr[i];
3396 if (isr_data->isr != isr || isr_data->arg != arg ||
3397 isr_data->mask != mask)
3398 continue;
3399
3400 /* found the correct isr */
3401
3402 isr_data->isr = NULL;
3403 isr_data->arg = NULL;
3404 isr_data->mask = 0;
3405
3406 ret = 0;
3407 break;
3408 }
3409
3410 if (ret == 0)
3411 _omap_dispc_set_irqs();
3412
3413 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3414
3415 return ret;
3416}
3417EXPORT_SYMBOL(omap_dispc_unregister_isr);
3418
3419#ifdef DEBUG
3420static void print_irq_status(u32 status)
3421{
3422 if ((status & dispc.irq_error_mask) == 0)
3423 return;
3424
3425 printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status);
3426
3427#define PIS(x) \
3428 if (status & DISPC_IRQ_##x) \
3429 printk(#x " ");
3430 PIS(GFX_FIFO_UNDERFLOW);
3431 PIS(OCP_ERR);
3432 PIS(VID1_FIFO_UNDERFLOW);
3433 PIS(VID2_FIFO_UNDERFLOW);
Archit Tanejab8c095b2011-09-13 18:20:33 +05303434 if (dss_feat_get_num_ovls() > 3)
3435 PIS(VID3_FIFO_UNDERFLOW);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003436 PIS(SYNC_LOST);
3437 PIS(SYNC_LOST_DIGIT);
Sumit Semwal2a205f32010-12-02 11:27:12 +00003438 if (dss_has_feature(FEAT_MGR_LCD2))
3439 PIS(SYNC_LOST2);
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303440 if (dss_has_feature(FEAT_MGR_LCD3))
3441 PIS(SYNC_LOST3);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003442#undef PIS
3443
3444 printk("\n");
3445}
3446#endif
3447
3448/* Called from dss.c. Note that we don't touch clocks here,
3449 * but we presume they are on because we got an IRQ. However,
3450 * an irq handler may turn the clocks off, so we may not have
3451 * clock later in the function. */
archit tanejaaffe3602011-02-23 08:41:03 +00003452static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003453{
3454 int i;
archit tanejaaffe3602011-02-23 08:41:03 +00003455 u32 irqstatus, irqenable;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003456 u32 handledirqs = 0;
3457 u32 unhandled_errors;
3458 struct omap_dispc_isr_data *isr_data;
3459 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
3460
3461 spin_lock(&dispc.irq_lock);
3462
3463 irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
archit tanejaaffe3602011-02-23 08:41:03 +00003464 irqenable = dispc_read_reg(DISPC_IRQENABLE);
3465
3466 /* IRQ is not for us */
3467 if (!(irqstatus & irqenable)) {
3468 spin_unlock(&dispc.irq_lock);
3469 return IRQ_NONE;
3470 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003471
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +02003472#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3473 spin_lock(&dispc.irq_stats_lock);
3474 dispc.irq_stats.irq_count++;
3475 dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs);
3476 spin_unlock(&dispc.irq_stats_lock);
3477#endif
3478
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003479#ifdef DEBUG
3480 if (dss_debug)
3481 print_irq_status(irqstatus);
3482#endif
3483 /* Ack the interrupt. Do it here before clocks are possibly turned
3484 * off */
3485 dispc_write_reg(DISPC_IRQSTATUS, irqstatus);
3486 /* flush posted write */
3487 dispc_read_reg(DISPC_IRQSTATUS);
3488
3489 /* make a copy and unlock, so that isrs can unregister
3490 * themselves */
3491 memcpy(registered_isr, dispc.registered_isr,
3492 sizeof(registered_isr));
3493
3494 spin_unlock(&dispc.irq_lock);
3495
3496 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3497 isr_data = &registered_isr[i];
3498
3499 if (!isr_data->isr)
3500 continue;
3501
3502 if (isr_data->mask & irqstatus) {
3503 isr_data->isr(isr_data->arg, irqstatus);
3504 handledirqs |= isr_data->mask;
3505 }
3506 }
3507
3508 spin_lock(&dispc.irq_lock);
3509
3510 unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
3511
3512 if (unhandled_errors) {
3513 dispc.error_irqs |= unhandled_errors;
3514
3515 dispc.irq_error_mask &= ~unhandled_errors;
3516 _omap_dispc_set_irqs();
3517
3518 schedule_work(&dispc.error_work);
3519 }
3520
3521 spin_unlock(&dispc.irq_lock);
archit tanejaaffe3602011-02-23 08:41:03 +00003522
3523 return IRQ_HANDLED;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003524}
3525
3526static void dispc_error_worker(struct work_struct *work)
3527{
3528 int i;
3529 u32 errors;
3530 unsigned long flags;
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03003531 static const unsigned fifo_underflow_bits[] = {
3532 DISPC_IRQ_GFX_FIFO_UNDERFLOW,
3533 DISPC_IRQ_VID1_FIFO_UNDERFLOW,
3534 DISPC_IRQ_VID2_FIFO_UNDERFLOW,
Archit Tanejab8c095b2011-09-13 18:20:33 +05303535 DISPC_IRQ_VID3_FIFO_UNDERFLOW,
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03003536 };
3537
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003538 spin_lock_irqsave(&dispc.irq_lock, flags);
3539 errors = dispc.error_irqs;
3540 dispc.error_irqs = 0;
3541 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3542
Dima Zavin13eae1f2011-06-27 10:31:05 -07003543 dispc_runtime_get();
3544
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03003545 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
3546 struct omap_overlay *ovl;
3547 unsigned bit;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003548
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03003549 ovl = omap_dss_get_overlay(i);
3550 bit = fifo_underflow_bits[i];
3551
3552 if (bit & errors) {
3553 DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
3554 ovl->name);
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03003555 dispc_ovl_enable(ovl->id, false);
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003556 dispc_mgr_go(ovl->manager->id);
Jassi Brard7ad7182012-07-24 19:33:55 +05303557 msleep(50);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003558 }
3559 }
3560
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03003561 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
3562 struct omap_overlay_manager *mgr;
3563 unsigned bit;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003564
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03003565 mgr = omap_dss_get_overlay_manager(i);
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05303566 bit = mgr_desc[i].sync_lost_irq;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003567
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03003568 if (bit & errors) {
3569 struct omap_dss_device *dssdev = mgr->device;
3570 bool enable;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003571
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03003572 DSSERR("SYNC_LOST on channel %s, restarting the output "
3573 "with video overlays disabled\n",
3574 mgr->name);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003575
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03003576 enable = dssdev->state == OMAP_DSS_DISPLAY_ACTIVE;
3577 dssdev->driver->disable(dssdev);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003578
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003579 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
3580 struct omap_overlay *ovl;
3581 ovl = omap_dss_get_overlay(i);
3582
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03003583 if (ovl->id != OMAP_DSS_GFX &&
3584 ovl->manager == mgr)
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03003585 dispc_ovl_enable(ovl->id, false);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003586 }
3587
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003588 dispc_mgr_go(mgr->id);
Jassi Brard7ad7182012-07-24 19:33:55 +05303589 msleep(50);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003590
Sumit Semwal2a205f32010-12-02 11:27:12 +00003591 if (enable)
3592 dssdev->driver->enable(dssdev);
3593 }
3594 }
3595
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003596 if (errors & DISPC_IRQ_OCP_ERR) {
3597 DSSERR("OCP_ERR\n");
3598 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
3599 struct omap_overlay_manager *mgr;
3600 mgr = omap_dss_get_overlay_manager(i);
Rob Clark00f17e42011-12-11 14:02:27 -06003601 if (mgr->device && mgr->device->driver)
3602 mgr->device->driver->disable(mgr->device);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003603 }
3604 }
3605
3606 spin_lock_irqsave(&dispc.irq_lock, flags);
3607 dispc.irq_error_mask |= errors;
3608 _omap_dispc_set_irqs();
3609 spin_unlock_irqrestore(&dispc.irq_lock, flags);
Dima Zavin13eae1f2011-06-27 10:31:05 -07003610
3611 dispc_runtime_put();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003612}
3613
3614int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
3615{
3616 void dispc_irq_wait_handler(void *data, u32 mask)
3617 {
3618 complete((struct completion *)data);
3619 }
3620
3621 int r;
3622 DECLARE_COMPLETION_ONSTACK(completion);
3623
3624 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
3625 irqmask);
3626
3627 if (r)
3628 return r;
3629
3630 timeout = wait_for_completion_timeout(&completion, timeout);
3631
3632 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
3633
3634 if (timeout == 0)
3635 return -ETIMEDOUT;
3636
3637 if (timeout == -ERESTARTSYS)
3638 return -ERESTARTSYS;
3639
3640 return 0;
3641}
3642
3643int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
3644 unsigned long timeout)
3645{
3646 void dispc_irq_wait_handler(void *data, u32 mask)
3647 {
3648 complete((struct completion *)data);
3649 }
3650
3651 int r;
3652 DECLARE_COMPLETION_ONSTACK(completion);
3653
3654 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
3655 irqmask);
3656
3657 if (r)
3658 return r;
3659
3660 timeout = wait_for_completion_interruptible_timeout(&completion,
3661 timeout);
3662
3663 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
3664
3665 if (timeout == 0)
3666 return -ETIMEDOUT;
3667
3668 if (timeout == -ERESTARTSYS)
3669 return -ERESTARTSYS;
3670
3671 return 0;
3672}
3673
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003674static void _omap_dispc_initialize_irq(void)
3675{
3676 unsigned long flags;
3677
3678 spin_lock_irqsave(&dispc.irq_lock, flags);
3679
3680 memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
3681
3682 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
Sumit Semwal2a205f32010-12-02 11:27:12 +00003683 if (dss_has_feature(FEAT_MGR_LCD2))
3684 dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +05303685 if (dss_has_feature(FEAT_MGR_LCD3))
3686 dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
Archit Tanejab8c095b2011-09-13 18:20:33 +05303687 if (dss_feat_get_num_ovls() > 3)
3688 dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003689
3690 /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
3691 * so clear it */
3692 dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS));
3693
3694 _omap_dispc_set_irqs();
3695
3696 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3697}
3698
3699void dispc_enable_sidle(void)
3700{
3701 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
3702}
3703
3704void dispc_disable_sidle(void)
3705{
3706 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
3707}
3708
3709static void _omap_dispc_initial_config(void)
3710{
3711 u32 l;
3712
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003713 /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
3714 if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
3715 l = dispc_read_reg(DISPC_DIVISOR);
3716 /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
3717 l = FLD_MOD(l, 1, 0, 0);
3718 l = FLD_MOD(l, 1, 23, 16);
3719 dispc_write_reg(DISPC_DIVISOR, l);
3720 }
3721
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003722 /* FUNCGATED */
Archit Taneja6ced40b2010-12-02 11:27:13 +00003723 if (dss_has_feature(FEAT_FUNCGATED))
3724 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003725
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003726 _dispc_setup_color_conv_coef();
3727
3728 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3729
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003730 dispc_init_fifos();
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03003731
3732 dispc_configure_burst_sizes();
Archit Taneja54128702011-09-08 11:29:17 +05303733
3734 dispc_ovl_enable_zorder_planes();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003735}
3736
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303737static const struct dispc_features omap24xx_dispc_feats __initconst = {
3738 .sw_start = 5,
3739 .fp_start = 15,
3740 .bp_start = 27,
3741 .sw_max = 64,
3742 .vp_max = 255,
3743 .hp_max = 256,
3744 .calc_scaling = dispc_ovl_calc_scaling_24xx,
3745 .calc_core_clk = calc_core_clk_24xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003746 .num_fifos = 3,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303747};
3748
3749static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
3750 .sw_start = 5,
3751 .fp_start = 15,
3752 .bp_start = 27,
3753 .sw_max = 64,
3754 .vp_max = 255,
3755 .hp_max = 256,
3756 .calc_scaling = dispc_ovl_calc_scaling_34xx,
3757 .calc_core_clk = calc_core_clk_34xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003758 .num_fifos = 3,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303759};
3760
3761static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
3762 .sw_start = 7,
3763 .fp_start = 19,
3764 .bp_start = 31,
3765 .sw_max = 256,
3766 .vp_max = 4095,
3767 .hp_max = 4096,
3768 .calc_scaling = dispc_ovl_calc_scaling_34xx,
3769 .calc_core_clk = calc_core_clk_34xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003770 .num_fifos = 3,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303771};
3772
3773static const struct dispc_features omap44xx_dispc_feats __initconst = {
3774 .sw_start = 7,
3775 .fp_start = 19,
3776 .bp_start = 31,
3777 .sw_max = 256,
3778 .vp_max = 4095,
3779 .hp_max = 4096,
3780 .calc_scaling = dispc_ovl_calc_scaling_44xx,
3781 .calc_core_clk = calc_core_clk_44xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003782 .num_fifos = 5,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303783};
3784
3785static int __init dispc_init_features(struct device *dev)
3786{
3787 const struct dispc_features *src;
3788 struct dispc_features *dst;
3789
3790 dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL);
3791 if (!dst) {
3792 dev_err(dev, "Failed to allocate DISPC Features\n");
3793 return -ENOMEM;
3794 }
3795
3796 if (cpu_is_omap24xx()) {
3797 src = &omap24xx_dispc_feats;
3798 } else if (cpu_is_omap34xx()) {
3799 if (omap_rev() < OMAP3430_REV_ES3_0)
3800 src = &omap34xx_rev1_0_dispc_feats;
3801 else
3802 src = &omap34xx_rev3_0_dispc_feats;
3803 } else if (cpu_is_omap44xx()) {
3804 src = &omap44xx_dispc_feats;
3805 } else {
3806 return -ENODEV;
3807 }
3808
3809 memcpy(dst, src, sizeof(*dst));
3810 dispc.feat = dst;
3811
3812 return 0;
3813}
3814
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003815/* DISPC HW IP initialisation */
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02003816static int __init omap_dispchw_probe(struct platform_device *pdev)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003817{
3818 u32 rev;
archit tanejaaffe3602011-02-23 08:41:03 +00003819 int r = 0;
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00003820 struct resource *dispc_mem;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003821 struct clk *clk;
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00003822
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003823 dispc.pdev = pdev;
3824
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303825 r = dispc_init_features(&dispc.pdev->dev);
3826 if (r)
3827 return r;
3828
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003829 spin_lock_init(&dispc.irq_lock);
3830
3831#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3832 spin_lock_init(&dispc.irq_stats_lock);
3833 dispc.irq_stats.last_reset = jiffies;
3834#endif
3835
3836 INIT_WORK(&dispc.error_work, dispc_error_worker);
3837
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00003838 dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
3839 if (!dispc_mem) {
3840 DSSERR("can't get IORESOURCE_MEM DISPC\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02003841 return -EINVAL;
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00003842 }
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02003843
Julia Lawall6e2a14d2012-01-24 14:00:45 +01003844 dispc.base = devm_ioremap(&pdev->dev, dispc_mem->start,
3845 resource_size(dispc_mem));
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003846 if (!dispc.base) {
3847 DSSERR("can't ioremap DISPC\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02003848 return -ENOMEM;
archit tanejaaffe3602011-02-23 08:41:03 +00003849 }
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02003850
archit tanejaaffe3602011-02-23 08:41:03 +00003851 dispc.irq = platform_get_irq(dispc.pdev, 0);
3852 if (dispc.irq < 0) {
3853 DSSERR("platform_get_irq failed\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02003854 return -ENODEV;
archit tanejaaffe3602011-02-23 08:41:03 +00003855 }
3856
Julia Lawall6e2a14d2012-01-24 14:00:45 +01003857 r = devm_request_irq(&pdev->dev, dispc.irq, omap_dispc_irq_handler,
3858 IRQF_SHARED, "OMAP DISPC", dispc.pdev);
archit tanejaaffe3602011-02-23 08:41:03 +00003859 if (r < 0) {
3860 DSSERR("request_irq failed\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02003861 return r;
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003862 }
3863
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02003864 clk = clk_get(&pdev->dev, "fck");
3865 if (IS_ERR(clk)) {
3866 DSSERR("can't get fck\n");
3867 r = PTR_ERR(clk);
3868 return r;
3869 }
3870
3871 dispc.dss_clk = clk;
3872
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003873 pm_runtime_enable(&pdev->dev);
3874
3875 r = dispc_runtime_get();
3876 if (r)
3877 goto err_runtime_get;
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003878
3879 _omap_dispc_initial_config();
3880
3881 _omap_dispc_initialize_irq();
3882
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003883 rev = dispc_read_reg(DISPC_REVISION);
Sumit Semwala06b62f2011-01-24 06:22:03 +00003884 dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003885 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
3886
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003887 dispc_runtime_put();
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003888
Tomi Valkeinene40402c2012-03-02 18:01:07 +02003889 dss_debugfs_create_file("dispc", dispc_dump_regs);
3890
3891#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3892 dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
3893#endif
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003894 return 0;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003895
3896err_runtime_get:
3897 pm_runtime_disable(&pdev->dev);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003898 clk_put(dispc.dss_clk);
archit tanejaaffe3602011-02-23 08:41:03 +00003899 return r;
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003900}
3901
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02003902static int __exit omap_dispchw_remove(struct platform_device *pdev)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003903{
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003904 pm_runtime_disable(&pdev->dev);
3905
3906 clk_put(dispc.dss_clk);
3907
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003908 return 0;
3909}
3910
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003911static int dispc_runtime_suspend(struct device *dev)
3912{
3913 dispc_save_context();
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003914
3915 return 0;
3916}
3917
3918static int dispc_runtime_resume(struct device *dev)
3919{
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +03003920 dispc_restore_context();
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003921
3922 return 0;
3923}
3924
3925static const struct dev_pm_ops dispc_pm_ops = {
3926 .runtime_suspend = dispc_runtime_suspend,
3927 .runtime_resume = dispc_runtime_resume,
3928};
3929
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003930static struct platform_driver omap_dispchw_driver = {
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02003931 .remove = __exit_p(omap_dispchw_remove),
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003932 .driver = {
3933 .name = "omapdss_dispc",
3934 .owner = THIS_MODULE,
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003935 .pm = &dispc_pm_ops,
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003936 },
3937};
3938
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02003939int __init dispc_init_platform_driver(void)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003940{
Tomi Valkeinen11436e12012-03-07 12:53:18 +02003941 return platform_driver_probe(&omap_dispchw_driver, omap_dispchw_probe);
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003942}
3943
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02003944void __exit dispc_uninit_platform_driver(void)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003945{
Tomi Valkeinen04c742c2012-02-23 15:32:37 +02003946 platform_driver_unregister(&omap_dispchw_driver);
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00003947}