aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/fbdev/omap2/dss
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2014-02-13 08:31:38 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2014-04-17 01:10:19 -0400
commitf7018c21350204c4cf628462f229d44d03545254 (patch)
tree408787177164cf51cc06f7aabdb04fcff8d2b6aa /drivers/video/fbdev/omap2/dss
parentc26ef3eb3c11274bad1b64498d0a134f85755250 (diff)
video: move fbdev to drivers/video/fbdev
The drivers/video directory is a mess. It contains generic video related files, directories for backlight, console, linux logo, lots of fbdev device drivers, fbdev framework files. Make some order into the chaos by creating drivers/video/fbdev directory, and move all fbdev related files there. No functionality is changed, although I guess it is possible that some subtle Makefile build order related issue could be created by this patch. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Acked-by: Rob Clark <robdclark@gmail.com> Acked-by: Jingoo Han <jg1.han@samsung.com> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/video/fbdev/omap2/dss')
-rw-r--r--drivers/video/fbdev/omap2/dss/Kconfig121
-rw-r--r--drivers/video/fbdev/omap2/dss/Makefile15
-rw-r--r--drivers/video/fbdev/omap2/dss/apply.c1700
-rw-r--r--drivers/video/fbdev/omap2/dss/core.c360
-rw-r--r--drivers/video/fbdev/omap2/dss/dispc-compat.c666
-rw-r--r--drivers/video/fbdev/omap2/dss/dispc-compat.h30
-rw-r--r--drivers/video/fbdev/omap2/dss/dispc.c3853
-rw-r--r--drivers/video/fbdev/omap2/dss/dispc.h917
-rw-r--r--drivers/video/fbdev/omap2/dss/dispc_coefs.c325
-rw-r--r--drivers/video/fbdev/omap2/dss/display-sysfs.c345
-rw-r--r--drivers/video/fbdev/omap2/dss/display.c338
-rw-r--r--drivers/video/fbdev/omap2/dss/dpi.c774
-rw-r--r--drivers/video/fbdev/omap2/dss/dsi.c5751
-rw-r--r--drivers/video/fbdev/omap2/dss/dss-of.c159
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.c972
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.h438
-rw-r--r--drivers/video/fbdev/omap2/dss/dss_features.c935
-rw-r--r--drivers/video/fbdev/omap2/dss/dss_features.h117
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi.h444
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4.c703
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4_core.c1036
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4_core.h276
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_common.c425
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_phy.c160
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_pll.c232
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_wp.c275
-rw-r--r--drivers/video/fbdev/omap2/dss/manager-sysfs.c529
-rw-r--r--drivers/video/fbdev/omap2/dss/manager.c263
-rw-r--r--drivers/video/fbdev/omap2/dss/output.c254
-rw-r--r--drivers/video/fbdev/omap2/dss/overlay-sysfs.c456
-rw-r--r--drivers/video/fbdev/omap2/dss/overlay.c202
-rw-r--r--drivers/video/fbdev/omap2/dss/rfbi.c1058
-rw-r--r--drivers/video/fbdev/omap2/dss/sdi.c433
-rw-r--r--drivers/video/fbdev/omap2/dss/venc.c980
-rw-r--r--drivers/video/fbdev/omap2/dss/venc_panel.c232
35 files changed, 25774 insertions, 0 deletions
diff --git a/drivers/video/fbdev/omap2/dss/Kconfig b/drivers/video/fbdev/omap2/dss/Kconfig
new file mode 100644
index 000000000000..dde4281663b1
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/Kconfig
@@ -0,0 +1,121 @@
1menuconfig OMAP2_DSS
2 tristate "OMAP2+ Display Subsystem support"
3 select VIDEOMODE_HELPERS
4 help
5 OMAP2+ Display Subsystem support.
6
7if OMAP2_DSS
8
9config OMAP2_DSS_DEBUG
10 bool "Debug support"
11 default n
12 help
13 This enables printing of debug messages. Alternatively, debug messages
14 can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting
15 appropriate flags in <debugfs>/dynamic_debug/control.
16
17config OMAP2_DSS_DEBUGFS
18 bool "Debugfs filesystem support"
19 depends on DEBUG_FS
20 default n
21 help
22 This enables debugfs for OMAPDSS at <debugfs>/omapdss. This enables
23 querying about clock configuration and register configuration of dss,
24 dispc, dsi, hdmi and rfbi.
25
26config OMAP2_DSS_COLLECT_IRQ_STATS
27 bool "Collect DSS IRQ statistics"
28 depends on OMAP2_DSS_DEBUGFS
29 default n
30 help
31 Collect DSS IRQ statistics, printable via debugfs.
32
33 The statistics can be found from
34 <debugfs>/omapdss/dispc_irq for DISPC interrupts, and
35 <debugfs>/omapdss/dsi_irq for DSI interrupts.
36
37config OMAP2_DSS_DPI
38 bool "DPI support"
39 default y
40 help
41 DPI Interface. This is the Parallel Display Interface.
42
43config OMAP2_DSS_RFBI
44 bool "RFBI support"
45 depends on BROKEN
46 default n
47 help
48 MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas
49 Instrument's terminology).
50
51 DBI is a bus between the host processor and a peripheral,
52 such as a display or a framebuffer chip.
53
54 See http://www.mipi.org/ for DBI specifications.
55
56config OMAP2_DSS_VENC
57 bool "VENC support"
58 default y
59 help
60 OMAP Video Encoder support for S-Video and composite TV-out.
61
62config OMAP4_DSS_HDMI
63 bool "HDMI support"
64 default y
65 help
66 HDMI Interface. This adds the High Definition Multimedia Interface.
67 See http://www.hdmi.org/ for HDMI specification.
68
69config OMAP4_DSS_HDMI_AUDIO
70 bool
71
72config OMAP2_DSS_SDI
73 bool "SDI support"
74 default n
75 help
76 SDI (Serial Display Interface) support.
77
78 SDI is a high speed one-way display serial bus between the host
79 processor and a display.
80
81config OMAP2_DSS_DSI
82 bool "DSI support"
83 default n
84 help
85 MIPI DSI (Display Serial Interface) support.
86
87 DSI is a high speed half-duplex serial interface between the host
88 processor and a peripheral, such as a display or a framebuffer chip.
89
90 See http://www.mipi.org/ for DSI specifications.
91
92config OMAP2_DSS_MIN_FCK_PER_PCK
93 int "Minimum FCK/PCK ratio (for scaling)"
94 range 0 32
95 default 0
96 help
97 This can be used to adjust the minimum FCK/PCK ratio.
98
99 With this you can make sure that DISPC FCK is at least
100 n x PCK. Video plane scaling requires higher FCK than
101 normally.
102
103 If this is set to 0, there's no extra constraint on the
104 DISPC FCK. However, the FCK will at minimum be
105 2xPCK (if active matrix) or 3xPCK (if passive matrix).
106
107 Max FCK is 173MHz, so this doesn't work if your PCK
108 is very high.
109
110config OMAP2_DSS_SLEEP_AFTER_VENC_RESET
111 bool "Sleep 20ms after VENC reset"
112 default y
113 help
114 There is a 20ms sleep after VENC reset which seemed to fix the
115 reset. The reason for the bug is unclear, and it's also unclear
116 on what platforms this happens.
117
118 This option enables the sleep, and is enabled by default. You can
119 disable the sleep if it doesn't cause problems on your platform.
120
121endif
diff --git a/drivers/video/fbdev/omap2/dss/Makefile b/drivers/video/fbdev/omap2/dss/Makefile
new file mode 100644
index 000000000000..8aec8bda27cc
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/Makefile
@@ -0,0 +1,15 @@
1obj-$(CONFIG_OMAP2_DSS) += omapdss.o
2# Core DSS files
3omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
4 output.o dss-of.o
5# DSS compat layer files
6omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
7 dispc-compat.o display-sysfs.o
8omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
9omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
10omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
11omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
12omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
13omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi4.o hdmi_common.o hdmi_wp.o hdmi_pll.o \
14 hdmi_phy.o hdmi4_core.o
15ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG
diff --git a/drivers/video/fbdev/omap2/dss/apply.c b/drivers/video/fbdev/omap2/dss/apply.c
new file mode 100644
index 000000000000..0a0b084ce65d
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/apply.c
@@ -0,0 +1,1700 @@
1/*
2 * Copyright (C) 2011 Texas Instruments
3 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#define DSS_SUBSYS_NAME "APPLY"
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/slab.h>
23#include <linux/spinlock.h>
24#include <linux/jiffies.h>
25
26#include <video/omapdss.h>
27
28#include "dss.h"
29#include "dss_features.h"
30#include "dispc-compat.h"
31
32/*
33 * We have 4 levels of cache for the dispc settings. First two are in SW and
34 * the latter two in HW.
35 *
36 * set_info()
37 * v
38 * +--------------------+
39 * | user_info |
40 * +--------------------+
41 * v
42 * apply()
43 * v
44 * +--------------------+
45 * | info |
46 * +--------------------+
47 * v
48 * write_regs()
49 * v
50 * +--------------------+
51 * | shadow registers |
52 * +--------------------+
53 * v
54 * VFP or lcd/digit_enable
55 * v
56 * +--------------------+
57 * | registers |
58 * +--------------------+
59 */
60
61struct ovl_priv_data {
62
63 bool user_info_dirty;
64 struct omap_overlay_info user_info;
65
66 bool info_dirty;
67 struct omap_overlay_info info;
68
69 bool shadow_info_dirty;
70
71 bool extra_info_dirty;
72 bool shadow_extra_info_dirty;
73
74 bool enabled;
75 u32 fifo_low, fifo_high;
76
77 /*
78 * True if overlay is to be enabled. Used to check and calculate configs
79 * for the overlay before it is enabled in the HW.
80 */
81 bool enabling;
82};
83
84struct mgr_priv_data {
85
86 bool user_info_dirty;
87 struct omap_overlay_manager_info user_info;
88
89 bool info_dirty;
90 struct omap_overlay_manager_info info;
91
92 bool shadow_info_dirty;
93
94 /* If true, GO bit is up and shadow registers cannot be written.
95 * Never true for manual update displays */
96 bool busy;
97
98 /* If true, dispc output is enabled */
99 bool updating;
100
101 /* If true, a display is enabled using this manager */
102 bool enabled;
103
104 bool extra_info_dirty;
105 bool shadow_extra_info_dirty;
106
107 struct omap_video_timings timings;
108 struct dss_lcd_mgr_config lcd_config;
109
110 void (*framedone_handler)(void *);
111 void *framedone_handler_data;
112};
113
114static struct {
115 struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS];
116 struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS];
117
118 bool irq_enabled;
119} dss_data;
120
121/* protects dss_data */
122static spinlock_t data_lock;
123/* lock for blocking functions */
124static DEFINE_MUTEX(apply_lock);
125static DECLARE_COMPLETION(extra_updated_completion);
126
127static void dss_register_vsync_isr(void);
128
129static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl)
130{
131 return &dss_data.ovl_priv_data_array[ovl->id];
132}
133
134static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr)
135{
136 return &dss_data.mgr_priv_data_array[mgr->id];
137}
138
139static void apply_init_priv(void)
140{
141 const int num_ovls = dss_feat_get_num_ovls();
142 struct mgr_priv_data *mp;
143 int i;
144
145 spin_lock_init(&data_lock);
146
147 for (i = 0; i < num_ovls; ++i) {
148 struct ovl_priv_data *op;
149
150 op = &dss_data.ovl_priv_data_array[i];
151
152 op->info.color_mode = OMAP_DSS_COLOR_RGB16;
153 op->info.rotation_type = OMAP_DSS_ROT_DMA;
154
155 op->info.global_alpha = 255;
156
157 switch (i) {
158 case 0:
159 op->info.zorder = 0;
160 break;
161 case 1:
162 op->info.zorder =
163 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0;
164 break;
165 case 2:
166 op->info.zorder =
167 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0;
168 break;
169 case 3:
170 op->info.zorder =
171 dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0;
172 break;
173 }
174
175 op->user_info = op->info;
176 }
177
178 /*
179 * Initialize some of the lcd_config fields for TV manager, this lets
180 * us prevent checking if the manager is LCD or TV at some places
181 */
182 mp = &dss_data.mgr_priv_data_array[OMAP_DSS_CHANNEL_DIGIT];
183
184 mp->lcd_config.video_port_width = 24;
185 mp->lcd_config.clock_info.lck_div = 1;
186 mp->lcd_config.clock_info.pck_div = 1;
187}
188
189/*
190 * A LCD manager's stallmode decides whether it is in manual or auto update. TV
191 * manager is always auto update, stallmode field for TV manager is false by
192 * default
193 */
194static bool ovl_manual_update(struct omap_overlay *ovl)
195{
196 struct mgr_priv_data *mp = get_mgr_priv(ovl->manager);
197
198 return mp->lcd_config.stallmode;
199}
200
201static bool mgr_manual_update(struct omap_overlay_manager *mgr)
202{
203 struct mgr_priv_data *mp = get_mgr_priv(mgr);
204
205 return mp->lcd_config.stallmode;
206}
207
208static int dss_check_settings_low(struct omap_overlay_manager *mgr,
209 bool applying)
210{
211 struct omap_overlay_info *oi;
212 struct omap_overlay_manager_info *mi;
213 struct omap_overlay *ovl;
214 struct omap_overlay_info *ois[MAX_DSS_OVERLAYS];
215 struct ovl_priv_data *op;
216 struct mgr_priv_data *mp;
217
218 mp = get_mgr_priv(mgr);
219
220 if (!mp->enabled)
221 return 0;
222
223 if (applying && mp->user_info_dirty)
224 mi = &mp->user_info;
225 else
226 mi = &mp->info;
227
228 /* collect the infos to be tested into the array */
229 list_for_each_entry(ovl, &mgr->overlays, list) {
230 op = get_ovl_priv(ovl);
231
232 if (!op->enabled && !op->enabling)
233 oi = NULL;
234 else if (applying && op->user_info_dirty)
235 oi = &op->user_info;
236 else
237 oi = &op->info;
238
239 ois[ovl->id] = oi;
240 }
241
242 return dss_mgr_check(mgr, mi, &mp->timings, &mp->lcd_config, ois);
243}
244
245/*
246 * check manager and overlay settings using overlay_info from data->info
247 */
248static int dss_check_settings(struct omap_overlay_manager *mgr)
249{
250 return dss_check_settings_low(mgr, false);
251}
252
253/*
254 * check manager and overlay settings using overlay_info from ovl->info if
255 * dirty and from data->info otherwise
256 */
257static int dss_check_settings_apply(struct omap_overlay_manager *mgr)
258{
259 return dss_check_settings_low(mgr, true);
260}
261
262static bool need_isr(void)
263{
264 const int num_mgrs = dss_feat_get_num_mgrs();
265 int i;
266
267 for (i = 0; i < num_mgrs; ++i) {
268 struct omap_overlay_manager *mgr;
269 struct mgr_priv_data *mp;
270 struct omap_overlay *ovl;
271
272 mgr = omap_dss_get_overlay_manager(i);
273 mp = get_mgr_priv(mgr);
274
275 if (!mp->enabled)
276 continue;
277
278 if (mgr_manual_update(mgr)) {
279 /* to catch FRAMEDONE */
280 if (mp->updating)
281 return true;
282 } else {
283 /* to catch GO bit going down */
284 if (mp->busy)
285 return true;
286
287 /* to write new values to registers */
288 if (mp->info_dirty)
289 return true;
290
291 /* to set GO bit */
292 if (mp->shadow_info_dirty)
293 return true;
294
295 /*
296 * NOTE: we don't check extra_info flags for disabled
297 * managers, once the manager is enabled, the extra_info
298 * related manager changes will be taken in by HW.
299 */
300
301 /* to write new values to registers */
302 if (mp->extra_info_dirty)
303 return true;
304
305 /* to set GO bit */
306 if (mp->shadow_extra_info_dirty)
307 return true;
308
309 list_for_each_entry(ovl, &mgr->overlays, list) {
310 struct ovl_priv_data *op;
311
312 op = get_ovl_priv(ovl);
313
314 /*
315 * NOTE: we check extra_info flags even for
316 * disabled overlays, as extra_infos need to be
317 * always written.
318 */
319
320 /* to write new values to registers */
321 if (op->extra_info_dirty)
322 return true;
323
324 /* to set GO bit */
325 if (op->shadow_extra_info_dirty)
326 return true;
327
328 if (!op->enabled)
329 continue;
330
331 /* to write new values to registers */
332 if (op->info_dirty)
333 return true;
334
335 /* to set GO bit */
336 if (op->shadow_info_dirty)
337 return true;
338 }
339 }
340 }
341
342 return false;
343}
344
345static bool need_go(struct omap_overlay_manager *mgr)
346{
347 struct omap_overlay *ovl;
348 struct mgr_priv_data *mp;
349 struct ovl_priv_data *op;
350
351 mp = get_mgr_priv(mgr);
352
353 if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty)
354 return true;
355
356 list_for_each_entry(ovl, &mgr->overlays, list) {
357 op = get_ovl_priv(ovl);
358 if (op->shadow_info_dirty || op->shadow_extra_info_dirty)
359 return true;
360 }
361
362 return false;
363}
364
365/* returns true if an extra_info field is currently being updated */
366static bool extra_info_update_ongoing(void)
367{
368 const int num_mgrs = dss_feat_get_num_mgrs();
369 int i;
370
371 for (i = 0; i < num_mgrs; ++i) {
372 struct omap_overlay_manager *mgr;
373 struct omap_overlay *ovl;
374 struct mgr_priv_data *mp;
375
376 mgr = omap_dss_get_overlay_manager(i);
377 mp = get_mgr_priv(mgr);
378
379 if (!mp->enabled)
380 continue;
381
382 if (!mp->updating)
383 continue;
384
385 if (mp->extra_info_dirty || mp->shadow_extra_info_dirty)
386 return true;
387
388 list_for_each_entry(ovl, &mgr->overlays, list) {
389 struct ovl_priv_data *op = get_ovl_priv(ovl);
390
391 if (op->extra_info_dirty || op->shadow_extra_info_dirty)
392 return true;
393 }
394 }
395
396 return false;
397}
398
399/* wait until no extra_info updates are pending */
400static void wait_pending_extra_info_updates(void)
401{
402 bool updating;
403 unsigned long flags;
404 unsigned long t;
405 int r;
406
407 spin_lock_irqsave(&data_lock, flags);
408
409 updating = extra_info_update_ongoing();
410
411 if (!updating) {
412 spin_unlock_irqrestore(&data_lock, flags);
413 return;
414 }
415
416 init_completion(&extra_updated_completion);
417
418 spin_unlock_irqrestore(&data_lock, flags);
419
420 t = msecs_to_jiffies(500);
421 r = wait_for_completion_timeout(&extra_updated_completion, t);
422 if (r == 0)
423 DSSWARN("timeout in wait_pending_extra_info_updates\n");
424}
425
426static struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr)
427{
428 struct omap_dss_device *dssdev;
429
430 dssdev = mgr->output;
431 if (dssdev == NULL)
432 return NULL;
433
434 while (dssdev->dst)
435 dssdev = dssdev->dst;
436
437 if (dssdev->driver)
438 return dssdev;
439 else
440 return NULL;
441}
442
443static struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl)
444{
445 return ovl->manager ? dss_mgr_get_device(ovl->manager) : NULL;
446}
447
448static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
449{
450 unsigned long timeout = msecs_to_jiffies(500);
451 u32 irq;
452 int r;
453
454 if (mgr->output == NULL)
455 return -ENODEV;
456
457 r = dispc_runtime_get();
458 if (r)
459 return r;
460
461 switch (mgr->output->id) {
462 case OMAP_DSS_OUTPUT_VENC:
463 irq = DISPC_IRQ_EVSYNC_ODD;
464 break;
465 case OMAP_DSS_OUTPUT_HDMI:
466 irq = DISPC_IRQ_EVSYNC_EVEN;
467 break;
468 default:
469 irq = dispc_mgr_get_vsync_irq(mgr->id);
470 break;
471 }
472
473 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
474
475 dispc_runtime_put();
476
477 return r;
478}
479
480static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
481{
482 unsigned long timeout = msecs_to_jiffies(500);
483 struct mgr_priv_data *mp = get_mgr_priv(mgr);
484 u32 irq;
485 unsigned long flags;
486 int r;
487 int i;
488
489 spin_lock_irqsave(&data_lock, flags);
490
491 if (mgr_manual_update(mgr)) {
492 spin_unlock_irqrestore(&data_lock, flags);
493 return 0;
494 }
495
496 if (!mp->enabled) {
497 spin_unlock_irqrestore(&data_lock, flags);
498 return 0;
499 }
500
501 spin_unlock_irqrestore(&data_lock, flags);
502
503 r = dispc_runtime_get();
504 if (r)
505 return r;
506
507 irq = dispc_mgr_get_vsync_irq(mgr->id);
508
509 i = 0;
510 while (1) {
511 bool shadow_dirty, dirty;
512
513 spin_lock_irqsave(&data_lock, flags);
514 dirty = mp->info_dirty;
515 shadow_dirty = mp->shadow_info_dirty;
516 spin_unlock_irqrestore(&data_lock, flags);
517
518 if (!dirty && !shadow_dirty) {
519 r = 0;
520 break;
521 }
522
523 /* 4 iterations is the worst case:
524 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
525 * 2 - first VSYNC, dirty = true
526 * 3 - dirty = false, shadow_dirty = true
527 * 4 - shadow_dirty = false */
528 if (i++ == 3) {
529 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
530 mgr->id);
531 r = 0;
532 break;
533 }
534
535 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
536 if (r == -ERESTARTSYS)
537 break;
538
539 if (r) {
540 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
541 break;
542 }
543 }
544
545 dispc_runtime_put();
546
547 return r;
548}
549
550static int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
551{
552 unsigned long timeout = msecs_to_jiffies(500);
553 struct ovl_priv_data *op;
554 struct mgr_priv_data *mp;
555 u32 irq;
556 unsigned long flags;
557 int r;
558 int i;
559
560 if (!ovl->manager)
561 return 0;
562
563 mp = get_mgr_priv(ovl->manager);
564
565 spin_lock_irqsave(&data_lock, flags);
566
567 if (ovl_manual_update(ovl)) {
568 spin_unlock_irqrestore(&data_lock, flags);
569 return 0;
570 }
571
572 if (!mp->enabled) {
573 spin_unlock_irqrestore(&data_lock, flags);
574 return 0;
575 }
576
577 spin_unlock_irqrestore(&data_lock, flags);
578
579 r = dispc_runtime_get();
580 if (r)
581 return r;
582
583 irq = dispc_mgr_get_vsync_irq(ovl->manager->id);
584
585 op = get_ovl_priv(ovl);
586 i = 0;
587 while (1) {
588 bool shadow_dirty, dirty;
589
590 spin_lock_irqsave(&data_lock, flags);
591 dirty = op->info_dirty;
592 shadow_dirty = op->shadow_info_dirty;
593 spin_unlock_irqrestore(&data_lock, flags);
594
595 if (!dirty && !shadow_dirty) {
596 r = 0;
597 break;
598 }
599
600 /* 4 iterations is the worst case:
601 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
602 * 2 - first VSYNC, dirty = true
603 * 3 - dirty = false, shadow_dirty = true
604 * 4 - shadow_dirty = false */
605 if (i++ == 3) {
606 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
607 ovl->id);
608 r = 0;
609 break;
610 }
611
612 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
613 if (r == -ERESTARTSYS)
614 break;
615
616 if (r) {
617 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
618 break;
619 }
620 }
621
622 dispc_runtime_put();
623
624 return r;
625}
626
627static void dss_ovl_write_regs(struct omap_overlay *ovl)
628{
629 struct ovl_priv_data *op = get_ovl_priv(ovl);
630 struct omap_overlay_info *oi;
631 bool replication;
632 struct mgr_priv_data *mp;
633 int r;
634
635 DSSDBG("writing ovl %d regs\n", ovl->id);
636
637 if (!op->enabled || !op->info_dirty)
638 return;
639
640 oi = &op->info;
641
642 mp = get_mgr_priv(ovl->manager);
643
644 replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode);
645
646 r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false);
647 if (r) {
648 /*
649 * We can't do much here, as this function can be called from
650 * vsync interrupt.
651 */
652 DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id);
653
654 /* This will leave fifo configurations in a nonoptimal state */
655 op->enabled = false;
656 dispc_ovl_enable(ovl->id, false);
657 return;
658 }
659
660 op->info_dirty = false;
661 if (mp->updating)
662 op->shadow_info_dirty = true;
663}
664
665static void dss_ovl_write_regs_extra(struct omap_overlay *ovl)
666{
667 struct ovl_priv_data *op = get_ovl_priv(ovl);
668 struct mgr_priv_data *mp;
669
670 DSSDBG("writing ovl %d regs extra\n", ovl->id);
671
672 if (!op->extra_info_dirty)
673 return;
674
675 /* note: write also when op->enabled == false, so that the ovl gets
676 * disabled */
677
678 dispc_ovl_enable(ovl->id, op->enabled);
679 dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high);
680
681 mp = get_mgr_priv(ovl->manager);
682
683 op->extra_info_dirty = false;
684 if (mp->updating)
685 op->shadow_extra_info_dirty = true;
686}
687
688static void dss_mgr_write_regs(struct omap_overlay_manager *mgr)
689{
690 struct mgr_priv_data *mp = get_mgr_priv(mgr);
691 struct omap_overlay *ovl;
692
693 DSSDBG("writing mgr %d regs\n", mgr->id);
694
695 if (!mp->enabled)
696 return;
697
698 WARN_ON(mp->busy);
699
700 /* Commit overlay settings */
701 list_for_each_entry(ovl, &mgr->overlays, list) {
702 dss_ovl_write_regs(ovl);
703 dss_ovl_write_regs_extra(ovl);
704 }
705
706 if (mp->info_dirty) {
707 dispc_mgr_setup(mgr->id, &mp->info);
708
709 mp->info_dirty = false;
710 if (mp->updating)
711 mp->shadow_info_dirty = true;
712 }
713}
714
715static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr)
716{
717 struct mgr_priv_data *mp = get_mgr_priv(mgr);
718
719 DSSDBG("writing mgr %d regs extra\n", mgr->id);
720
721 if (!mp->extra_info_dirty)
722 return;
723
724 dispc_mgr_set_timings(mgr->id, &mp->timings);
725
726 /* lcd_config parameters */
727 if (dss_mgr_is_lcd(mgr->id))
728 dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config);
729
730 mp->extra_info_dirty = false;
731 if (mp->updating)
732 mp->shadow_extra_info_dirty = true;
733}
734
735static void dss_write_regs(void)
736{
737 const int num_mgrs = omap_dss_get_num_overlay_managers();
738 int i;
739
740 for (i = 0; i < num_mgrs; ++i) {
741 struct omap_overlay_manager *mgr;
742 struct mgr_priv_data *mp;
743 int r;
744
745 mgr = omap_dss_get_overlay_manager(i);
746 mp = get_mgr_priv(mgr);
747
748 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
749 continue;
750
751 r = dss_check_settings(mgr);
752 if (r) {
753 DSSERR("cannot write registers for manager %s: "
754 "illegal configuration\n", mgr->name);
755 continue;
756 }
757
758 dss_mgr_write_regs(mgr);
759 dss_mgr_write_regs_extra(mgr);
760 }
761}
762
763static void dss_set_go_bits(void)
764{
765 const int num_mgrs = omap_dss_get_num_overlay_managers();
766 int i;
767
768 for (i = 0; i < num_mgrs; ++i) {
769 struct omap_overlay_manager *mgr;
770 struct mgr_priv_data *mp;
771
772 mgr = omap_dss_get_overlay_manager(i);
773 mp = get_mgr_priv(mgr);
774
775 if (!mp->enabled || mgr_manual_update(mgr) || mp->busy)
776 continue;
777
778 if (!need_go(mgr))
779 continue;
780
781 mp->busy = true;
782
783 if (!dss_data.irq_enabled && need_isr())
784 dss_register_vsync_isr();
785
786 dispc_mgr_go(mgr->id);
787 }
788
789}
790
791static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr)
792{
793 struct omap_overlay *ovl;
794 struct mgr_priv_data *mp;
795 struct ovl_priv_data *op;
796
797 mp = get_mgr_priv(mgr);
798 mp->shadow_info_dirty = false;
799 mp->shadow_extra_info_dirty = false;
800
801 list_for_each_entry(ovl, &mgr->overlays, list) {
802 op = get_ovl_priv(ovl);
803 op->shadow_info_dirty = false;
804 op->shadow_extra_info_dirty = false;
805 }
806}
807
808static int dss_mgr_connect_compat(struct omap_overlay_manager *mgr,
809 struct omap_dss_device *dst)
810{
811 return mgr->set_output(mgr, dst);
812}
813
814static void dss_mgr_disconnect_compat(struct omap_overlay_manager *mgr,
815 struct omap_dss_device *dst)
816{
817 mgr->unset_output(mgr);
818}
819
820static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr)
821{
822 struct mgr_priv_data *mp = get_mgr_priv(mgr);
823 unsigned long flags;
824 int r;
825
826 spin_lock_irqsave(&data_lock, flags);
827
828 WARN_ON(mp->updating);
829
830 r = dss_check_settings(mgr);
831 if (r) {
832 DSSERR("cannot start manual update: illegal configuration\n");
833 spin_unlock_irqrestore(&data_lock, flags);
834 return;
835 }
836
837 dss_mgr_write_regs(mgr);
838 dss_mgr_write_regs_extra(mgr);
839
840 mp->updating = true;
841
842 if (!dss_data.irq_enabled && need_isr())
843 dss_register_vsync_isr();
844
845 dispc_mgr_enable_sync(mgr->id);
846
847 spin_unlock_irqrestore(&data_lock, flags);
848}
849
850static void dss_apply_irq_handler(void *data, u32 mask);
851
852static void dss_register_vsync_isr(void)
853{
854 const int num_mgrs = dss_feat_get_num_mgrs();
855 u32 mask;
856 int r, i;
857
858 mask = 0;
859 for (i = 0; i < num_mgrs; ++i)
860 mask |= dispc_mgr_get_vsync_irq(i);
861
862 for (i = 0; i < num_mgrs; ++i)
863 mask |= dispc_mgr_get_framedone_irq(i);
864
865 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask);
866 WARN_ON(r);
867
868 dss_data.irq_enabled = true;
869}
870
871static void dss_unregister_vsync_isr(void)
872{
873 const int num_mgrs = dss_feat_get_num_mgrs();
874 u32 mask;
875 int r, i;
876
877 mask = 0;
878 for (i = 0; i < num_mgrs; ++i)
879 mask |= dispc_mgr_get_vsync_irq(i);
880
881 for (i = 0; i < num_mgrs; ++i)
882 mask |= dispc_mgr_get_framedone_irq(i);
883
884 r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask);
885 WARN_ON(r);
886
887 dss_data.irq_enabled = false;
888}
889
890static void dss_apply_irq_handler(void *data, u32 mask)
891{
892 const int num_mgrs = dss_feat_get_num_mgrs();
893 int i;
894 bool extra_updating;
895
896 spin_lock(&data_lock);
897
898 /* clear busy, updating flags, shadow_dirty flags */
899 for (i = 0; i < num_mgrs; i++) {
900 struct omap_overlay_manager *mgr;
901 struct mgr_priv_data *mp;
902
903 mgr = omap_dss_get_overlay_manager(i);
904 mp = get_mgr_priv(mgr);
905
906 if (!mp->enabled)
907 continue;
908
909 mp->updating = dispc_mgr_is_enabled(i);
910
911 if (!mgr_manual_update(mgr)) {
912 bool was_busy = mp->busy;
913 mp->busy = dispc_mgr_go_busy(i);
914
915 if (was_busy && !mp->busy)
916 mgr_clear_shadow_dirty(mgr);
917 }
918 }
919
920 dss_write_regs();
921 dss_set_go_bits();
922
923 extra_updating = extra_info_update_ongoing();
924 if (!extra_updating)
925 complete_all(&extra_updated_completion);
926
927 /* call framedone handlers for manual update displays */
928 for (i = 0; i < num_mgrs; i++) {
929 struct omap_overlay_manager *mgr;
930 struct mgr_priv_data *mp;
931
932 mgr = omap_dss_get_overlay_manager(i);
933 mp = get_mgr_priv(mgr);
934
935 if (!mgr_manual_update(mgr) || !mp->framedone_handler)
936 continue;
937
938 if (mask & dispc_mgr_get_framedone_irq(i))
939 mp->framedone_handler(mp->framedone_handler_data);
940 }
941
942 if (!need_isr())
943 dss_unregister_vsync_isr();
944
945 spin_unlock(&data_lock);
946}
947
948static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl)
949{
950 struct ovl_priv_data *op;
951
952 op = get_ovl_priv(ovl);
953
954 if (!op->user_info_dirty)
955 return;
956
957 op->user_info_dirty = false;
958 op->info_dirty = true;
959 op->info = op->user_info;
960}
961
962static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr)
963{
964 struct mgr_priv_data *mp;
965
966 mp = get_mgr_priv(mgr);
967
968 if (!mp->user_info_dirty)
969 return;
970
971 mp->user_info_dirty = false;
972 mp->info_dirty = true;
973 mp->info = mp->user_info;
974}
975
976static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
977{
978 unsigned long flags;
979 struct omap_overlay *ovl;
980 int r;
981
982 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
983
984 spin_lock_irqsave(&data_lock, flags);
985
986 r = dss_check_settings_apply(mgr);
987 if (r) {
988 spin_unlock_irqrestore(&data_lock, flags);
989 DSSERR("failed to apply settings: illegal configuration.\n");
990 return r;
991 }
992
993 /* Configure overlays */
994 list_for_each_entry(ovl, &mgr->overlays, list)
995 omap_dss_mgr_apply_ovl(ovl);
996
997 /* Configure manager */
998 omap_dss_mgr_apply_mgr(mgr);
999
1000 dss_write_regs();
1001 dss_set_go_bits();
1002
1003 spin_unlock_irqrestore(&data_lock, flags);
1004
1005 return 0;
1006}
1007
1008static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable)
1009{
1010 struct ovl_priv_data *op;
1011
1012 op = get_ovl_priv(ovl);
1013
1014 if (op->enabled == enable)
1015 return;
1016
1017 op->enabled = enable;
1018 op->extra_info_dirty = true;
1019}
1020
1021static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl,
1022 u32 fifo_low, u32 fifo_high)
1023{
1024 struct ovl_priv_data *op = get_ovl_priv(ovl);
1025
1026 if (op->fifo_low == fifo_low && op->fifo_high == fifo_high)
1027 return;
1028
1029 op->fifo_low = fifo_low;
1030 op->fifo_high = fifo_high;
1031 op->extra_info_dirty = true;
1032}
1033
1034static void dss_ovl_setup_fifo(struct omap_overlay *ovl)
1035{
1036 struct ovl_priv_data *op = get_ovl_priv(ovl);
1037 u32 fifo_low, fifo_high;
1038 bool use_fifo_merge = false;
1039
1040 if (!op->enabled && !op->enabling)
1041 return;
1042
1043 dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high,
1044 use_fifo_merge, ovl_manual_update(ovl));
1045
1046 dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high);
1047}
1048
1049static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr)
1050{
1051 struct omap_overlay *ovl;
1052 struct mgr_priv_data *mp;
1053
1054 mp = get_mgr_priv(mgr);
1055
1056 if (!mp->enabled)
1057 return;
1058
1059 list_for_each_entry(ovl, &mgr->overlays, list)
1060 dss_ovl_setup_fifo(ovl);
1061}
1062
1063static void dss_setup_fifos(void)
1064{
1065 const int num_mgrs = omap_dss_get_num_overlay_managers();
1066 struct omap_overlay_manager *mgr;
1067 int i;
1068
1069 for (i = 0; i < num_mgrs; ++i) {
1070 mgr = omap_dss_get_overlay_manager(i);
1071 dss_mgr_setup_fifos(mgr);
1072 }
1073}
1074
1075static int dss_mgr_enable_compat(struct omap_overlay_manager *mgr)
1076{
1077 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1078 unsigned long flags;
1079 int r;
1080
1081 mutex_lock(&apply_lock);
1082
1083 if (mp->enabled)
1084 goto out;
1085
1086 spin_lock_irqsave(&data_lock, flags);
1087
1088 mp->enabled = true;
1089
1090 r = dss_check_settings(mgr);
1091 if (r) {
1092 DSSERR("failed to enable manager %d: check_settings failed\n",
1093 mgr->id);
1094 goto err;
1095 }
1096
1097 dss_setup_fifos();
1098
1099 dss_write_regs();
1100 dss_set_go_bits();
1101
1102 if (!mgr_manual_update(mgr))
1103 mp->updating = true;
1104
1105 if (!dss_data.irq_enabled && need_isr())
1106 dss_register_vsync_isr();
1107
1108 spin_unlock_irqrestore(&data_lock, flags);
1109
1110 if (!mgr_manual_update(mgr))
1111 dispc_mgr_enable_sync(mgr->id);
1112
1113out:
1114 mutex_unlock(&apply_lock);
1115
1116 return 0;
1117
1118err:
1119 mp->enabled = false;
1120 spin_unlock_irqrestore(&data_lock, flags);
1121 mutex_unlock(&apply_lock);
1122 return r;
1123}
1124
1125static void dss_mgr_disable_compat(struct omap_overlay_manager *mgr)
1126{
1127 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1128 unsigned long flags;
1129
1130 mutex_lock(&apply_lock);
1131
1132 if (!mp->enabled)
1133 goto out;
1134
1135 if (!mgr_manual_update(mgr))
1136 dispc_mgr_disable_sync(mgr->id);
1137
1138 spin_lock_irqsave(&data_lock, flags);
1139
1140 mp->updating = false;
1141 mp->enabled = false;
1142
1143 spin_unlock_irqrestore(&data_lock, flags);
1144
1145out:
1146 mutex_unlock(&apply_lock);
1147}
1148
1149static int dss_mgr_set_info(struct omap_overlay_manager *mgr,
1150 struct omap_overlay_manager_info *info)
1151{
1152 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1153 unsigned long flags;
1154 int r;
1155
1156 r = dss_mgr_simple_check(mgr, info);
1157 if (r)
1158 return r;
1159
1160 spin_lock_irqsave(&data_lock, flags);
1161
1162 mp->user_info = *info;
1163 mp->user_info_dirty = true;
1164
1165 spin_unlock_irqrestore(&data_lock, flags);
1166
1167 return 0;
1168}
1169
1170static void dss_mgr_get_info(struct omap_overlay_manager *mgr,
1171 struct omap_overlay_manager_info *info)
1172{
1173 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1174 unsigned long flags;
1175
1176 spin_lock_irqsave(&data_lock, flags);
1177
1178 *info = mp->user_info;
1179
1180 spin_unlock_irqrestore(&data_lock, flags);
1181}
1182
1183static int dss_mgr_set_output(struct omap_overlay_manager *mgr,
1184 struct omap_dss_device *output)
1185{
1186 int r;
1187
1188 mutex_lock(&apply_lock);
1189
1190 if (mgr->output) {
1191 DSSERR("manager %s is already connected to an output\n",
1192 mgr->name);
1193 r = -EINVAL;
1194 goto err;
1195 }
1196
1197 if ((mgr->supported_outputs & output->id) == 0) {
1198 DSSERR("output does not support manager %s\n",
1199 mgr->name);
1200 r = -EINVAL;
1201 goto err;
1202 }
1203
1204 output->manager = mgr;
1205 mgr->output = output;
1206
1207 mutex_unlock(&apply_lock);
1208
1209 return 0;
1210err:
1211 mutex_unlock(&apply_lock);
1212 return r;
1213}
1214
1215static int dss_mgr_unset_output(struct omap_overlay_manager *mgr)
1216{
1217 int r;
1218 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1219 unsigned long flags;
1220
1221 mutex_lock(&apply_lock);
1222
1223 if (!mgr->output) {
1224 DSSERR("failed to unset output, output not set\n");
1225 r = -EINVAL;
1226 goto err;
1227 }
1228
1229 spin_lock_irqsave(&data_lock, flags);
1230
1231 if (mp->enabled) {
1232 DSSERR("output can't be unset when manager is enabled\n");
1233 r = -EINVAL;
1234 goto err1;
1235 }
1236
1237 spin_unlock_irqrestore(&data_lock, flags);
1238
1239 mgr->output->manager = NULL;
1240 mgr->output = NULL;
1241
1242 mutex_unlock(&apply_lock);
1243
1244 return 0;
1245err1:
1246 spin_unlock_irqrestore(&data_lock, flags);
1247err:
1248 mutex_unlock(&apply_lock);
1249
1250 return r;
1251}
1252
1253static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr,
1254 const struct omap_video_timings *timings)
1255{
1256 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1257
1258 mp->timings = *timings;
1259 mp->extra_info_dirty = true;
1260}
1261
1262static void dss_mgr_set_timings_compat(struct omap_overlay_manager *mgr,
1263 const struct omap_video_timings *timings)
1264{
1265 unsigned long flags;
1266 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1267
1268 spin_lock_irqsave(&data_lock, flags);
1269
1270 if (mp->updating) {
1271 DSSERR("cannot set timings for %s: manager needs to be disabled\n",
1272 mgr->name);
1273 goto out;
1274 }
1275
1276 dss_apply_mgr_timings(mgr, timings);
1277out:
1278 spin_unlock_irqrestore(&data_lock, flags);
1279}
1280
1281static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr,
1282 const struct dss_lcd_mgr_config *config)
1283{
1284 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1285
1286 mp->lcd_config = *config;
1287 mp->extra_info_dirty = true;
1288}
1289
1290static void dss_mgr_set_lcd_config_compat(struct omap_overlay_manager *mgr,
1291 const struct dss_lcd_mgr_config *config)
1292{
1293 unsigned long flags;
1294 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1295
1296 spin_lock_irqsave(&data_lock, flags);
1297
1298 if (mp->enabled) {
1299 DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n",
1300 mgr->name);
1301 goto out;
1302 }
1303
1304 dss_apply_mgr_lcd_config(mgr, config);
1305out:
1306 spin_unlock_irqrestore(&data_lock, flags);
1307}
1308
1309static int dss_ovl_set_info(struct omap_overlay *ovl,
1310 struct omap_overlay_info *info)
1311{
1312 struct ovl_priv_data *op = get_ovl_priv(ovl);
1313 unsigned long flags;
1314 int r;
1315
1316 r = dss_ovl_simple_check(ovl, info);
1317 if (r)
1318 return r;
1319
1320 spin_lock_irqsave(&data_lock, flags);
1321
1322 op->user_info = *info;
1323 op->user_info_dirty = true;
1324
1325 spin_unlock_irqrestore(&data_lock, flags);
1326
1327 return 0;
1328}
1329
1330static void dss_ovl_get_info(struct omap_overlay *ovl,
1331 struct omap_overlay_info *info)
1332{
1333 struct ovl_priv_data *op = get_ovl_priv(ovl);
1334 unsigned long flags;
1335
1336 spin_lock_irqsave(&data_lock, flags);
1337
1338 *info = op->user_info;
1339
1340 spin_unlock_irqrestore(&data_lock, flags);
1341}
1342
1343static int dss_ovl_set_manager(struct omap_overlay *ovl,
1344 struct omap_overlay_manager *mgr)
1345{
1346 struct ovl_priv_data *op = get_ovl_priv(ovl);
1347 unsigned long flags;
1348 int r;
1349
1350 if (!mgr)
1351 return -EINVAL;
1352
1353 mutex_lock(&apply_lock);
1354
1355 if (ovl->manager) {
1356 DSSERR("overlay '%s' already has a manager '%s'\n",
1357 ovl->name, ovl->manager->name);
1358 r = -EINVAL;
1359 goto err;
1360 }
1361
1362 r = dispc_runtime_get();
1363 if (r)
1364 goto err;
1365
1366 spin_lock_irqsave(&data_lock, flags);
1367
1368 if (op->enabled) {
1369 spin_unlock_irqrestore(&data_lock, flags);
1370 DSSERR("overlay has to be disabled to change the manager\n");
1371 r = -EINVAL;
1372 goto err1;
1373 }
1374
1375 dispc_ovl_set_channel_out(ovl->id, mgr->id);
1376
1377 ovl->manager = mgr;
1378 list_add_tail(&ovl->list, &mgr->overlays);
1379
1380 spin_unlock_irqrestore(&data_lock, flags);
1381
1382 dispc_runtime_put();
1383
1384 mutex_unlock(&apply_lock);
1385
1386 return 0;
1387
1388err1:
1389 dispc_runtime_put();
1390err:
1391 mutex_unlock(&apply_lock);
1392 return r;
1393}
1394
1395static int dss_ovl_unset_manager(struct omap_overlay *ovl)
1396{
1397 struct ovl_priv_data *op = get_ovl_priv(ovl);
1398 unsigned long flags;
1399 int r;
1400
1401 mutex_lock(&apply_lock);
1402
1403 if (!ovl->manager) {
1404 DSSERR("failed to detach overlay: manager not set\n");
1405 r = -EINVAL;
1406 goto err;
1407 }
1408
1409 spin_lock_irqsave(&data_lock, flags);
1410
1411 if (op->enabled) {
1412 spin_unlock_irqrestore(&data_lock, flags);
1413 DSSERR("overlay has to be disabled to unset the manager\n");
1414 r = -EINVAL;
1415 goto err;
1416 }
1417
1418 spin_unlock_irqrestore(&data_lock, flags);
1419
1420 /* wait for pending extra_info updates to ensure the ovl is disabled */
1421 wait_pending_extra_info_updates();
1422
1423 /*
1424 * For a manual update display, there is no guarantee that the overlay
1425 * is really disabled in HW, we may need an extra update from this
1426 * manager before the configurations can go in. Return an error if the
1427 * overlay needed an update from the manager.
1428 *
1429 * TODO: Instead of returning an error, try to do a dummy manager update
1430 * here to disable the overlay in hardware. Use the *GATED fields in
1431 * the DISPC_CONFIG registers to do a dummy update.
1432 */
1433 spin_lock_irqsave(&data_lock, flags);
1434
1435 if (ovl_manual_update(ovl) && op->extra_info_dirty) {
1436 spin_unlock_irqrestore(&data_lock, flags);
1437 DSSERR("need an update to change the manager\n");
1438 r = -EINVAL;
1439 goto err;
1440 }
1441
1442 ovl->manager = NULL;
1443 list_del(&ovl->list);
1444
1445 spin_unlock_irqrestore(&data_lock, flags);
1446
1447 mutex_unlock(&apply_lock);
1448
1449 return 0;
1450err:
1451 mutex_unlock(&apply_lock);
1452 return r;
1453}
1454
1455static bool dss_ovl_is_enabled(struct omap_overlay *ovl)
1456{
1457 struct ovl_priv_data *op = get_ovl_priv(ovl);
1458 unsigned long flags;
1459 bool e;
1460
1461 spin_lock_irqsave(&data_lock, flags);
1462
1463 e = op->enabled;
1464
1465 spin_unlock_irqrestore(&data_lock, flags);
1466
1467 return e;
1468}
1469
1470static int dss_ovl_enable(struct omap_overlay *ovl)
1471{
1472 struct ovl_priv_data *op = get_ovl_priv(ovl);
1473 unsigned long flags;
1474 int r;
1475
1476 mutex_lock(&apply_lock);
1477
1478 if (op->enabled) {
1479 r = 0;
1480 goto err1;
1481 }
1482
1483 if (ovl->manager == NULL || ovl->manager->output == NULL) {
1484 r = -EINVAL;
1485 goto err1;
1486 }
1487
1488 spin_lock_irqsave(&data_lock, flags);
1489
1490 op->enabling = true;
1491
1492 r = dss_check_settings(ovl->manager);
1493 if (r) {
1494 DSSERR("failed to enable overlay %d: check_settings failed\n",
1495 ovl->id);
1496 goto err2;
1497 }
1498
1499 dss_setup_fifos();
1500
1501 op->enabling = false;
1502 dss_apply_ovl_enable(ovl, true);
1503
1504 dss_write_regs();
1505 dss_set_go_bits();
1506
1507 spin_unlock_irqrestore(&data_lock, flags);
1508
1509 mutex_unlock(&apply_lock);
1510
1511 return 0;
1512err2:
1513 op->enabling = false;
1514 spin_unlock_irqrestore(&data_lock, flags);
1515err1:
1516 mutex_unlock(&apply_lock);
1517 return r;
1518}
1519
1520static int dss_ovl_disable(struct omap_overlay *ovl)
1521{
1522 struct ovl_priv_data *op = get_ovl_priv(ovl);
1523 unsigned long flags;
1524 int r;
1525
1526 mutex_lock(&apply_lock);
1527
1528 if (!op->enabled) {
1529 r = 0;
1530 goto err;
1531 }
1532
1533 if (ovl->manager == NULL || ovl->manager->output == NULL) {
1534 r = -EINVAL;
1535 goto err;
1536 }
1537
1538 spin_lock_irqsave(&data_lock, flags);
1539
1540 dss_apply_ovl_enable(ovl, false);
1541 dss_write_regs();
1542 dss_set_go_bits();
1543
1544 spin_unlock_irqrestore(&data_lock, flags);
1545
1546 mutex_unlock(&apply_lock);
1547
1548 return 0;
1549
1550err:
1551 mutex_unlock(&apply_lock);
1552 return r;
1553}
1554
1555static int dss_mgr_register_framedone_handler_compat(struct omap_overlay_manager *mgr,
1556 void (*handler)(void *), void *data)
1557{
1558 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1559
1560 if (mp->framedone_handler)
1561 return -EBUSY;
1562
1563 mp->framedone_handler = handler;
1564 mp->framedone_handler_data = data;
1565
1566 return 0;
1567}
1568
1569static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_manager *mgr,
1570 void (*handler)(void *), void *data)
1571{
1572 struct mgr_priv_data *mp = get_mgr_priv(mgr);
1573
1574 WARN_ON(mp->framedone_handler != handler ||
1575 mp->framedone_handler_data != data);
1576
1577 mp->framedone_handler = NULL;
1578 mp->framedone_handler_data = NULL;
1579}
1580
1581static const struct dss_mgr_ops apply_mgr_ops = {
1582 .connect = dss_mgr_connect_compat,
1583 .disconnect = dss_mgr_disconnect_compat,
1584 .start_update = dss_mgr_start_update_compat,
1585 .enable = dss_mgr_enable_compat,
1586 .disable = dss_mgr_disable_compat,
1587 .set_timings = dss_mgr_set_timings_compat,
1588 .set_lcd_config = dss_mgr_set_lcd_config_compat,
1589 .register_framedone_handler = dss_mgr_register_framedone_handler_compat,
1590 .unregister_framedone_handler = dss_mgr_unregister_framedone_handler_compat,
1591};
1592
1593static int compat_refcnt;
1594static DEFINE_MUTEX(compat_init_lock);
1595
1596int omapdss_compat_init(void)
1597{
1598 struct platform_device *pdev = dss_get_core_pdev();
1599 int i, r;
1600
1601 mutex_lock(&compat_init_lock);
1602
1603 if (compat_refcnt++ > 0)
1604 goto out;
1605
1606 apply_init_priv();
1607
1608 dss_init_overlay_managers_sysfs(pdev);
1609 dss_init_overlays(pdev);
1610
1611 for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
1612 struct omap_overlay_manager *mgr;
1613
1614 mgr = omap_dss_get_overlay_manager(i);
1615
1616 mgr->set_output = &dss_mgr_set_output;
1617 mgr->unset_output = &dss_mgr_unset_output;
1618 mgr->apply = &omap_dss_mgr_apply;
1619 mgr->set_manager_info = &dss_mgr_set_info;
1620 mgr->get_manager_info = &dss_mgr_get_info;
1621 mgr->wait_for_go = &dss_mgr_wait_for_go;
1622 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
1623 mgr->get_device = &dss_mgr_get_device;
1624 }
1625
1626 for (i = 0; i < omap_dss_get_num_overlays(); i++) {
1627 struct omap_overlay *ovl = omap_dss_get_overlay(i);
1628
1629 ovl->is_enabled = &dss_ovl_is_enabled;
1630 ovl->enable = &dss_ovl_enable;
1631 ovl->disable = &dss_ovl_disable;
1632 ovl->set_manager = &dss_ovl_set_manager;
1633 ovl->unset_manager = &dss_ovl_unset_manager;
1634 ovl->set_overlay_info = &dss_ovl_set_info;
1635 ovl->get_overlay_info = &dss_ovl_get_info;
1636 ovl->wait_for_go = &dss_mgr_wait_for_go_ovl;
1637 ovl->get_device = &dss_ovl_get_device;
1638 }
1639
1640 r = dss_install_mgr_ops(&apply_mgr_ops);
1641 if (r)
1642 goto err_mgr_ops;
1643
1644 r = display_init_sysfs(pdev);
1645 if (r)
1646 goto err_disp_sysfs;
1647
1648 dispc_runtime_get();
1649
1650 r = dss_dispc_initialize_irq();
1651 if (r)
1652 goto err_init_irq;
1653
1654 dispc_runtime_put();
1655
1656out:
1657 mutex_unlock(&compat_init_lock);
1658
1659 return 0;
1660
1661err_init_irq:
1662 dispc_runtime_put();
1663 display_uninit_sysfs(pdev);
1664
1665err_disp_sysfs:
1666 dss_uninstall_mgr_ops();
1667
1668err_mgr_ops:
1669 dss_uninit_overlay_managers_sysfs(pdev);
1670 dss_uninit_overlays(pdev);
1671
1672 compat_refcnt--;
1673
1674 mutex_unlock(&compat_init_lock);
1675
1676 return r;
1677}
1678EXPORT_SYMBOL(omapdss_compat_init);
1679
1680void omapdss_compat_uninit(void)
1681{
1682 struct platform_device *pdev = dss_get_core_pdev();
1683
1684 mutex_lock(&compat_init_lock);
1685
1686 if (--compat_refcnt > 0)
1687 goto out;
1688
1689 dss_dispc_uninitialize_irq();
1690
1691 display_uninit_sysfs(pdev);
1692
1693 dss_uninstall_mgr_ops();
1694
1695 dss_uninit_overlay_managers_sysfs(pdev);
1696 dss_uninit_overlays(pdev);
1697out:
1698 mutex_unlock(&compat_init_lock);
1699}
1700EXPORT_SYMBOL(omapdss_compat_uninit);
diff --git a/drivers/video/fbdev/omap2/dss/core.c b/drivers/video/fbdev/omap2/dss/core.c
new file mode 100644
index 000000000000..ffa45c894cd4
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/core.c
@@ -0,0 +1,360 @@
1/*
2 * linux/drivers/video/omap2/dss/core.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 "CORE"
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/clk.h>
28#include <linux/err.h>
29#include <linux/platform_device.h>
30#include <linux/seq_file.h>
31#include <linux/debugfs.h>
32#include <linux/io.h>
33#include <linux/device.h>
34#include <linux/regulator/consumer.h>
35#include <linux/suspend.h>
36#include <linux/slab.h>
37
38#include <video/omapdss.h>
39
40#include "dss.h"
41#include "dss_features.h"
42
43static struct {
44 struct platform_device *pdev;
45
46 const char *default_display_name;
47} core;
48
49static char *def_disp_name;
50module_param_named(def_disp, def_disp_name, charp, 0);
51MODULE_PARM_DESC(def_disp, "default display name");
52
53static bool dss_initialized;
54
55const char *omapdss_get_default_display_name(void)
56{
57 return core.default_display_name;
58}
59EXPORT_SYMBOL(omapdss_get_default_display_name);
60
61enum omapdss_version omapdss_get_version(void)
62{
63 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
64 return pdata->version;
65}
66EXPORT_SYMBOL(omapdss_get_version);
67
68bool omapdss_is_initialized(void)
69{
70 return dss_initialized;
71}
72EXPORT_SYMBOL(omapdss_is_initialized);
73
74struct platform_device *dss_get_core_pdev(void)
75{
76 return core.pdev;
77}
78
79int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask)
80{
81 struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
82
83 if (!board_data->dsi_enable_pads)
84 return -ENOENT;
85
86 return board_data->dsi_enable_pads(dsi_id, lane_mask);
87}
88
89void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask)
90{
91 struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
92
93 if (!board_data->dsi_disable_pads)
94 return;
95
96 return board_data->dsi_disable_pads(dsi_id, lane_mask);
97}
98
99int dss_set_min_bus_tput(struct device *dev, unsigned long tput)
100{
101 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
102
103 if (pdata->set_min_bus_tput)
104 return pdata->set_min_bus_tput(dev, tput);
105 else
106 return 0;
107}
108
109#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
110static int dss_debug_show(struct seq_file *s, void *unused)
111{
112 void (*func)(struct seq_file *) = s->private;
113 func(s);
114 return 0;
115}
116
117static int dss_debug_open(struct inode *inode, struct file *file)
118{
119 return single_open(file, dss_debug_show, inode->i_private);
120}
121
122static const struct file_operations dss_debug_fops = {
123 .open = dss_debug_open,
124 .read = seq_read,
125 .llseek = seq_lseek,
126 .release = single_release,
127};
128
129static struct dentry *dss_debugfs_dir;
130
131static int dss_initialize_debugfs(void)
132{
133 dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
134 if (IS_ERR(dss_debugfs_dir)) {
135 int err = PTR_ERR(dss_debugfs_dir);
136 dss_debugfs_dir = NULL;
137 return err;
138 }
139
140 debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
141 &dss_debug_dump_clocks, &dss_debug_fops);
142
143 return 0;
144}
145
146static void dss_uninitialize_debugfs(void)
147{
148 if (dss_debugfs_dir)
149 debugfs_remove_recursive(dss_debugfs_dir);
150}
151
152int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
153{
154 struct dentry *d;
155
156 d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir,
157 write, &dss_debug_fops);
158
159 return PTR_ERR_OR_ZERO(d);
160}
161#else /* CONFIG_OMAP2_DSS_DEBUGFS */
162static inline int dss_initialize_debugfs(void)
163{
164 return 0;
165}
166static inline void dss_uninitialize_debugfs(void)
167{
168}
169int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
170{
171 return 0;
172}
173#endif /* CONFIG_OMAP2_DSS_DEBUGFS */
174
175/* PLATFORM DEVICE */
176static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d)
177{
178 DSSDBG("pm notif %lu\n", v);
179
180 switch (v) {
181 case PM_SUSPEND_PREPARE:
182 DSSDBG("suspending displays\n");
183 return dss_suspend_all_devices();
184
185 case PM_POST_SUSPEND:
186 DSSDBG("resuming displays\n");
187 return dss_resume_all_devices();
188
189 default:
190 return 0;
191 }
192}
193
194static struct notifier_block omap_dss_pm_notif_block = {
195 .notifier_call = omap_dss_pm_notif,
196};
197
198static int __init omap_dss_probe(struct platform_device *pdev)
199{
200 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
201 int r;
202
203 core.pdev = pdev;
204
205 dss_features_init(omapdss_get_version());
206
207 r = dss_initialize_debugfs();
208 if (r)
209 goto err_debugfs;
210
211 if (def_disp_name)
212 core.default_display_name = def_disp_name;
213 else if (pdata->default_display_name)
214 core.default_display_name = pdata->default_display_name;
215 else if (pdata->default_device)
216 core.default_display_name = pdata->default_device->name;
217
218 register_pm_notifier(&omap_dss_pm_notif_block);
219
220 return 0;
221
222err_debugfs:
223
224 return r;
225}
226
227static int omap_dss_remove(struct platform_device *pdev)
228{
229 unregister_pm_notifier(&omap_dss_pm_notif_block);
230
231 dss_uninitialize_debugfs();
232
233 return 0;
234}
235
236static void omap_dss_shutdown(struct platform_device *pdev)
237{
238 DSSDBG("shutdown\n");
239 dss_disable_all_devices();
240}
241
242static struct platform_driver omap_dss_driver = {
243 .remove = omap_dss_remove,
244 .shutdown = omap_dss_shutdown,
245 .driver = {
246 .name = "omapdss",
247 .owner = THIS_MODULE,
248 },
249};
250
251/* INIT */
252static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
253#ifdef CONFIG_OMAP2_DSS_DSI
254 dsi_init_platform_driver,
255#endif
256#ifdef CONFIG_OMAP2_DSS_DPI
257 dpi_init_platform_driver,
258#endif
259#ifdef CONFIG_OMAP2_DSS_SDI
260 sdi_init_platform_driver,
261#endif
262#ifdef CONFIG_OMAP2_DSS_RFBI
263 rfbi_init_platform_driver,
264#endif
265#ifdef CONFIG_OMAP2_DSS_VENC
266 venc_init_platform_driver,
267#endif
268#ifdef CONFIG_OMAP4_DSS_HDMI
269 hdmi4_init_platform_driver,
270#endif
271};
272
273static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = {
274#ifdef CONFIG_OMAP2_DSS_DSI
275 dsi_uninit_platform_driver,
276#endif
277#ifdef CONFIG_OMAP2_DSS_DPI
278 dpi_uninit_platform_driver,
279#endif
280#ifdef CONFIG_OMAP2_DSS_SDI
281 sdi_uninit_platform_driver,
282#endif
283#ifdef CONFIG_OMAP2_DSS_RFBI
284 rfbi_uninit_platform_driver,
285#endif
286#ifdef CONFIG_OMAP2_DSS_VENC
287 venc_uninit_platform_driver,
288#endif
289#ifdef CONFIG_OMAP4_DSS_HDMI
290 hdmi4_uninit_platform_driver,
291#endif
292};
293
294static bool dss_output_drv_loaded[ARRAY_SIZE(dss_output_drv_reg_funcs)];
295
296static int __init omap_dss_init(void)
297{
298 int r;
299 int i;
300
301 r = platform_driver_probe(&omap_dss_driver, omap_dss_probe);
302 if (r)
303 return r;
304
305 r = dss_init_platform_driver();
306 if (r) {
307 DSSERR("Failed to initialize DSS platform driver\n");
308 goto err_dss;
309 }
310
311 r = dispc_init_platform_driver();
312 if (r) {
313 DSSERR("Failed to initialize dispc platform driver\n");
314 goto err_dispc;
315 }
316
317 /*
318 * It's ok if the output-driver register fails. It happens, for example,
319 * when there is no output-device (e.g. SDI for OMAP4).
320 */
321 for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) {
322 r = dss_output_drv_reg_funcs[i]();
323 if (r == 0)
324 dss_output_drv_loaded[i] = true;
325 }
326
327 dss_initialized = true;
328
329 return 0;
330
331err_dispc:
332 dss_uninit_platform_driver();
333err_dss:
334 platform_driver_unregister(&omap_dss_driver);
335
336 return r;
337}
338
339static void __exit omap_dss_exit(void)
340{
341 int i;
342
343 for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i) {
344 if (dss_output_drv_loaded[i])
345 dss_output_drv_unreg_funcs[i]();
346 }
347
348 dispc_uninit_platform_driver();
349 dss_uninit_platform_driver();
350
351 platform_driver_unregister(&omap_dss_driver);
352}
353
354module_init(omap_dss_init);
355module_exit(omap_dss_exit);
356
357MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
358MODULE_DESCRIPTION("OMAP2/3 Display Subsystem");
359MODULE_LICENSE("GPL v2");
360
diff --git a/drivers/video/fbdev/omap2/dss/dispc-compat.c b/drivers/video/fbdev/omap2/dss/dispc-compat.c
new file mode 100644
index 000000000000..83779c2b292a
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/dispc-compat.c
@@ -0,0 +1,666 @@
1/*
2 * Copyright (C) 2012 Texas Instruments
3 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#define DSS_SUBSYS_NAME "APPLY"
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/slab.h>
23#include <linux/spinlock.h>
24#include <linux/jiffies.h>
25#include <linux/delay.h>
26#include <linux/interrupt.h>
27#include <linux/seq_file.h>
28
29#include <video/omapdss.h>
30
31#include "dss.h"
32#include "dss_features.h"
33#include "dispc-compat.h"
34
35#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
36 DISPC_IRQ_OCP_ERR | \
37 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
38 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
39 DISPC_IRQ_SYNC_LOST | \
40 DISPC_IRQ_SYNC_LOST_DIGIT)
41
42#define DISPC_MAX_NR_ISRS 8
43
44struct omap_dispc_isr_data {
45 omap_dispc_isr_t isr;
46 void *arg;
47 u32 mask;
48};
49
50struct dispc_irq_stats {
51 unsigned long last_reset;
52 unsigned irq_count;
53 unsigned irqs[32];
54};
55
56static struct {
57 spinlock_t irq_lock;
58 u32 irq_error_mask;
59 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
60 u32 error_irqs;
61 struct work_struct error_work;
62
63#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
64 spinlock_t irq_stats_lock;
65 struct dispc_irq_stats irq_stats;
66#endif
67} dispc_compat;
68
69
70#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
71static void dispc_dump_irqs(struct seq_file *s)
72{
73 unsigned long flags;
74 struct dispc_irq_stats stats;
75
76 spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags);
77
78 stats = dispc_compat.irq_stats;
79 memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats));
80 dispc_compat.irq_stats.last_reset = jiffies;
81
82 spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags);
83
84 seq_printf(s, "period %u ms\n",
85 jiffies_to_msecs(jiffies - stats.last_reset));
86
87 seq_printf(s, "irqs %d\n", stats.irq_count);
88#define PIS(x) \
89 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
90
91 PIS(FRAMEDONE);
92 PIS(VSYNC);
93 PIS(EVSYNC_EVEN);
94 PIS(EVSYNC_ODD);
95 PIS(ACBIAS_COUNT_STAT);
96 PIS(PROG_LINE_NUM);
97 PIS(GFX_FIFO_UNDERFLOW);
98 PIS(GFX_END_WIN);
99 PIS(PAL_GAMMA_MASK);
100 PIS(OCP_ERR);
101 PIS(VID1_FIFO_UNDERFLOW);
102 PIS(VID1_END_WIN);
103 PIS(VID2_FIFO_UNDERFLOW);
104 PIS(VID2_END_WIN);
105 if (dss_feat_get_num_ovls() > 3) {
106 PIS(VID3_FIFO_UNDERFLOW);
107 PIS(VID3_END_WIN);
108 }
109 PIS(SYNC_LOST);
110 PIS(SYNC_LOST_DIGIT);
111 PIS(WAKEUP);
112 if (dss_has_feature(FEAT_MGR_LCD2)) {
113 PIS(FRAMEDONE2);
114 PIS(VSYNC2);
115 PIS(ACBIAS_COUNT_STAT2);
116 PIS(SYNC_LOST2);
117 }
118 if (dss_has_feature(FEAT_MGR_LCD3)) {
119 PIS(FRAMEDONE3);
120 PIS(VSYNC3);
121 PIS(ACBIAS_COUNT_STAT3);
122 PIS(SYNC_LOST3);
123 }
124#undef PIS
125}
126#endif
127
128/* dispc.irq_lock has to be locked by the caller */
129static void _omap_dispc_set_irqs(void)
130{
131 u32 mask;
132 int i;
133 struct omap_dispc_isr_data *isr_data;
134
135 mask = dispc_compat.irq_error_mask;
136
137 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
138 isr_data = &dispc_compat.registered_isr[i];
139
140 if (isr_data->isr == NULL)
141 continue;
142
143 mask |= isr_data->mask;
144 }
145
146 dispc_write_irqenable(mask);
147}
148
149int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
150{
151 int i;
152 int ret;
153 unsigned long flags;
154 struct omap_dispc_isr_data *isr_data;
155
156 if (isr == NULL)
157 return -EINVAL;
158
159 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
160
161 /* check for duplicate entry */
162 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
163 isr_data = &dispc_compat.registered_isr[i];
164 if (isr_data->isr == isr && isr_data->arg == arg &&
165 isr_data->mask == mask) {
166 ret = -EINVAL;
167 goto err;
168 }
169 }
170
171 isr_data = NULL;
172 ret = -EBUSY;
173
174 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
175 isr_data = &dispc_compat.registered_isr[i];
176
177 if (isr_data->isr != NULL)
178 continue;
179
180 isr_data->isr = isr;
181 isr_data->arg = arg;
182 isr_data->mask = mask;
183 ret = 0;
184
185 break;
186 }
187
188 if (ret)
189 goto err;
190
191 _omap_dispc_set_irqs();
192
193 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
194
195 return 0;
196err:
197 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
198
199 return ret;
200}
201EXPORT_SYMBOL(omap_dispc_register_isr);
202
203int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
204{
205 int i;
206 unsigned long flags;
207 int ret = -EINVAL;
208 struct omap_dispc_isr_data *isr_data;
209
210 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
211
212 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
213 isr_data = &dispc_compat.registered_isr[i];
214 if (isr_data->isr != isr || isr_data->arg != arg ||
215 isr_data->mask != mask)
216 continue;
217
218 /* found the correct isr */
219
220 isr_data->isr = NULL;
221 isr_data->arg = NULL;
222 isr_data->mask = 0;
223
224 ret = 0;
225 break;
226 }
227
228 if (ret == 0)
229 _omap_dispc_set_irqs();
230
231 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
232
233 return ret;
234}
235EXPORT_SYMBOL(omap_dispc_unregister_isr);
236
237static void print_irq_status(u32 status)
238{
239 if ((status & dispc_compat.irq_error_mask) == 0)
240 return;
241
242#define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
243
244 pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
245 status,
246 PIS(OCP_ERR),
247 PIS(GFX_FIFO_UNDERFLOW),
248 PIS(VID1_FIFO_UNDERFLOW),
249 PIS(VID2_FIFO_UNDERFLOW),
250 dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "",
251 PIS(SYNC_LOST),
252 PIS(SYNC_LOST_DIGIT),
253 dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "",
254 dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : "");
255#undef PIS
256}
257
258/* Called from dss.c. Note that we don't touch clocks here,
259 * but we presume they are on because we got an IRQ. However,
260 * an irq handler may turn the clocks off, so we may not have
261 * clock later in the function. */
262static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
263{
264 int i;
265 u32 irqstatus, irqenable;
266 u32 handledirqs = 0;
267 u32 unhandled_errors;
268 struct omap_dispc_isr_data *isr_data;
269 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
270
271 spin_lock(&dispc_compat.irq_lock);
272
273 irqstatus = dispc_read_irqstatus();
274 irqenable = dispc_read_irqenable();
275
276 /* IRQ is not for us */
277 if (!(irqstatus & irqenable)) {
278 spin_unlock(&dispc_compat.irq_lock);
279 return IRQ_NONE;
280 }
281
282#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
283 spin_lock(&dispc_compat.irq_stats_lock);
284 dispc_compat.irq_stats.irq_count++;
285 dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs);
286 spin_unlock(&dispc_compat.irq_stats_lock);
287#endif
288
289 print_irq_status(irqstatus);
290
291 /* Ack the interrupt. Do it here before clocks are possibly turned
292 * off */
293 dispc_clear_irqstatus(irqstatus);
294 /* flush posted write */
295 dispc_read_irqstatus();
296
297 /* make a copy and unlock, so that isrs can unregister
298 * themselves */
299 memcpy(registered_isr, dispc_compat.registered_isr,
300 sizeof(registered_isr));
301
302 spin_unlock(&dispc_compat.irq_lock);
303
304 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
305 isr_data = &registered_isr[i];
306
307 if (!isr_data->isr)
308 continue;
309
310 if (isr_data->mask & irqstatus) {
311 isr_data->isr(isr_data->arg, irqstatus);
312 handledirqs |= isr_data->mask;
313 }
314 }
315
316 spin_lock(&dispc_compat.irq_lock);
317
318 unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask;
319
320 if (unhandled_errors) {
321 dispc_compat.error_irqs |= unhandled_errors;
322
323 dispc_compat.irq_error_mask &= ~unhandled_errors;
324 _omap_dispc_set_irqs();
325
326 schedule_work(&dispc_compat.error_work);
327 }
328
329 spin_unlock(&dispc_compat.irq_lock);
330
331 return IRQ_HANDLED;
332}
333
334static void dispc_error_worker(struct work_struct *work)
335{
336 int i;
337 u32 errors;
338 unsigned long flags;
339 static const unsigned fifo_underflow_bits[] = {
340 DISPC_IRQ_GFX_FIFO_UNDERFLOW,
341 DISPC_IRQ_VID1_FIFO_UNDERFLOW,
342 DISPC_IRQ_VID2_FIFO_UNDERFLOW,
343 DISPC_IRQ_VID3_FIFO_UNDERFLOW,
344 };
345
346 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
347 errors = dispc_compat.error_irqs;
348 dispc_compat.error_irqs = 0;
349 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
350
351 dispc_runtime_get();
352
353 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
354 struct omap_overlay *ovl;
355 unsigned bit;
356
357 ovl = omap_dss_get_overlay(i);
358 bit = fifo_underflow_bits[i];
359
360 if (bit & errors) {
361 DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
362 ovl->name);
363 ovl->disable(ovl);
364 msleep(50);
365 }
366 }
367
368 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
369 struct omap_overlay_manager *mgr;
370 unsigned bit;
371
372 mgr = omap_dss_get_overlay_manager(i);
373 bit = dispc_mgr_get_sync_lost_irq(i);
374
375 if (bit & errors) {
376 int j;
377
378 DSSERR("SYNC_LOST on channel %s, restarting the output "
379 "with video overlays disabled\n",
380 mgr->name);
381
382 dss_mgr_disable(mgr);
383
384 for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
385 struct omap_overlay *ovl;
386 ovl = omap_dss_get_overlay(j);
387
388 if (ovl->id != OMAP_DSS_GFX &&
389 ovl->manager == mgr)
390 ovl->disable(ovl);
391 }
392
393 dss_mgr_enable(mgr);
394 }
395 }
396
397 if (errors & DISPC_IRQ_OCP_ERR) {
398 DSSERR("OCP_ERR\n");
399 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
400 struct omap_overlay_manager *mgr;
401
402 mgr = omap_dss_get_overlay_manager(i);
403 dss_mgr_disable(mgr);
404 }
405 }
406
407 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
408 dispc_compat.irq_error_mask |= errors;
409 _omap_dispc_set_irqs();
410 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
411
412 dispc_runtime_put();
413}
414
415int dss_dispc_initialize_irq(void)
416{
417 int r;
418
419#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
420 spin_lock_init(&dispc_compat.irq_stats_lock);
421 dispc_compat.irq_stats.last_reset = jiffies;
422 dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
423#endif
424
425 spin_lock_init(&dispc_compat.irq_lock);
426
427 memset(dispc_compat.registered_isr, 0,
428 sizeof(dispc_compat.registered_isr));
429
430 dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR;
431 if (dss_has_feature(FEAT_MGR_LCD2))
432 dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
433 if (dss_has_feature(FEAT_MGR_LCD3))
434 dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
435 if (dss_feat_get_num_ovls() > 3)
436 dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
437
438 /*
439 * there's SYNC_LOST_DIGIT waiting after enabling the DSS,
440 * so clear it
441 */
442 dispc_clear_irqstatus(dispc_read_irqstatus());
443
444 INIT_WORK(&dispc_compat.error_work, dispc_error_worker);
445
446 _omap_dispc_set_irqs();
447
448 r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);
449 if (r) {
450 DSSERR("dispc_request_irq failed\n");
451 return r;
452 }
453
454 return 0;
455}
456
457void dss_dispc_uninitialize_irq(void)
458{
459 dispc_free_irq(&dispc_compat);
460}
461
462static void dispc_mgr_disable_isr(void *data, u32 mask)
463{
464 struct completion *compl = data;
465 complete(compl);
466}
467
468static void dispc_mgr_enable_lcd_out(enum omap_channel channel)
469{
470 dispc_mgr_enable(channel, true);
471}
472
473static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
474{
475 DECLARE_COMPLETION_ONSTACK(framedone_compl);
476 int r;
477 u32 irq;
478
479 if (dispc_mgr_is_enabled(channel) == false)
480 return;
481
482 /*
483 * When we disable LCD output, we need to wait for FRAMEDONE to know
484 * that DISPC has finished with the LCD output.
485 */
486
487 irq = dispc_mgr_get_framedone_irq(channel);
488
489 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
490 irq);
491 if (r)
492 DSSERR("failed to register FRAMEDONE isr\n");
493
494 dispc_mgr_enable(channel, false);
495
496 /* if we couldn't register for framedone, just sleep and exit */
497 if (r) {
498 msleep(100);
499 return;
500 }
501
502 if (!wait_for_completion_timeout(&framedone_compl,
503 msecs_to_jiffies(100)))
504 DSSERR("timeout waiting for FRAME DONE\n");
505
506 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
507 irq);
508 if (r)
509 DSSERR("failed to unregister FRAMEDONE isr\n");
510}
511
512static void dispc_digit_out_enable_isr(void *data, u32 mask)
513{
514 struct completion *compl = data;
515
516 /* ignore any sync lost interrupts */
517 if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
518 complete(compl);
519}
520
521static void dispc_mgr_enable_digit_out(void)
522{
523 DECLARE_COMPLETION_ONSTACK(vsync_compl);
524 int r;
525 u32 irq_mask;
526
527 if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == true)
528 return;
529
530 /*
531 * Digit output produces some sync lost interrupts during the first
532 * frame when enabling. Those need to be ignored, so we register for the
533 * sync lost irq to prevent the error handler from triggering.
534 */
535
536 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
537 dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
538
539 r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
540 irq_mask);
541 if (r) {
542 DSSERR("failed to register %x isr\n", irq_mask);
543 return;
544 }
545
546 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
547
548 /* wait for the first evsync */
549 if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))
550 DSSERR("timeout waiting for digit out to start\n");
551
552 r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
553 irq_mask);
554 if (r)
555 DSSERR("failed to unregister %x isr\n", irq_mask);
556}
557
558static void dispc_mgr_disable_digit_out(void)
559{
560 DECLARE_COMPLETION_ONSTACK(framedone_compl);
561 int r, i;
562 u32 irq_mask;
563 int num_irqs;
564
565 if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == false)
566 return;
567
568 /*
569 * When we disable the digit output, we need to wait for FRAMEDONE to
570 * know that DISPC has finished with the output.
571 */
572
573 irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
574 num_irqs = 1;
575
576 if (!irq_mask) {
577 /*
578 * omap 2/3 don't have framedone irq for TV, so we need to use
579 * vsyncs for this.
580 */
581
582 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
583 /*
584 * We need to wait for both even and odd vsyncs. Note that this
585 * is not totally reliable, as we could get a vsync interrupt
586 * before we disable the output, which leads to timeout in the
587 * wait_for_completion.
588 */
589 num_irqs = 2;
590 }
591
592 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
593 irq_mask);
594 if (r)
595 DSSERR("failed to register %x isr\n", irq_mask);
596
597 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
598
599 /* if we couldn't register the irq, just sleep and exit */
600 if (r) {
601 msleep(100);
602 return;
603 }
604
605 for (i = 0; i < num_irqs; ++i) {
606 if (!wait_for_completion_timeout(&framedone_compl,
607 msecs_to_jiffies(100)))
608 DSSERR("timeout waiting for digit out to stop\n");
609 }
610
611 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
612 irq_mask);
613 if (r)
614 DSSERR("failed to unregister %x isr\n", irq_mask);
615}
616
617void dispc_mgr_enable_sync(enum omap_channel channel)
618{
619 if (dss_mgr_is_lcd(channel))
620 dispc_mgr_enable_lcd_out(channel);
621 else if (channel == OMAP_DSS_CHANNEL_DIGIT)
622 dispc_mgr_enable_digit_out();
623 else
624 WARN_ON(1);
625}
626
627void dispc_mgr_disable_sync(enum omap_channel channel)
628{
629 if (dss_mgr_is_lcd(channel))
630 dispc_mgr_disable_lcd_out(channel);
631 else if (channel == OMAP_DSS_CHANNEL_DIGIT)
632 dispc_mgr_disable_digit_out();
633 else
634 WARN_ON(1);
635}
636
637int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
638 unsigned long timeout)
639{
640 void dispc_irq_wait_handler(void *data, u32 mask)
641 {
642 complete((struct completion *)data);
643 }
644
645 int r;
646 DECLARE_COMPLETION_ONSTACK(completion);
647
648 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
649 irqmask);
650
651 if (r)
652 return r;
653
654 timeout = wait_for_completion_interruptible_timeout(&completion,
655 timeout);
656
657 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
658
659 if (timeout == 0)
660 return -ETIMEDOUT;
661
662 if (timeout == -ERESTARTSYS)
663 return -ERESTARTSYS;
664
665 return 0;
666}
diff --git a/drivers/video/fbdev/omap2/dss/dispc-compat.h b/drivers/video/fbdev/omap2/dss/dispc-compat.h
new file mode 100644
index 000000000000..14a69b3d4fb0
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/dispc-compat.h
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2012 Texas Instruments
3 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef __OMAP2_DSS_DISPC_COMPAT_H
19#define __OMAP2_DSS_DISPC_COMPAT_H
20
21void dispc_mgr_enable_sync(enum omap_channel channel);
22void dispc_mgr_disable_sync(enum omap_channel channel);
23
24int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
25 unsigned long timeout);
26
27int dss_dispc_initialize_irq(void);
28void dss_dispc_uninitialize_irq(void);
29
30#endif
diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/video/fbdev/omap2/dss/dispc.c
new file mode 100644
index 000000000000..f18397c33e8f
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/dispc.c
@@ -0,0 +1,3853 @@
1/*
2 * linux/drivers/video/omap2/dss/dispc.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DISPC"
24
25#include <linux/kernel.h>
26#include <linux/dma-mapping.h>
27#include <linux/vmalloc.h>
28#include <linux/export.h>
29#include <linux/clk.h>
30#include <linux/io.h>
31#include <linux/jiffies.h>
32#include <linux/seq_file.h>
33#include <linux/delay.h>
34#include <linux/workqueue.h>
35#include <linux/hardirq.h>
36#include <linux/platform_device.h>
37#include <linux/pm_runtime.h>
38#include <linux/sizes.h>
39
40#include <video/omapdss.h>
41
42#include "dss.h"
43#include "dss_features.h"
44#include "dispc.h"
45
46/* DISPC */
47#define DISPC_SZ_REGS SZ_4K
48
49enum omap_burst_size {
50 BURST_SIZE_X2 = 0,
51 BURST_SIZE_X4 = 1,
52 BURST_SIZE_X8 = 2,
53};
54
55#define REG_GET(idx, start, end) \
56 FLD_GET(dispc_read_reg(idx), start, end)
57
58#define REG_FLD_MOD(idx, val, start, end) \
59 dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
60
61struct dispc_features {
62 u8 sw_start;
63 u8 fp_start;
64 u8 bp_start;
65 u16 sw_max;
66 u16 vp_max;
67 u16 hp_max;
68 u8 mgr_width_start;
69 u8 mgr_height_start;
70 u16 mgr_width_max;
71 u16 mgr_height_max;
72 unsigned long max_lcd_pclk;
73 unsigned long max_tv_pclk;
74 int (*calc_scaling) (unsigned long pclk, unsigned long lclk,
75 const struct omap_video_timings *mgr_timings,
76 u16 width, u16 height, u16 out_width, u16 out_height,
77 enum omap_color_mode color_mode, bool *five_taps,
78 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
79 u16 pos_x, unsigned long *core_clk, bool mem_to_mem);
80 unsigned long (*calc_core_clk) (unsigned long pclk,
81 u16 width, u16 height, u16 out_width, u16 out_height,
82 bool mem_to_mem);
83 u8 num_fifos;
84
85 /* swap GFX & WB fifos */
86 bool gfx_fifo_workaround:1;
87
88 /* no DISPC_IRQ_FRAMEDONETV on this SoC */
89 bool no_framedone_tv:1;
90
91 /* revert to the OMAP4 mechanism of DISPC Smart Standby operation */
92 bool mstandby_workaround:1;
93
94 bool set_max_preload:1;
95};
96
97#define DISPC_MAX_NR_FIFOS 5
98
99static struct {
100 struct platform_device *pdev;
101 void __iomem *base;
102
103 int irq;
104 irq_handler_t user_handler;
105 void *user_data;
106
107 unsigned long core_clk_rate;
108 unsigned long tv_pclk_rate;
109
110 u32 fifo_size[DISPC_MAX_NR_FIFOS];
111 /* maps which plane is using a fifo. fifo-id -> plane-id */
112 int fifo_assignment[DISPC_MAX_NR_FIFOS];
113
114 bool ctx_valid;
115 u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
116
117 const struct dispc_features *feat;
118
119 bool is_enabled;
120} dispc;
121
122enum omap_color_component {
123 /* used for all color formats for OMAP3 and earlier
124 * and for RGB and Y color component on OMAP4
125 */
126 DISPC_COLOR_COMPONENT_RGB_Y = 1 << 0,
127 /* used for UV component for
128 * OMAP_DSS_COLOR_YUV2, OMAP_DSS_COLOR_UYVY, OMAP_DSS_COLOR_NV12
129 * color formats on OMAP4
130 */
131 DISPC_COLOR_COMPONENT_UV = 1 << 1,
132};
133
134enum mgr_reg_fields {
135 DISPC_MGR_FLD_ENABLE,
136 DISPC_MGR_FLD_STNTFT,
137 DISPC_MGR_FLD_GO,
138 DISPC_MGR_FLD_TFTDATALINES,
139 DISPC_MGR_FLD_STALLMODE,
140 DISPC_MGR_FLD_TCKENABLE,
141 DISPC_MGR_FLD_TCKSELECTION,
142 DISPC_MGR_FLD_CPR,
143 DISPC_MGR_FLD_FIFOHANDCHECK,
144 /* used to maintain a count of the above fields */
145 DISPC_MGR_FLD_NUM,
146};
147
148struct dispc_reg_field {
149 u16 reg;
150 u8 high;
151 u8 low;
152};
153
154static const struct {
155 const char *name;
156 u32 vsync_irq;
157 u32 framedone_irq;
158 u32 sync_lost_irq;
159 struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM];
160} mgr_desc[] = {
161 [OMAP_DSS_CHANNEL_LCD] = {
162 .name = "LCD",
163 .vsync_irq = DISPC_IRQ_VSYNC,
164 .framedone_irq = DISPC_IRQ_FRAMEDONE,
165 .sync_lost_irq = DISPC_IRQ_SYNC_LOST,
166 .reg_desc = {
167 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 },
168 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 },
169 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 5, 5 },
170 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL, 9, 8 },
171 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL, 11, 11 },
172 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 10, 10 },
173 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 11, 11 },
174 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG, 15, 15 },
175 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
176 },
177 },
178 [OMAP_DSS_CHANNEL_DIGIT] = {
179 .name = "DIGIT",
180 .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN,
181 .framedone_irq = DISPC_IRQ_FRAMEDONETV,
182 .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT,
183 .reg_desc = {
184 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 },
185 [DISPC_MGR_FLD_STNTFT] = { },
186 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 6, 6 },
187 [DISPC_MGR_FLD_TFTDATALINES] = { },
188 [DISPC_MGR_FLD_STALLMODE] = { },
189 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 12, 12 },
190 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 13, 13 },
191 [DISPC_MGR_FLD_CPR] = { },
192 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
193 },
194 },
195 [OMAP_DSS_CHANNEL_LCD2] = {
196 .name = "LCD2",
197 .vsync_irq = DISPC_IRQ_VSYNC2,
198 .framedone_irq = DISPC_IRQ_FRAMEDONE2,
199 .sync_lost_irq = DISPC_IRQ_SYNC_LOST2,
200 .reg_desc = {
201 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 },
202 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 },
203 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL2, 5, 5 },
204 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL2, 9, 8 },
205 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL2, 11, 11 },
206 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG2, 10, 10 },
207 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG2, 11, 11 },
208 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG2, 15, 15 },
209 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG2, 16, 16 },
210 },
211 },
212 [OMAP_DSS_CHANNEL_LCD3] = {
213 .name = "LCD3",
214 .vsync_irq = DISPC_IRQ_VSYNC3,
215 .framedone_irq = DISPC_IRQ_FRAMEDONE3,
216 .sync_lost_irq = DISPC_IRQ_SYNC_LOST3,
217 .reg_desc = {
218 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 },
219 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 },
220 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL3, 5, 5 },
221 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL3, 9, 8 },
222 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL3, 11, 11 },
223 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG3, 10, 10 },
224 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG3, 11, 11 },
225 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG3, 15, 15 },
226 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG3, 16, 16 },
227 },
228 },
229};
230
231struct color_conv_coef {
232 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
233 int full_range;
234};
235
236static unsigned long dispc_plane_pclk_rate(enum omap_plane plane);
237static unsigned long dispc_plane_lclk_rate(enum omap_plane plane);
238
239static inline void dispc_write_reg(const u16 idx, u32 val)
240{
241 __raw_writel(val, dispc.base + idx);
242}
243
244static inline u32 dispc_read_reg(const u16 idx)
245{
246 return __raw_readl(dispc.base + idx);
247}
248
249static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld)
250{
251 const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
252 return REG_GET(rfld.reg, rfld.high, rfld.low);
253}
254
255static void mgr_fld_write(enum omap_channel channel,
256 enum mgr_reg_fields regfld, int val) {
257 const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
258 REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low);
259}
260
261#define SR(reg) \
262 dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
263#define RR(reg) \
264 dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
265
266static void dispc_save_context(void)
267{
268 int i, j;
269
270 DSSDBG("dispc_save_context\n");
271
272 SR(IRQENABLE);
273 SR(CONTROL);
274 SR(CONFIG);
275 SR(LINE_NUMBER);
276 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
277 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
278 SR(GLOBAL_ALPHA);
279 if (dss_has_feature(FEAT_MGR_LCD2)) {
280 SR(CONTROL2);
281 SR(CONFIG2);
282 }
283 if (dss_has_feature(FEAT_MGR_LCD3)) {
284 SR(CONTROL3);
285 SR(CONFIG3);
286 }
287
288 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
289 SR(DEFAULT_COLOR(i));
290 SR(TRANS_COLOR(i));
291 SR(SIZE_MGR(i));
292 if (i == OMAP_DSS_CHANNEL_DIGIT)
293 continue;
294 SR(TIMING_H(i));
295 SR(TIMING_V(i));
296 SR(POL_FREQ(i));
297 SR(DIVISORo(i));
298
299 SR(DATA_CYCLE1(i));
300 SR(DATA_CYCLE2(i));
301 SR(DATA_CYCLE3(i));
302
303 if (dss_has_feature(FEAT_CPR)) {
304 SR(CPR_COEF_R(i));
305 SR(CPR_COEF_G(i));
306 SR(CPR_COEF_B(i));
307 }
308 }
309
310 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
311 SR(OVL_BA0(i));
312 SR(OVL_BA1(i));
313 SR(OVL_POSITION(i));
314 SR(OVL_SIZE(i));
315 SR(OVL_ATTRIBUTES(i));
316 SR(OVL_FIFO_THRESHOLD(i));
317 SR(OVL_ROW_INC(i));
318 SR(OVL_PIXEL_INC(i));
319 if (dss_has_feature(FEAT_PRELOAD))
320 SR(OVL_PRELOAD(i));
321 if (i == OMAP_DSS_GFX) {
322 SR(OVL_WINDOW_SKIP(i));
323 SR(OVL_TABLE_BA(i));
324 continue;
325 }
326 SR(OVL_FIR(i));
327 SR(OVL_PICTURE_SIZE(i));
328 SR(OVL_ACCU0(i));
329 SR(OVL_ACCU1(i));
330
331 for (j = 0; j < 8; j++)
332 SR(OVL_FIR_COEF_H(i, j));
333
334 for (j = 0; j < 8; j++)
335 SR(OVL_FIR_COEF_HV(i, j));
336
337 for (j = 0; j < 5; j++)
338 SR(OVL_CONV_COEF(i, j));
339
340 if (dss_has_feature(FEAT_FIR_COEF_V)) {
341 for (j = 0; j < 8; j++)
342 SR(OVL_FIR_COEF_V(i, j));
343 }
344
345 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
346 SR(OVL_BA0_UV(i));
347 SR(OVL_BA1_UV(i));
348 SR(OVL_FIR2(i));
349 SR(OVL_ACCU2_0(i));
350 SR(OVL_ACCU2_1(i));
351
352 for (j = 0; j < 8; j++)
353 SR(OVL_FIR_COEF_H2(i, j));
354
355 for (j = 0; j < 8; j++)
356 SR(OVL_FIR_COEF_HV2(i, j));
357
358 for (j = 0; j < 8; j++)
359 SR(OVL_FIR_COEF_V2(i, j));
360 }
361 if (dss_has_feature(FEAT_ATTR2))
362 SR(OVL_ATTRIBUTES2(i));
363 }
364
365 if (dss_has_feature(FEAT_CORE_CLK_DIV))
366 SR(DIVISOR);
367
368 dispc.ctx_valid = true;
369
370 DSSDBG("context saved\n");
371}
372
373static void dispc_restore_context(void)
374{
375 int i, j;
376
377 DSSDBG("dispc_restore_context\n");
378
379 if (!dispc.ctx_valid)
380 return;
381
382 /*RR(IRQENABLE);*/
383 /*RR(CONTROL);*/
384 RR(CONFIG);
385 RR(LINE_NUMBER);
386 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
387 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
388 RR(GLOBAL_ALPHA);
389 if (dss_has_feature(FEAT_MGR_LCD2))
390 RR(CONFIG2);
391 if (dss_has_feature(FEAT_MGR_LCD3))
392 RR(CONFIG3);
393
394 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
395 RR(DEFAULT_COLOR(i));
396 RR(TRANS_COLOR(i));
397 RR(SIZE_MGR(i));
398 if (i == OMAP_DSS_CHANNEL_DIGIT)
399 continue;
400 RR(TIMING_H(i));
401 RR(TIMING_V(i));
402 RR(POL_FREQ(i));
403 RR(DIVISORo(i));
404
405 RR(DATA_CYCLE1(i));
406 RR(DATA_CYCLE2(i));
407 RR(DATA_CYCLE3(i));
408
409 if (dss_has_feature(FEAT_CPR)) {
410 RR(CPR_COEF_R(i));
411 RR(CPR_COEF_G(i));
412 RR(CPR_COEF_B(i));
413 }
414 }
415
416 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
417 RR(OVL_BA0(i));
418 RR(OVL_BA1(i));
419 RR(OVL_POSITION(i));
420 RR(OVL_SIZE(i));
421 RR(OVL_ATTRIBUTES(i));
422 RR(OVL_FIFO_THRESHOLD(i));
423 RR(OVL_ROW_INC(i));
424 RR(OVL_PIXEL_INC(i));
425 if (dss_has_feature(FEAT_PRELOAD))
426 RR(OVL_PRELOAD(i));
427 if (i == OMAP_DSS_GFX) {
428 RR(OVL_WINDOW_SKIP(i));
429 RR(OVL_TABLE_BA(i));
430 continue;
431 }
432 RR(OVL_FIR(i));
433 RR(OVL_PICTURE_SIZE(i));
434 RR(OVL_ACCU0(i));
435 RR(OVL_ACCU1(i));
436
437 for (j = 0; j < 8; j++)
438 RR(OVL_FIR_COEF_H(i, j));
439
440 for (j = 0; j < 8; j++)
441 RR(OVL_FIR_COEF_HV(i, j));
442
443 for (j = 0; j < 5; j++)
444 RR(OVL_CONV_COEF(i, j));
445
446 if (dss_has_feature(FEAT_FIR_COEF_V)) {
447 for (j = 0; j < 8; j++)
448 RR(OVL_FIR_COEF_V(i, j));
449 }
450
451 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
452 RR(OVL_BA0_UV(i));
453 RR(OVL_BA1_UV(i));
454 RR(OVL_FIR2(i));
455 RR(OVL_ACCU2_0(i));
456 RR(OVL_ACCU2_1(i));
457
458 for (j = 0; j < 8; j++)
459 RR(OVL_FIR_COEF_H2(i, j));
460
461 for (j = 0; j < 8; j++)
462 RR(OVL_FIR_COEF_HV2(i, j));
463
464 for (j = 0; j < 8; j++)
465 RR(OVL_FIR_COEF_V2(i, j));
466 }
467 if (dss_has_feature(FEAT_ATTR2))
468 RR(OVL_ATTRIBUTES2(i));
469 }
470
471 if (dss_has_feature(FEAT_CORE_CLK_DIV))
472 RR(DIVISOR);
473
474 /* enable last, because LCD & DIGIT enable are here */
475 RR(CONTROL);
476 if (dss_has_feature(FEAT_MGR_LCD2))
477 RR(CONTROL2);
478 if (dss_has_feature(FEAT_MGR_LCD3))
479 RR(CONTROL3);
480 /* clear spurious SYNC_LOST_DIGIT interrupts */
481 dispc_clear_irqstatus(DISPC_IRQ_SYNC_LOST_DIGIT);
482
483 /*
484 * enable last so IRQs won't trigger before
485 * the context is fully restored
486 */
487 RR(IRQENABLE);
488
489 DSSDBG("context restored\n");
490}
491
492#undef SR
493#undef RR
494
495int dispc_runtime_get(void)
496{
497 int r;
498
499 DSSDBG("dispc_runtime_get\n");
500
501 r = pm_runtime_get_sync(&dispc.pdev->dev);
502 WARN_ON(r < 0);
503 return r < 0 ? r : 0;
504}
505EXPORT_SYMBOL(dispc_runtime_get);
506
507void dispc_runtime_put(void)
508{
509 int r;
510
511 DSSDBG("dispc_runtime_put\n");
512
513 r = pm_runtime_put_sync(&dispc.pdev->dev);
514 WARN_ON(r < 0 && r != -ENOSYS);
515}
516EXPORT_SYMBOL(dispc_runtime_put);
517
518u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)
519{
520 return mgr_desc[channel].vsync_irq;
521}
522EXPORT_SYMBOL(dispc_mgr_get_vsync_irq);
523
524u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
525{
526 if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv)
527 return 0;
528
529 return mgr_desc[channel].framedone_irq;
530}
531EXPORT_SYMBOL(dispc_mgr_get_framedone_irq);
532
533u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel)
534{
535 return mgr_desc[channel].sync_lost_irq;
536}
537EXPORT_SYMBOL(dispc_mgr_get_sync_lost_irq);
538
539u32 dispc_wb_get_framedone_irq(void)
540{
541 return DISPC_IRQ_FRAMEDONEWB;
542}
543
544bool dispc_mgr_go_busy(enum omap_channel channel)
545{
546 return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
547}
548EXPORT_SYMBOL(dispc_mgr_go_busy);
549
550void dispc_mgr_go(enum omap_channel channel)
551{
552 WARN_ON(dispc_mgr_is_enabled(channel) == false);
553 WARN_ON(dispc_mgr_go_busy(channel));
554
555 DSSDBG("GO %s\n", mgr_desc[channel].name);
556
557 mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1);
558}
559EXPORT_SYMBOL(dispc_mgr_go);
560
561bool dispc_wb_go_busy(void)
562{
563 return REG_GET(DISPC_CONTROL2, 6, 6) == 1;
564}
565
566void dispc_wb_go(void)
567{
568 enum omap_plane plane = OMAP_DSS_WB;
569 bool enable, go;
570
571 enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1;
572
573 if (!enable)
574 return;
575
576 go = REG_GET(DISPC_CONTROL2, 6, 6) == 1;
577 if (go) {
578 DSSERR("GO bit not down for WB\n");
579 return;
580 }
581
582 REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6);
583}
584
585static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value)
586{
587 dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
588}
589
590static void dispc_ovl_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
591{
592 dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value);
593}
594
595static void dispc_ovl_write_firv_reg(enum omap_plane plane, int reg, u32 value)
596{
597 dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value);
598}
599
600static void dispc_ovl_write_firh2_reg(enum omap_plane plane, int reg, u32 value)
601{
602 BUG_ON(plane == OMAP_DSS_GFX);
603
604 dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value);
605}
606
607static void dispc_ovl_write_firhv2_reg(enum omap_plane plane, int reg,
608 u32 value)
609{
610 BUG_ON(plane == OMAP_DSS_GFX);
611
612 dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
613}
614
615static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
616{
617 BUG_ON(plane == OMAP_DSS_GFX);
618
619 dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
620}
621
622static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc,
623 int fir_vinc, int five_taps,
624 enum omap_color_component color_comp)
625{
626 const struct dispc_coef *h_coef, *v_coef;
627 int i;
628
629 h_coef = dispc_ovl_get_scale_coef(fir_hinc, true);
630 v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps);
631
632 for (i = 0; i < 8; i++) {
633 u32 h, hv;
634
635 h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0)
636 | FLD_VAL(h_coef[i].hc1_vc0, 15, 8)
637 | FLD_VAL(h_coef[i].hc2_vc1, 23, 16)
638 | FLD_VAL(h_coef[i].hc3_vc2, 31, 24);
639 hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0)
640 | FLD_VAL(v_coef[i].hc1_vc0, 15, 8)
641 | FLD_VAL(v_coef[i].hc2_vc1, 23, 16)
642 | FLD_VAL(v_coef[i].hc3_vc2, 31, 24);
643
644 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
645 dispc_ovl_write_firh_reg(plane, i, h);
646 dispc_ovl_write_firhv_reg(plane, i, hv);
647 } else {
648 dispc_ovl_write_firh2_reg(plane, i, h);
649 dispc_ovl_write_firhv2_reg(plane, i, hv);
650 }
651
652 }
653
654 if (five_taps) {
655 for (i = 0; i < 8; i++) {
656 u32 v;
657 v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0)
658 | FLD_VAL(v_coef[i].hc4_vc22, 15, 8);
659 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
660 dispc_ovl_write_firv_reg(plane, i, v);
661 else
662 dispc_ovl_write_firv2_reg(plane, i, v);
663 }
664 }
665}
666
667
668static void dispc_ovl_write_color_conv_coef(enum omap_plane plane,
669 const struct color_conv_coef *ct)
670{
671#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
672
673 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry));
674 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb));
675 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr));
676 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by));
677 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb));
678
679 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11);
680
681#undef CVAL
682}
683
684static void dispc_setup_color_conv_coef(void)
685{
686 int i;
687 int num_ovl = dss_feat_get_num_ovls();
688 int num_wb = dss_feat_get_num_wbs();
689 const struct color_conv_coef ctbl_bt601_5_ovl = {
690 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
691 };
692 const struct color_conv_coef ctbl_bt601_5_wb = {
693 66, 112, -38, 129, -94, -74, 25, -18, 112, 0,
694 };
695
696 for (i = 1; i < num_ovl; i++)
697 dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl);
698
699 for (; i < num_wb; i++)
700 dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_wb);
701}
702
703static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr)
704{
705 dispc_write_reg(DISPC_OVL_BA0(plane), paddr);
706}
707
708static void dispc_ovl_set_ba1(enum omap_plane plane, u32 paddr)
709{
710 dispc_write_reg(DISPC_OVL_BA1(plane), paddr);
711}
712
713static void dispc_ovl_set_ba0_uv(enum omap_plane plane, u32 paddr)
714{
715 dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr);
716}
717
718static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr)
719{
720 dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
721}
722
723static void dispc_ovl_set_pos(enum omap_plane plane,
724 enum omap_overlay_caps caps, int x, int y)
725{
726 u32 val;
727
728 if ((caps & OMAP_DSS_OVL_CAP_POS) == 0)
729 return;
730
731 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
732
733 dispc_write_reg(DISPC_OVL_POSITION(plane), val);
734}
735
736static void dispc_ovl_set_input_size(enum omap_plane plane, int width,
737 int height)
738{
739 u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
740
741 if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB)
742 dispc_write_reg(DISPC_OVL_SIZE(plane), val);
743 else
744 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
745}
746
747static void dispc_ovl_set_output_size(enum omap_plane plane, int width,
748 int height)
749{
750 u32 val;
751
752 BUG_ON(plane == OMAP_DSS_GFX);
753
754 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
755
756 if (plane == OMAP_DSS_WB)
757 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
758 else
759 dispc_write_reg(DISPC_OVL_SIZE(plane), val);
760}
761
762static void dispc_ovl_set_zorder(enum omap_plane plane,
763 enum omap_overlay_caps caps, u8 zorder)
764{
765 if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
766 return;
767
768 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
769}
770
771static void dispc_ovl_enable_zorder_planes(void)
772{
773 int i;
774
775 if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
776 return;
777
778 for (i = 0; i < dss_feat_get_num_ovls(); i++)
779 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
780}
781
782static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane,
783 enum omap_overlay_caps caps, bool enable)
784{
785 if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
786 return;
787
788 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
789}
790
791static void dispc_ovl_setup_global_alpha(enum omap_plane plane,
792 enum omap_overlay_caps caps, u8 global_alpha)
793{
794 static const unsigned shifts[] = { 0, 8, 16, 24, };
795 int shift;
796
797 if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
798 return;
799
800 shift = shifts[plane];
801 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift);
802}
803
804static void dispc_ovl_set_pix_inc(enum omap_plane plane, s32 inc)
805{
806 dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc);
807}
808
809static void dispc_ovl_set_row_inc(enum omap_plane plane, s32 inc)
810{
811 dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc);
812}
813
814static void dispc_ovl_set_color_mode(enum omap_plane plane,
815 enum omap_color_mode color_mode)
816{
817 u32 m = 0;
818 if (plane != OMAP_DSS_GFX) {
819 switch (color_mode) {
820 case OMAP_DSS_COLOR_NV12:
821 m = 0x0; break;
822 case OMAP_DSS_COLOR_RGBX16:
823 m = 0x1; break;
824 case OMAP_DSS_COLOR_RGBA16:
825 m = 0x2; break;
826 case OMAP_DSS_COLOR_RGB12U:
827 m = 0x4; break;
828 case OMAP_DSS_COLOR_ARGB16:
829 m = 0x5; break;
830 case OMAP_DSS_COLOR_RGB16:
831 m = 0x6; break;
832 case OMAP_DSS_COLOR_ARGB16_1555:
833 m = 0x7; break;
834 case OMAP_DSS_COLOR_RGB24U:
835 m = 0x8; break;
836 case OMAP_DSS_COLOR_RGB24P:
837 m = 0x9; break;
838 case OMAP_DSS_COLOR_YUV2:
839 m = 0xa; break;
840 case OMAP_DSS_COLOR_UYVY:
841 m = 0xb; break;
842 case OMAP_DSS_COLOR_ARGB32:
843 m = 0xc; break;
844 case OMAP_DSS_COLOR_RGBA32:
845 m = 0xd; break;
846 case OMAP_DSS_COLOR_RGBX32:
847 m = 0xe; break;
848 case OMAP_DSS_COLOR_XRGB16_1555:
849 m = 0xf; break;
850 default:
851 BUG(); return;
852 }
853 } else {
854 switch (color_mode) {
855 case OMAP_DSS_COLOR_CLUT1:
856 m = 0x0; break;
857 case OMAP_DSS_COLOR_CLUT2:
858 m = 0x1; break;
859 case OMAP_DSS_COLOR_CLUT4:
860 m = 0x2; break;
861 case OMAP_DSS_COLOR_CLUT8:
862 m = 0x3; break;
863 case OMAP_DSS_COLOR_RGB12U:
864 m = 0x4; break;
865 case OMAP_DSS_COLOR_ARGB16:
866 m = 0x5; break;
867 case OMAP_DSS_COLOR_RGB16:
868 m = 0x6; break;
869 case OMAP_DSS_COLOR_ARGB16_1555:
870 m = 0x7; break;
871 case OMAP_DSS_COLOR_RGB24U:
872 m = 0x8; break;
873 case OMAP_DSS_COLOR_RGB24P:
874 m = 0x9; break;
875 case OMAP_DSS_COLOR_RGBX16:
876 m = 0xa; break;
877 case OMAP_DSS_COLOR_RGBA16:
878 m = 0xb; break;
879 case OMAP_DSS_COLOR_ARGB32:
880 m = 0xc; break;
881 case OMAP_DSS_COLOR_RGBA32:
882 m = 0xd; break;
883 case OMAP_DSS_COLOR_RGBX32:
884 m = 0xe; break;
885 case OMAP_DSS_COLOR_XRGB16_1555:
886 m = 0xf; break;
887 default:
888 BUG(); return;
889 }
890 }
891
892 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
893}
894
895static void dispc_ovl_configure_burst_type(enum omap_plane plane,
896 enum omap_dss_rotation_type rotation_type)
897{
898 if (dss_has_feature(FEAT_BURST_2D) == 0)
899 return;
900
901 if (rotation_type == OMAP_DSS_ROT_TILER)
902 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29);
903 else
904 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29);
905}
906
907void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel)
908{
909 int shift;
910 u32 val;
911 int chan = 0, chan2 = 0;
912
913 switch (plane) {
914 case OMAP_DSS_GFX:
915 shift = 8;
916 break;
917 case OMAP_DSS_VIDEO1:
918 case OMAP_DSS_VIDEO2:
919 case OMAP_DSS_VIDEO3:
920 shift = 16;
921 break;
922 default:
923 BUG();
924 return;
925 }
926
927 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
928 if (dss_has_feature(FEAT_MGR_LCD2)) {
929 switch (channel) {
930 case OMAP_DSS_CHANNEL_LCD:
931 chan = 0;
932 chan2 = 0;
933 break;
934 case OMAP_DSS_CHANNEL_DIGIT:
935 chan = 1;
936 chan2 = 0;
937 break;
938 case OMAP_DSS_CHANNEL_LCD2:
939 chan = 0;
940 chan2 = 1;
941 break;
942 case OMAP_DSS_CHANNEL_LCD3:
943 if (dss_has_feature(FEAT_MGR_LCD3)) {
944 chan = 0;
945 chan2 = 2;
946 } else {
947 BUG();
948 return;
949 }
950 break;
951 default:
952 BUG();
953 return;
954 }
955
956 val = FLD_MOD(val, chan, shift, shift);
957 val = FLD_MOD(val, chan2, 31, 30);
958 } else {
959 val = FLD_MOD(val, channel, shift, shift);
960 }
961 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
962}
963EXPORT_SYMBOL(dispc_ovl_set_channel_out);
964
965static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
966{
967 int shift;
968 u32 val;
969 enum omap_channel channel;
970
971 switch (plane) {
972 case OMAP_DSS_GFX:
973 shift = 8;
974 break;
975 case OMAP_DSS_VIDEO1:
976 case OMAP_DSS_VIDEO2:
977 case OMAP_DSS_VIDEO3:
978 shift = 16;
979 break;
980 default:
981 BUG();
982 return 0;
983 }
984
985 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
986
987 if (dss_has_feature(FEAT_MGR_LCD3)) {
988 if (FLD_GET(val, 31, 30) == 0)
989 channel = FLD_GET(val, shift, shift);
990 else if (FLD_GET(val, 31, 30) == 1)
991 channel = OMAP_DSS_CHANNEL_LCD2;
992 else
993 channel = OMAP_DSS_CHANNEL_LCD3;
994 } else if (dss_has_feature(FEAT_MGR_LCD2)) {
995 if (FLD_GET(val, 31, 30) == 0)
996 channel = FLD_GET(val, shift, shift);
997 else
998 channel = OMAP_DSS_CHANNEL_LCD2;
999 } else {
1000 channel = FLD_GET(val, shift, shift);
1001 }
1002
1003 return channel;
1004}
1005
1006void dispc_wb_set_channel_in(enum dss_writeback_channel channel)
1007{
1008 enum omap_plane plane = OMAP_DSS_WB;
1009
1010 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16);
1011}
1012
1013static void dispc_ovl_set_burst_size(enum omap_plane plane,
1014 enum omap_burst_size burst_size)
1015{
1016 static const unsigned shifts[] = { 6, 14, 14, 14, 14, };
1017 int shift;
1018
1019 shift = shifts[plane];
1020 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift);
1021}
1022
1023static void dispc_configure_burst_sizes(void)
1024{
1025 int i;
1026 const int burst_size = BURST_SIZE_X8;
1027
1028 /* Configure burst size always to maximum size */
1029 for (i = 0; i < dss_feat_get_num_ovls(); ++i)
1030 dispc_ovl_set_burst_size(i, burst_size);
1031}
1032
1033static u32 dispc_ovl_get_burst_size(enum omap_plane plane)
1034{
1035 unsigned unit = dss_feat_get_burst_size_unit();
1036 /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
1037 return unit * 8;
1038}
1039
1040void dispc_enable_gamma_table(bool enable)
1041{
1042 /*
1043 * This is partially implemented to support only disabling of
1044 * the gamma table.
1045 */
1046 if (enable) {
1047 DSSWARN("Gamma table enabling for TV not yet supported");
1048 return;
1049 }
1050
1051 REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
1052}
1053
1054static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
1055{
1056 if (channel == OMAP_DSS_CHANNEL_DIGIT)
1057 return;
1058
1059 mgr_fld_write(channel, DISPC_MGR_FLD_CPR, enable);
1060}
1061
1062static void dispc_mgr_set_cpr_coef(enum omap_channel channel,
1063 const struct omap_dss_cpr_coefs *coefs)
1064{
1065 u32 coef_r, coef_g, coef_b;
1066
1067 if (!dss_mgr_is_lcd(channel))
1068 return;
1069
1070 coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
1071 FLD_VAL(coefs->rb, 9, 0);
1072 coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) |
1073 FLD_VAL(coefs->gb, 9, 0);
1074 coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) |
1075 FLD_VAL(coefs->bb, 9, 0);
1076
1077 dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r);
1078 dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g);
1079 dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b);
1080}
1081
1082static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable)
1083{
1084 u32 val;
1085
1086 BUG_ON(plane == OMAP_DSS_GFX);
1087
1088 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
1089 val = FLD_MOD(val, enable, 9, 9);
1090 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
1091}
1092
1093static void dispc_ovl_enable_replication(enum omap_plane plane,
1094 enum omap_overlay_caps caps, bool enable)
1095{
1096 static const unsigned shifts[] = { 5, 10, 10, 10 };
1097 int shift;
1098
1099 if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0)
1100 return;
1101
1102 shift = shifts[plane];
1103 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
1104}
1105
1106static void dispc_mgr_set_size(enum omap_channel channel, u16 width,
1107 u16 height)
1108{
1109 u32 val;
1110
1111 val = FLD_VAL(height - 1, dispc.feat->mgr_height_start, 16) |
1112 FLD_VAL(width - 1, dispc.feat->mgr_width_start, 0);
1113
1114 dispc_write_reg(DISPC_SIZE_MGR(channel), val);
1115}
1116
1117static void dispc_init_fifos(void)
1118{
1119 u32 size;
1120 int fifo;
1121 u8 start, end;
1122 u32 unit;
1123
1124 unit = dss_feat_get_buffer_size_unit();
1125
1126 dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
1127
1128 for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1129 size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end);
1130 size *= unit;
1131 dispc.fifo_size[fifo] = size;
1132
1133 /*
1134 * By default fifos are mapped directly to overlays, fifo 0 to
1135 * ovl 0, fifo 1 to ovl 1, etc.
1136 */
1137 dispc.fifo_assignment[fifo] = fifo;
1138 }
1139
1140 /*
1141 * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo
1142 * causes problems with certain use cases, like using the tiler in 2D
1143 * mode. The below hack swaps the fifos of GFX and WB planes, thus
1144 * giving GFX plane a larger fifo. WB but should work fine with a
1145 * smaller fifo.
1146 */
1147 if (dispc.feat->gfx_fifo_workaround) {
1148 u32 v;
1149
1150 v = dispc_read_reg(DISPC_GLOBAL_BUFFER);
1151
1152 v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */
1153 v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */
1154 v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */
1155 v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */
1156
1157 dispc_write_reg(DISPC_GLOBAL_BUFFER, v);
1158
1159 dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB;
1160 dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX;
1161 }
1162}
1163
1164static u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
1165{
1166 int fifo;
1167 u32 size = 0;
1168
1169 for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1170 if (dispc.fifo_assignment[fifo] == plane)
1171 size += dispc.fifo_size[fifo];
1172 }
1173
1174 return size;
1175}
1176
1177void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
1178{
1179 u8 hi_start, hi_end, lo_start, lo_end;
1180 u32 unit;
1181
1182 unit = dss_feat_get_buffer_size_unit();
1183
1184 WARN_ON(low % unit != 0);
1185 WARN_ON(high % unit != 0);
1186
1187 low /= unit;
1188 high /= unit;
1189
1190 dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
1191 dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
1192
1193 DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n",
1194 plane,
1195 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
1196 lo_start, lo_end) * unit,
1197 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
1198 hi_start, hi_end) * unit,
1199 low * unit, high * unit);
1200
1201 dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
1202 FLD_VAL(high, hi_start, hi_end) |
1203 FLD_VAL(low, lo_start, lo_end));
1204
1205 /*
1206 * configure the preload to the pipeline's high threhold, if HT it's too
1207 * large for the preload field, set the threshold to the maximum value
1208 * that can be held by the preload register
1209 */
1210 if (dss_has_feature(FEAT_PRELOAD) && dispc.feat->set_max_preload &&
1211 plane != OMAP_DSS_WB)
1212 dispc_write_reg(DISPC_OVL_PRELOAD(plane), min(high, 0xfffu));
1213}
1214EXPORT_SYMBOL(dispc_ovl_set_fifo_threshold);
1215
1216void dispc_enable_fifomerge(bool enable)
1217{
1218 if (!dss_has_feature(FEAT_FIFO_MERGE)) {
1219 WARN_ON(enable);
1220 return;
1221 }
1222
1223 DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1224 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
1225}
1226
1227void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
1228 u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
1229 bool manual_update)
1230{
1231 /*
1232 * All sizes are in bytes. Both the buffer and burst are made of
1233 * buffer_units, and the fifo thresholds must be buffer_unit aligned.
1234 */
1235
1236 unsigned buf_unit = dss_feat_get_buffer_size_unit();
1237 unsigned ovl_fifo_size, total_fifo_size, burst_size;
1238 int i;
1239
1240 burst_size = dispc_ovl_get_burst_size(plane);
1241 ovl_fifo_size = dispc_ovl_get_fifo_size(plane);
1242
1243 if (use_fifomerge) {
1244 total_fifo_size = 0;
1245 for (i = 0; i < dss_feat_get_num_ovls(); ++i)
1246 total_fifo_size += dispc_ovl_get_fifo_size(i);
1247 } else {
1248 total_fifo_size = ovl_fifo_size;
1249 }
1250
1251 /*
1252 * We use the same low threshold for both fifomerge and non-fifomerge
1253 * cases, but for fifomerge we calculate the high threshold using the
1254 * combined fifo size
1255 */
1256
1257 if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
1258 *fifo_low = ovl_fifo_size - burst_size * 2;
1259 *fifo_high = total_fifo_size - burst_size;
1260 } else if (plane == OMAP_DSS_WB) {
1261 /*
1262 * Most optimal configuration for writeback is to push out data
1263 * to the interconnect the moment writeback pushes enough pixels
1264 * in the FIFO to form a burst
1265 */
1266 *fifo_low = 0;
1267 *fifo_high = burst_size;
1268 } else {
1269 *fifo_low = ovl_fifo_size - burst_size;
1270 *fifo_high = total_fifo_size - buf_unit;
1271 }
1272}
1273EXPORT_SYMBOL(dispc_ovl_compute_fifo_thresholds);
1274
1275static void dispc_ovl_set_fir(enum omap_plane plane,
1276 int hinc, int vinc,
1277 enum omap_color_component color_comp)
1278{
1279 u32 val;
1280
1281 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
1282 u8 hinc_start, hinc_end, vinc_start, vinc_end;
1283
1284 dss_feat_get_reg_field(FEAT_REG_FIRHINC,
1285 &hinc_start, &hinc_end);
1286 dss_feat_get_reg_field(FEAT_REG_FIRVINC,
1287 &vinc_start, &vinc_end);
1288 val = FLD_VAL(vinc, vinc_start, vinc_end) |
1289 FLD_VAL(hinc, hinc_start, hinc_end);
1290
1291 dispc_write_reg(DISPC_OVL_FIR(plane), val);
1292 } else {
1293 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1294 dispc_write_reg(DISPC_OVL_FIR2(plane), val);
1295 }
1296}
1297
1298static void dispc_ovl_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
1299{
1300 u32 val;
1301 u8 hor_start, hor_end, vert_start, vert_end;
1302
1303 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1304 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1305
1306 val = FLD_VAL(vaccu, vert_start, vert_end) |
1307 FLD_VAL(haccu, hor_start, hor_end);
1308
1309 dispc_write_reg(DISPC_OVL_ACCU0(plane), val);
1310}
1311
1312static void dispc_ovl_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
1313{
1314 u32 val;
1315 u8 hor_start, hor_end, vert_start, vert_end;
1316
1317 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1318 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1319
1320 val = FLD_VAL(vaccu, vert_start, vert_end) |
1321 FLD_VAL(haccu, hor_start, hor_end);
1322
1323 dispc_write_reg(DISPC_OVL_ACCU1(plane), val);
1324}
1325
1326static void dispc_ovl_set_vid_accu2_0(enum omap_plane plane, int haccu,
1327 int vaccu)
1328{
1329 u32 val;
1330
1331 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1332 dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val);
1333}
1334
1335static void dispc_ovl_set_vid_accu2_1(enum omap_plane plane, int haccu,
1336 int vaccu)
1337{
1338 u32 val;
1339
1340 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1341 dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val);
1342}
1343
1344static void dispc_ovl_set_scale_param(enum omap_plane plane,
1345 u16 orig_width, u16 orig_height,
1346 u16 out_width, u16 out_height,
1347 bool five_taps, u8 rotation,
1348 enum omap_color_component color_comp)
1349{
1350 int fir_hinc, fir_vinc;
1351
1352 fir_hinc = 1024 * orig_width / out_width;
1353 fir_vinc = 1024 * orig_height / out_height;
1354
1355 dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps,
1356 color_comp);
1357 dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp);
1358}
1359
1360static void dispc_ovl_set_accu_uv(enum omap_plane plane,
1361 u16 orig_width, u16 orig_height, u16 out_width, u16 out_height,
1362 bool ilace, enum omap_color_mode color_mode, u8 rotation)
1363{
1364 int h_accu2_0, h_accu2_1;
1365 int v_accu2_0, v_accu2_1;
1366 int chroma_hinc, chroma_vinc;
1367 int idx;
1368
1369 struct accu {
1370 s8 h0_m, h0_n;
1371 s8 h1_m, h1_n;
1372 s8 v0_m, v0_n;
1373 s8 v1_m, v1_n;
1374 };
1375
1376 const struct accu *accu_table;
1377 const struct accu *accu_val;
1378
1379 static const struct accu accu_nv12[4] = {
1380 { 0, 1, 0, 1 , -1, 2, 0, 1 },
1381 { 1, 2, -3, 4 , 0, 1, 0, 1 },
1382 { -1, 1, 0, 1 , -1, 2, 0, 1 },
1383 { -1, 2, -1, 2 , -1, 1, 0, 1 },
1384 };
1385
1386 static const struct accu accu_nv12_ilace[4] = {
1387 { 0, 1, 0, 1 , -3, 4, -1, 4 },
1388 { -1, 4, -3, 4 , 0, 1, 0, 1 },
1389 { -1, 1, 0, 1 , -1, 4, -3, 4 },
1390 { -3, 4, -3, 4 , -1, 1, 0, 1 },
1391 };
1392
1393 static const struct accu accu_yuv[4] = {
1394 { 0, 1, 0, 1, 0, 1, 0, 1 },
1395 { 0, 1, 0, 1, 0, 1, 0, 1 },
1396 { -1, 1, 0, 1, 0, 1, 0, 1 },
1397 { 0, 1, 0, 1, -1, 1, 0, 1 },
1398 };
1399
1400 switch (rotation) {
1401 case OMAP_DSS_ROT_0:
1402 idx = 0;
1403 break;
1404 case OMAP_DSS_ROT_90:
1405 idx = 1;
1406 break;
1407 case OMAP_DSS_ROT_180:
1408 idx = 2;
1409 break;
1410 case OMAP_DSS_ROT_270:
1411 idx = 3;
1412 break;
1413 default:
1414 BUG();
1415 return;
1416 }
1417
1418 switch (color_mode) {
1419 case OMAP_DSS_COLOR_NV12:
1420 if (ilace)
1421 accu_table = accu_nv12_ilace;
1422 else
1423 accu_table = accu_nv12;
1424 break;
1425 case OMAP_DSS_COLOR_YUV2:
1426 case OMAP_DSS_COLOR_UYVY:
1427 accu_table = accu_yuv;
1428 break;
1429 default:
1430 BUG();
1431 return;
1432 }
1433
1434 accu_val = &accu_table[idx];
1435
1436 chroma_hinc = 1024 * orig_width / out_width;
1437 chroma_vinc = 1024 * orig_height / out_height;
1438
1439 h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024;
1440 h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024;
1441 v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024;
1442 v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024;
1443
1444 dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0);
1445 dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1);
1446}
1447
1448static void dispc_ovl_set_scaling_common(enum omap_plane plane,
1449 u16 orig_width, u16 orig_height,
1450 u16 out_width, u16 out_height,
1451 bool ilace, bool five_taps,
1452 bool fieldmode, enum omap_color_mode color_mode,
1453 u8 rotation)
1454{
1455 int accu0 = 0;
1456 int accu1 = 0;
1457 u32 l;
1458
1459 dispc_ovl_set_scale_param(plane, orig_width, orig_height,
1460 out_width, out_height, five_taps,
1461 rotation, DISPC_COLOR_COMPONENT_RGB_Y);
1462 l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
1463
1464 /* RESIZEENABLE and VERTICALTAPS */
1465 l &= ~((0x3 << 5) | (0x1 << 21));
1466 l |= (orig_width != out_width) ? (1 << 5) : 0;
1467 l |= (orig_height != out_height) ? (1 << 6) : 0;
1468 l |= five_taps ? (1 << 21) : 0;
1469
1470 /* VRESIZECONF and HRESIZECONF */
1471 if (dss_has_feature(FEAT_RESIZECONF)) {
1472 l &= ~(0x3 << 7);
1473 l |= (orig_width <= out_width) ? 0 : (1 << 7);
1474 l |= (orig_height <= out_height) ? 0 : (1 << 8);
1475 }
1476
1477 /* LINEBUFFERSPLIT */
1478 if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) {
1479 l &= ~(0x1 << 22);
1480 l |= five_taps ? (1 << 22) : 0;
1481 }
1482
1483 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
1484
1485 /*
1486 * field 0 = even field = bottom field
1487 * field 1 = odd field = top field
1488 */
1489 if (ilace && !fieldmode) {
1490 accu1 = 0;
1491 accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff;
1492 if (accu0 >= 1024/2) {
1493 accu1 = 1024/2;
1494 accu0 -= accu1;
1495 }
1496 }
1497
1498 dispc_ovl_set_vid_accu0(plane, 0, accu0);
1499 dispc_ovl_set_vid_accu1(plane, 0, accu1);
1500}
1501
1502static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
1503 u16 orig_width, u16 orig_height,
1504 u16 out_width, u16 out_height,
1505 bool ilace, bool five_taps,
1506 bool fieldmode, enum omap_color_mode color_mode,
1507 u8 rotation)
1508{
1509 int scale_x = out_width != orig_width;
1510 int scale_y = out_height != orig_height;
1511 bool chroma_upscale = plane != OMAP_DSS_WB ? true : false;
1512
1513 if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE))
1514 return;
1515 if ((color_mode != OMAP_DSS_COLOR_YUV2 &&
1516 color_mode != OMAP_DSS_COLOR_UYVY &&
1517 color_mode != OMAP_DSS_COLOR_NV12)) {
1518 /* reset chroma resampling for RGB formats */
1519 if (plane != OMAP_DSS_WB)
1520 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
1521 return;
1522 }
1523
1524 dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width,
1525 out_height, ilace, color_mode, rotation);
1526
1527 switch (color_mode) {
1528 case OMAP_DSS_COLOR_NV12:
1529 if (chroma_upscale) {
1530 /* UV is subsampled by 2 horizontally and vertically */
1531 orig_height >>= 1;
1532 orig_width >>= 1;
1533 } else {
1534 /* UV is downsampled by 2 horizontally and vertically */
1535 orig_height <<= 1;
1536 orig_width <<= 1;
1537 }
1538
1539 break;
1540 case OMAP_DSS_COLOR_YUV2:
1541 case OMAP_DSS_COLOR_UYVY:
1542 /* For YUV422 with 90/270 rotation, we don't upsample chroma */
1543 if (rotation == OMAP_DSS_ROT_0 ||
1544 rotation == OMAP_DSS_ROT_180) {
1545 if (chroma_upscale)
1546 /* UV is subsampled by 2 horizontally */
1547 orig_width >>= 1;
1548 else
1549 /* UV is downsampled by 2 horizontally */
1550 orig_width <<= 1;
1551 }
1552
1553 /* must use FIR for YUV422 if rotated */
1554 if (rotation != OMAP_DSS_ROT_0)
1555 scale_x = scale_y = true;
1556
1557 break;
1558 default:
1559 BUG();
1560 return;
1561 }
1562
1563 if (out_width != orig_width)
1564 scale_x = true;
1565 if (out_height != orig_height)
1566 scale_y = true;
1567
1568 dispc_ovl_set_scale_param(plane, orig_width, orig_height,
1569 out_width, out_height, five_taps,
1570 rotation, DISPC_COLOR_COMPONENT_UV);
1571
1572 if (plane != OMAP_DSS_WB)
1573 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane),
1574 (scale_x || scale_y) ? 1 : 0, 8, 8);
1575
1576 /* set H scaling */
1577 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
1578 /* set V scaling */
1579 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
1580}
1581
1582static void dispc_ovl_set_scaling(enum omap_plane plane,
1583 u16 orig_width, u16 orig_height,
1584 u16 out_width, u16 out_height,
1585 bool ilace, bool five_taps,
1586 bool fieldmode, enum omap_color_mode color_mode,
1587 u8 rotation)
1588{
1589 BUG_ON(plane == OMAP_DSS_GFX);
1590
1591 dispc_ovl_set_scaling_common(plane,
1592 orig_width, orig_height,
1593 out_width, out_height,
1594 ilace, five_taps,
1595 fieldmode, color_mode,
1596 rotation);
1597
1598 dispc_ovl_set_scaling_uv(plane,
1599 orig_width, orig_height,
1600 out_width, out_height,
1601 ilace, five_taps,
1602 fieldmode, color_mode,
1603 rotation);
1604}
1605
1606static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
1607 enum omap_dss_rotation_type rotation_type,
1608 bool mirroring, enum omap_color_mode color_mode)
1609{
1610 bool row_repeat = false;
1611 int vidrot = 0;
1612
1613 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1614 color_mode == OMAP_DSS_COLOR_UYVY) {
1615
1616 if (mirroring) {
1617 switch (rotation) {
1618 case OMAP_DSS_ROT_0:
1619 vidrot = 2;
1620 break;
1621 case OMAP_DSS_ROT_90:
1622 vidrot = 1;
1623 break;
1624 case OMAP_DSS_ROT_180:
1625 vidrot = 0;
1626 break;
1627 case OMAP_DSS_ROT_270:
1628 vidrot = 3;
1629 break;
1630 }
1631 } else {
1632 switch (rotation) {
1633 case OMAP_DSS_ROT_0:
1634 vidrot = 0;
1635 break;
1636 case OMAP_DSS_ROT_90:
1637 vidrot = 1;
1638 break;
1639 case OMAP_DSS_ROT_180:
1640 vidrot = 2;
1641 break;
1642 case OMAP_DSS_ROT_270:
1643 vidrot = 3;
1644 break;
1645 }
1646 }
1647
1648 if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
1649 row_repeat = true;
1650 else
1651 row_repeat = false;
1652 }
1653
1654 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
1655 if (dss_has_feature(FEAT_ROWREPEATENABLE))
1656 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
1657 row_repeat ? 1 : 0, 18, 18);
1658
1659 if (color_mode == OMAP_DSS_COLOR_NV12) {
1660 bool doublestride = (rotation_type == OMAP_DSS_ROT_TILER) &&
1661 (rotation == OMAP_DSS_ROT_0 ||
1662 rotation == OMAP_DSS_ROT_180);
1663 /* DOUBLESTRIDE */
1664 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22);
1665 }
1666
1667}
1668
1669static int color_mode_to_bpp(enum omap_color_mode color_mode)
1670{
1671 switch (color_mode) {
1672 case OMAP_DSS_COLOR_CLUT1:
1673 return 1;
1674 case OMAP_DSS_COLOR_CLUT2:
1675 return 2;
1676 case OMAP_DSS_COLOR_CLUT4:
1677 return 4;
1678 case OMAP_DSS_COLOR_CLUT8:
1679 case OMAP_DSS_COLOR_NV12:
1680 return 8;
1681 case OMAP_DSS_COLOR_RGB12U:
1682 case OMAP_DSS_COLOR_RGB16:
1683 case OMAP_DSS_COLOR_ARGB16:
1684 case OMAP_DSS_COLOR_YUV2:
1685 case OMAP_DSS_COLOR_UYVY:
1686 case OMAP_DSS_COLOR_RGBA16:
1687 case OMAP_DSS_COLOR_RGBX16:
1688 case OMAP_DSS_COLOR_ARGB16_1555:
1689 case OMAP_DSS_COLOR_XRGB16_1555:
1690 return 16;
1691 case OMAP_DSS_COLOR_RGB24P:
1692 return 24;
1693 case OMAP_DSS_COLOR_RGB24U:
1694 case OMAP_DSS_COLOR_ARGB32:
1695 case OMAP_DSS_COLOR_RGBA32:
1696 case OMAP_DSS_COLOR_RGBX32:
1697 return 32;
1698 default:
1699 BUG();
1700 return 0;
1701 }
1702}
1703
1704static s32 pixinc(int pixels, u8 ps)
1705{
1706 if (pixels == 1)
1707 return 1;
1708 else if (pixels > 1)
1709 return 1 + (pixels - 1) * ps;
1710 else if (pixels < 0)
1711 return 1 - (-pixels + 1) * ps;
1712 else
1713 BUG();
1714 return 0;
1715}
1716
1717static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
1718 u16 screen_width,
1719 u16 width, u16 height,
1720 enum omap_color_mode color_mode, bool fieldmode,
1721 unsigned int field_offset,
1722 unsigned *offset0, unsigned *offset1,
1723 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
1724{
1725 u8 ps;
1726
1727 /* FIXME CLUT formats */
1728 switch (color_mode) {
1729 case OMAP_DSS_COLOR_CLUT1:
1730 case OMAP_DSS_COLOR_CLUT2:
1731 case OMAP_DSS_COLOR_CLUT4:
1732 case OMAP_DSS_COLOR_CLUT8:
1733 BUG();
1734 return;
1735 case OMAP_DSS_COLOR_YUV2:
1736 case OMAP_DSS_COLOR_UYVY:
1737 ps = 4;
1738 break;
1739 default:
1740 ps = color_mode_to_bpp(color_mode) / 8;
1741 break;
1742 }
1743
1744 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1745 width, height);
1746
1747 /*
1748 * field 0 = even field = bottom field
1749 * field 1 = odd field = top field
1750 */
1751 switch (rotation + mirror * 4) {
1752 case OMAP_DSS_ROT_0:
1753 case OMAP_DSS_ROT_180:
1754 /*
1755 * If the pixel format is YUV or UYVY divide the width
1756 * of the image by 2 for 0 and 180 degree rotation.
1757 */
1758 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1759 color_mode == OMAP_DSS_COLOR_UYVY)
1760 width = width >> 1;
1761 case OMAP_DSS_ROT_90:
1762 case OMAP_DSS_ROT_270:
1763 *offset1 = 0;
1764 if (field_offset)
1765 *offset0 = field_offset * screen_width * ps;
1766 else
1767 *offset0 = 0;
1768
1769 *row_inc = pixinc(1 +
1770 (y_predecim * screen_width - x_predecim * width) +
1771 (fieldmode ? screen_width : 0), ps);
1772 *pix_inc = pixinc(x_predecim, ps);
1773 break;
1774
1775 case OMAP_DSS_ROT_0 + 4:
1776 case OMAP_DSS_ROT_180 + 4:
1777 /* If the pixel format is YUV or UYVY divide the width
1778 * of the image by 2 for 0 degree and 180 degree
1779 */
1780 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1781 color_mode == OMAP_DSS_COLOR_UYVY)
1782 width = width >> 1;
1783 case OMAP_DSS_ROT_90 + 4:
1784 case OMAP_DSS_ROT_270 + 4:
1785 *offset1 = 0;
1786 if (field_offset)
1787 *offset0 = field_offset * screen_width * ps;
1788 else
1789 *offset0 = 0;
1790 *row_inc = pixinc(1 -
1791 (y_predecim * screen_width + x_predecim * width) -
1792 (fieldmode ? screen_width : 0), ps);
1793 *pix_inc = pixinc(x_predecim, ps);
1794 break;
1795
1796 default:
1797 BUG();
1798 return;
1799 }
1800}
1801
1802static void calc_dma_rotation_offset(u8 rotation, bool mirror,
1803 u16 screen_width,
1804 u16 width, u16 height,
1805 enum omap_color_mode color_mode, bool fieldmode,
1806 unsigned int field_offset,
1807 unsigned *offset0, unsigned *offset1,
1808 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
1809{
1810 u8 ps;
1811 u16 fbw, fbh;
1812
1813 /* FIXME CLUT formats */
1814 switch (color_mode) {
1815 case OMAP_DSS_COLOR_CLUT1:
1816 case OMAP_DSS_COLOR_CLUT2:
1817 case OMAP_DSS_COLOR_CLUT4:
1818 case OMAP_DSS_COLOR_CLUT8:
1819 BUG();
1820 return;
1821 default:
1822 ps = color_mode_to_bpp(color_mode) / 8;
1823 break;
1824 }
1825
1826 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1827 width, height);
1828
1829 /* width & height are overlay sizes, convert to fb sizes */
1830
1831 if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) {
1832 fbw = width;
1833 fbh = height;
1834 } else {
1835 fbw = height;
1836 fbh = width;
1837 }
1838
1839 /*
1840 * field 0 = even field = bottom field
1841 * field 1 = odd field = top field
1842 */
1843 switch (rotation + mirror * 4) {
1844 case OMAP_DSS_ROT_0:
1845 *offset1 = 0;
1846 if (field_offset)
1847 *offset0 = *offset1 + field_offset * screen_width * ps;
1848 else
1849 *offset0 = *offset1;
1850 *row_inc = pixinc(1 +
1851 (y_predecim * screen_width - fbw * x_predecim) +
1852 (fieldmode ? screen_width : 0), ps);
1853 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1854 color_mode == OMAP_DSS_COLOR_UYVY)
1855 *pix_inc = pixinc(x_predecim, 2 * ps);
1856 else
1857 *pix_inc = pixinc(x_predecim, ps);
1858 break;
1859 case OMAP_DSS_ROT_90:
1860 *offset1 = screen_width * (fbh - 1) * ps;
1861 if (field_offset)
1862 *offset0 = *offset1 + field_offset * ps;
1863 else
1864 *offset0 = *offset1;
1865 *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) +
1866 y_predecim + (fieldmode ? 1 : 0), ps);
1867 *pix_inc = pixinc(-x_predecim * screen_width, ps);
1868 break;
1869 case OMAP_DSS_ROT_180:
1870 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1871 if (field_offset)
1872 *offset0 = *offset1 - field_offset * screen_width * ps;
1873 else
1874 *offset0 = *offset1;
1875 *row_inc = pixinc(-1 -
1876 (y_predecim * screen_width - fbw * x_predecim) -
1877 (fieldmode ? screen_width : 0), ps);
1878 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1879 color_mode == OMAP_DSS_COLOR_UYVY)
1880 *pix_inc = pixinc(-x_predecim, 2 * ps);
1881 else
1882 *pix_inc = pixinc(-x_predecim, ps);
1883 break;
1884 case OMAP_DSS_ROT_270:
1885 *offset1 = (fbw - 1) * ps;
1886 if (field_offset)
1887 *offset0 = *offset1 - field_offset * ps;
1888 else
1889 *offset0 = *offset1;
1890 *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) -
1891 y_predecim - (fieldmode ? 1 : 0), ps);
1892 *pix_inc = pixinc(x_predecim * screen_width, ps);
1893 break;
1894
1895 /* mirroring */
1896 case OMAP_DSS_ROT_0 + 4:
1897 *offset1 = (fbw - 1) * ps;
1898 if (field_offset)
1899 *offset0 = *offset1 + field_offset * screen_width * ps;
1900 else
1901 *offset0 = *offset1;
1902 *row_inc = pixinc(y_predecim * screen_width * 2 - 1 +
1903 (fieldmode ? screen_width : 0),
1904 ps);
1905 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1906 color_mode == OMAP_DSS_COLOR_UYVY)
1907 *pix_inc = pixinc(-x_predecim, 2 * ps);
1908 else
1909 *pix_inc = pixinc(-x_predecim, ps);
1910 break;
1911
1912 case OMAP_DSS_ROT_90 + 4:
1913 *offset1 = 0;
1914 if (field_offset)
1915 *offset0 = *offset1 + field_offset * ps;
1916 else
1917 *offset0 = *offset1;
1918 *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) +
1919 y_predecim + (fieldmode ? 1 : 0),
1920 ps);
1921 *pix_inc = pixinc(x_predecim * screen_width, ps);
1922 break;
1923
1924 case OMAP_DSS_ROT_180 + 4:
1925 *offset1 = screen_width * (fbh - 1) * ps;
1926 if (field_offset)
1927 *offset0 = *offset1 - field_offset * screen_width * ps;
1928 else
1929 *offset0 = *offset1;
1930 *row_inc = pixinc(1 - y_predecim * screen_width * 2 -
1931 (fieldmode ? screen_width : 0),
1932 ps);
1933 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1934 color_mode == OMAP_DSS_COLOR_UYVY)
1935 *pix_inc = pixinc(x_predecim, 2 * ps);
1936 else
1937 *pix_inc = pixinc(x_predecim, ps);
1938 break;
1939
1940 case OMAP_DSS_ROT_270 + 4:
1941 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1942 if (field_offset)
1943 *offset0 = *offset1 - field_offset * ps;
1944 else
1945 *offset0 = *offset1;
1946 *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) -
1947 y_predecim - (fieldmode ? 1 : 0),
1948 ps);
1949 *pix_inc = pixinc(-x_predecim * screen_width, ps);
1950 break;
1951
1952 default:
1953 BUG();
1954 return;
1955 }
1956}
1957
1958static void calc_tiler_rotation_offset(u16 screen_width, u16 width,
1959 enum omap_color_mode color_mode, bool fieldmode,
1960 unsigned int field_offset, unsigned *offset0, unsigned *offset1,
1961 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
1962{
1963 u8 ps;
1964
1965 switch (color_mode) {
1966 case OMAP_DSS_COLOR_CLUT1:
1967 case OMAP_DSS_COLOR_CLUT2:
1968 case OMAP_DSS_COLOR_CLUT4:
1969 case OMAP_DSS_COLOR_CLUT8:
1970 BUG();
1971 return;
1972 default:
1973 ps = color_mode_to_bpp(color_mode) / 8;
1974 break;
1975 }
1976
1977 DSSDBG("scrw %d, width %d\n", screen_width, width);
1978
1979 /*
1980 * field 0 = even field = bottom field
1981 * field 1 = odd field = top field
1982 */
1983 *offset1 = 0;
1984 if (field_offset)
1985 *offset0 = *offset1 + field_offset * screen_width * ps;
1986 else
1987 *offset0 = *offset1;
1988 *row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) +
1989 (fieldmode ? screen_width : 0), ps);
1990 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1991 color_mode == OMAP_DSS_COLOR_UYVY)
1992 *pix_inc = pixinc(x_predecim, 2 * ps);
1993 else
1994 *pix_inc = pixinc(x_predecim, ps);
1995}
1996
1997/*
1998 * This function is used to avoid synclosts in OMAP3, because of some
1999 * undocumented horizontal position and timing related limitations.
2000 */
2001static int check_horiz_timing_omap3(unsigned long pclk, unsigned long lclk,
2002 const struct omap_video_timings *t, u16 pos_x,
2003 u16 width, u16 height, u16 out_width, u16 out_height,
2004 bool five_taps)
2005{
2006 const int ds = DIV_ROUND_UP(height, out_height);
2007 unsigned long nonactive;
2008 static const u8 limits[3] = { 8, 10, 20 };
2009 u64 val, blank;
2010 int i;
2011
2012 nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width;
2013
2014 i = 0;
2015 if (out_height < height)
2016 i++;
2017 if (out_width < width)
2018 i++;
2019 blank = div_u64((u64)(t->hbp + t->hsw + t->hfp) * lclk, pclk);
2020 DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]);
2021 if (blank <= limits[i])
2022 return -EINVAL;
2023
2024 /* FIXME add checks for 3-tap filter once the limitations are known */
2025 if (!five_taps)
2026 return 0;
2027
2028 /*
2029 * Pixel data should be prepared before visible display point starts.
2030 * So, atleast DS-2 lines must have already been fetched by DISPC
2031 * during nonactive - pos_x period.
2032 */
2033 val = div_u64((u64)(nonactive - pos_x) * lclk, pclk);
2034 DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n",
2035 val, max(0, ds - 2) * width);
2036 if (val < max(0, ds - 2) * width)
2037 return -EINVAL;
2038
2039 /*
2040 * All lines need to be refilled during the nonactive period of which
2041 * only one line can be loaded during the active period. So, atleast
2042 * DS - 1 lines should be loaded during nonactive period.
2043 */
2044 val = div_u64((u64)nonactive * lclk, pclk);
2045 DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n",
2046 val, max(0, ds - 1) * width);
2047 if (val < max(0, ds - 1) * width)
2048 return -EINVAL;
2049
2050 return 0;
2051}
2052
2053static unsigned long calc_core_clk_five_taps(unsigned long pclk,
2054 const struct omap_video_timings *mgr_timings, u16 width,
2055 u16 height, u16 out_width, u16 out_height,
2056 enum omap_color_mode color_mode)
2057{
2058 u32 core_clk = 0;
2059 u64 tmp;
2060
2061 if (height <= out_height && width <= out_width)
2062 return (unsigned long) pclk;
2063
2064 if (height > out_height) {
2065 unsigned int ppl = mgr_timings->x_res;
2066
2067 tmp = pclk * height * out_width;
2068 do_div(tmp, 2 * out_height * ppl);
2069 core_clk = tmp;
2070
2071 if (height > 2 * out_height) {
2072 if (ppl == out_width)
2073 return 0;
2074
2075 tmp = pclk * (height - 2 * out_height) * out_width;
2076 do_div(tmp, 2 * out_height * (ppl - out_width));
2077 core_clk = max_t(u32, core_clk, tmp);
2078 }
2079 }
2080
2081 if (width > out_width) {
2082 tmp = pclk * width;
2083 do_div(tmp, out_width);
2084 core_clk = max_t(u32, core_clk, tmp);
2085
2086 if (color_mode == OMAP_DSS_COLOR_RGB24U)
2087 core_clk <<= 1;
2088 }
2089
2090 return core_clk;
2091}
2092
2093static unsigned long calc_core_clk_24xx(unsigned long pclk, u16 width,
2094 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
2095{
2096 if (height > out_height && width > out_width)
2097 return pclk * 4;
2098 else
2099 return pclk * 2;
2100}
2101
2102static unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width,
2103 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
2104{
2105 unsigned int hf, vf;
2106
2107 /*
2108 * FIXME how to determine the 'A' factor
2109 * for the no downscaling case ?
2110 */
2111
2112 if (width > 3 * out_width)
2113 hf = 4;
2114 else if (width > 2 * out_width)
2115 hf = 3;
2116 else if (width > out_width)
2117 hf = 2;
2118 else
2119 hf = 1;
2120 if (height > out_height)
2121 vf = 2;
2122 else
2123 vf = 1;
2124
2125 return pclk * vf * hf;
2126}
2127
2128static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width,
2129 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
2130{
2131 /*
2132 * If the overlay/writeback is in mem to mem mode, there are no
2133 * downscaling limitations with respect to pixel clock, return 1 as
2134 * required core clock to represent that we have sufficient enough
2135 * core clock to do maximum downscaling
2136 */
2137 if (mem_to_mem)
2138 return 1;
2139
2140 if (width > out_width)
2141 return DIV_ROUND_UP(pclk, out_width) * width;
2142 else
2143 return pclk;
2144}
2145
2146static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk,
2147 const struct omap_video_timings *mgr_timings,
2148 u16 width, u16 height, u16 out_width, u16 out_height,
2149 enum omap_color_mode color_mode, bool *five_taps,
2150 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
2151 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
2152{
2153 int error;
2154 u16 in_width, in_height;
2155 int min_factor = min(*decim_x, *decim_y);
2156 const int maxsinglelinewidth =
2157 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
2158
2159 *five_taps = false;
2160
2161 do {
2162 in_height = height / *decim_y;
2163 in_width = width / *decim_x;
2164 *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
2165 in_height, out_width, out_height, mem_to_mem);
2166 error = (in_width > maxsinglelinewidth || !*core_clk ||
2167 *core_clk > dispc_core_clk_rate());
2168 if (error) {
2169 if (*decim_x == *decim_y) {
2170 *decim_x = min_factor;
2171 ++*decim_y;
2172 } else {
2173 swap(*decim_x, *decim_y);
2174 if (*decim_x < *decim_y)
2175 ++*decim_x;
2176 }
2177 }
2178 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2179
2180 if (in_width > maxsinglelinewidth) {
2181 DSSERR("Cannot scale max input width exceeded");
2182 return -EINVAL;
2183 }
2184 return 0;
2185}
2186
2187static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk,
2188 const struct omap_video_timings *mgr_timings,
2189 u16 width, u16 height, u16 out_width, u16 out_height,
2190 enum omap_color_mode color_mode, bool *five_taps,
2191 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
2192 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
2193{
2194 int error;
2195 u16 in_width, in_height;
2196 int min_factor = min(*decim_x, *decim_y);
2197 const int maxsinglelinewidth =
2198 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
2199
2200 do {
2201 in_height = height / *decim_y;
2202 in_width = width / *decim_x;
2203 *five_taps = in_height > out_height;
2204
2205 if (in_width > maxsinglelinewidth)
2206 if (in_height > out_height &&
2207 in_height < out_height * 2)
2208 *five_taps = false;
2209again:
2210 if (*five_taps)
2211 *core_clk = calc_core_clk_five_taps(pclk, mgr_timings,
2212 in_width, in_height, out_width,
2213 out_height, color_mode);
2214 else
2215 *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
2216 in_height, out_width, out_height,
2217 mem_to_mem);
2218
2219 error = check_horiz_timing_omap3(pclk, lclk, mgr_timings,
2220 pos_x, in_width, in_height, out_width,
2221 out_height, *five_taps);
2222 if (error && *five_taps) {
2223 *five_taps = false;
2224 goto again;
2225 }
2226
2227 error = (error || in_width > maxsinglelinewidth * 2 ||
2228 (in_width > maxsinglelinewidth && *five_taps) ||
2229 !*core_clk || *core_clk > dispc_core_clk_rate());
2230 if (error) {
2231 if (*decim_x == *decim_y) {
2232 *decim_x = min_factor;
2233 ++*decim_y;
2234 } else {
2235 swap(*decim_x, *decim_y);
2236 if (*decim_x < *decim_y)
2237 ++*decim_x;
2238 }
2239 }
2240 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2241
2242 if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, width,
2243 height, out_width, out_height, *five_taps)) {
2244 DSSERR("horizontal timing too tight\n");
2245 return -EINVAL;
2246 }
2247
2248 if (in_width > (maxsinglelinewidth * 2)) {
2249 DSSERR("Cannot setup scaling");
2250 DSSERR("width exceeds maximum width possible");
2251 return -EINVAL;
2252 }
2253
2254 if (in_width > maxsinglelinewidth && *five_taps) {
2255 DSSERR("cannot setup scaling with five taps");
2256 return -EINVAL;
2257 }
2258 return 0;
2259}
2260
2261static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk,
2262 const struct omap_video_timings *mgr_timings,
2263 u16 width, u16 height, u16 out_width, u16 out_height,
2264 enum omap_color_mode color_mode, bool *five_taps,
2265 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
2266 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
2267{
2268 u16 in_width, in_width_max;
2269 int decim_x_min = *decim_x;
2270 u16 in_height = height / *decim_y;
2271 const int maxsinglelinewidth =
2272 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
2273 const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
2274
2275 if (mem_to_mem) {
2276 in_width_max = out_width * maxdownscale;
2277 } else {
2278 in_width_max = dispc_core_clk_rate() /
2279 DIV_ROUND_UP(pclk, out_width);
2280 }
2281
2282 *decim_x = DIV_ROUND_UP(width, in_width_max);
2283
2284 *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
2285 if (*decim_x > *x_predecim)
2286 return -EINVAL;
2287
2288 do {
2289 in_width = width / *decim_x;
2290 } while (*decim_x <= *x_predecim &&
2291 in_width > maxsinglelinewidth && ++*decim_x);
2292
2293 if (in_width > maxsinglelinewidth) {
2294 DSSERR("Cannot scale width exceeds max line width");
2295 return -EINVAL;
2296 }
2297
2298 *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height,
2299 out_width, out_height, mem_to_mem);
2300 return 0;
2301}
2302
2303static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk,
2304 enum omap_overlay_caps caps,
2305 const struct omap_video_timings *mgr_timings,
2306 u16 width, u16 height, u16 out_width, u16 out_height,
2307 enum omap_color_mode color_mode, bool *five_taps,
2308 int *x_predecim, int *y_predecim, u16 pos_x,
2309 enum omap_dss_rotation_type rotation_type, bool mem_to_mem)
2310{
2311 const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
2312 const int max_decim_limit = 16;
2313 unsigned long core_clk = 0;
2314 int decim_x, decim_y, ret;
2315
2316 if (width == out_width && height == out_height)
2317 return 0;
2318
2319 if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
2320 return -EINVAL;
2321
2322 if (mem_to_mem) {
2323 *x_predecim = *y_predecim = 1;
2324 } else {
2325 *x_predecim = max_decim_limit;
2326 *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER &&
2327 dss_has_feature(FEAT_BURST_2D)) ?
2328 2 : max_decim_limit;
2329 }
2330
2331 if (color_mode == OMAP_DSS_COLOR_CLUT1 ||
2332 color_mode == OMAP_DSS_COLOR_CLUT2 ||
2333 color_mode == OMAP_DSS_COLOR_CLUT4 ||
2334 color_mode == OMAP_DSS_COLOR_CLUT8) {
2335 *x_predecim = 1;
2336 *y_predecim = 1;
2337 *five_taps = false;
2338 return 0;
2339 }
2340
2341 decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
2342 decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
2343
2344 if (decim_x > *x_predecim || out_width > width * 8)
2345 return -EINVAL;
2346
2347 if (decim_y > *y_predecim || out_height > height * 8)
2348 return -EINVAL;
2349
2350 ret = dispc.feat->calc_scaling(pclk, lclk, mgr_timings, width, height,
2351 out_width, out_height, color_mode, five_taps,
2352 x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk,
2353 mem_to_mem);
2354 if (ret)
2355 return ret;
2356
2357 DSSDBG("required core clk rate = %lu Hz\n", core_clk);
2358 DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate());
2359
2360 if (!core_clk || core_clk > dispc_core_clk_rate()) {
2361 DSSERR("failed to set up scaling, "
2362 "required core clk rate = %lu Hz, "
2363 "current core clk rate = %lu Hz\n",
2364 core_clk, dispc_core_clk_rate());
2365 return -EINVAL;
2366 }
2367
2368 *x_predecim = decim_x;
2369 *y_predecim = decim_y;
2370 return 0;
2371}
2372
2373int dispc_ovl_check(enum omap_plane plane, enum omap_channel channel,
2374 const struct omap_overlay_info *oi,
2375 const struct omap_video_timings *timings,
2376 int *x_predecim, int *y_predecim)
2377{
2378 enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane);
2379 bool five_taps = true;
2380 bool fieldmode = false;
2381 u16 in_height = oi->height;
2382 u16 in_width = oi->width;
2383 bool ilace = timings->interlace;
2384 u16 out_width, out_height;
2385 int pos_x = oi->pos_x;
2386 unsigned long pclk = dispc_mgr_pclk_rate(channel);
2387 unsigned long lclk = dispc_mgr_lclk_rate(channel);
2388
2389 out_width = oi->out_width == 0 ? oi->width : oi->out_width;
2390 out_height = oi->out_height == 0 ? oi->height : oi->out_height;
2391
2392 if (ilace && oi->height == out_height)
2393 fieldmode = true;
2394
2395 if (ilace) {
2396 if (fieldmode)
2397 in_height /= 2;
2398 out_height /= 2;
2399
2400 DSSDBG("adjusting for ilace: height %d, out_height %d\n",
2401 in_height, out_height);
2402 }
2403
2404 if (!dss_feat_color_mode_supported(plane, oi->color_mode))
2405 return -EINVAL;
2406
2407 return dispc_ovl_calc_scaling(pclk, lclk, caps, timings, in_width,
2408 in_height, out_width, out_height, oi->color_mode,
2409 &five_taps, x_predecim, y_predecim, pos_x,
2410 oi->rotation_type, false);
2411}
2412EXPORT_SYMBOL(dispc_ovl_check);
2413
2414static int dispc_ovl_setup_common(enum omap_plane plane,
2415 enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr,
2416 u16 screen_width, int pos_x, int pos_y, u16 width, u16 height,
2417 u16 out_width, u16 out_height, enum omap_color_mode color_mode,
2418 u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha,
2419 u8 global_alpha, enum omap_dss_rotation_type rotation_type,
2420 bool replication, const struct omap_video_timings *mgr_timings,
2421 bool mem_to_mem)
2422{
2423 bool five_taps = true;
2424 bool fieldmode = false;
2425 int r, cconv = 0;
2426 unsigned offset0, offset1;
2427 s32 row_inc;
2428 s32 pix_inc;
2429 u16 frame_width, frame_height;
2430 unsigned int field_offset = 0;
2431 u16 in_height = height;
2432 u16 in_width = width;
2433 int x_predecim = 1, y_predecim = 1;
2434 bool ilace = mgr_timings->interlace;
2435 unsigned long pclk = dispc_plane_pclk_rate(plane);
2436 unsigned long lclk = dispc_plane_lclk_rate(plane);
2437
2438 if (paddr == 0)
2439 return -EINVAL;
2440
2441 out_width = out_width == 0 ? width : out_width;
2442 out_height = out_height == 0 ? height : out_height;
2443
2444 if (ilace && height == out_height)
2445 fieldmode = true;
2446
2447 if (ilace) {
2448 if (fieldmode)
2449 in_height /= 2;
2450 pos_y /= 2;
2451 out_height /= 2;
2452
2453 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
2454 "out_height %d\n", in_height, pos_y,
2455 out_height);
2456 }
2457
2458 if (!dss_feat_color_mode_supported(plane, color_mode))
2459 return -EINVAL;
2460
2461 r = dispc_ovl_calc_scaling(pclk, lclk, caps, mgr_timings, in_width,
2462 in_height, out_width, out_height, color_mode,
2463 &five_taps, &x_predecim, &y_predecim, pos_x,
2464 rotation_type, mem_to_mem);
2465 if (r)
2466 return r;
2467
2468 in_width = in_width / x_predecim;
2469 in_height = in_height / y_predecim;
2470
2471 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2472 color_mode == OMAP_DSS_COLOR_UYVY ||
2473 color_mode == OMAP_DSS_COLOR_NV12)
2474 cconv = 1;
2475
2476 if (ilace && !fieldmode) {
2477 /*
2478 * when downscaling the bottom field may have to start several
2479 * source lines below the top field. Unfortunately ACCUI
2480 * registers will only hold the fractional part of the offset
2481 * so the integer part must be added to the base address of the
2482 * bottom field.
2483 */
2484 if (!in_height || in_height == out_height)
2485 field_offset = 0;
2486 else
2487 field_offset = in_height / out_height / 2;
2488 }
2489
2490 /* Fields are independent but interleaved in memory. */
2491 if (fieldmode)
2492 field_offset = 1;
2493
2494 offset0 = 0;
2495 offset1 = 0;
2496 row_inc = 0;
2497 pix_inc = 0;
2498
2499 if (plane == OMAP_DSS_WB) {
2500 frame_width = out_width;
2501 frame_height = out_height;
2502 } else {
2503 frame_width = in_width;
2504 frame_height = height;
2505 }
2506
2507 if (rotation_type == OMAP_DSS_ROT_TILER)
2508 calc_tiler_rotation_offset(screen_width, frame_width,
2509 color_mode, fieldmode, field_offset,
2510 &offset0, &offset1, &row_inc, &pix_inc,
2511 x_predecim, y_predecim);
2512 else if (rotation_type == OMAP_DSS_ROT_DMA)
2513 calc_dma_rotation_offset(rotation, mirror, screen_width,
2514 frame_width, frame_height,
2515 color_mode, fieldmode, field_offset,
2516 &offset0, &offset1, &row_inc, &pix_inc,
2517 x_predecim, y_predecim);
2518 else
2519 calc_vrfb_rotation_offset(rotation, mirror,
2520 screen_width, frame_width, frame_height,
2521 color_mode, fieldmode, field_offset,
2522 &offset0, &offset1, &row_inc, &pix_inc,
2523 x_predecim, y_predecim);
2524
2525 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
2526 offset0, offset1, row_inc, pix_inc);
2527
2528 dispc_ovl_set_color_mode(plane, color_mode);
2529
2530 dispc_ovl_configure_burst_type(plane, rotation_type);
2531
2532 dispc_ovl_set_ba0(plane, paddr + offset0);
2533 dispc_ovl_set_ba1(plane, paddr + offset1);
2534
2535 if (OMAP_DSS_COLOR_NV12 == color_mode) {
2536 dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0);
2537 dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1);
2538 }
2539
2540 dispc_ovl_set_row_inc(plane, row_inc);
2541 dispc_ovl_set_pix_inc(plane, pix_inc);
2542
2543 DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width,
2544 in_height, out_width, out_height);
2545
2546 dispc_ovl_set_pos(plane, caps, pos_x, pos_y);
2547
2548 dispc_ovl_set_input_size(plane, in_width, in_height);
2549
2550 if (caps & OMAP_DSS_OVL_CAP_SCALE) {
2551 dispc_ovl_set_scaling(plane, in_width, in_height, out_width,
2552 out_height, ilace, five_taps, fieldmode,
2553 color_mode, rotation);
2554 dispc_ovl_set_output_size(plane, out_width, out_height);
2555 dispc_ovl_set_vid_color_conv(plane, cconv);
2556 }
2557
2558 dispc_ovl_set_rotation_attrs(plane, rotation, rotation_type, mirror,
2559 color_mode);
2560
2561 dispc_ovl_set_zorder(plane, caps, zorder);
2562 dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha);
2563 dispc_ovl_setup_global_alpha(plane, caps, global_alpha);
2564
2565 dispc_ovl_enable_replication(plane, caps, replication);
2566
2567 return 0;
2568}
2569
2570int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
2571 bool replication, const struct omap_video_timings *mgr_timings,
2572 bool mem_to_mem)
2573{
2574 int r;
2575 enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane);
2576 enum omap_channel channel;
2577
2578 channel = dispc_ovl_get_channel_out(plane);
2579
2580 DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
2581 "%dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n",
2582 plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x,
2583 oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height,
2584 oi->color_mode, oi->rotation, oi->mirror, channel, replication);
2585
2586 r = dispc_ovl_setup_common(plane, caps, oi->paddr, oi->p_uv_addr,
2587 oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
2588 oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
2589 oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha,
2590 oi->rotation_type, replication, mgr_timings, mem_to_mem);
2591
2592 return r;
2593}
2594EXPORT_SYMBOL(dispc_ovl_setup);
2595
2596int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
2597 bool mem_to_mem, const struct omap_video_timings *mgr_timings)
2598{
2599 int r;
2600 u32 l;
2601 enum omap_plane plane = OMAP_DSS_WB;
2602 const int pos_x = 0, pos_y = 0;
2603 const u8 zorder = 0, global_alpha = 0;
2604 const bool replication = false;
2605 bool truncation;
2606 int in_width = mgr_timings->x_res;
2607 int in_height = mgr_timings->y_res;
2608 enum omap_overlay_caps caps =
2609 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA;
2610
2611 DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, "
2612 "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width,
2613 in_height, wi->width, wi->height, wi->color_mode, wi->rotation,
2614 wi->mirror);
2615
2616 r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr,
2617 wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width,
2618 wi->height, wi->color_mode, wi->rotation, wi->mirror, zorder,
2619 wi->pre_mult_alpha, global_alpha, wi->rotation_type,
2620 replication, mgr_timings, mem_to_mem);
2621
2622 switch (wi->color_mode) {
2623 case OMAP_DSS_COLOR_RGB16:
2624 case OMAP_DSS_COLOR_RGB24P:
2625 case OMAP_DSS_COLOR_ARGB16:
2626 case OMAP_DSS_COLOR_RGBA16:
2627 case OMAP_DSS_COLOR_RGB12U:
2628 case OMAP_DSS_COLOR_ARGB16_1555:
2629 case OMAP_DSS_COLOR_XRGB16_1555:
2630 case OMAP_DSS_COLOR_RGBX16:
2631 truncation = true;
2632 break;
2633 default:
2634 truncation = false;
2635 break;
2636 }
2637
2638 /* setup extra DISPC_WB_ATTRIBUTES */
2639 l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
2640 l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */
2641 l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */
2642 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
2643
2644 return r;
2645}
2646
2647int dispc_ovl_enable(enum omap_plane plane, bool enable)
2648{
2649 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
2650
2651 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
2652
2653 return 0;
2654}
2655EXPORT_SYMBOL(dispc_ovl_enable);
2656
2657bool dispc_ovl_enabled(enum omap_plane plane)
2658{
2659 return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0);
2660}
2661EXPORT_SYMBOL(dispc_ovl_enabled);
2662
2663void dispc_mgr_enable(enum omap_channel channel, bool enable)
2664{
2665 mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable);
2666 /* flush posted write */
2667 mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
2668}
2669EXPORT_SYMBOL(dispc_mgr_enable);
2670
2671bool dispc_mgr_is_enabled(enum omap_channel channel)
2672{
2673 return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
2674}
2675EXPORT_SYMBOL(dispc_mgr_is_enabled);
2676
2677void dispc_wb_enable(bool enable)
2678{
2679 dispc_ovl_enable(OMAP_DSS_WB, enable);
2680}
2681
2682bool dispc_wb_is_enabled(void)
2683{
2684 return dispc_ovl_enabled(OMAP_DSS_WB);
2685}
2686
2687static void dispc_lcd_enable_signal_polarity(bool act_high)
2688{
2689 if (!dss_has_feature(FEAT_LCDENABLEPOL))
2690 return;
2691
2692 REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
2693}
2694
2695void dispc_lcd_enable_signal(bool enable)
2696{
2697 if (!dss_has_feature(FEAT_LCDENABLESIGNAL))
2698 return;
2699
2700 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
2701}
2702
2703void dispc_pck_free_enable(bool enable)
2704{
2705 if (!dss_has_feature(FEAT_PCKFREEENABLE))
2706 return;
2707
2708 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
2709}
2710
2711static void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable)
2712{
2713 mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable);
2714}
2715
2716
2717static void dispc_mgr_set_lcd_type_tft(enum omap_channel channel)
2718{
2719 mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1);
2720}
2721
2722void dispc_set_loadmode(enum omap_dss_load_mode mode)
2723{
2724 REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
2725}
2726
2727
2728static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color)
2729{
2730 dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
2731}
2732
2733static void dispc_mgr_set_trans_key(enum omap_channel ch,
2734 enum omap_dss_trans_key_type type,
2735 u32 trans_key)
2736{
2737 mgr_fld_write(ch, DISPC_MGR_FLD_TCKSELECTION, type);
2738
2739 dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
2740}
2741
2742static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
2743{
2744 mgr_fld_write(ch, DISPC_MGR_FLD_TCKENABLE, enable);
2745}
2746
2747static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch,
2748 bool enable)
2749{
2750 if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
2751 return;
2752
2753 if (ch == OMAP_DSS_CHANNEL_LCD)
2754 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
2755 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2756 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
2757}
2758
2759void dispc_mgr_setup(enum omap_channel channel,
2760 const struct omap_overlay_manager_info *info)
2761{
2762 dispc_mgr_set_default_color(channel, info->default_color);
2763 dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key);
2764 dispc_mgr_enable_trans_key(channel, info->trans_enabled);
2765 dispc_mgr_enable_alpha_fixed_zorder(channel,
2766 info->partial_alpha_enabled);
2767 if (dss_has_feature(FEAT_CPR)) {
2768 dispc_mgr_enable_cpr(channel, info->cpr_enable);
2769 dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs);
2770 }
2771}
2772EXPORT_SYMBOL(dispc_mgr_setup);
2773
2774static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
2775{
2776 int code;
2777
2778 switch (data_lines) {
2779 case 12:
2780 code = 0;
2781 break;
2782 case 16:
2783 code = 1;
2784 break;
2785 case 18:
2786 code = 2;
2787 break;
2788 case 24:
2789 code = 3;
2790 break;
2791 default:
2792 BUG();
2793 return;
2794 }
2795
2796 mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code);
2797}
2798
2799static void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode)
2800{
2801 u32 l;
2802 int gpout0, gpout1;
2803
2804 switch (mode) {
2805 case DSS_IO_PAD_MODE_RESET:
2806 gpout0 = 0;
2807 gpout1 = 0;
2808 break;
2809 case DSS_IO_PAD_MODE_RFBI:
2810 gpout0 = 1;
2811 gpout1 = 0;
2812 break;
2813 case DSS_IO_PAD_MODE_BYPASS:
2814 gpout0 = 1;
2815 gpout1 = 1;
2816 break;
2817 default:
2818 BUG();
2819 return;
2820 }
2821
2822 l = dispc_read_reg(DISPC_CONTROL);
2823 l = FLD_MOD(l, gpout0, 15, 15);
2824 l = FLD_MOD(l, gpout1, 16, 16);
2825 dispc_write_reg(DISPC_CONTROL, l);
2826}
2827
2828static void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable)
2829{
2830 mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable);
2831}
2832
2833void dispc_mgr_set_lcd_config(enum omap_channel channel,
2834 const struct dss_lcd_mgr_config *config)
2835{
2836 dispc_mgr_set_io_pad_mode(config->io_pad_mode);
2837
2838 dispc_mgr_enable_stallmode(channel, config->stallmode);
2839 dispc_mgr_enable_fifohandcheck(channel, config->fifohandcheck);
2840
2841 dispc_mgr_set_clock_div(channel, &config->clock_info);
2842
2843 dispc_mgr_set_tft_data_lines(channel, config->video_port_width);
2844
2845 dispc_lcd_enable_signal_polarity(config->lcden_sig_polarity);
2846
2847 dispc_mgr_set_lcd_type_tft(channel);
2848}
2849EXPORT_SYMBOL(dispc_mgr_set_lcd_config);
2850
2851static bool _dispc_mgr_size_ok(u16 width, u16 height)
2852{
2853 return width <= dispc.feat->mgr_width_max &&
2854 height <= dispc.feat->mgr_height_max;
2855}
2856
2857static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
2858 int vsw, int vfp, int vbp)
2859{
2860 if (hsw < 1 || hsw > dispc.feat->sw_max ||
2861 hfp < 1 || hfp > dispc.feat->hp_max ||
2862 hbp < 1 || hbp > dispc.feat->hp_max ||
2863 vsw < 1 || vsw > dispc.feat->sw_max ||
2864 vfp < 0 || vfp > dispc.feat->vp_max ||
2865 vbp < 0 || vbp > dispc.feat->vp_max)
2866 return false;
2867 return true;
2868}
2869
2870static bool _dispc_mgr_pclk_ok(enum omap_channel channel,
2871 unsigned long pclk)
2872{
2873 if (dss_mgr_is_lcd(channel))
2874 return pclk <= dispc.feat->max_lcd_pclk ? true : false;
2875 else
2876 return pclk <= dispc.feat->max_tv_pclk ? true : false;
2877}
2878
2879bool dispc_mgr_timings_ok(enum omap_channel channel,
2880 const struct omap_video_timings *timings)
2881{
2882 bool timings_ok;
2883
2884 timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res);
2885
2886 timings_ok &= _dispc_mgr_pclk_ok(channel, timings->pixelclock);
2887
2888 if (dss_mgr_is_lcd(channel)) {
2889 timings_ok &= _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2890 timings->hbp, timings->vsw, timings->vfp,
2891 timings->vbp);
2892 }
2893
2894 return timings_ok;
2895}
2896
2897static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
2898 int hfp, int hbp, int vsw, int vfp, int vbp,
2899 enum omap_dss_signal_level vsync_level,
2900 enum omap_dss_signal_level hsync_level,
2901 enum omap_dss_signal_edge data_pclk_edge,
2902 enum omap_dss_signal_level de_level,
2903 enum omap_dss_signal_edge sync_pclk_edge)
2904
2905{
2906 u32 timing_h, timing_v, l;
2907 bool onoff, rf, ipc;
2908
2909 timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) |
2910 FLD_VAL(hfp-1, dispc.feat->fp_start, 8) |
2911 FLD_VAL(hbp-1, dispc.feat->bp_start, 20);
2912 timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) |
2913 FLD_VAL(vfp, dispc.feat->fp_start, 8) |
2914 FLD_VAL(vbp, dispc.feat->bp_start, 20);
2915
2916 dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
2917 dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
2918
2919 switch (data_pclk_edge) {
2920 case OMAPDSS_DRIVE_SIG_RISING_EDGE:
2921 ipc = false;
2922 break;
2923 case OMAPDSS_DRIVE_SIG_FALLING_EDGE:
2924 ipc = true;
2925 break;
2926 case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES:
2927 default:
2928 BUG();
2929 }
2930
2931 switch (sync_pclk_edge) {
2932 case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES:
2933 onoff = false;
2934 rf = false;
2935 break;
2936 case OMAPDSS_DRIVE_SIG_FALLING_EDGE:
2937 onoff = true;
2938 rf = false;
2939 break;
2940 case OMAPDSS_DRIVE_SIG_RISING_EDGE:
2941 onoff = true;
2942 rf = true;
2943 break;
2944 default:
2945 BUG();
2946 }
2947
2948 l = dispc_read_reg(DISPC_POL_FREQ(channel));
2949 l |= FLD_VAL(onoff, 17, 17);
2950 l |= FLD_VAL(rf, 16, 16);
2951 l |= FLD_VAL(de_level, 15, 15);
2952 l |= FLD_VAL(ipc, 14, 14);
2953 l |= FLD_VAL(hsync_level, 13, 13);
2954 l |= FLD_VAL(vsync_level, 12, 12);
2955 dispc_write_reg(DISPC_POL_FREQ(channel), l);
2956}
2957
2958/* change name to mode? */
2959void dispc_mgr_set_timings(enum omap_channel channel,
2960 const struct omap_video_timings *timings)
2961{
2962 unsigned xtot, ytot;
2963 unsigned long ht, vt;
2964 struct omap_video_timings t = *timings;
2965
2966 DSSDBG("channel %d xres %u yres %u\n", channel, t.x_res, t.y_res);
2967
2968 if (!dispc_mgr_timings_ok(channel, &t)) {
2969 BUG();
2970 return;
2971 }
2972
2973 if (dss_mgr_is_lcd(channel)) {
2974 _dispc_mgr_set_lcd_timings(channel, t.hsw, t.hfp, t.hbp, t.vsw,
2975 t.vfp, t.vbp, t.vsync_level, t.hsync_level,
2976 t.data_pclk_edge, t.de_level, t.sync_pclk_edge);
2977
2978 xtot = t.x_res + t.hfp + t.hsw + t.hbp;
2979 ytot = t.y_res + t.vfp + t.vsw + t.vbp;
2980
2981 ht = timings->pixelclock / xtot;
2982 vt = timings->pixelclock / xtot / ytot;
2983
2984 DSSDBG("pck %u\n", timings->pixelclock);
2985 DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
2986 t.hsw, t.hfp, t.hbp, t.vsw, t.vfp, t.vbp);
2987 DSSDBG("vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d\n",
2988 t.vsync_level, t.hsync_level, t.data_pclk_edge,
2989 t.de_level, t.sync_pclk_edge);
2990
2991 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
2992 } else {
2993 if (t.interlace == true)
2994 t.y_res /= 2;
2995 }
2996
2997 dispc_mgr_set_size(channel, t.x_res, t.y_res);
2998}
2999EXPORT_SYMBOL(dispc_mgr_set_timings);
3000
3001static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
3002 u16 pck_div)
3003{
3004 BUG_ON(lck_div < 1);
3005 BUG_ON(pck_div < 1);
3006
3007 dispc_write_reg(DISPC_DIVISORo(channel),
3008 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
3009
3010 if (dss_has_feature(FEAT_CORE_CLK_DIV) == false &&
3011 channel == OMAP_DSS_CHANNEL_LCD)
3012 dispc.core_clk_rate = dispc_fclk_rate() / lck_div;
3013}
3014
3015static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
3016 int *pck_div)
3017{
3018 u32 l;
3019 l = dispc_read_reg(DISPC_DIVISORo(channel));
3020 *lck_div = FLD_GET(l, 23, 16);
3021 *pck_div = FLD_GET(l, 7, 0);
3022}
3023
3024unsigned long dispc_fclk_rate(void)
3025{
3026 struct platform_device *dsidev;
3027 unsigned long r = 0;
3028
3029 switch (dss_get_dispc_clk_source()) {
3030 case OMAP_DSS_CLK_SRC_FCK:
3031 r = dss_get_dispc_clk_rate();
3032 break;
3033 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
3034 dsidev = dsi_get_dsidev_from_id(0);
3035 r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
3036 break;
3037 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
3038 dsidev = dsi_get_dsidev_from_id(1);
3039 r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
3040 break;
3041 default:
3042 BUG();
3043 return 0;
3044 }
3045
3046 return r;
3047}
3048
3049unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
3050{
3051 struct platform_device *dsidev;
3052 int lcd;
3053 unsigned long r;
3054 u32 l;
3055
3056 if (dss_mgr_is_lcd(channel)) {
3057 l = dispc_read_reg(DISPC_DIVISORo(channel));
3058
3059 lcd = FLD_GET(l, 23, 16);
3060
3061 switch (dss_get_lcd_clk_source(channel)) {
3062 case OMAP_DSS_CLK_SRC_FCK:
3063 r = dss_get_dispc_clk_rate();
3064 break;
3065 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
3066 dsidev = dsi_get_dsidev_from_id(0);
3067 r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
3068 break;
3069 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
3070 dsidev = dsi_get_dsidev_from_id(1);
3071 r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
3072 break;
3073 default:
3074 BUG();
3075 return 0;
3076 }
3077
3078 return r / lcd;
3079 } else {
3080 return dispc_fclk_rate();
3081 }
3082}
3083
3084unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
3085{
3086 unsigned long r;
3087
3088 if (dss_mgr_is_lcd(channel)) {
3089 int pcd;
3090 u32 l;
3091
3092 l = dispc_read_reg(DISPC_DIVISORo(channel));
3093
3094 pcd = FLD_GET(l, 7, 0);
3095
3096 r = dispc_mgr_lclk_rate(channel);
3097
3098 return r / pcd;
3099 } else {
3100 return dispc.tv_pclk_rate;
3101 }
3102}
3103
3104void dispc_set_tv_pclk(unsigned long pclk)
3105{
3106 dispc.tv_pclk_rate = pclk;
3107}
3108
3109unsigned long dispc_core_clk_rate(void)
3110{
3111 return dispc.core_clk_rate;
3112}
3113
3114static unsigned long dispc_plane_pclk_rate(enum omap_plane plane)
3115{
3116 enum omap_channel channel;
3117
3118 if (plane == OMAP_DSS_WB)
3119 return 0;
3120
3121 channel = dispc_ovl_get_channel_out(plane);
3122
3123 return dispc_mgr_pclk_rate(channel);
3124}
3125
3126static unsigned long dispc_plane_lclk_rate(enum omap_plane plane)
3127{
3128 enum omap_channel channel;
3129
3130 if (plane == OMAP_DSS_WB)
3131 return 0;
3132
3133 channel = dispc_ovl_get_channel_out(plane);
3134
3135 return dispc_mgr_lclk_rate(channel);
3136}
3137
3138static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel)
3139{
3140 int lcd, pcd;
3141 enum omap_dss_clk_source lcd_clk_src;
3142
3143 seq_printf(s, "- %s -\n", mgr_desc[channel].name);
3144
3145 lcd_clk_src = dss_get_lcd_clk_source(channel);
3146
3147 seq_printf(s, "%s clk source = %s (%s)\n", mgr_desc[channel].name,
3148 dss_get_generic_clk_source_name(lcd_clk_src),
3149 dss_feat_get_clk_source_name(lcd_clk_src));
3150
3151 dispc_mgr_get_lcd_divisor(channel, &lcd, &pcd);
3152
3153 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
3154 dispc_mgr_lclk_rate(channel), lcd);
3155 seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
3156 dispc_mgr_pclk_rate(channel), pcd);
3157}
3158
3159void dispc_dump_clocks(struct seq_file *s)
3160{
3161 int lcd;
3162 u32 l;
3163 enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
3164
3165 if (dispc_runtime_get())
3166 return;
3167
3168 seq_printf(s, "- DISPC -\n");
3169
3170 seq_printf(s, "dispc fclk source = %s (%s)\n",
3171 dss_get_generic_clk_source_name(dispc_clk_src),
3172 dss_feat_get_clk_source_name(dispc_clk_src));
3173
3174 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
3175
3176 if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
3177 seq_printf(s, "- DISPC-CORE-CLK -\n");
3178 l = dispc_read_reg(DISPC_DIVISOR);
3179 lcd = FLD_GET(l, 23, 16);
3180
3181 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
3182 (dispc_fclk_rate()/lcd), lcd);
3183 }
3184
3185 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD);
3186
3187 if (dss_has_feature(FEAT_MGR_LCD2))
3188 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD2);
3189 if (dss_has_feature(FEAT_MGR_LCD3))
3190 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3);
3191
3192 dispc_runtime_put();
3193}
3194
3195static void dispc_dump_regs(struct seq_file *s)
3196{
3197 int i, j;
3198 const char *mgr_names[] = {
3199 [OMAP_DSS_CHANNEL_LCD] = "LCD",
3200 [OMAP_DSS_CHANNEL_DIGIT] = "TV",
3201 [OMAP_DSS_CHANNEL_LCD2] = "LCD2",
3202 [OMAP_DSS_CHANNEL_LCD3] = "LCD3",
3203 };
3204 const char *ovl_names[] = {
3205 [OMAP_DSS_GFX] = "GFX",
3206 [OMAP_DSS_VIDEO1] = "VID1",
3207 [OMAP_DSS_VIDEO2] = "VID2",
3208 [OMAP_DSS_VIDEO3] = "VID3",
3209 };
3210 const char **p_names;
3211
3212#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
3213
3214 if (dispc_runtime_get())
3215 return;
3216
3217 /* DISPC common registers */
3218 DUMPREG(DISPC_REVISION);
3219 DUMPREG(DISPC_SYSCONFIG);
3220 DUMPREG(DISPC_SYSSTATUS);
3221 DUMPREG(DISPC_IRQSTATUS);
3222 DUMPREG(DISPC_IRQENABLE);
3223 DUMPREG(DISPC_CONTROL);
3224 DUMPREG(DISPC_CONFIG);
3225 DUMPREG(DISPC_CAPABLE);
3226 DUMPREG(DISPC_LINE_STATUS);
3227 DUMPREG(DISPC_LINE_NUMBER);
3228 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
3229 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
3230 DUMPREG(DISPC_GLOBAL_ALPHA);
3231 if (dss_has_feature(FEAT_MGR_LCD2)) {
3232 DUMPREG(DISPC_CONTROL2);
3233 DUMPREG(DISPC_CONFIG2);
3234 }
3235 if (dss_has_feature(FEAT_MGR_LCD3)) {
3236 DUMPREG(DISPC_CONTROL3);
3237 DUMPREG(DISPC_CONFIG3);
3238 }
3239 if (dss_has_feature(FEAT_MFLAG))
3240 DUMPREG(DISPC_GLOBAL_MFLAG_ATTRIBUTE);
3241
3242#undef DUMPREG
3243
3244#define DISPC_REG(i, name) name(i)
3245#define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
3246 (int)(48 - strlen(#r) - strlen(p_names[i])), " ", \
3247 dispc_read_reg(DISPC_REG(i, r)))
3248
3249 p_names = mgr_names;
3250
3251 /* DISPC channel specific registers */
3252 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
3253 DUMPREG(i, DISPC_DEFAULT_COLOR);
3254 DUMPREG(i, DISPC_TRANS_COLOR);
3255 DUMPREG(i, DISPC_SIZE_MGR);
3256
3257 if (i == OMAP_DSS_CHANNEL_DIGIT)
3258 continue;
3259
3260 DUMPREG(i, DISPC_DEFAULT_COLOR);
3261 DUMPREG(i, DISPC_TRANS_COLOR);
3262 DUMPREG(i, DISPC_TIMING_H);
3263 DUMPREG(i, DISPC_TIMING_V);
3264 DUMPREG(i, DISPC_POL_FREQ);
3265 DUMPREG(i, DISPC_DIVISORo);
3266 DUMPREG(i, DISPC_SIZE_MGR);
3267
3268 DUMPREG(i, DISPC_DATA_CYCLE1);
3269 DUMPREG(i, DISPC_DATA_CYCLE2);
3270 DUMPREG(i, DISPC_DATA_CYCLE3);
3271
3272 if (dss_has_feature(FEAT_CPR)) {
3273 DUMPREG(i, DISPC_CPR_COEF_R);
3274 DUMPREG(i, DISPC_CPR_COEF_G);
3275 DUMPREG(i, DISPC_CPR_COEF_B);
3276 }
3277 }
3278
3279 p_names = ovl_names;
3280
3281 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
3282 DUMPREG(i, DISPC_OVL_BA0);
3283 DUMPREG(i, DISPC_OVL_BA1);
3284 DUMPREG(i, DISPC_OVL_POSITION);
3285 DUMPREG(i, DISPC_OVL_SIZE);
3286 DUMPREG(i, DISPC_OVL_ATTRIBUTES);
3287 DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
3288 DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
3289 DUMPREG(i, DISPC_OVL_ROW_INC);
3290 DUMPREG(i, DISPC_OVL_PIXEL_INC);
3291 if (dss_has_feature(FEAT_PRELOAD))
3292 DUMPREG(i, DISPC_OVL_PRELOAD);
3293
3294 if (i == OMAP_DSS_GFX) {
3295 DUMPREG(i, DISPC_OVL_WINDOW_SKIP);
3296 DUMPREG(i, DISPC_OVL_TABLE_BA);
3297 continue;
3298 }
3299
3300 DUMPREG(i, DISPC_OVL_FIR);
3301 DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
3302 DUMPREG(i, DISPC_OVL_ACCU0);
3303 DUMPREG(i, DISPC_OVL_ACCU1);
3304 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
3305 DUMPREG(i, DISPC_OVL_BA0_UV);
3306 DUMPREG(i, DISPC_OVL_BA1_UV);
3307 DUMPREG(i, DISPC_OVL_FIR2);
3308 DUMPREG(i, DISPC_OVL_ACCU2_0);
3309 DUMPREG(i, DISPC_OVL_ACCU2_1);
3310 }
3311 if (dss_has_feature(FEAT_ATTR2))
3312 DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
3313 if (dss_has_feature(FEAT_PRELOAD))
3314 DUMPREG(i, DISPC_OVL_PRELOAD);
3315 if (dss_has_feature(FEAT_MFLAG))
3316 DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
3317 }
3318
3319#undef DISPC_REG
3320#undef DUMPREG
3321
3322#define DISPC_REG(plane, name, i) name(plane, i)
3323#define DUMPREG(plane, name, i) \
3324 seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \
3325 (int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \
3326 dispc_read_reg(DISPC_REG(plane, name, i)))
3327
3328 /* Video pipeline coefficient registers */
3329
3330 /* start from OMAP_DSS_VIDEO1 */
3331 for (i = 1; i < dss_feat_get_num_ovls(); i++) {
3332 for (j = 0; j < 8; j++)
3333 DUMPREG(i, DISPC_OVL_FIR_COEF_H, j);
3334
3335 for (j = 0; j < 8; j++)
3336 DUMPREG(i, DISPC_OVL_FIR_COEF_HV, j);
3337
3338 for (j = 0; j < 5; j++)
3339 DUMPREG(i, DISPC_OVL_CONV_COEF, j);
3340
3341 if (dss_has_feature(FEAT_FIR_COEF_V)) {
3342 for (j = 0; j < 8; j++)
3343 DUMPREG(i, DISPC_OVL_FIR_COEF_V, j);
3344 }
3345
3346 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
3347 for (j = 0; j < 8; j++)
3348 DUMPREG(i, DISPC_OVL_FIR_COEF_H2, j);
3349
3350 for (j = 0; j < 8; j++)
3351 DUMPREG(i, DISPC_OVL_FIR_COEF_HV2, j);
3352
3353 for (j = 0; j < 8; j++)
3354 DUMPREG(i, DISPC_OVL_FIR_COEF_V2, j);
3355 }
3356 }
3357
3358 dispc_runtime_put();
3359
3360#undef DISPC_REG
3361#undef DUMPREG
3362}
3363
3364/* calculate clock rates using dividers in cinfo */
3365int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
3366 struct dispc_clock_info *cinfo)
3367{
3368 if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
3369 return -EINVAL;
3370 if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
3371 return -EINVAL;
3372
3373 cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
3374 cinfo->pck = cinfo->lck / cinfo->pck_div;
3375
3376 return 0;
3377}
3378
3379bool dispc_div_calc(unsigned long dispc,
3380 unsigned long pck_min, unsigned long pck_max,
3381 dispc_div_calc_func func, void *data)
3382{
3383 int lckd, lckd_start, lckd_stop;
3384 int pckd, pckd_start, pckd_stop;
3385 unsigned long pck, lck;
3386 unsigned long lck_max;
3387 unsigned long pckd_hw_min, pckd_hw_max;
3388 unsigned min_fck_per_pck;
3389 unsigned long fck;
3390
3391#ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
3392 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
3393#else
3394 min_fck_per_pck = 0;
3395#endif
3396
3397 pckd_hw_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);
3398 pckd_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD);
3399
3400 lck_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
3401
3402 pck_min = pck_min ? pck_min : 1;
3403 pck_max = pck_max ? pck_max : ULONG_MAX;
3404
3405 lckd_start = max(DIV_ROUND_UP(dispc, lck_max), 1ul);
3406 lckd_stop = min(dispc / pck_min, 255ul);
3407
3408 for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) {
3409 lck = dispc / lckd;
3410
3411 pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min);
3412 pckd_stop = min(lck / pck_min, pckd_hw_max);
3413
3414 for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) {
3415 pck = lck / pckd;
3416
3417 /*
3418 * For OMAP2/3 the DISPC fclk is the same as LCD's logic
3419 * clock, which means we're configuring DISPC fclk here
3420 * also. Thus we need to use the calculated lck. For
3421 * OMAP4+ the DISPC fclk is a separate clock.
3422 */
3423 if (dss_has_feature(FEAT_CORE_CLK_DIV))
3424 fck = dispc_core_clk_rate();
3425 else
3426 fck = lck;
3427
3428 if (fck < pck * min_fck_per_pck)
3429 continue;
3430
3431 if (func(lckd, pckd, lck, pck, data))
3432 return true;
3433 }
3434 }
3435
3436 return false;
3437}
3438
3439void dispc_mgr_set_clock_div(enum omap_channel channel,
3440 const struct dispc_clock_info *cinfo)
3441{
3442 DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
3443 DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
3444
3445 dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
3446}
3447
3448int dispc_mgr_get_clock_div(enum omap_channel channel,
3449 struct dispc_clock_info *cinfo)
3450{
3451 unsigned long fck;
3452
3453 fck = dispc_fclk_rate();
3454
3455 cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16);
3456 cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0);
3457
3458 cinfo->lck = fck / cinfo->lck_div;
3459 cinfo->pck = cinfo->lck / cinfo->pck_div;
3460
3461 return 0;
3462}
3463
3464u32 dispc_read_irqstatus(void)
3465{
3466 return dispc_read_reg(DISPC_IRQSTATUS);
3467}
3468EXPORT_SYMBOL(dispc_read_irqstatus);
3469
3470void dispc_clear_irqstatus(u32 mask)
3471{
3472 dispc_write_reg(DISPC_IRQSTATUS, mask);
3473}
3474EXPORT_SYMBOL(dispc_clear_irqstatus);
3475
3476u32 dispc_read_irqenable(void)
3477{
3478 return dispc_read_reg(DISPC_IRQENABLE);
3479}
3480EXPORT_SYMBOL(dispc_read_irqenable);
3481
3482void dispc_write_irqenable(u32 mask)
3483{
3484 u32 old_mask = dispc_read_reg(DISPC_IRQENABLE);
3485
3486 /* clear the irqstatus for newly enabled irqs */
3487 dispc_clear_irqstatus((mask ^ old_mask) & mask);
3488
3489 dispc_write_reg(DISPC_IRQENABLE, mask);
3490}
3491EXPORT_SYMBOL(dispc_write_irqenable);
3492
3493void dispc_enable_sidle(void)
3494{
3495 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
3496}
3497
3498void dispc_disable_sidle(void)
3499{
3500 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
3501}
3502
3503static void _omap_dispc_initial_config(void)
3504{
3505 u32 l;
3506
3507 /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
3508 if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
3509 l = dispc_read_reg(DISPC_DIVISOR);
3510 /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
3511 l = FLD_MOD(l, 1, 0, 0);
3512 l = FLD_MOD(l, 1, 23, 16);
3513 dispc_write_reg(DISPC_DIVISOR, l);
3514
3515 dispc.core_clk_rate = dispc_fclk_rate();
3516 }
3517
3518 /* FUNCGATED */
3519 if (dss_has_feature(FEAT_FUNCGATED))
3520 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
3521
3522 dispc_setup_color_conv_coef();
3523
3524 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3525
3526 dispc_init_fifos();
3527
3528 dispc_configure_burst_sizes();
3529
3530 dispc_ovl_enable_zorder_planes();
3531
3532 if (dispc.feat->mstandby_workaround)
3533 REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0);
3534}
3535
3536static const struct dispc_features omap24xx_dispc_feats __initconst = {
3537 .sw_start = 5,
3538 .fp_start = 15,
3539 .bp_start = 27,
3540 .sw_max = 64,
3541 .vp_max = 255,
3542 .hp_max = 256,
3543 .mgr_width_start = 10,
3544 .mgr_height_start = 26,
3545 .mgr_width_max = 2048,
3546 .mgr_height_max = 2048,
3547 .max_lcd_pclk = 66500000,
3548 .calc_scaling = dispc_ovl_calc_scaling_24xx,
3549 .calc_core_clk = calc_core_clk_24xx,
3550 .num_fifos = 3,
3551 .no_framedone_tv = true,
3552 .set_max_preload = false,
3553};
3554
3555static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
3556 .sw_start = 5,
3557 .fp_start = 15,
3558 .bp_start = 27,
3559 .sw_max = 64,
3560 .vp_max = 255,
3561 .hp_max = 256,
3562 .mgr_width_start = 10,
3563 .mgr_height_start = 26,
3564 .mgr_width_max = 2048,
3565 .mgr_height_max = 2048,
3566 .max_lcd_pclk = 173000000,
3567 .max_tv_pclk = 59000000,
3568 .calc_scaling = dispc_ovl_calc_scaling_34xx,
3569 .calc_core_clk = calc_core_clk_34xx,
3570 .num_fifos = 3,
3571 .no_framedone_tv = true,
3572 .set_max_preload = false,
3573};
3574
3575static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
3576 .sw_start = 7,
3577 .fp_start = 19,
3578 .bp_start = 31,
3579 .sw_max = 256,
3580 .vp_max = 4095,
3581 .hp_max = 4096,
3582 .mgr_width_start = 10,
3583 .mgr_height_start = 26,
3584 .mgr_width_max = 2048,
3585 .mgr_height_max = 2048,
3586 .max_lcd_pclk = 173000000,
3587 .max_tv_pclk = 59000000,
3588 .calc_scaling = dispc_ovl_calc_scaling_34xx,
3589 .calc_core_clk = calc_core_clk_34xx,
3590 .num_fifos = 3,
3591 .no_framedone_tv = true,
3592 .set_max_preload = false,
3593};
3594
3595static const struct dispc_features omap44xx_dispc_feats __initconst = {
3596 .sw_start = 7,
3597 .fp_start = 19,
3598 .bp_start = 31,
3599 .sw_max = 256,
3600 .vp_max = 4095,
3601 .hp_max = 4096,
3602 .mgr_width_start = 10,
3603 .mgr_height_start = 26,
3604 .mgr_width_max = 2048,
3605 .mgr_height_max = 2048,
3606 .max_lcd_pclk = 170000000,
3607 .max_tv_pclk = 185625000,
3608 .calc_scaling = dispc_ovl_calc_scaling_44xx,
3609 .calc_core_clk = calc_core_clk_44xx,
3610 .num_fifos = 5,
3611 .gfx_fifo_workaround = true,
3612 .set_max_preload = true,
3613};
3614
3615static const struct dispc_features omap54xx_dispc_feats __initconst = {
3616 .sw_start = 7,
3617 .fp_start = 19,
3618 .bp_start = 31,
3619 .sw_max = 256,
3620 .vp_max = 4095,
3621 .hp_max = 4096,
3622 .mgr_width_start = 11,
3623 .mgr_height_start = 27,
3624 .mgr_width_max = 4096,
3625 .mgr_height_max = 4096,
3626 .max_lcd_pclk = 170000000,
3627 .max_tv_pclk = 186000000,
3628 .calc_scaling = dispc_ovl_calc_scaling_44xx,
3629 .calc_core_clk = calc_core_clk_44xx,
3630 .num_fifos = 5,
3631 .gfx_fifo_workaround = true,
3632 .mstandby_workaround = true,
3633 .set_max_preload = true,
3634};
3635
3636static int __init dispc_init_features(struct platform_device *pdev)
3637{
3638 const struct dispc_features *src;
3639 struct dispc_features *dst;
3640
3641 dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
3642 if (!dst) {
3643 dev_err(&pdev->dev, "Failed to allocate DISPC Features\n");
3644 return -ENOMEM;
3645 }
3646
3647 switch (omapdss_get_version()) {
3648 case OMAPDSS_VER_OMAP24xx:
3649 src = &omap24xx_dispc_feats;
3650 break;
3651
3652 case OMAPDSS_VER_OMAP34xx_ES1:
3653 src = &omap34xx_rev1_0_dispc_feats;
3654 break;
3655
3656 case OMAPDSS_VER_OMAP34xx_ES3:
3657 case OMAPDSS_VER_OMAP3630:
3658 case OMAPDSS_VER_AM35xx:
3659 src = &omap34xx_rev3_0_dispc_feats;
3660 break;
3661
3662 case OMAPDSS_VER_OMAP4430_ES1:
3663 case OMAPDSS_VER_OMAP4430_ES2:
3664 case OMAPDSS_VER_OMAP4:
3665 src = &omap44xx_dispc_feats;
3666 break;
3667
3668 case OMAPDSS_VER_OMAP5:
3669 src = &omap54xx_dispc_feats;
3670 break;
3671
3672 default:
3673 return -ENODEV;
3674 }
3675
3676 memcpy(dst, src, sizeof(*dst));
3677 dispc.feat = dst;
3678
3679 return 0;
3680}
3681
3682static irqreturn_t dispc_irq_handler(int irq, void *arg)
3683{
3684 if (!dispc.is_enabled)
3685 return IRQ_NONE;
3686
3687 return dispc.user_handler(irq, dispc.user_data);
3688}
3689
3690int dispc_request_irq(irq_handler_t handler, void *dev_id)
3691{
3692 int r;
3693
3694 if (dispc.user_handler != NULL)
3695 return -EBUSY;
3696
3697 dispc.user_handler = handler;
3698 dispc.user_data = dev_id;
3699
3700 /* ensure the dispc_irq_handler sees the values above */
3701 smp_wmb();
3702
3703 r = devm_request_irq(&dispc.pdev->dev, dispc.irq, dispc_irq_handler,
3704 IRQF_SHARED, "OMAP DISPC", &dispc);
3705 if (r) {
3706 dispc.user_handler = NULL;
3707 dispc.user_data = NULL;
3708 }
3709
3710 return r;
3711}
3712EXPORT_SYMBOL(dispc_request_irq);
3713
3714void dispc_free_irq(void *dev_id)
3715{
3716 devm_free_irq(&dispc.pdev->dev, dispc.irq, &dispc);
3717
3718 dispc.user_handler = NULL;
3719 dispc.user_data = NULL;
3720}
3721EXPORT_SYMBOL(dispc_free_irq);
3722
3723/* DISPC HW IP initialisation */
3724static int __init omap_dispchw_probe(struct platform_device *pdev)
3725{
3726 u32 rev;
3727 int r = 0;
3728 struct resource *dispc_mem;
3729
3730 dispc.pdev = pdev;
3731
3732 r = dispc_init_features(dispc.pdev);
3733 if (r)
3734 return r;
3735
3736 dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
3737 if (!dispc_mem) {
3738 DSSERR("can't get IORESOURCE_MEM DISPC\n");
3739 return -EINVAL;
3740 }
3741
3742 dispc.base = devm_ioremap(&pdev->dev, dispc_mem->start,
3743 resource_size(dispc_mem));
3744 if (!dispc.base) {
3745 DSSERR("can't ioremap DISPC\n");
3746 return -ENOMEM;
3747 }
3748
3749 dispc.irq = platform_get_irq(dispc.pdev, 0);
3750 if (dispc.irq < 0) {
3751 DSSERR("platform_get_irq failed\n");
3752 return -ENODEV;
3753 }
3754
3755 pm_runtime_enable(&pdev->dev);
3756
3757 r = dispc_runtime_get();
3758 if (r)
3759 goto err_runtime_get;
3760
3761 _omap_dispc_initial_config();
3762
3763 rev = dispc_read_reg(DISPC_REVISION);
3764 dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
3765 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
3766
3767 dispc_runtime_put();
3768
3769 dss_init_overlay_managers();
3770
3771 dss_debugfs_create_file("dispc", dispc_dump_regs);
3772
3773 return 0;
3774
3775err_runtime_get:
3776 pm_runtime_disable(&pdev->dev);
3777 return r;
3778}
3779
3780static int __exit omap_dispchw_remove(struct platform_device *pdev)
3781{
3782 pm_runtime_disable(&pdev->dev);
3783
3784 dss_uninit_overlay_managers();
3785
3786 return 0;
3787}
3788
3789static int dispc_runtime_suspend(struct device *dev)
3790{
3791 dispc.is_enabled = false;
3792 /* ensure the dispc_irq_handler sees the is_enabled value */
3793 smp_wmb();
3794 /* wait for current handler to finish before turning the DISPC off */
3795 synchronize_irq(dispc.irq);
3796
3797 dispc_save_context();
3798
3799 return 0;
3800}
3801
3802static int dispc_runtime_resume(struct device *dev)
3803{
3804 /*
3805 * The reset value for load mode is 0 (OMAP_DSS_LOAD_CLUT_AND_FRAME)
3806 * but we always initialize it to 2 (OMAP_DSS_LOAD_FRAME_ONLY) in
3807 * _omap_dispc_initial_config(). We can thus use it to detect if
3808 * we have lost register context.
3809 */
3810 if (REG_GET(DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) {
3811 _omap_dispc_initial_config();
3812
3813 dispc_restore_context();
3814 }
3815
3816 dispc.is_enabled = true;
3817 /* ensure the dispc_irq_handler sees the is_enabled value */
3818 smp_wmb();
3819
3820 return 0;
3821}
3822
3823static const struct dev_pm_ops dispc_pm_ops = {
3824 .runtime_suspend = dispc_runtime_suspend,
3825 .runtime_resume = dispc_runtime_resume,
3826};
3827
3828static const struct of_device_id dispc_of_match[] = {
3829 { .compatible = "ti,omap2-dispc", },
3830 { .compatible = "ti,omap3-dispc", },
3831 { .compatible = "ti,omap4-dispc", },
3832 {},
3833};
3834
3835static struct platform_driver omap_dispchw_driver = {
3836 .remove = __exit_p(omap_dispchw_remove),
3837 .driver = {
3838 .name = "omapdss_dispc",
3839 .owner = THIS_MODULE,
3840 .pm = &dispc_pm_ops,
3841 .of_match_table = dispc_of_match,
3842 },
3843};
3844
3845int __init dispc_init_platform_driver(void)
3846{
3847 return platform_driver_probe(&omap_dispchw_driver, omap_dispchw_probe);
3848}
3849
3850void __exit dispc_uninit_platform_driver(void)
3851{
3852 platform_driver_unregister(&omap_dispchw_driver);
3853}
diff --git a/drivers/video/fbdev/omap2/dss/dispc.h b/drivers/video/fbdev/omap2/dss/dispc.h
new file mode 100644
index 000000000000..78edb449c763
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/dispc.h
@@ -0,0 +1,917 @@
1/*
2 * linux/drivers/video/omap2/dss/dispc.h
3 *
4 * Copyright (C) 2011 Texas Instruments
5 * Author: Archit Taneja <archit@ti.com>
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __OMAP2_DISPC_REG_H
22#define __OMAP2_DISPC_REG_H
23
24/* DISPC common registers */
25#define DISPC_REVISION 0x0000
26#define DISPC_SYSCONFIG 0x0010
27#define DISPC_SYSSTATUS 0x0014
28#define DISPC_IRQSTATUS 0x0018
29#define DISPC_IRQENABLE 0x001C
30#define DISPC_CONTROL 0x0040
31#define DISPC_CONFIG 0x0044
32#define DISPC_CAPABLE 0x0048
33#define DISPC_LINE_STATUS 0x005C
34#define DISPC_LINE_NUMBER 0x0060
35#define DISPC_GLOBAL_ALPHA 0x0074
36#define DISPC_CONTROL2 0x0238
37#define DISPC_CONFIG2 0x0620
38#define DISPC_DIVISOR 0x0804
39#define DISPC_GLOBAL_BUFFER 0x0800
40#define DISPC_CONTROL3 0x0848
41#define DISPC_CONFIG3 0x084C
42#define DISPC_MSTANDBY_CTRL 0x0858
43#define DISPC_GLOBAL_MFLAG_ATTRIBUTE 0x085C
44
45/* DISPC overlay registers */
46#define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \
47 DISPC_BA0_OFFSET(n))
48#define DISPC_OVL_BA1(n) (DISPC_OVL_BASE(n) + \
49 DISPC_BA1_OFFSET(n))
50#define DISPC_OVL_BA0_UV(n) (DISPC_OVL_BASE(n) + \
51 DISPC_BA0_UV_OFFSET(n))
52#define DISPC_OVL_BA1_UV(n) (DISPC_OVL_BASE(n) + \
53 DISPC_BA1_UV_OFFSET(n))
54#define DISPC_OVL_POSITION(n) (DISPC_OVL_BASE(n) + \
55 DISPC_POS_OFFSET(n))
56#define DISPC_OVL_SIZE(n) (DISPC_OVL_BASE(n) + \
57 DISPC_SIZE_OFFSET(n))
58#define DISPC_OVL_ATTRIBUTES(n) (DISPC_OVL_BASE(n) + \
59 DISPC_ATTR_OFFSET(n))
60#define DISPC_OVL_ATTRIBUTES2(n) (DISPC_OVL_BASE(n) + \
61 DISPC_ATTR2_OFFSET(n))
62#define DISPC_OVL_FIFO_THRESHOLD(n) (DISPC_OVL_BASE(n) + \
63 DISPC_FIFO_THRESH_OFFSET(n))
64#define DISPC_OVL_FIFO_SIZE_STATUS(n) (DISPC_OVL_BASE(n) + \
65 DISPC_FIFO_SIZE_STATUS_OFFSET(n))
66#define DISPC_OVL_ROW_INC(n) (DISPC_OVL_BASE(n) + \
67 DISPC_ROW_INC_OFFSET(n))
68#define DISPC_OVL_PIXEL_INC(n) (DISPC_OVL_BASE(n) + \
69 DISPC_PIX_INC_OFFSET(n))
70#define DISPC_OVL_WINDOW_SKIP(n) (DISPC_OVL_BASE(n) + \
71 DISPC_WINDOW_SKIP_OFFSET(n))
72#define DISPC_OVL_TABLE_BA(n) (DISPC_OVL_BASE(n) + \
73 DISPC_TABLE_BA_OFFSET(n))
74#define DISPC_OVL_FIR(n) (DISPC_OVL_BASE(n) + \
75 DISPC_FIR_OFFSET(n))
76#define DISPC_OVL_FIR2(n) (DISPC_OVL_BASE(n) + \
77 DISPC_FIR2_OFFSET(n))
78#define DISPC_OVL_PICTURE_SIZE(n) (DISPC_OVL_BASE(n) + \
79 DISPC_PIC_SIZE_OFFSET(n))
80#define DISPC_OVL_ACCU0(n) (DISPC_OVL_BASE(n) + \
81 DISPC_ACCU0_OFFSET(n))
82#define DISPC_OVL_ACCU1(n) (DISPC_OVL_BASE(n) + \
83 DISPC_ACCU1_OFFSET(n))
84#define DISPC_OVL_ACCU2_0(n) (DISPC_OVL_BASE(n) + \
85 DISPC_ACCU2_0_OFFSET(n))
86#define DISPC_OVL_ACCU2_1(n) (DISPC_OVL_BASE(n) + \
87 DISPC_ACCU2_1_OFFSET(n))
88#define DISPC_OVL_FIR_COEF_H(n, i) (DISPC_OVL_BASE(n) + \
89 DISPC_FIR_COEF_H_OFFSET(n, i))
90#define DISPC_OVL_FIR_COEF_HV(n, i) (DISPC_OVL_BASE(n) + \
91 DISPC_FIR_COEF_HV_OFFSET(n, i))
92#define DISPC_OVL_FIR_COEF_H2(n, i) (DISPC_OVL_BASE(n) + \
93 DISPC_FIR_COEF_H2_OFFSET(n, i))
94#define DISPC_OVL_FIR_COEF_HV2(n, i) (DISPC_OVL_BASE(n) + \
95 DISPC_FIR_COEF_HV2_OFFSET(n, i))
96#define DISPC_OVL_CONV_COEF(n, i) (DISPC_OVL_BASE(n) + \
97 DISPC_CONV_COEF_OFFSET(n, i))
98#define DISPC_OVL_FIR_COEF_V(n, i) (DISPC_OVL_BASE(n) + \
99 DISPC_FIR_COEF_V_OFFSET(n, i))
100#define DISPC_OVL_FIR_COEF_V2(n, i) (DISPC_OVL_BASE(n) + \
101 DISPC_FIR_COEF_V2_OFFSET(n, i))
102#define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \
103 DISPC_PRELOAD_OFFSET(n))
104#define DISPC_OVL_MFLAG_THRESHOLD(n) (DISPC_OVL_BASE(n) + \
105 DISPC_MFLAG_THRESHOLD_OFFSET(n))
106
107/* DISPC up/downsampling FIR filter coefficient structure */
108struct dispc_coef {
109 s8 hc4_vc22;
110 s8 hc3_vc2;
111 u8 hc2_vc1;
112 s8 hc1_vc0;
113 s8 hc0_vc00;
114};
115
116const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps);
117
118/* DISPC manager/channel specific registers */
119static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel)
120{
121 switch (channel) {
122 case OMAP_DSS_CHANNEL_LCD:
123 return 0x004C;
124 case OMAP_DSS_CHANNEL_DIGIT:
125 return 0x0050;
126 case OMAP_DSS_CHANNEL_LCD2:
127 return 0x03AC;
128 case OMAP_DSS_CHANNEL_LCD3:
129 return 0x0814;
130 default:
131 BUG();
132 return 0;
133 }
134}
135
136static inline u16 DISPC_TRANS_COLOR(enum omap_channel channel)
137{
138 switch (channel) {
139 case OMAP_DSS_CHANNEL_LCD:
140 return 0x0054;
141 case OMAP_DSS_CHANNEL_DIGIT:
142 return 0x0058;
143 case OMAP_DSS_CHANNEL_LCD2:
144 return 0x03B0;
145 case OMAP_DSS_CHANNEL_LCD3:
146 return 0x0818;
147 default:
148 BUG();
149 return 0;
150 }
151}
152
153static inline u16 DISPC_TIMING_H(enum omap_channel channel)
154{
155 switch (channel) {
156 case OMAP_DSS_CHANNEL_LCD:
157 return 0x0064;
158 case OMAP_DSS_CHANNEL_DIGIT:
159 BUG();
160 return 0;
161 case OMAP_DSS_CHANNEL_LCD2:
162 return 0x0400;
163 case OMAP_DSS_CHANNEL_LCD3:
164 return 0x0840;
165 default:
166 BUG();
167 return 0;
168 }
169}
170
171static inline u16 DISPC_TIMING_V(enum omap_channel channel)
172{
173 switch (channel) {
174 case OMAP_DSS_CHANNEL_LCD:
175 return 0x0068;
176 case OMAP_DSS_CHANNEL_DIGIT:
177 BUG();
178 return 0;
179 case OMAP_DSS_CHANNEL_LCD2:
180 return 0x0404;
181 case OMAP_DSS_CHANNEL_LCD3:
182 return 0x0844;
183 default:
184 BUG();
185 return 0;
186 }
187}
188
189static inline u16 DISPC_POL_FREQ(enum omap_channel channel)
190{
191 switch (channel) {
192 case OMAP_DSS_CHANNEL_LCD:
193 return 0x006C;
194 case OMAP_DSS_CHANNEL_DIGIT:
195 BUG();
196 return 0;
197 case OMAP_DSS_CHANNEL_LCD2:
198 return 0x0408;
199 case OMAP_DSS_CHANNEL_LCD3:
200 return 0x083C;
201 default:
202 BUG();
203 return 0;
204 }
205}
206
207static inline u16 DISPC_DIVISORo(enum omap_channel channel)
208{
209 switch (channel) {
210 case OMAP_DSS_CHANNEL_LCD:
211 return 0x0070;
212 case OMAP_DSS_CHANNEL_DIGIT:
213 BUG();
214 return 0;
215 case OMAP_DSS_CHANNEL_LCD2:
216 return 0x040C;
217 case OMAP_DSS_CHANNEL_LCD3:
218 return 0x0838;
219 default:
220 BUG();
221 return 0;
222 }
223}
224
225/* Named as DISPC_SIZE_LCD, DISPC_SIZE_DIGIT and DISPC_SIZE_LCD2 in TRM */
226static inline u16 DISPC_SIZE_MGR(enum omap_channel channel)
227{
228 switch (channel) {
229 case OMAP_DSS_CHANNEL_LCD:
230 return 0x007C;
231 case OMAP_DSS_CHANNEL_DIGIT:
232 return 0x0078;
233 case OMAP_DSS_CHANNEL_LCD2:
234 return 0x03CC;
235 case OMAP_DSS_CHANNEL_LCD3:
236 return 0x0834;
237 default:
238 BUG();
239 return 0;
240 }
241}
242
243static inline u16 DISPC_DATA_CYCLE1(enum omap_channel channel)
244{
245 switch (channel) {
246 case OMAP_DSS_CHANNEL_LCD:
247 return 0x01D4;
248 case OMAP_DSS_CHANNEL_DIGIT:
249 BUG();
250 return 0;
251 case OMAP_DSS_CHANNEL_LCD2:
252 return 0x03C0;
253 case OMAP_DSS_CHANNEL_LCD3:
254 return 0x0828;
255 default:
256 BUG();
257 return 0;
258 }
259}
260
261static inline u16 DISPC_DATA_CYCLE2(enum omap_channel channel)
262{
263 switch (channel) {
264 case OMAP_DSS_CHANNEL_LCD:
265 return 0x01D8;
266 case OMAP_DSS_CHANNEL_DIGIT:
267 BUG();
268 return 0;
269 case OMAP_DSS_CHANNEL_LCD2:
270 return 0x03C4;
271 case OMAP_DSS_CHANNEL_LCD3:
272 return 0x082C;
273 default:
274 BUG();
275 return 0;
276 }
277}
278
279static inline u16 DISPC_DATA_CYCLE3(enum omap_channel channel)
280{
281 switch (channel) {
282 case OMAP_DSS_CHANNEL_LCD:
283 return 0x01DC;
284 case OMAP_DSS_CHANNEL_DIGIT:
285 BUG();
286 return 0;
287 case OMAP_DSS_CHANNEL_LCD2:
288 return 0x03C8;
289 case OMAP_DSS_CHANNEL_LCD3:
290 return 0x0830;
291 default:
292 BUG();
293 return 0;
294 }
295}
296
297static inline u16 DISPC_CPR_COEF_R(enum omap_channel channel)
298{
299 switch (channel) {
300 case OMAP_DSS_CHANNEL_LCD:
301 return 0x0220;
302 case OMAP_DSS_CHANNEL_DIGIT:
303 BUG();
304 return 0;
305 case OMAP_DSS_CHANNEL_LCD2:
306 return 0x03BC;
307 case OMAP_DSS_CHANNEL_LCD3:
308 return 0x0824;
309 default:
310 BUG();
311 return 0;
312 }
313}
314
315static inline u16 DISPC_CPR_COEF_G(enum omap_channel channel)
316{
317 switch (channel) {
318 case OMAP_DSS_CHANNEL_LCD:
319 return 0x0224;
320 case OMAP_DSS_CHANNEL_DIGIT:
321 BUG();
322 return 0;
323 case OMAP_DSS_CHANNEL_LCD2:
324 return 0x03B8;
325 case OMAP_DSS_CHANNEL_LCD3:
326 return 0x0820;
327 default:
328 BUG();
329 return 0;
330 }
331}
332
333static inline u16 DISPC_CPR_COEF_B(enum omap_channel channel)
334{
335 switch (channel) {
336 case OMAP_DSS_CHANNEL_LCD:
337 return 0x0228;
338 case OMAP_DSS_CHANNEL_DIGIT:
339 BUG();
340 return 0;
341 case OMAP_DSS_CHANNEL_LCD2:
342 return 0x03B4;
343 case OMAP_DSS_CHANNEL_LCD3:
344 return 0x081C;
345 default:
346 BUG();
347 return 0;
348 }
349}
350
351/* DISPC overlay register base addresses */
352static inline u16 DISPC_OVL_BASE(enum omap_plane plane)
353{
354 switch (plane) {
355 case OMAP_DSS_GFX:
356 return 0x0080;
357 case OMAP_DSS_VIDEO1:
358 return 0x00BC;
359 case OMAP_DSS_VIDEO2:
360 return 0x014C;
361 case OMAP_DSS_VIDEO3:
362 return 0x0300;
363 case OMAP_DSS_WB:
364 return 0x0500;
365 default:
366 BUG();
367 return 0;
368 }
369}
370
371/* DISPC overlay register offsets */
372static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane)
373{
374 switch (plane) {
375 case OMAP_DSS_GFX:
376 case OMAP_DSS_VIDEO1:
377 case OMAP_DSS_VIDEO2:
378 return 0x0000;
379 case OMAP_DSS_VIDEO3:
380 case OMAP_DSS_WB:
381 return 0x0008;
382 default:
383 BUG();
384 return 0;
385 }
386}
387
388static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane)
389{
390 switch (plane) {
391 case OMAP_DSS_GFX:
392 case OMAP_DSS_VIDEO1:
393 case OMAP_DSS_VIDEO2:
394 return 0x0004;
395 case OMAP_DSS_VIDEO3:
396 case OMAP_DSS_WB:
397 return 0x000C;
398 default:
399 BUG();
400 return 0;
401 }
402}
403
404static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
405{
406 switch (plane) {
407 case OMAP_DSS_GFX:
408 BUG();
409 return 0;
410 case OMAP_DSS_VIDEO1:
411 return 0x0544;
412 case OMAP_DSS_VIDEO2:
413 return 0x04BC;
414 case OMAP_DSS_VIDEO3:
415 return 0x0310;
416 case OMAP_DSS_WB:
417 return 0x0118;
418 default:
419 BUG();
420 return 0;
421 }
422}
423
424static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
425{
426 switch (plane) {
427 case OMAP_DSS_GFX:
428 BUG();
429 return 0;
430 case OMAP_DSS_VIDEO1:
431 return 0x0548;
432 case OMAP_DSS_VIDEO2:
433 return 0x04C0;
434 case OMAP_DSS_VIDEO3:
435 return 0x0314;
436 case OMAP_DSS_WB:
437 return 0x011C;
438 default:
439 BUG();
440 return 0;
441 }
442}
443
444static inline u16 DISPC_POS_OFFSET(enum omap_plane plane)
445{
446 switch (plane) {
447 case OMAP_DSS_GFX:
448 case OMAP_DSS_VIDEO1:
449 case OMAP_DSS_VIDEO2:
450 return 0x0008;
451 case OMAP_DSS_VIDEO3:
452 return 0x009C;
453 default:
454 BUG();
455 return 0;
456 }
457}
458
459static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane)
460{
461 switch (plane) {
462 case OMAP_DSS_GFX:
463 case OMAP_DSS_VIDEO1:
464 case OMAP_DSS_VIDEO2:
465 return 0x000C;
466 case OMAP_DSS_VIDEO3:
467 case OMAP_DSS_WB:
468 return 0x00A8;
469 default:
470 BUG();
471 return 0;
472 }
473}
474
475static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane)
476{
477 switch (plane) {
478 case OMAP_DSS_GFX:
479 return 0x0020;
480 case OMAP_DSS_VIDEO1:
481 case OMAP_DSS_VIDEO2:
482 return 0x0010;
483 case OMAP_DSS_VIDEO3:
484 case OMAP_DSS_WB:
485 return 0x0070;
486 default:
487 BUG();
488 return 0;
489 }
490}
491
492static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
493{
494 switch (plane) {
495 case OMAP_DSS_GFX:
496 BUG();
497 return 0;
498 case OMAP_DSS_VIDEO1:
499 return 0x0568;
500 case OMAP_DSS_VIDEO2:
501 return 0x04DC;
502 case OMAP_DSS_VIDEO3:
503 return 0x032C;
504 case OMAP_DSS_WB:
505 return 0x0310;
506 default:
507 BUG();
508 return 0;
509 }
510}
511
512static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane)
513{
514 switch (plane) {
515 case OMAP_DSS_GFX:
516 return 0x0024;
517 case OMAP_DSS_VIDEO1:
518 case OMAP_DSS_VIDEO2:
519 return 0x0014;
520 case OMAP_DSS_VIDEO3:
521 case OMAP_DSS_WB:
522 return 0x008C;
523 default:
524 BUG();
525 return 0;
526 }
527}
528
529static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane)
530{
531 switch (plane) {
532 case OMAP_DSS_GFX:
533 return 0x0028;
534 case OMAP_DSS_VIDEO1:
535 case OMAP_DSS_VIDEO2:
536 return 0x0018;
537 case OMAP_DSS_VIDEO3:
538 case OMAP_DSS_WB:
539 return 0x0088;
540 default:
541 BUG();
542 return 0;
543 }
544}
545
546static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane)
547{
548 switch (plane) {
549 case OMAP_DSS_GFX:
550 return 0x002C;
551 case OMAP_DSS_VIDEO1:
552 case OMAP_DSS_VIDEO2:
553 return 0x001C;
554 case OMAP_DSS_VIDEO3:
555 case OMAP_DSS_WB:
556 return 0x00A4;
557 default:
558 BUG();
559 return 0;
560 }
561}
562
563static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane)
564{
565 switch (plane) {
566 case OMAP_DSS_GFX:
567 return 0x0030;
568 case OMAP_DSS_VIDEO1:
569 case OMAP_DSS_VIDEO2:
570 return 0x0020;
571 case OMAP_DSS_VIDEO3:
572 case OMAP_DSS_WB:
573 return 0x0098;
574 default:
575 BUG();
576 return 0;
577 }
578}
579
580static inline u16 DISPC_WINDOW_SKIP_OFFSET(enum omap_plane plane)
581{
582 switch (plane) {
583 case OMAP_DSS_GFX:
584 return 0x0034;
585 case OMAP_DSS_VIDEO1:
586 case OMAP_DSS_VIDEO2:
587 case OMAP_DSS_VIDEO3:
588 BUG();
589 return 0;
590 default:
591 BUG();
592 return 0;
593 }
594}
595
596static inline u16 DISPC_TABLE_BA_OFFSET(enum omap_plane plane)
597{
598 switch (plane) {
599 case OMAP_DSS_GFX:
600 return 0x0038;
601 case OMAP_DSS_VIDEO1:
602 case OMAP_DSS_VIDEO2:
603 case OMAP_DSS_VIDEO3:
604 BUG();
605 return 0;
606 default:
607 BUG();
608 return 0;
609 }
610}
611
612static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
613{
614 switch (plane) {
615 case OMAP_DSS_GFX:
616 BUG();
617 return 0;
618 case OMAP_DSS_VIDEO1:
619 case OMAP_DSS_VIDEO2:
620 return 0x0024;
621 case OMAP_DSS_VIDEO3:
622 case OMAP_DSS_WB:
623 return 0x0090;
624 default:
625 BUG();
626 return 0;
627 }
628}
629
630static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
631{
632 switch (plane) {
633 case OMAP_DSS_GFX:
634 BUG();
635 return 0;
636 case OMAP_DSS_VIDEO1:
637 return 0x0580;
638 case OMAP_DSS_VIDEO2:
639 return 0x055C;
640 case OMAP_DSS_VIDEO3:
641 return 0x0424;
642 case OMAP_DSS_WB:
643 return 0x290;
644 default:
645 BUG();
646 return 0;
647 }
648}
649
650static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
651{
652 switch (plane) {
653 case OMAP_DSS_GFX:
654 BUG();
655 return 0;
656 case OMAP_DSS_VIDEO1:
657 case OMAP_DSS_VIDEO2:
658 return 0x0028;
659 case OMAP_DSS_VIDEO3:
660 case OMAP_DSS_WB:
661 return 0x0094;
662 default:
663 BUG();
664 return 0;
665 }
666}
667
668
669static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
670{
671 switch (plane) {
672 case OMAP_DSS_GFX:
673 BUG();
674 return 0;
675 case OMAP_DSS_VIDEO1:
676 case OMAP_DSS_VIDEO2:
677 return 0x002C;
678 case OMAP_DSS_VIDEO3:
679 case OMAP_DSS_WB:
680 return 0x0000;
681 default:
682 BUG();
683 return 0;
684 }
685}
686
687static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
688{
689 switch (plane) {
690 case OMAP_DSS_GFX:
691 BUG();
692 return 0;
693 case OMAP_DSS_VIDEO1:
694 return 0x0584;
695 case OMAP_DSS_VIDEO2:
696 return 0x0560;
697 case OMAP_DSS_VIDEO3:
698 return 0x0428;
699 case OMAP_DSS_WB:
700 return 0x0294;
701 default:
702 BUG();
703 return 0;
704 }
705}
706
707static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
708{
709 switch (plane) {
710 case OMAP_DSS_GFX:
711 BUG();
712 return 0;
713 case OMAP_DSS_VIDEO1:
714 case OMAP_DSS_VIDEO2:
715 return 0x0030;
716 case OMAP_DSS_VIDEO3:
717 case OMAP_DSS_WB:
718 return 0x0004;
719 default:
720 BUG();
721 return 0;
722 }
723}
724
725static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
726{
727 switch (plane) {
728 case OMAP_DSS_GFX:
729 BUG();
730 return 0;
731 case OMAP_DSS_VIDEO1:
732 return 0x0588;
733 case OMAP_DSS_VIDEO2:
734 return 0x0564;
735 case OMAP_DSS_VIDEO3:
736 return 0x042C;
737 case OMAP_DSS_WB:
738 return 0x0298;
739 default:
740 BUG();
741 return 0;
742 }
743}
744
745/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
746static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
747{
748 switch (plane) {
749 case OMAP_DSS_GFX:
750 BUG();
751 return 0;
752 case OMAP_DSS_VIDEO1:
753 case OMAP_DSS_VIDEO2:
754 return 0x0034 + i * 0x8;
755 case OMAP_DSS_VIDEO3:
756 case OMAP_DSS_WB:
757 return 0x0010 + i * 0x8;
758 default:
759 BUG();
760 return 0;
761 }
762}
763
764/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
765static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
766{
767 switch (plane) {
768 case OMAP_DSS_GFX:
769 BUG();
770 return 0;
771 case OMAP_DSS_VIDEO1:
772 return 0x058C + i * 0x8;
773 case OMAP_DSS_VIDEO2:
774 return 0x0568 + i * 0x8;
775 case OMAP_DSS_VIDEO3:
776 return 0x0430 + i * 0x8;
777 case OMAP_DSS_WB:
778 return 0x02A0 + i * 0x8;
779 default:
780 BUG();
781 return 0;
782 }
783}
784
785/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
786static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
787{
788 switch (plane) {
789 case OMAP_DSS_GFX:
790 BUG();
791 return 0;
792 case OMAP_DSS_VIDEO1:
793 case OMAP_DSS_VIDEO2:
794 return 0x0038 + i * 0x8;
795 case OMAP_DSS_VIDEO3:
796 case OMAP_DSS_WB:
797 return 0x0014 + i * 0x8;
798 default:
799 BUG();
800 return 0;
801 }
802}
803
804/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
805static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
806{
807 switch (plane) {
808 case OMAP_DSS_GFX:
809 BUG();
810 return 0;
811 case OMAP_DSS_VIDEO1:
812 return 0x0590 + i * 8;
813 case OMAP_DSS_VIDEO2:
814 return 0x056C + i * 0x8;
815 case OMAP_DSS_VIDEO3:
816 return 0x0434 + i * 0x8;
817 case OMAP_DSS_WB:
818 return 0x02A4 + i * 0x8;
819 default:
820 BUG();
821 return 0;
822 }
823}
824
825/* coef index i = {0, 1, 2, 3, 4,} */
826static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i)
827{
828 switch (plane) {
829 case OMAP_DSS_GFX:
830 BUG();
831 return 0;
832 case OMAP_DSS_VIDEO1:
833 case OMAP_DSS_VIDEO2:
834 case OMAP_DSS_VIDEO3:
835 case OMAP_DSS_WB:
836 return 0x0074 + i * 0x4;
837 default:
838 BUG();
839 return 0;
840 }
841}
842
843/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
844static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
845{
846 switch (plane) {
847 case OMAP_DSS_GFX:
848 BUG();
849 return 0;
850 case OMAP_DSS_VIDEO1:
851 return 0x0124 + i * 0x4;
852 case OMAP_DSS_VIDEO2:
853 return 0x00B4 + i * 0x4;
854 case OMAP_DSS_VIDEO3:
855 case OMAP_DSS_WB:
856 return 0x0050 + i * 0x4;
857 default:
858 BUG();
859 return 0;
860 }
861}
862
863/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
864static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
865{
866 switch (plane) {
867 case OMAP_DSS_GFX:
868 BUG();
869 return 0;
870 case OMAP_DSS_VIDEO1:
871 return 0x05CC + i * 0x4;
872 case OMAP_DSS_VIDEO2:
873 return 0x05A8 + i * 0x4;
874 case OMAP_DSS_VIDEO3:
875 return 0x0470 + i * 0x4;
876 case OMAP_DSS_WB:
877 return 0x02E0 + i * 0x4;
878 default:
879 BUG();
880 return 0;
881 }
882}
883
884static inline u16 DISPC_PRELOAD_OFFSET(enum omap_plane plane)
885{
886 switch (plane) {
887 case OMAP_DSS_GFX:
888 return 0x01AC;
889 case OMAP_DSS_VIDEO1:
890 return 0x0174;
891 case OMAP_DSS_VIDEO2:
892 return 0x00E8;
893 case OMAP_DSS_VIDEO3:
894 return 0x00A0;
895 default:
896 BUG();
897 return 0;
898 }
899}
900
901static inline u16 DISPC_MFLAG_THRESHOLD_OFFSET(enum omap_plane plane)
902{
903 switch (plane) {
904 case OMAP_DSS_GFX:
905 return 0x0860;
906 case OMAP_DSS_VIDEO1:
907 return 0x0864;
908 case OMAP_DSS_VIDEO2:
909 return 0x0868;
910 case OMAP_DSS_VIDEO3:
911 return 0x086c;
912 default:
913 BUG();
914 return 0;
915 }
916}
917#endif
diff --git a/drivers/video/fbdev/omap2/dss/dispc_coefs.c b/drivers/video/fbdev/omap2/dss/dispc_coefs.c
new file mode 100644
index 000000000000..038c15b04215
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/dispc_coefs.c
@@ -0,0 +1,325 @@
1/*
2 * linux/drivers/video/omap2/dss/dispc_coefs.c
3 *
4 * Copyright (C) 2011 Texas Instruments
5 * Author: Chandrabhanu Mahapatra <cmahapatra@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/kernel.h>
21#include <video/omapdss.h>
22
23#include "dispc.h"
24
25static const struct dispc_coef coef3_M8[8] = {
26 { 0, 0, 128, 0, 0 },
27 { 0, -4, 123, 9, 0 },
28 { 0, -4, 108, 24, 0 },
29 { 0, -2, 87, 43, 0 },
30 { 0, 64, 64, 0, 0 },
31 { 0, 43, 87, -2, 0 },
32 { 0, 24, 108, -4, 0 },
33 { 0, 9, 123, -4, 0 },
34};
35
36static const struct dispc_coef coef3_M9[8] = {
37 { 0, 6, 116, 6, 0 },
38 { 0, 0, 112, 16, 0 },
39 { 0, -2, 100, 30, 0 },
40 { 0, -2, 83, 47, 0 },
41 { 0, 64, 64, 0, 0 },
42 { 0, 47, 83, -2, 0 },
43 { 0, 30, 100, -2, 0 },
44 { 0, 16, 112, 0, 0 },
45};
46
47static const struct dispc_coef coef3_M10[8] = {
48 { 0, 10, 108, 10, 0 },
49 { 0, 3, 104, 21, 0 },
50 { 0, 0, 94, 34, 0 },
51 { 0, -1, 80, 49, 0 },
52 { 0, 64, 64, 0, 0 },
53 { 0, 49, 80, -1, 0 },
54 { 0, 34, 94, 0, 0 },
55 { 0, 21, 104, 3, 0 },
56};
57
58static const struct dispc_coef coef3_M11[8] = {
59 { 0, 14, 100, 14, 0 },
60 { 0, 6, 98, 24, 0 },
61 { 0, 2, 90, 36, 0 },
62 { 0, 0, 78, 50, 0 },
63 { 0, 64, 64, 0, 0 },
64 { 0, 50, 78, 0, 0 },
65 { 0, 36, 90, 2, 0 },
66 { 0, 24, 98, 6, 0 },
67};
68
69static const struct dispc_coef coef3_M12[8] = {
70 { 0, 16, 96, 16, 0 },
71 { 0, 9, 93, 26, 0 },
72 { 0, 4, 86, 38, 0 },
73 { 0, 1, 76, 51, 0 },
74 { 0, 64, 64, 0, 0 },
75 { 0, 51, 76, 1, 0 },
76 { 0, 38, 86, 4, 0 },
77 { 0, 26, 93, 9, 0 },
78};
79
80static const struct dispc_coef coef3_M13[8] = {
81 { 0, 18, 92, 18, 0 },
82 { 0, 10, 90, 28, 0 },
83 { 0, 5, 83, 40, 0 },
84 { 0, 1, 75, 52, 0 },
85 { 0, 64, 64, 0, 0 },
86 { 0, 52, 75, 1, 0 },
87 { 0, 40, 83, 5, 0 },
88 { 0, 28, 90, 10, 0 },
89};
90
91static const struct dispc_coef coef3_M14[8] = {
92 { 0, 20, 88, 20, 0 },
93 { 0, 12, 86, 30, 0 },
94 { 0, 6, 81, 41, 0 },
95 { 0, 2, 74, 52, 0 },
96 { 0, 64, 64, 0, 0 },
97 { 0, 52, 74, 2, 0 },
98 { 0, 41, 81, 6, 0 },
99 { 0, 30, 86, 12, 0 },
100};
101
102static const struct dispc_coef coef3_M16[8] = {
103 { 0, 22, 84, 22, 0 },
104 { 0, 14, 82, 32, 0 },
105 { 0, 8, 78, 42, 0 },
106 { 0, 3, 72, 53, 0 },
107 { 0, 64, 64, 0, 0 },
108 { 0, 53, 72, 3, 0 },
109 { 0, 42, 78, 8, 0 },
110 { 0, 32, 82, 14, 0 },
111};
112
113static const struct dispc_coef coef3_M19[8] = {
114 { 0, 24, 80, 24, 0 },
115 { 0, 16, 79, 33, 0 },
116 { 0, 9, 76, 43, 0 },
117 { 0, 4, 70, 54, 0 },
118 { 0, 64, 64, 0, 0 },
119 { 0, 54, 70, 4, 0 },
120 { 0, 43, 76, 9, 0 },
121 { 0, 33, 79, 16, 0 },
122};
123
124static const struct dispc_coef coef3_M22[8] = {
125 { 0, 25, 78, 25, 0 },
126 { 0, 17, 77, 34, 0 },
127 { 0, 10, 74, 44, 0 },
128 { 0, 5, 69, 54, 0 },
129 { 0, 64, 64, 0, 0 },
130 { 0, 54, 69, 5, 0 },
131 { 0, 44, 74, 10, 0 },
132 { 0, 34, 77, 17, 0 },
133};
134
135static const struct dispc_coef coef3_M26[8] = {
136 { 0, 26, 76, 26, 0 },
137 { 0, 19, 74, 35, 0 },
138 { 0, 11, 72, 45, 0 },
139 { 0, 5, 69, 54, 0 },
140 { 0, 64, 64, 0, 0 },
141 { 0, 54, 69, 5, 0 },
142 { 0, 45, 72, 11, 0 },
143 { 0, 35, 74, 19, 0 },
144};
145
146static const struct dispc_coef coef3_M32[8] = {
147 { 0, 27, 74, 27, 0 },
148 { 0, 19, 73, 36, 0 },
149 { 0, 12, 71, 45, 0 },
150 { 0, 6, 68, 54, 0 },
151 { 0, 64, 64, 0, 0 },
152 { 0, 54, 68, 6, 0 },
153 { 0, 45, 71, 12, 0 },
154 { 0, 36, 73, 19, 0 },
155};
156
157static const struct dispc_coef coef5_M8[8] = {
158 { 0, 0, 128, 0, 0 },
159 { -2, 14, 125, -10, 1 },
160 { -6, 33, 114, -15, 2 },
161 { -10, 55, 98, -16, 1 },
162 { 0, -14, 78, 78, -14 },
163 { 1, -16, 98, 55, -10 },
164 { 2, -15, 114, 33, -6 },
165 { 1, -10, 125, 14, -2 },
166};
167
168static const struct dispc_coef coef5_M9[8] = {
169 { -3, 10, 114, 10, -3 },
170 { -6, 24, 111, 0, -1 },
171 { -8, 40, 103, -7, 0 },
172 { -11, 58, 91, -11, 1 },
173 { 0, -12, 76, 76, -12 },
174 { 1, -11, 91, 58, -11 },
175 { 0, -7, 103, 40, -8 },
176 { -1, 0, 111, 24, -6 },
177};
178
179static const struct dispc_coef coef5_M10[8] = {
180 { -4, 18, 100, 18, -4 },
181 { -6, 30, 99, 8, -3 },
182 { -8, 44, 93, 0, -1 },
183 { -9, 58, 84, -5, 0 },
184 { 0, -8, 72, 72, -8 },
185 { 0, -5, 84, 58, -9 },
186 { -1, 0, 93, 44, -8 },
187 { -3, 8, 99, 30, -6 },
188};
189
190static const struct dispc_coef coef5_M11[8] = {
191 { -5, 23, 92, 23, -5 },
192 { -6, 34, 90, 13, -3 },
193 { -6, 45, 85, 6, -2 },
194 { -6, 57, 78, 0, -1 },
195 { 0, -4, 68, 68, -4 },
196 { -1, 0, 78, 57, -6 },
197 { -2, 6, 85, 45, -6 },
198 { -3, 13, 90, 34, -6 },
199};
200
201static const struct dispc_coef coef5_M12[8] = {
202 { -4, 26, 84, 26, -4 },
203 { -5, 36, 82, 18, -3 },
204 { -4, 46, 78, 10, -2 },
205 { -3, 55, 72, 5, -1 },
206 { 0, 0, 64, 64, 0 },
207 { -1, 5, 72, 55, -3 },
208 { -2, 10, 78, 46, -4 },
209 { -3, 18, 82, 36, -5 },
210};
211
212static const struct dispc_coef coef5_M13[8] = {
213 { -3, 28, 78, 28, -3 },
214 { -3, 37, 76, 21, -3 },
215 { -2, 45, 73, 14, -2 },
216 { 0, 53, 68, 8, -1 },
217 { 0, 3, 61, 61, 3 },
218 { -1, 8, 68, 53, 0 },
219 { -2, 14, 73, 45, -2 },
220 { -3, 21, 76, 37, -3 },
221};
222
223static const struct dispc_coef coef5_M14[8] = {
224 { -2, 30, 72, 30, -2 },
225 { -1, 37, 71, 23, -2 },
226 { 0, 45, 69, 16, -2 },
227 { 3, 52, 64, 10, -1 },
228 { 0, 6, 58, 58, 6 },
229 { -1, 10, 64, 52, 3 },
230 { -2, 16, 69, 45, 0 },
231 { -2, 23, 71, 37, -1 },
232};
233
234static const struct dispc_coef coef5_M16[8] = {
235 { 0, 31, 66, 31, 0 },
236 { 1, 38, 65, 25, -1 },
237 { 3, 44, 62, 20, -1 },
238 { 6, 49, 59, 14, 0 },
239 { 0, 10, 54, 54, 10 },
240 { 0, 14, 59, 49, 6 },
241 { -1, 20, 62, 44, 3 },
242 { -1, 25, 65, 38, 1 },
243};
244
245static const struct dispc_coef coef5_M19[8] = {
246 { 3, 32, 58, 32, 3 },
247 { 4, 38, 58, 27, 1 },
248 { 7, 42, 55, 23, 1 },
249 { 10, 46, 54, 18, 0 },
250 { 0, 14, 50, 50, 14 },
251 { 0, 18, 54, 46, 10 },
252 { 1, 23, 55, 42, 7 },
253 { 1, 27, 58, 38, 4 },
254};
255
256static const struct dispc_coef coef5_M22[8] = {
257 { 4, 33, 54, 33, 4 },
258 { 6, 37, 54, 28, 3 },
259 { 9, 41, 53, 24, 1 },
260 { 12, 45, 51, 20, 0 },
261 { 0, 16, 48, 48, 16 },
262 { 0, 20, 51, 45, 12 },
263 { 1, 24, 53, 41, 9 },
264 { 3, 28, 54, 37, 6 },
265};
266
267static const struct dispc_coef coef5_M26[8] = {
268 { 6, 33, 50, 33, 6 },
269 { 8, 36, 51, 29, 4 },
270 { 11, 40, 50, 25, 2 },
271 { 14, 43, 48, 22, 1 },
272 { 0, 18, 46, 46, 18 },
273 { 1, 22, 48, 43, 14 },
274 { 2, 25, 50, 40, 11 },
275 { 4, 29, 51, 36, 8 },
276};
277
278static const struct dispc_coef coef5_M32[8] = {
279 { 7, 33, 48, 33, 7 },
280 { 10, 36, 48, 29, 5 },
281 { 13, 39, 47, 26, 3 },
282 { 16, 42, 46, 23, 1 },
283 { 0, 19, 45, 45, 19 },
284 { 1, 23, 46, 42, 16 },
285 { 3, 26, 47, 39, 13 },
286 { 5, 29, 48, 36, 10 },
287};
288
289const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps)
290{
291 int i;
292 static const struct {
293 int Mmin;
294 int Mmax;
295 const struct dispc_coef *coef_3;
296 const struct dispc_coef *coef_5;
297 } coefs[] = {
298 { 27, 32, coef3_M32, coef5_M32 },
299 { 23, 26, coef3_M26, coef5_M26 },
300 { 20, 22, coef3_M22, coef5_M22 },
301 { 17, 19, coef3_M19, coef5_M19 },
302 { 15, 16, coef3_M16, coef5_M16 },
303 { 14, 14, coef3_M14, coef5_M14 },
304 { 13, 13, coef3_M13, coef5_M13 },
305 { 12, 12, coef3_M12, coef5_M12 },
306 { 11, 11, coef3_M11, coef5_M11 },
307 { 10, 10, coef3_M10, coef5_M10 },
308 { 9, 9, coef3_M9, coef5_M9 },
309 { 4, 8, coef3_M8, coef5_M8 },
310 /*
311 * When upscaling more than two times, blockiness and outlines
312 * around the image are observed when M8 tables are used. M11,
313 * M16 and M19 tables are used to prevent this.
314 */
315 { 3, 3, coef3_M11, coef5_M11 },
316 { 2, 2, coef3_M16, coef5_M16 },
317 { 0, 1, coef3_M19, coef5_M19 },
318 };
319
320 inc /= 128;
321 for (i = 0; i < ARRAY_SIZE(coefs); ++i)
322 if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax)
323 return five_taps ? coefs[i].coef_5 : coefs[i].coef_3;
324 return NULL;
325}
diff --git a/drivers/video/fbdev/omap2/dss/display-sysfs.c b/drivers/video/fbdev/omap2/dss/display-sysfs.c
new file mode 100644
index 000000000000..5a2095a98ed8
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/display-sysfs.c
@@ -0,0 +1,345 @@
1/*
2 * Copyright (C) 2009 Nokia Corporation
3 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
4 *
5 * Some code and ideas taken from drivers/video/omap/ driver
6 * by Imre Deak.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#define DSS_SUBSYS_NAME "DISPLAY"
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/platform_device.h>
26#include <linux/sysfs.h>
27
28#include <video/omapdss.h>
29#include "dss.h"
30
31static struct omap_dss_device *to_dss_device_sysfs(struct device *dev)
32{
33 struct omap_dss_device *dssdev = NULL;
34
35 for_each_dss_dev(dssdev) {
36 if (dssdev->dev == dev) {
37 omap_dss_put_device(dssdev);
38 return dssdev;
39 }
40 }
41
42 return NULL;
43}
44
45static ssize_t display_name_show(struct device *dev,
46 struct device_attribute *attr, char *buf)
47{
48 struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
49
50 return snprintf(buf, PAGE_SIZE, "%s\n",
51 dssdev->name ?
52 dssdev->name : "");
53}
54
55static ssize_t display_enabled_show(struct device *dev,
56 struct device_attribute *attr, char *buf)
57{
58 struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
59
60 return snprintf(buf, PAGE_SIZE, "%d\n",
61 omapdss_device_is_enabled(dssdev));
62}
63
64static ssize_t display_enabled_store(struct device *dev,
65 struct device_attribute *attr,
66 const char *buf, size_t size)
67{
68 struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
69 int r;
70 bool enable;
71
72 r = strtobool(buf, &enable);
73 if (r)
74 return r;
75
76 if (enable == omapdss_device_is_enabled(dssdev))
77 return size;
78
79 if (omapdss_device_is_connected(dssdev) == false)
80 return -ENODEV;
81
82 if (enable) {
83 r = dssdev->driver->enable(dssdev);
84 if (r)
85 return r;
86 } else {
87 dssdev->driver->disable(dssdev);
88 }
89
90 return size;
91}
92
93static ssize_t display_tear_show(struct device *dev,
94 struct device_attribute *attr, char *buf)
95{
96 struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
97 return snprintf(buf, PAGE_SIZE, "%d\n",
98 dssdev->driver->get_te ?
99 dssdev->driver->get_te(dssdev) : 0);
100}
101
102static ssize_t display_tear_store(struct device *dev,
103 struct device_attribute *attr, const char *buf, size_t size)
104{
105 struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
106 int r;
107 bool te;
108
109 if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
110 return -ENOENT;
111
112 r = strtobool(buf, &te);
113 if (r)
114 return r;
115
116 r = dssdev->driver->enable_te(dssdev, te);
117 if (r)
118 return r;
119
120 return size;
121}
122
123static ssize_t display_timings_show(struct device *dev,
124 struct device_attribute *attr, char *buf)
125{
126 struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
127 struct omap_video_timings t;
128
129 if (!dssdev->driver->get_timings)
130 return -ENOENT;
131
132 dssdev->driver->get_timings(dssdev, &t);
133
134 return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
135 t.pixelclock,
136 t.x_res, t.hfp, t.hbp, t.hsw,
137 t.y_res, t.vfp, t.vbp, t.vsw);
138}
139
140static ssize_t display_timings_store(struct device *dev,
141 struct device_attribute *attr, const char *buf, size_t size)
142{
143 struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
144 struct omap_video_timings t = dssdev->panel.timings;
145 int r, found;
146
147 if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
148 return -ENOENT;
149
150 found = 0;
151#ifdef CONFIG_OMAP2_DSS_VENC
152 if (strncmp("pal", buf, 3) == 0) {
153 t = omap_dss_pal_timings;
154 found = 1;
155 } else if (strncmp("ntsc", buf, 4) == 0) {
156 t = omap_dss_ntsc_timings;
157 found = 1;
158 }
159#endif
160 if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
161 &t.pixelclock,
162 &t.x_res, &t.hfp, &t.hbp, &t.hsw,
163 &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
164 return -EINVAL;
165
166 r = dssdev->driver->check_timings(dssdev, &t);
167 if (r)
168 return r;
169
170 dssdev->driver->disable(dssdev);
171 dssdev->driver->set_timings(dssdev, &t);
172 r = dssdev->driver->enable(dssdev);
173 if (r)
174 return r;
175
176 return size;
177}
178
179static ssize_t display_rotate_show(struct device *dev,
180 struct device_attribute *attr, char *buf)
181{
182 struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
183 int rotate;
184 if (!dssdev->driver->get_rotate)
185 return -ENOENT;
186 rotate = dssdev->driver->get_rotate(dssdev);
187 return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
188}
189
190static ssize_t display_rotate_store(struct device *dev,
191 struct device_attribute *attr, const char *buf, size_t size)
192{
193 struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
194 int rot, r;
195
196 if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
197 return -ENOENT;
198
199 r = kstrtoint(buf, 0, &rot);
200 if (r)
201 return r;
202
203 r = dssdev->driver->set_rotate(dssdev, rot);
204 if (r)
205 return r;
206
207 return size;
208}
209
210static ssize_t display_mirror_show(struct device *dev,
211 struct device_attribute *attr, char *buf)
212{
213 struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
214 int mirror;
215 if (!dssdev->driver->get_mirror)
216 return -ENOENT;
217 mirror = dssdev->driver->get_mirror(dssdev);
218 return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
219}
220
221static ssize_t display_mirror_store(struct device *dev,
222 struct device_attribute *attr, const char *buf, size_t size)
223{
224 struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
225 int r;
226 bool mirror;
227
228 if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
229 return -ENOENT;
230
231 r = strtobool(buf, &mirror);
232 if (r)
233 return r;
234
235 r = dssdev->driver->set_mirror(dssdev, mirror);
236 if (r)
237 return r;
238
239 return size;
240}
241
242static ssize_t display_wss_show(struct device *dev,
243 struct device_attribute *attr, char *buf)
244{
245 struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
246 unsigned int wss;
247
248 if (!dssdev->driver->get_wss)
249 return -ENOENT;
250
251 wss = dssdev->driver->get_wss(dssdev);
252
253 return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
254}
255
256static ssize_t display_wss_store(struct device *dev,
257 struct device_attribute *attr, const char *buf, size_t size)
258{
259 struct omap_dss_device *dssdev = to_dss_device_sysfs(dev);
260 u32 wss;
261 int r;
262
263 if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
264 return -ENOENT;
265
266 r = kstrtou32(buf, 0, &wss);
267 if (r)
268 return r;
269
270 if (wss > 0xfffff)
271 return -EINVAL;
272
273 r = dssdev->driver->set_wss(dssdev, wss);
274 if (r)
275 return r;
276
277 return size;
278}
279
280static DEVICE_ATTR(display_name, S_IRUGO, display_name_show, NULL);
281static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
282 display_enabled_show, display_enabled_store);
283static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
284 display_tear_show, display_tear_store);
285static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
286 display_timings_show, display_timings_store);
287static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
288 display_rotate_show, display_rotate_store);
289static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
290 display_mirror_show, display_mirror_store);
291static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
292 display_wss_show, display_wss_store);
293
294static const struct attribute *display_sysfs_attrs[] = {
295 &dev_attr_display_name.attr,
296 &dev_attr_enabled.attr,
297 &dev_attr_tear_elim.attr,
298 &dev_attr_timings.attr,
299 &dev_attr_rotate.attr,
300 &dev_attr_mirror.attr,
301 &dev_attr_wss.attr,
302 NULL
303};
304
305int display_init_sysfs(struct platform_device *pdev)
306{
307 struct omap_dss_device *dssdev = NULL;
308 int r;
309
310 for_each_dss_dev(dssdev) {
311 struct kobject *kobj = &dssdev->dev->kobj;
312
313 r = sysfs_create_files(kobj, display_sysfs_attrs);
314 if (r) {
315 DSSERR("failed to create sysfs files\n");
316 goto err;
317 }
318
319 r = sysfs_create_link(&pdev->dev.kobj, kobj, dssdev->alias);
320 if (r) {
321 sysfs_remove_files(kobj, display_sysfs_attrs);
322
323 DSSERR("failed to create sysfs display link\n");
324 goto err;
325 }
326 }
327
328 return 0;
329
330err:
331 display_uninit_sysfs(pdev);
332
333 return r;
334}
335
336void display_uninit_sysfs(struct platform_device *pdev)
337{
338 struct omap_dss_device *dssdev = NULL;
339
340 for_each_dss_dev(dssdev) {
341 sysfs_remove_link(&pdev->dev.kobj, dssdev->alias);
342 sysfs_remove_files(&dssdev->dev->kobj,
343 display_sysfs_attrs);
344 }
345}
diff --git a/drivers/video/fbdev/omap2/dss/display.c b/drivers/video/fbdev/omap2/dss/display.c
new file mode 100644
index 000000000000..2412a0dd0c13
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/display.c
@@ -0,0 +1,338 @@
1/*
2 * linux/drivers/video/omap2/dss/display.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 "DISPLAY"
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/jiffies.h>
28#include <linux/platform_device.h>
29#include <linux/of.h>
30
31#include <video/omapdss.h>
32#include "dss.h"
33#include "dss_features.h"
34
35void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
36 u16 *xres, u16 *yres)
37{
38 *xres = dssdev->panel.timings.x_res;
39 *yres = dssdev->panel.timings.y_res;
40}
41EXPORT_SYMBOL(omapdss_default_get_resolution);
42
43int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
44{
45 switch (dssdev->type) {
46 case OMAP_DISPLAY_TYPE_DPI:
47 if (dssdev->phy.dpi.data_lines == 24)
48 return 24;
49 else
50 return 16;
51
52 case OMAP_DISPLAY_TYPE_DBI:
53 if (dssdev->ctrl.pixel_size == 24)
54 return 24;
55 else
56 return 16;
57 case OMAP_DISPLAY_TYPE_DSI:
58 if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16)
59 return 24;
60 else
61 return 16;
62 case OMAP_DISPLAY_TYPE_VENC:
63 case OMAP_DISPLAY_TYPE_SDI:
64 case OMAP_DISPLAY_TYPE_HDMI:
65 case OMAP_DISPLAY_TYPE_DVI:
66 return 24;
67 default:
68 BUG();
69 return 0;
70 }
71}
72EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);
73
74void omapdss_default_get_timings(struct omap_dss_device *dssdev,
75 struct omap_video_timings *timings)
76{
77 *timings = dssdev->panel.timings;
78}
79EXPORT_SYMBOL(omapdss_default_get_timings);
80
81int dss_suspend_all_devices(void)
82{
83 struct omap_dss_device *dssdev = NULL;
84
85 for_each_dss_dev(dssdev) {
86 if (!dssdev->driver)
87 continue;
88
89 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
90 dssdev->driver->disable(dssdev);
91 dssdev->activate_after_resume = true;
92 } else {
93 dssdev->activate_after_resume = false;
94 }
95 }
96
97 return 0;
98}
99
100int dss_resume_all_devices(void)
101{
102 struct omap_dss_device *dssdev = NULL;
103
104 for_each_dss_dev(dssdev) {
105 if (!dssdev->driver)
106 continue;
107
108 if (dssdev->activate_after_resume) {
109 dssdev->driver->enable(dssdev);
110 dssdev->activate_after_resume = false;
111 }
112 }
113
114 return 0;
115}
116
117void dss_disable_all_devices(void)
118{
119 struct omap_dss_device *dssdev = NULL;
120
121 for_each_dss_dev(dssdev) {
122 if (!dssdev->driver)
123 continue;
124
125 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
126 dssdev->driver->disable(dssdev);
127 }
128}
129
130static LIST_HEAD(panel_list);
131static DEFINE_MUTEX(panel_list_mutex);
132static int disp_num_counter;
133
134int omapdss_register_display(struct omap_dss_device *dssdev)
135{
136 struct omap_dss_driver *drv = dssdev->driver;
137 int id;
138
139 /*
140 * Note: this presumes all the displays are either using DT or non-DT,
141 * which normally should be the case. This also presumes that all
142 * displays either have an DT alias, or none has.
143 */
144
145 if (dssdev->dev->of_node) {
146 id = of_alias_get_id(dssdev->dev->of_node, "display");
147
148 if (id < 0)
149 id = disp_num_counter++;
150 } else {
151 id = disp_num_counter++;
152 }
153
154 snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id);
155
156 /* Use 'label' property for name, if it exists */
157 if (dssdev->dev->of_node)
158 of_property_read_string(dssdev->dev->of_node, "label",
159 &dssdev->name);
160
161 if (dssdev->name == NULL)
162 dssdev->name = dssdev->alias;
163
164 if (drv && drv->get_resolution == NULL)
165 drv->get_resolution = omapdss_default_get_resolution;
166 if (drv && drv->get_recommended_bpp == NULL)
167 drv->get_recommended_bpp = omapdss_default_get_recommended_bpp;
168 if (drv && drv->get_timings == NULL)
169 drv->get_timings = omapdss_default_get_timings;
170
171 mutex_lock(&panel_list_mutex);
172 list_add_tail(&dssdev->panel_list, &panel_list);
173 mutex_unlock(&panel_list_mutex);
174 return 0;
175}
176EXPORT_SYMBOL(omapdss_register_display);
177
178void omapdss_unregister_display(struct omap_dss_device *dssdev)
179{
180 mutex_lock(&panel_list_mutex);
181 list_del(&dssdev->panel_list);
182 mutex_unlock(&panel_list_mutex);
183}
184EXPORT_SYMBOL(omapdss_unregister_display);
185
186struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev)
187{
188 if (!try_module_get(dssdev->owner))
189 return NULL;
190
191 if (get_device(dssdev->dev) == NULL) {
192 module_put(dssdev->owner);
193 return NULL;
194 }
195
196 return dssdev;
197}
198EXPORT_SYMBOL(omap_dss_get_device);
199
200void omap_dss_put_device(struct omap_dss_device *dssdev)
201{
202 put_device(dssdev->dev);
203 module_put(dssdev->owner);
204}
205EXPORT_SYMBOL(omap_dss_put_device);
206
207/*
208 * ref count of the found device is incremented.
209 * ref count of from-device is decremented.
210 */
211struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
212{
213 struct list_head *l;
214 struct omap_dss_device *dssdev;
215
216 mutex_lock(&panel_list_mutex);
217
218 if (list_empty(&panel_list)) {
219 dssdev = NULL;
220 goto out;
221 }
222
223 if (from == NULL) {
224 dssdev = list_first_entry(&panel_list, struct omap_dss_device,
225 panel_list);
226 omap_dss_get_device(dssdev);
227 goto out;
228 }
229
230 omap_dss_put_device(from);
231
232 list_for_each(l, &panel_list) {
233 dssdev = list_entry(l, struct omap_dss_device, panel_list);
234 if (dssdev == from) {
235 if (list_is_last(l, &panel_list)) {
236 dssdev = NULL;
237 goto out;
238 }
239
240 dssdev = list_entry(l->next, struct omap_dss_device,
241 panel_list);
242 omap_dss_get_device(dssdev);
243 goto out;
244 }
245 }
246
247 WARN(1, "'from' dssdev not found\n");
248
249 dssdev = NULL;
250out:
251 mutex_unlock(&panel_list_mutex);
252 return dssdev;
253}
254EXPORT_SYMBOL(omap_dss_get_next_device);
255
256struct omap_dss_device *omap_dss_find_device(void *data,
257 int (*match)(struct omap_dss_device *dssdev, void *data))
258{
259 struct omap_dss_device *dssdev = NULL;
260
261 while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
262 if (match(dssdev, data))
263 return dssdev;
264 }
265
266 return NULL;
267}
268EXPORT_SYMBOL(omap_dss_find_device);
269
270void videomode_to_omap_video_timings(const struct videomode *vm,
271 struct omap_video_timings *ovt)
272{
273 memset(ovt, 0, sizeof(*ovt));
274
275 ovt->pixelclock = vm->pixelclock;
276 ovt->x_res = vm->hactive;
277 ovt->hbp = vm->hback_porch;
278 ovt->hfp = vm->hfront_porch;
279 ovt->hsw = vm->hsync_len;
280 ovt->y_res = vm->vactive;
281 ovt->vbp = vm->vback_porch;
282 ovt->vfp = vm->vfront_porch;
283 ovt->vsw = vm->vsync_len;
284
285 ovt->vsync_level = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
286 OMAPDSS_SIG_ACTIVE_HIGH :
287 OMAPDSS_SIG_ACTIVE_LOW;
288 ovt->hsync_level = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
289 OMAPDSS_SIG_ACTIVE_HIGH :
290 OMAPDSS_SIG_ACTIVE_LOW;
291 ovt->de_level = vm->flags & DISPLAY_FLAGS_DE_HIGH ?
292 OMAPDSS_SIG_ACTIVE_HIGH :
293 OMAPDSS_SIG_ACTIVE_LOW;
294 ovt->data_pclk_edge = vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE ?
295 OMAPDSS_DRIVE_SIG_RISING_EDGE :
296 OMAPDSS_DRIVE_SIG_FALLING_EDGE;
297
298 ovt->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
299}
300EXPORT_SYMBOL(videomode_to_omap_video_timings);
301
302void omap_video_timings_to_videomode(const struct omap_video_timings *ovt,
303 struct videomode *vm)
304{
305 memset(vm, 0, sizeof(*vm));
306
307 vm->pixelclock = ovt->pixelclock;
308
309 vm->hactive = ovt->x_res;
310 vm->hback_porch = ovt->hbp;
311 vm->hfront_porch = ovt->hfp;
312 vm->hsync_len = ovt->hsw;
313 vm->vactive = ovt->y_res;
314 vm->vback_porch = ovt->vbp;
315 vm->vfront_porch = ovt->vfp;
316 vm->vsync_len = ovt->vsw;
317
318 if (ovt->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
319 vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
320 else
321 vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
322
323 if (ovt->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH)
324 vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
325 else
326 vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
327
328 if (ovt->de_level == OMAPDSS_SIG_ACTIVE_HIGH)
329 vm->flags |= DISPLAY_FLAGS_DE_HIGH;
330 else
331 vm->flags |= DISPLAY_FLAGS_DE_LOW;
332
333 if (ovt->data_pclk_edge == OMAPDSS_DRIVE_SIG_RISING_EDGE)
334 vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
335 else
336 vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
337}
338EXPORT_SYMBOL(omap_video_timings_to_videomode);
diff --git a/drivers/video/fbdev/omap2/dss/dpi.c b/drivers/video/fbdev/omap2/dss/dpi.c
new file mode 100644
index 000000000000..157921db447a
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/dpi.c
@@ -0,0 +1,774 @@
1/*
2 * linux/drivers/video/omap2/dss/dpi.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 "DPI"
24
25#include <linux/kernel.h>
26#include <linux/delay.h>
27#include <linux/export.h>
28#include <linux/err.h>
29#include <linux/errno.h>
30#include <linux/platform_device.h>
31#include <linux/regulator/consumer.h>
32#include <linux/string.h>
33#include <linux/of.h>
34
35#include <video/omapdss.h>
36
37#include "dss.h"
38#include "dss_features.h"
39
40static struct {
41 struct platform_device *pdev;
42
43 struct regulator *vdds_dsi_reg;
44 struct platform_device *dsidev;
45
46 struct mutex lock;
47
48 struct omap_video_timings timings;
49 struct dss_lcd_mgr_config mgr_config;
50 int data_lines;
51
52 struct omap_dss_device output;
53
54 bool port_initialized;
55} dpi;
56
57static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
58{
59 /*
60 * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
61 * would also be used for DISPC fclk. Meaning, when the DPI output is
62 * disabled, DISPC clock will be disabled, and TV out will stop.
63 */
64 switch (omapdss_get_version()) {
65 case OMAPDSS_VER_OMAP24xx:
66 case OMAPDSS_VER_OMAP34xx_ES1:
67 case OMAPDSS_VER_OMAP34xx_ES3:
68 case OMAPDSS_VER_OMAP3630:
69 case OMAPDSS_VER_AM35xx:
70 return NULL;
71
72 case OMAPDSS_VER_OMAP4430_ES1:
73 case OMAPDSS_VER_OMAP4430_ES2:
74 case OMAPDSS_VER_OMAP4:
75 switch (channel) {
76 case OMAP_DSS_CHANNEL_LCD:
77 return dsi_get_dsidev_from_id(0);
78 case OMAP_DSS_CHANNEL_LCD2:
79 return dsi_get_dsidev_from_id(1);
80 default:
81 return NULL;
82 }
83
84 case OMAPDSS_VER_OMAP5:
85 switch (channel) {
86 case OMAP_DSS_CHANNEL_LCD:
87 return dsi_get_dsidev_from_id(0);
88 case OMAP_DSS_CHANNEL_LCD3:
89 return dsi_get_dsidev_from_id(1);
90 default:
91 return NULL;
92 }
93
94 default:
95 return NULL;
96 }
97}
98
99static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
100{
101 switch (channel) {
102 case OMAP_DSS_CHANNEL_LCD:
103 return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC;
104 case OMAP_DSS_CHANNEL_LCD2:
105 return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
106 default:
107 /* this shouldn't happen */
108 WARN_ON(1);
109 return OMAP_DSS_CLK_SRC_FCK;
110 }
111}
112
113struct dpi_clk_calc_ctx {
114 struct platform_device *dsidev;
115
116 /* inputs */
117
118 unsigned long pck_min, pck_max;
119
120 /* outputs */
121
122 struct dsi_clock_info dsi_cinfo;
123 unsigned long fck;
124 struct dispc_clock_info dispc_cinfo;
125};
126
127static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
128 unsigned long pck, void *data)
129{
130 struct dpi_clk_calc_ctx *ctx = data;
131
132 /*
133 * Odd dividers give us uneven duty cycle, causing problem when level
134 * shifted. So skip all odd dividers when the pixel clock is on the
135 * higher side.
136 */
137 if (ctx->pck_min >= 100000000) {
138 if (lckd > 1 && lckd % 2 != 0)
139 return false;
140
141 if (pckd > 1 && pckd % 2 != 0)
142 return false;
143 }
144
145 ctx->dispc_cinfo.lck_div = lckd;
146 ctx->dispc_cinfo.pck_div = pckd;
147 ctx->dispc_cinfo.lck = lck;
148 ctx->dispc_cinfo.pck = pck;
149
150 return true;
151}
152
153
154static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
155 void *data)
156{
157 struct dpi_clk_calc_ctx *ctx = data;
158
159 /*
160 * Odd dividers give us uneven duty cycle, causing problem when level
161 * shifted. So skip all odd dividers when the pixel clock is on the
162 * higher side.
163 */
164 if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 100000000)
165 return false;
166
167 ctx->dsi_cinfo.regm_dispc = regm_dispc;
168 ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
169
170 return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
171 dpi_calc_dispc_cb, ctx);
172}
173
174
175static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint,
176 unsigned long pll,
177 void *data)
178{
179 struct dpi_clk_calc_ctx *ctx = data;
180
181 ctx->dsi_cinfo.regn = regn;
182 ctx->dsi_cinfo.regm = regm;
183 ctx->dsi_cinfo.fint = fint;
184 ctx->dsi_cinfo.clkin4ddr = pll;
185
186 return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min,
187 dpi_calc_hsdiv_cb, ctx);
188}
189
190static bool dpi_calc_dss_cb(unsigned long fck, void *data)
191{
192 struct dpi_clk_calc_ctx *ctx = data;
193
194 ctx->fck = fck;
195
196 return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
197 dpi_calc_dispc_cb, ctx);
198}
199
200static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
201{
202 unsigned long clkin;
203 unsigned long pll_min, pll_max;
204
205 clkin = dsi_get_pll_clkin(dpi.dsidev);
206
207 memset(ctx, 0, sizeof(*ctx));
208 ctx->dsidev = dpi.dsidev;
209 ctx->pck_min = pck - 1000;
210 ctx->pck_max = pck + 1000;
211 ctx->dsi_cinfo.clkin = clkin;
212
213 pll_min = 0;
214 pll_max = 0;
215
216 return dsi_pll_calc(dpi.dsidev, clkin,
217 pll_min, pll_max,
218 dpi_calc_pll_cb, ctx);
219}
220
221static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
222{
223 int i;
224
225 /*
226 * DSS fck gives us very few possibilities, so finding a good pixel
227 * clock may not be possible. We try multiple times to find the clock,
228 * each time widening the pixel clock range we look for, up to
229 * +/- ~15MHz.
230 */
231
232 for (i = 0; i < 25; ++i) {
233 bool ok;
234
235 memset(ctx, 0, sizeof(*ctx));
236 if (pck > 1000 * i * i * i)
237 ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
238 else
239 ctx->pck_min = 0;
240 ctx->pck_max = pck + 1000 * i * i * i;
241
242 ok = dss_div_calc(pck, ctx->pck_min, dpi_calc_dss_cb, ctx);
243 if (ok)
244 return ok;
245 }
246
247 return false;
248}
249
250
251
252static int dpi_set_dsi_clk(enum omap_channel channel,
253 unsigned long pck_req, unsigned long *fck, int *lck_div,
254 int *pck_div)
255{
256 struct dpi_clk_calc_ctx ctx;
257 int r;
258 bool ok;
259
260 ok = dpi_dsi_clk_calc(pck_req, &ctx);
261 if (!ok)
262 return -EINVAL;
263
264 r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo);
265 if (r)
266 return r;
267
268 dss_select_lcd_clk_source(channel,
269 dpi_get_alt_clk_src(channel));
270
271 dpi.mgr_config.clock_info = ctx.dispc_cinfo;
272
273 *fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
274 *lck_div = ctx.dispc_cinfo.lck_div;
275 *pck_div = ctx.dispc_cinfo.pck_div;
276
277 return 0;
278}
279
280static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
281 int *lck_div, int *pck_div)
282{
283 struct dpi_clk_calc_ctx ctx;
284 int r;
285 bool ok;
286
287 ok = dpi_dss_clk_calc(pck_req, &ctx);
288 if (!ok)
289 return -EINVAL;
290
291 r = dss_set_fck_rate(ctx.fck);
292 if (r)
293 return r;
294
295 dpi.mgr_config.clock_info = ctx.dispc_cinfo;
296
297 *fck = ctx.fck;
298 *lck_div = ctx.dispc_cinfo.lck_div;
299 *pck_div = ctx.dispc_cinfo.pck_div;
300
301 return 0;
302}
303
304static int dpi_set_mode(struct omap_overlay_manager *mgr)
305{
306 struct omap_video_timings *t = &dpi.timings;
307 int lck_div = 0, pck_div = 0;
308 unsigned long fck = 0;
309 unsigned long pck;
310 int r = 0;
311
312 if (dpi.dsidev)
313 r = dpi_set_dsi_clk(mgr->id, t->pixelclock, &fck,
314 &lck_div, &pck_div);
315 else
316 r = dpi_set_dispc_clk(t->pixelclock, &fck,
317 &lck_div, &pck_div);
318 if (r)
319 return r;
320
321 pck = fck / lck_div / pck_div;
322
323 if (pck != t->pixelclock) {
324 DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
325 t->pixelclock, pck);
326
327 t->pixelclock = pck;
328 }
329
330 dss_mgr_set_timings(mgr, t);
331
332 return 0;
333}
334
335static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr)
336{
337 dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
338
339 dpi.mgr_config.stallmode = false;
340 dpi.mgr_config.fifohandcheck = false;
341
342 dpi.mgr_config.video_port_width = dpi.data_lines;
343
344 dpi.mgr_config.lcden_sig_polarity = 0;
345
346 dss_mgr_set_lcd_config(mgr, &dpi.mgr_config);
347}
348
349static int dpi_display_enable(struct omap_dss_device *dssdev)
350{
351 struct omap_dss_device *out = &dpi.output;
352 int r;
353
354 mutex_lock(&dpi.lock);
355
356 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) {
357 DSSERR("no VDSS_DSI regulator\n");
358 r = -ENODEV;
359 goto err_no_reg;
360 }
361
362 if (out == NULL || out->manager == NULL) {
363 DSSERR("failed to enable display: no output/manager\n");
364 r = -ENODEV;
365 goto err_no_out_mgr;
366 }
367
368 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
369 r = regulator_enable(dpi.vdds_dsi_reg);
370 if (r)
371 goto err_reg_enable;
372 }
373
374 r = dispc_runtime_get();
375 if (r)
376 goto err_get_dispc;
377
378 r = dss_dpi_select_source(out->manager->id);
379 if (r)
380 goto err_src_sel;
381
382 if (dpi.dsidev) {
383 r = dsi_runtime_get(dpi.dsidev);
384 if (r)
385 goto err_get_dsi;
386
387 r = dsi_pll_init(dpi.dsidev, 0, 1);
388 if (r)
389 goto err_dsi_pll_init;
390 }
391
392 r = dpi_set_mode(out->manager);
393 if (r)
394 goto err_set_mode;
395
396 dpi_config_lcd_manager(out->manager);
397
398 mdelay(2);
399
400 r = dss_mgr_enable(out->manager);
401 if (r)
402 goto err_mgr_enable;
403
404 mutex_unlock(&dpi.lock);
405
406 return 0;
407
408err_mgr_enable:
409err_set_mode:
410 if (dpi.dsidev)
411 dsi_pll_uninit(dpi.dsidev, true);
412err_dsi_pll_init:
413 if (dpi.dsidev)
414 dsi_runtime_put(dpi.dsidev);
415err_get_dsi:
416err_src_sel:
417 dispc_runtime_put();
418err_get_dispc:
419 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
420 regulator_disable(dpi.vdds_dsi_reg);
421err_reg_enable:
422err_no_out_mgr:
423err_no_reg:
424 mutex_unlock(&dpi.lock);
425 return r;
426}
427
428static void dpi_display_disable(struct omap_dss_device *dssdev)
429{
430 struct omap_overlay_manager *mgr = dpi.output.manager;
431
432 mutex_lock(&dpi.lock);
433
434 dss_mgr_disable(mgr);
435
436 if (dpi.dsidev) {
437 dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
438 dsi_pll_uninit(dpi.dsidev, true);
439 dsi_runtime_put(dpi.dsidev);
440 }
441
442 dispc_runtime_put();
443
444 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
445 regulator_disable(dpi.vdds_dsi_reg);
446
447 mutex_unlock(&dpi.lock);
448}
449
450static void dpi_set_timings(struct omap_dss_device *dssdev,
451 struct omap_video_timings *timings)
452{
453 DSSDBG("dpi_set_timings\n");
454
455 mutex_lock(&dpi.lock);
456
457 dpi.timings = *timings;
458
459 mutex_unlock(&dpi.lock);
460}
461
462static void dpi_get_timings(struct omap_dss_device *dssdev,
463 struct omap_video_timings *timings)
464{
465 mutex_lock(&dpi.lock);
466
467 *timings = dpi.timings;
468
469 mutex_unlock(&dpi.lock);
470}
471
472static int dpi_check_timings(struct omap_dss_device *dssdev,
473 struct omap_video_timings *timings)
474{
475 struct omap_overlay_manager *mgr = dpi.output.manager;
476 int lck_div, pck_div;
477 unsigned long fck;
478 unsigned long pck;
479 struct dpi_clk_calc_ctx ctx;
480 bool ok;
481
482 if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
483 return -EINVAL;
484
485 if (timings->pixelclock == 0)
486 return -EINVAL;
487
488 if (dpi.dsidev) {
489 ok = dpi_dsi_clk_calc(timings->pixelclock, &ctx);
490 if (!ok)
491 return -EINVAL;
492
493 fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
494 } else {
495 ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
496 if (!ok)
497 return -EINVAL;
498
499 fck = ctx.fck;
500 }
501
502 lck_div = ctx.dispc_cinfo.lck_div;
503 pck_div = ctx.dispc_cinfo.pck_div;
504
505 pck = fck / lck_div / pck_div;
506
507 timings->pixelclock = pck;
508
509 return 0;
510}
511
512static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
513{
514 mutex_lock(&dpi.lock);
515
516 dpi.data_lines = data_lines;
517
518 mutex_unlock(&dpi.lock);
519}
520
521static int dpi_verify_dsi_pll(struct platform_device *dsidev)
522{
523 int r;
524
525 /* do initial setup with the PLL to see if it is operational */
526
527 r = dsi_runtime_get(dsidev);
528 if (r)
529 return r;
530
531 r = dsi_pll_init(dsidev, 0, 1);
532 if (r) {
533 dsi_runtime_put(dsidev);
534 return r;
535 }
536
537 dsi_pll_uninit(dsidev, true);
538 dsi_runtime_put(dsidev);
539
540 return 0;
541}
542
543static int dpi_init_regulator(void)
544{
545 struct regulator *vdds_dsi;
546
547 if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
548 return 0;
549
550 if (dpi.vdds_dsi_reg)
551 return 0;
552
553 vdds_dsi = devm_regulator_get(&dpi.pdev->dev, "vdds_dsi");
554 if (IS_ERR(vdds_dsi)) {
555 if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
556 DSSERR("can't get VDDS_DSI regulator\n");
557 return PTR_ERR(vdds_dsi);
558 }
559
560 dpi.vdds_dsi_reg = vdds_dsi;
561
562 return 0;
563}
564
565static void dpi_init_pll(void)
566{
567 struct platform_device *dsidev;
568
569 if (dpi.dsidev)
570 return;
571
572 dsidev = dpi_get_dsidev(dpi.output.dispc_channel);
573 if (!dsidev)
574 return;
575
576 if (dpi_verify_dsi_pll(dsidev)) {
577 DSSWARN("DSI PLL not operational\n");
578 return;
579 }
580
581 dpi.dsidev = dsidev;
582}
583
584/*
585 * Return a hardcoded channel for the DPI output. This should work for
586 * current use cases, but this can be later expanded to either resolve
587 * the channel in some more dynamic manner, or get the channel as a user
588 * parameter.
589 */
590static enum omap_channel dpi_get_channel(void)
591{
592 switch (omapdss_get_version()) {
593 case OMAPDSS_VER_OMAP24xx:
594 case OMAPDSS_VER_OMAP34xx_ES1:
595 case OMAPDSS_VER_OMAP34xx_ES3:
596 case OMAPDSS_VER_OMAP3630:
597 case OMAPDSS_VER_AM35xx:
598 return OMAP_DSS_CHANNEL_LCD;
599
600 case OMAPDSS_VER_OMAP4430_ES1:
601 case OMAPDSS_VER_OMAP4430_ES2:
602 case OMAPDSS_VER_OMAP4:
603 return OMAP_DSS_CHANNEL_LCD2;
604
605 case OMAPDSS_VER_OMAP5:
606 return OMAP_DSS_CHANNEL_LCD3;
607
608 default:
609 DSSWARN("unsupported DSS version\n");
610 return OMAP_DSS_CHANNEL_LCD;
611 }
612}
613
614static int dpi_connect(struct omap_dss_device *dssdev,
615 struct omap_dss_device *dst)
616{
617 struct omap_overlay_manager *mgr;
618 int r;
619
620 r = dpi_init_regulator();
621 if (r)
622 return r;
623
624 dpi_init_pll();
625
626 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
627 if (!mgr)
628 return -ENODEV;
629
630 r = dss_mgr_connect(mgr, dssdev);
631 if (r)
632 return r;
633
634 r = omapdss_output_set_device(dssdev, dst);
635 if (r) {
636 DSSERR("failed to connect output to new device: %s\n",
637 dst->name);
638 dss_mgr_disconnect(mgr, dssdev);
639 return r;
640 }
641
642 return 0;
643}
644
645static void dpi_disconnect(struct omap_dss_device *dssdev,
646 struct omap_dss_device *dst)
647{
648 WARN_ON(dst != dssdev->dst);
649
650 if (dst != dssdev->dst)
651 return;
652
653 omapdss_output_unset_device(dssdev);
654
655 if (dssdev->manager)
656 dss_mgr_disconnect(dssdev->manager, dssdev);
657}
658
659static const struct omapdss_dpi_ops dpi_ops = {
660 .connect = dpi_connect,
661 .disconnect = dpi_disconnect,
662
663 .enable = dpi_display_enable,
664 .disable = dpi_display_disable,
665
666 .check_timings = dpi_check_timings,
667 .set_timings = dpi_set_timings,
668 .get_timings = dpi_get_timings,
669
670 .set_data_lines = dpi_set_data_lines,
671};
672
673static void dpi_init_output(struct platform_device *pdev)
674{
675 struct omap_dss_device *out = &dpi.output;
676
677 out->dev = &pdev->dev;
678 out->id = OMAP_DSS_OUTPUT_DPI;
679 out->output_type = OMAP_DISPLAY_TYPE_DPI;
680 out->name = "dpi.0";
681 out->dispc_channel = dpi_get_channel();
682 out->ops.dpi = &dpi_ops;
683 out->owner = THIS_MODULE;
684
685 omapdss_register_output(out);
686}
687
688static void __exit dpi_uninit_output(struct platform_device *pdev)
689{
690 struct omap_dss_device *out = &dpi.output;
691
692 omapdss_unregister_output(out);
693}
694
695static int omap_dpi_probe(struct platform_device *pdev)
696{
697 dpi.pdev = pdev;
698
699 mutex_init(&dpi.lock);
700
701 dpi_init_output(pdev);
702
703 return 0;
704}
705
706static int __exit omap_dpi_remove(struct platform_device *pdev)
707{
708 dpi_uninit_output(pdev);
709
710 return 0;
711}
712
713static struct platform_driver omap_dpi_driver = {
714 .probe = omap_dpi_probe,
715 .remove = __exit_p(omap_dpi_remove),
716 .driver = {
717 .name = "omapdss_dpi",
718 .owner = THIS_MODULE,
719 },
720};
721
722int __init dpi_init_platform_driver(void)
723{
724 return platform_driver_register(&omap_dpi_driver);
725}
726
727void __exit dpi_uninit_platform_driver(void)
728{
729 platform_driver_unregister(&omap_dpi_driver);
730}
731
732int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
733{
734 struct device_node *ep;
735 u32 datalines;
736 int r;
737
738 ep = omapdss_of_get_next_endpoint(port, NULL);
739 if (!ep)
740 return 0;
741
742 r = of_property_read_u32(ep, "data-lines", &datalines);
743 if (r) {
744 DSSERR("failed to parse datalines\n");
745 goto err_datalines;
746 }
747
748 dpi.data_lines = datalines;
749
750 of_node_put(ep);
751
752 dpi.pdev = pdev;
753
754 mutex_init(&dpi.lock);
755
756 dpi_init_output(pdev);
757
758 dpi.port_initialized = true;
759
760 return 0;
761
762err_datalines:
763 of_node_put(ep);
764
765 return r;
766}
767
768void __exit dpi_uninit_port(void)
769{
770 if (!dpi.port_initialized)
771 return;
772
773 dpi_uninit_output(dpi.pdev);
774}
diff --git a/drivers/video/fbdev/omap2/dss/dsi.c b/drivers/video/fbdev/omap2/dss/dsi.c
new file mode 100644
index 000000000000..8be9b04d8849
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/dsi.c
@@ -0,0 +1,5751 @@
1/*
2 * linux/drivers/video/omap2/dss/dsi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#define DSS_SUBSYS_NAME "DSI"
21
22#include <linux/kernel.h>
23#include <linux/io.h>
24#include <linux/clk.h>
25#include <linux/device.h>
26#include <linux/err.h>
27#include <linux/interrupt.h>
28#include <linux/delay.h>
29#include <linux/mutex.h>
30#include <linux/module.h>
31#include <linux/semaphore.h>
32#include <linux/seq_file.h>
33#include <linux/platform_device.h>
34#include <linux/regulator/consumer.h>
35#include <linux/wait.h>
36#include <linux/workqueue.h>
37#include <linux/sched.h>
38#include <linux/slab.h>
39#include <linux/debugfs.h>
40#include <linux/pm_runtime.h>
41#include <linux/of.h>
42#include <linux/of_platform.h>
43
44#include <video/omapdss.h>
45#include <video/mipi_display.h>
46
47#include "dss.h"
48#include "dss_features.h"
49
50#define DSI_CATCH_MISSING_TE
51
52struct dsi_reg { u16 module; u16 idx; };
53
54#define DSI_REG(mod, idx) ((const struct dsi_reg) { mod, idx })
55
56/* DSI Protocol Engine */
57
58#define DSI_PROTO 0
59#define DSI_PROTO_SZ 0x200
60
61#define DSI_REVISION DSI_REG(DSI_PROTO, 0x0000)
62#define DSI_SYSCONFIG DSI_REG(DSI_PROTO, 0x0010)
63#define DSI_SYSSTATUS DSI_REG(DSI_PROTO, 0x0014)
64#define DSI_IRQSTATUS DSI_REG(DSI_PROTO, 0x0018)
65#define DSI_IRQENABLE DSI_REG(DSI_PROTO, 0x001C)
66#define DSI_CTRL DSI_REG(DSI_PROTO, 0x0040)
67#define DSI_GNQ DSI_REG(DSI_PROTO, 0x0044)
68#define DSI_COMPLEXIO_CFG1 DSI_REG(DSI_PROTO, 0x0048)
69#define DSI_COMPLEXIO_IRQ_STATUS DSI_REG(DSI_PROTO, 0x004C)
70#define DSI_COMPLEXIO_IRQ_ENABLE DSI_REG(DSI_PROTO, 0x0050)
71#define DSI_CLK_CTRL DSI_REG(DSI_PROTO, 0x0054)
72#define DSI_TIMING1 DSI_REG(DSI_PROTO, 0x0058)
73#define DSI_TIMING2 DSI_REG(DSI_PROTO, 0x005C)
74#define DSI_VM_TIMING1 DSI_REG(DSI_PROTO, 0x0060)
75#define DSI_VM_TIMING2 DSI_REG(DSI_PROTO, 0x0064)
76#define DSI_VM_TIMING3 DSI_REG(DSI_PROTO, 0x0068)
77#define DSI_CLK_TIMING DSI_REG(DSI_PROTO, 0x006C)
78#define DSI_TX_FIFO_VC_SIZE DSI_REG(DSI_PROTO, 0x0070)
79#define DSI_RX_FIFO_VC_SIZE DSI_REG(DSI_PROTO, 0x0074)
80#define DSI_COMPLEXIO_CFG2 DSI_REG(DSI_PROTO, 0x0078)
81#define DSI_RX_FIFO_VC_FULLNESS DSI_REG(DSI_PROTO, 0x007C)
82#define DSI_VM_TIMING4 DSI_REG(DSI_PROTO, 0x0080)
83#define DSI_TX_FIFO_VC_EMPTINESS DSI_REG(DSI_PROTO, 0x0084)
84#define DSI_VM_TIMING5 DSI_REG(DSI_PROTO, 0x0088)
85#define DSI_VM_TIMING6 DSI_REG(DSI_PROTO, 0x008C)
86#define DSI_VM_TIMING7 DSI_REG(DSI_PROTO, 0x0090)
87#define DSI_STOPCLK_TIMING DSI_REG(DSI_PROTO, 0x0094)
88#define DSI_VC_CTRL(n) DSI_REG(DSI_PROTO, 0x0100 + (n * 0x20))
89#define DSI_VC_TE(n) DSI_REG(DSI_PROTO, 0x0104 + (n * 0x20))
90#define DSI_VC_LONG_PACKET_HEADER(n) DSI_REG(DSI_PROTO, 0x0108 + (n * 0x20))
91#define DSI_VC_LONG_PACKET_PAYLOAD(n) DSI_REG(DSI_PROTO, 0x010C + (n * 0x20))
92#define DSI_VC_SHORT_PACKET_HEADER(n) DSI_REG(DSI_PROTO, 0x0110 + (n * 0x20))
93#define DSI_VC_IRQSTATUS(n) DSI_REG(DSI_PROTO, 0x0118 + (n * 0x20))
94#define DSI_VC_IRQENABLE(n) DSI_REG(DSI_PROTO, 0x011C + (n * 0x20))
95
96/* DSIPHY_SCP */
97
98#define DSI_PHY 1
99#define DSI_PHY_OFFSET 0x200
100#define DSI_PHY_SZ 0x40
101
102#define DSI_DSIPHY_CFG0 DSI_REG(DSI_PHY, 0x0000)
103#define DSI_DSIPHY_CFG1 DSI_REG(DSI_PHY, 0x0004)
104#define DSI_DSIPHY_CFG2 DSI_REG(DSI_PHY, 0x0008)
105#define DSI_DSIPHY_CFG5 DSI_REG(DSI_PHY, 0x0014)
106#define DSI_DSIPHY_CFG10 DSI_REG(DSI_PHY, 0x0028)
107
108/* DSI_PLL_CTRL_SCP */
109
110#define DSI_PLL 2
111#define DSI_PLL_OFFSET 0x300
112#define DSI_PLL_SZ 0x20
113
114#define DSI_PLL_CONTROL DSI_REG(DSI_PLL, 0x0000)
115#define DSI_PLL_STATUS DSI_REG(DSI_PLL, 0x0004)
116#define DSI_PLL_GO DSI_REG(DSI_PLL, 0x0008)
117#define DSI_PLL_CONFIGURATION1 DSI_REG(DSI_PLL, 0x000C)
118#define DSI_PLL_CONFIGURATION2 DSI_REG(DSI_PLL, 0x0010)
119
120#define REG_GET(dsidev, idx, start, end) \
121 FLD_GET(dsi_read_reg(dsidev, idx), start, end)
122
123#define REG_FLD_MOD(dsidev, idx, val, start, end) \
124 dsi_write_reg(dsidev, idx, FLD_MOD(dsi_read_reg(dsidev, idx), val, start, end))
125
126/* Global interrupts */
127#define DSI_IRQ_VC0 (1 << 0)
128#define DSI_IRQ_VC1 (1 << 1)
129#define DSI_IRQ_VC2 (1 << 2)
130#define DSI_IRQ_VC3 (1 << 3)
131#define DSI_IRQ_WAKEUP (1 << 4)
132#define DSI_IRQ_RESYNC (1 << 5)
133#define DSI_IRQ_PLL_LOCK (1 << 7)
134#define DSI_IRQ_PLL_UNLOCK (1 << 8)
135#define DSI_IRQ_PLL_RECALL (1 << 9)
136#define DSI_IRQ_COMPLEXIO_ERR (1 << 10)
137#define DSI_IRQ_HS_TX_TIMEOUT (1 << 14)
138#define DSI_IRQ_LP_RX_TIMEOUT (1 << 15)
139#define DSI_IRQ_TE_TRIGGER (1 << 16)
140#define DSI_IRQ_ACK_TRIGGER (1 << 17)
141#define DSI_IRQ_SYNC_LOST (1 << 18)
142#define DSI_IRQ_LDO_POWER_GOOD (1 << 19)
143#define DSI_IRQ_TA_TIMEOUT (1 << 20)
144#define DSI_IRQ_ERROR_MASK \
145 (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \
146 DSI_IRQ_TA_TIMEOUT | DSI_IRQ_SYNC_LOST)
147#define DSI_IRQ_CHANNEL_MASK 0xf
148
149/* Virtual channel interrupts */
150#define DSI_VC_IRQ_CS (1 << 0)
151#define DSI_VC_IRQ_ECC_CORR (1 << 1)
152#define DSI_VC_IRQ_PACKET_SENT (1 << 2)
153#define DSI_VC_IRQ_FIFO_TX_OVF (1 << 3)
154#define DSI_VC_IRQ_FIFO_RX_OVF (1 << 4)
155#define DSI_VC_IRQ_BTA (1 << 5)
156#define DSI_VC_IRQ_ECC_NO_CORR (1 << 6)
157#define DSI_VC_IRQ_FIFO_TX_UDF (1 << 7)
158#define DSI_VC_IRQ_PP_BUSY_CHANGE (1 << 8)
159#define DSI_VC_IRQ_ERROR_MASK \
160 (DSI_VC_IRQ_CS | DSI_VC_IRQ_ECC_CORR | DSI_VC_IRQ_FIFO_TX_OVF | \
161 DSI_VC_IRQ_FIFO_RX_OVF | DSI_VC_IRQ_ECC_NO_CORR | \
162 DSI_VC_IRQ_FIFO_TX_UDF)
163
164/* ComplexIO interrupts */
165#define DSI_CIO_IRQ_ERRSYNCESC1 (1 << 0)
166#define DSI_CIO_IRQ_ERRSYNCESC2 (1 << 1)
167#define DSI_CIO_IRQ_ERRSYNCESC3 (1 << 2)
168#define DSI_CIO_IRQ_ERRSYNCESC4 (1 << 3)
169#define DSI_CIO_IRQ_ERRSYNCESC5 (1 << 4)
170#define DSI_CIO_IRQ_ERRESC1 (1 << 5)
171#define DSI_CIO_IRQ_ERRESC2 (1 << 6)
172#define DSI_CIO_IRQ_ERRESC3 (1 << 7)
173#define DSI_CIO_IRQ_ERRESC4 (1 << 8)
174#define DSI_CIO_IRQ_ERRESC5 (1 << 9)
175#define DSI_CIO_IRQ_ERRCONTROL1 (1 << 10)
176#define DSI_CIO_IRQ_ERRCONTROL2 (1 << 11)
177#define DSI_CIO_IRQ_ERRCONTROL3 (1 << 12)
178#define DSI_CIO_IRQ_ERRCONTROL4 (1 << 13)
179#define DSI_CIO_IRQ_ERRCONTROL5 (1 << 14)
180#define DSI_CIO_IRQ_STATEULPS1 (1 << 15)
181#define DSI_CIO_IRQ_STATEULPS2 (1 << 16)
182#define DSI_CIO_IRQ_STATEULPS3 (1 << 17)
183#define DSI_CIO_IRQ_STATEULPS4 (1 << 18)
184#define DSI_CIO_IRQ_STATEULPS5 (1 << 19)
185#define DSI_CIO_IRQ_ERRCONTENTIONLP0_1 (1 << 20)
186#define DSI_CIO_IRQ_ERRCONTENTIONLP1_1 (1 << 21)
187#define DSI_CIO_IRQ_ERRCONTENTIONLP0_2 (1 << 22)
188#define DSI_CIO_IRQ_ERRCONTENTIONLP1_2 (1 << 23)
189#define DSI_CIO_IRQ_ERRCONTENTIONLP0_3 (1 << 24)
190#define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25)
191#define DSI_CIO_IRQ_ERRCONTENTIONLP0_4 (1 << 26)
192#define DSI_CIO_IRQ_ERRCONTENTIONLP1_4 (1 << 27)
193#define DSI_CIO_IRQ_ERRCONTENTIONLP0_5 (1 << 28)
194#define DSI_CIO_IRQ_ERRCONTENTIONLP1_5 (1 << 29)
195#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30)
196#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31)
197#define DSI_CIO_IRQ_ERROR_MASK \
198 (DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \
199 DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRSYNCESC4 | \
200 DSI_CIO_IRQ_ERRSYNCESC5 | \
201 DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \
202 DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRESC4 | \
203 DSI_CIO_IRQ_ERRESC5 | \
204 DSI_CIO_IRQ_ERRCONTROL1 | DSI_CIO_IRQ_ERRCONTROL2 | \
205 DSI_CIO_IRQ_ERRCONTROL3 | DSI_CIO_IRQ_ERRCONTROL4 | \
206 DSI_CIO_IRQ_ERRCONTROL5 | \
207 DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \
208 DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \
209 DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3 | \
210 DSI_CIO_IRQ_ERRCONTENTIONLP0_4 | DSI_CIO_IRQ_ERRCONTENTIONLP1_4 | \
211 DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5)
212
213typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
214
215static int dsi_display_init_dispc(struct platform_device *dsidev,
216 struct omap_overlay_manager *mgr);
217static void dsi_display_uninit_dispc(struct platform_device *dsidev,
218 struct omap_overlay_manager *mgr);
219
220static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel);
221
222#define DSI_MAX_NR_ISRS 2
223#define DSI_MAX_NR_LANES 5
224
225enum dsi_lane_function {
226 DSI_LANE_UNUSED = 0,
227 DSI_LANE_CLK,
228 DSI_LANE_DATA1,
229 DSI_LANE_DATA2,
230 DSI_LANE_DATA3,
231 DSI_LANE_DATA4,
232};
233
234struct dsi_lane_config {
235 enum dsi_lane_function function;
236 u8 polarity;
237};
238
239struct dsi_isr_data {
240 omap_dsi_isr_t isr;
241 void *arg;
242 u32 mask;
243};
244
245enum fifo_size {
246 DSI_FIFO_SIZE_0 = 0,
247 DSI_FIFO_SIZE_32 = 1,
248 DSI_FIFO_SIZE_64 = 2,
249 DSI_FIFO_SIZE_96 = 3,
250 DSI_FIFO_SIZE_128 = 4,
251};
252
253enum dsi_vc_source {
254 DSI_VC_SOURCE_L4 = 0,
255 DSI_VC_SOURCE_VP,
256};
257
258struct dsi_irq_stats {
259 unsigned long last_reset;
260 unsigned irq_count;
261 unsigned dsi_irqs[32];
262 unsigned vc_irqs[4][32];
263 unsigned cio_irqs[32];
264};
265
266struct dsi_isr_tables {
267 struct dsi_isr_data isr_table[DSI_MAX_NR_ISRS];
268 struct dsi_isr_data isr_table_vc[4][DSI_MAX_NR_ISRS];
269 struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
270};
271
272struct dsi_clk_calc_ctx {
273 struct platform_device *dsidev;
274
275 /* inputs */
276
277 const struct omap_dss_dsi_config *config;
278
279 unsigned long req_pck_min, req_pck_nom, req_pck_max;
280
281 /* outputs */
282
283 struct dsi_clock_info dsi_cinfo;
284 struct dispc_clock_info dispc_cinfo;
285
286 struct omap_video_timings dispc_vm;
287 struct omap_dss_dsi_videomode_timings dsi_vm;
288};
289
290struct dsi_data {
291 struct platform_device *pdev;
292 void __iomem *proto_base;
293 void __iomem *phy_base;
294 void __iomem *pll_base;
295
296 int module_id;
297
298 int irq;
299
300 bool is_enabled;
301
302 struct clk *dss_clk;
303 struct clk *sys_clk;
304
305 struct dispc_clock_info user_dispc_cinfo;
306 struct dsi_clock_info user_dsi_cinfo;
307
308 struct dsi_clock_info current_cinfo;
309
310 bool vdds_dsi_enabled;
311 struct regulator *vdds_dsi_reg;
312
313 struct {
314 enum dsi_vc_source source;
315 struct omap_dss_device *dssdev;
316 enum fifo_size tx_fifo_size;
317 enum fifo_size rx_fifo_size;
318 int vc_id;
319 } vc[4];
320
321 struct mutex lock;
322 struct semaphore bus_lock;
323
324 unsigned pll_locked;
325
326 spinlock_t irq_lock;
327 struct dsi_isr_tables isr_tables;
328 /* space for a copy used by the interrupt handler */
329 struct dsi_isr_tables isr_tables_copy;
330
331 int update_channel;
332#ifdef DSI_PERF_MEASURE
333 unsigned update_bytes;
334#endif
335
336 bool te_enabled;
337 bool ulps_enabled;
338
339 void (*framedone_callback)(int, void *);
340 void *framedone_data;
341
342 struct delayed_work framedone_timeout_work;
343
344#ifdef DSI_CATCH_MISSING_TE
345 struct timer_list te_timer;
346#endif
347
348 unsigned long cache_req_pck;
349 unsigned long cache_clk_freq;
350 struct dsi_clock_info cache_cinfo;
351
352 u32 errors;
353 spinlock_t errors_lock;
354#ifdef DSI_PERF_MEASURE
355 ktime_t perf_setup_time;
356 ktime_t perf_start_time;
357#endif
358 int debug_read;
359 int debug_write;
360
361#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
362 spinlock_t irq_stats_lock;
363 struct dsi_irq_stats irq_stats;
364#endif
365 /* DSI PLL Parameter Ranges */
366 unsigned long regm_max, regn_max;
367 unsigned long regm_dispc_max, regm_dsi_max;
368 unsigned long fint_min, fint_max;
369 unsigned long lpdiv_max;
370
371 unsigned num_lanes_supported;
372 unsigned line_buffer_size;
373
374 struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
375 unsigned num_lanes_used;
376
377 unsigned scp_clk_refcount;
378
379 struct dss_lcd_mgr_config mgr_config;
380 struct omap_video_timings timings;
381 enum omap_dss_dsi_pixel_format pix_fmt;
382 enum omap_dss_dsi_mode mode;
383 struct omap_dss_dsi_videomode_timings vm_timings;
384
385 struct omap_dss_device output;
386};
387
388struct dsi_packet_sent_handler_data {
389 struct platform_device *dsidev;
390 struct completion *completion;
391};
392
393struct dsi_module_id_data {
394 u32 address;
395 int id;
396};
397
398static const struct of_device_id dsi_of_match[];
399
400#ifdef DSI_PERF_MEASURE
401static bool dsi_perf;
402module_param(dsi_perf, bool, 0644);
403#endif
404
405static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev)
406{
407 return dev_get_drvdata(&dsidev->dev);
408}
409
410static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
411{
412 return to_platform_device(dssdev->dev);
413}
414
415struct platform_device *dsi_get_dsidev_from_id(int module)
416{
417 struct omap_dss_device *out;
418 enum omap_dss_output_id id;
419
420 switch (module) {
421 case 0:
422 id = OMAP_DSS_OUTPUT_DSI1;
423 break;
424 case 1:
425 id = OMAP_DSS_OUTPUT_DSI2;
426 break;
427 default:
428 return NULL;
429 }
430
431 out = omap_dss_get_output(id);
432
433 return out ? to_platform_device(out->dev) : NULL;
434}
435
436static inline void dsi_write_reg(struct platform_device *dsidev,
437 const struct dsi_reg idx, u32 val)
438{
439 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
440 void __iomem *base;
441
442 switch(idx.module) {
443 case DSI_PROTO: base = dsi->proto_base; break;
444 case DSI_PHY: base = dsi->phy_base; break;
445 case DSI_PLL: base = dsi->pll_base; break;
446 default: return;
447 }
448
449 __raw_writel(val, base + idx.idx);
450}
451
452static inline u32 dsi_read_reg(struct platform_device *dsidev,
453 const struct dsi_reg idx)
454{
455 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
456 void __iomem *base;
457
458 switch(idx.module) {
459 case DSI_PROTO: base = dsi->proto_base; break;
460 case DSI_PHY: base = dsi->phy_base; break;
461 case DSI_PLL: base = dsi->pll_base; break;
462 default: return 0;
463 }
464
465 return __raw_readl(base + idx.idx);
466}
467
468static void dsi_bus_lock(struct omap_dss_device *dssdev)
469{
470 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
471 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
472
473 down(&dsi->bus_lock);
474}
475
476static void dsi_bus_unlock(struct omap_dss_device *dssdev)
477{
478 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
479 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
480
481 up(&dsi->bus_lock);
482}
483
484static bool dsi_bus_is_locked(struct platform_device *dsidev)
485{
486 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
487
488 return dsi->bus_lock.count == 0;
489}
490
491static void dsi_completion_handler(void *data, u32 mask)
492{
493 complete((struct completion *)data);
494}
495
496static inline int wait_for_bit_change(struct platform_device *dsidev,
497 const struct dsi_reg idx, int bitnum, int value)
498{
499 unsigned long timeout;
500 ktime_t wait;
501 int t;
502
503 /* first busyloop to see if the bit changes right away */
504 t = 100;
505 while (t-- > 0) {
506 if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
507 return value;
508 }
509
510 /* then loop for 500ms, sleeping for 1ms in between */
511 timeout = jiffies + msecs_to_jiffies(500);
512 while (time_before(jiffies, timeout)) {
513 if (REG_GET(dsidev, idx, bitnum, bitnum) == value)
514 return value;
515
516 wait = ns_to_ktime(1000 * 1000);
517 set_current_state(TASK_UNINTERRUPTIBLE);
518 schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
519 }
520
521 return !value;
522}
523
524u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
525{
526 switch (fmt) {
527 case OMAP_DSS_DSI_FMT_RGB888:
528 case OMAP_DSS_DSI_FMT_RGB666:
529 return 24;
530 case OMAP_DSS_DSI_FMT_RGB666_PACKED:
531 return 18;
532 case OMAP_DSS_DSI_FMT_RGB565:
533 return 16;
534 default:
535 BUG();
536 return 0;
537 }
538}
539
540#ifdef DSI_PERF_MEASURE
541static void dsi_perf_mark_setup(struct platform_device *dsidev)
542{
543 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
544 dsi->perf_setup_time = ktime_get();
545}
546
547static void dsi_perf_mark_start(struct platform_device *dsidev)
548{
549 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
550 dsi->perf_start_time = ktime_get();
551}
552
553static void dsi_perf_show(struct platform_device *dsidev, const char *name)
554{
555 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
556 ktime_t t, setup_time, trans_time;
557 u32 total_bytes;
558 u32 setup_us, trans_us, total_us;
559
560 if (!dsi_perf)
561 return;
562
563 t = ktime_get();
564
565 setup_time = ktime_sub(dsi->perf_start_time, dsi->perf_setup_time);
566 setup_us = (u32)ktime_to_us(setup_time);
567 if (setup_us == 0)
568 setup_us = 1;
569
570 trans_time = ktime_sub(t, dsi->perf_start_time);
571 trans_us = (u32)ktime_to_us(trans_time);
572 if (trans_us == 0)
573 trans_us = 1;
574
575 total_us = setup_us + trans_us;
576
577 total_bytes = dsi->update_bytes;
578
579 printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
580 "%u bytes, %u kbytes/sec\n",
581 name,
582 setup_us,
583 trans_us,
584 total_us,
585 1000*1000 / total_us,
586 total_bytes,
587 total_bytes * 1000 / total_us);
588}
589#else
590static inline void dsi_perf_mark_setup(struct platform_device *dsidev)
591{
592}
593
594static inline void dsi_perf_mark_start(struct platform_device *dsidev)
595{
596}
597
598static inline void dsi_perf_show(struct platform_device *dsidev,
599 const char *name)
600{
601}
602#endif
603
604static int verbose_irq;
605
606static void print_irq_status(u32 status)
607{
608 if (status == 0)
609 return;
610
611 if (!verbose_irq && (status & ~DSI_IRQ_CHANNEL_MASK) == 0)
612 return;
613
614#define PIS(x) (status & DSI_IRQ_##x) ? (#x " ") : ""
615
616 pr_debug("DSI IRQ: 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
617 status,
618 verbose_irq ? PIS(VC0) : "",
619 verbose_irq ? PIS(VC1) : "",
620 verbose_irq ? PIS(VC2) : "",
621 verbose_irq ? PIS(VC3) : "",
622 PIS(WAKEUP),
623 PIS(RESYNC),
624 PIS(PLL_LOCK),
625 PIS(PLL_UNLOCK),
626 PIS(PLL_RECALL),
627 PIS(COMPLEXIO_ERR),
628 PIS(HS_TX_TIMEOUT),
629 PIS(LP_RX_TIMEOUT),
630 PIS(TE_TRIGGER),
631 PIS(ACK_TRIGGER),
632 PIS(SYNC_LOST),
633 PIS(LDO_POWER_GOOD),
634 PIS(TA_TIMEOUT));
635#undef PIS
636}
637
638static void print_irq_status_vc(int channel, u32 status)
639{
640 if (status == 0)
641 return;
642
643 if (!verbose_irq && (status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
644 return;
645
646#define PIS(x) (status & DSI_VC_IRQ_##x) ? (#x " ") : ""
647
648 pr_debug("DSI VC(%d) IRQ 0x%x: %s%s%s%s%s%s%s%s%s\n",
649 channel,
650 status,
651 PIS(CS),
652 PIS(ECC_CORR),
653 PIS(ECC_NO_CORR),
654 verbose_irq ? PIS(PACKET_SENT) : "",
655 PIS(BTA),
656 PIS(FIFO_TX_OVF),
657 PIS(FIFO_RX_OVF),
658 PIS(FIFO_TX_UDF),
659 PIS(PP_BUSY_CHANGE));
660#undef PIS
661}
662
663static void print_irq_status_cio(u32 status)
664{
665 if (status == 0)
666 return;
667
668#define PIS(x) (status & DSI_CIO_IRQ_##x) ? (#x " ") : ""
669
670 pr_debug("DSI CIO IRQ 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
671 status,
672 PIS(ERRSYNCESC1),
673 PIS(ERRSYNCESC2),
674 PIS(ERRSYNCESC3),
675 PIS(ERRESC1),
676 PIS(ERRESC2),
677 PIS(ERRESC3),
678 PIS(ERRCONTROL1),
679 PIS(ERRCONTROL2),
680 PIS(ERRCONTROL3),
681 PIS(STATEULPS1),
682 PIS(STATEULPS2),
683 PIS(STATEULPS3),
684 PIS(ERRCONTENTIONLP0_1),
685 PIS(ERRCONTENTIONLP1_1),
686 PIS(ERRCONTENTIONLP0_2),
687 PIS(ERRCONTENTIONLP1_2),
688 PIS(ERRCONTENTIONLP0_3),
689 PIS(ERRCONTENTIONLP1_3),
690 PIS(ULPSACTIVENOT_ALL0),
691 PIS(ULPSACTIVENOT_ALL1));
692#undef PIS
693}
694
695#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
696static void dsi_collect_irq_stats(struct platform_device *dsidev, u32 irqstatus,
697 u32 *vcstatus, u32 ciostatus)
698{
699 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
700 int i;
701
702 spin_lock(&dsi->irq_stats_lock);
703
704 dsi->irq_stats.irq_count++;
705 dss_collect_irq_stats(irqstatus, dsi->irq_stats.dsi_irqs);
706
707 for (i = 0; i < 4; ++i)
708 dss_collect_irq_stats(vcstatus[i], dsi->irq_stats.vc_irqs[i]);
709
710 dss_collect_irq_stats(ciostatus, dsi->irq_stats.cio_irqs);
711
712 spin_unlock(&dsi->irq_stats_lock);
713}
714#else
715#define dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus)
716#endif
717
718static int debug_irq;
719
720static void dsi_handle_irq_errors(struct platform_device *dsidev, u32 irqstatus,
721 u32 *vcstatus, u32 ciostatus)
722{
723 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
724 int i;
725
726 if (irqstatus & DSI_IRQ_ERROR_MASK) {
727 DSSERR("DSI error, irqstatus %x\n", irqstatus);
728 print_irq_status(irqstatus);
729 spin_lock(&dsi->errors_lock);
730 dsi->errors |= irqstatus & DSI_IRQ_ERROR_MASK;
731 spin_unlock(&dsi->errors_lock);
732 } else if (debug_irq) {
733 print_irq_status(irqstatus);
734 }
735
736 for (i = 0; i < 4; ++i) {
737 if (vcstatus[i] & DSI_VC_IRQ_ERROR_MASK) {
738 DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
739 i, vcstatus[i]);
740 print_irq_status_vc(i, vcstatus[i]);
741 } else if (debug_irq) {
742 print_irq_status_vc(i, vcstatus[i]);
743 }
744 }
745
746 if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
747 DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
748 print_irq_status_cio(ciostatus);
749 } else if (debug_irq) {
750 print_irq_status_cio(ciostatus);
751 }
752}
753
754static void dsi_call_isrs(struct dsi_isr_data *isr_array,
755 unsigned isr_array_size, u32 irqstatus)
756{
757 struct dsi_isr_data *isr_data;
758 int i;
759
760 for (i = 0; i < isr_array_size; i++) {
761 isr_data = &isr_array[i];
762 if (isr_data->isr && isr_data->mask & irqstatus)
763 isr_data->isr(isr_data->arg, irqstatus);
764 }
765}
766
767static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
768 u32 irqstatus, u32 *vcstatus, u32 ciostatus)
769{
770 int i;
771
772 dsi_call_isrs(isr_tables->isr_table,
773 ARRAY_SIZE(isr_tables->isr_table),
774 irqstatus);
775
776 for (i = 0; i < 4; ++i) {
777 if (vcstatus[i] == 0)
778 continue;
779 dsi_call_isrs(isr_tables->isr_table_vc[i],
780 ARRAY_SIZE(isr_tables->isr_table_vc[i]),
781 vcstatus[i]);
782 }
783
784 if (ciostatus != 0)
785 dsi_call_isrs(isr_tables->isr_table_cio,
786 ARRAY_SIZE(isr_tables->isr_table_cio),
787 ciostatus);
788}
789
790static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
791{
792 struct platform_device *dsidev;
793 struct dsi_data *dsi;
794 u32 irqstatus, vcstatus[4], ciostatus;
795 int i;
796
797 dsidev = (struct platform_device *) arg;
798 dsi = dsi_get_dsidrv_data(dsidev);
799
800 if (!dsi->is_enabled)
801 return IRQ_NONE;
802
803 spin_lock(&dsi->irq_lock);
804
805 irqstatus = dsi_read_reg(dsidev, DSI_IRQSTATUS);
806
807 /* IRQ is not for us */
808 if (!irqstatus) {
809 spin_unlock(&dsi->irq_lock);
810 return IRQ_NONE;
811 }
812
813 dsi_write_reg(dsidev, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
814 /* flush posted write */
815 dsi_read_reg(dsidev, DSI_IRQSTATUS);
816
817 for (i = 0; i < 4; ++i) {
818 if ((irqstatus & (1 << i)) == 0) {
819 vcstatus[i] = 0;
820 continue;
821 }
822
823 vcstatus[i] = dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
824
825 dsi_write_reg(dsidev, DSI_VC_IRQSTATUS(i), vcstatus[i]);
826 /* flush posted write */
827 dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
828 }
829
830 if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
831 ciostatus = dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
832
833 dsi_write_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
834 /* flush posted write */
835 dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
836 } else {
837 ciostatus = 0;
838 }
839
840#ifdef DSI_CATCH_MISSING_TE
841 if (irqstatus & DSI_IRQ_TE_TRIGGER)
842 del_timer(&dsi->te_timer);
843#endif
844
845 /* make a copy and unlock, so that isrs can unregister
846 * themselves */
847 memcpy(&dsi->isr_tables_copy, &dsi->isr_tables,
848 sizeof(dsi->isr_tables));
849
850 spin_unlock(&dsi->irq_lock);
851
852 dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus);
853
854 dsi_handle_irq_errors(dsidev, irqstatus, vcstatus, ciostatus);
855
856 dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus);
857
858 return IRQ_HANDLED;
859}
860
861/* dsi->irq_lock has to be locked by the caller */
862static void _omap_dsi_configure_irqs(struct platform_device *dsidev,
863 struct dsi_isr_data *isr_array,
864 unsigned isr_array_size, u32 default_mask,
865 const struct dsi_reg enable_reg,
866 const struct dsi_reg status_reg)
867{
868 struct dsi_isr_data *isr_data;
869 u32 mask;
870 u32 old_mask;
871 int i;
872
873 mask = default_mask;
874
875 for (i = 0; i < isr_array_size; i++) {
876 isr_data = &isr_array[i];
877
878 if (isr_data->isr == NULL)
879 continue;
880
881 mask |= isr_data->mask;
882 }
883
884 old_mask = dsi_read_reg(dsidev, enable_reg);
885 /* clear the irqstatus for newly enabled irqs */
886 dsi_write_reg(dsidev, status_reg, (mask ^ old_mask) & mask);
887 dsi_write_reg(dsidev, enable_reg, mask);
888
889 /* flush posted writes */
890 dsi_read_reg(dsidev, enable_reg);
891 dsi_read_reg(dsidev, status_reg);
892}
893
894/* dsi->irq_lock has to be locked by the caller */
895static void _omap_dsi_set_irqs(struct platform_device *dsidev)
896{
897 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
898 u32 mask = DSI_IRQ_ERROR_MASK;
899#ifdef DSI_CATCH_MISSING_TE
900 mask |= DSI_IRQ_TE_TRIGGER;
901#endif
902 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table,
903 ARRAY_SIZE(dsi->isr_tables.isr_table), mask,
904 DSI_IRQENABLE, DSI_IRQSTATUS);
905}
906
907/* dsi->irq_lock has to be locked by the caller */
908static void _omap_dsi_set_irqs_vc(struct platform_device *dsidev, int vc)
909{
910 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
911
912 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_vc[vc],
913 ARRAY_SIZE(dsi->isr_tables.isr_table_vc[vc]),
914 DSI_VC_IRQ_ERROR_MASK,
915 DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
916}
917
918/* dsi->irq_lock has to be locked by the caller */
919static void _omap_dsi_set_irqs_cio(struct platform_device *dsidev)
920{
921 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
922
923 _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_cio,
924 ARRAY_SIZE(dsi->isr_tables.isr_table_cio),
925 DSI_CIO_IRQ_ERROR_MASK,
926 DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
927}
928
929static void _dsi_initialize_irq(struct platform_device *dsidev)
930{
931 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
932 unsigned long flags;
933 int vc;
934
935 spin_lock_irqsave(&dsi->irq_lock, flags);
936
937 memset(&dsi->isr_tables, 0, sizeof(dsi->isr_tables));
938
939 _omap_dsi_set_irqs(dsidev);
940 for (vc = 0; vc < 4; ++vc)
941 _omap_dsi_set_irqs_vc(dsidev, vc);
942 _omap_dsi_set_irqs_cio(dsidev);
943
944 spin_unlock_irqrestore(&dsi->irq_lock, flags);
945}
946
947static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
948 struct dsi_isr_data *isr_array, unsigned isr_array_size)
949{
950 struct dsi_isr_data *isr_data;
951 int free_idx;
952 int i;
953
954 BUG_ON(isr == NULL);
955
956 /* check for duplicate entry and find a free slot */
957 free_idx = -1;
958 for (i = 0; i < isr_array_size; i++) {
959 isr_data = &isr_array[i];
960
961 if (isr_data->isr == isr && isr_data->arg == arg &&
962 isr_data->mask == mask) {
963 return -EINVAL;
964 }
965
966 if (isr_data->isr == NULL && free_idx == -1)
967 free_idx = i;
968 }
969
970 if (free_idx == -1)
971 return -EBUSY;
972
973 isr_data = &isr_array[free_idx];
974 isr_data->isr = isr;
975 isr_data->arg = arg;
976 isr_data->mask = mask;
977
978 return 0;
979}
980
981static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
982 struct dsi_isr_data *isr_array, unsigned isr_array_size)
983{
984 struct dsi_isr_data *isr_data;
985 int i;
986
987 for (i = 0; i < isr_array_size; i++) {
988 isr_data = &isr_array[i];
989 if (isr_data->isr != isr || isr_data->arg != arg ||
990 isr_data->mask != mask)
991 continue;
992
993 isr_data->isr = NULL;
994 isr_data->arg = NULL;
995 isr_data->mask = 0;
996
997 return 0;
998 }
999
1000 return -EINVAL;
1001}
1002
1003static int dsi_register_isr(struct platform_device *dsidev, omap_dsi_isr_t isr,
1004 void *arg, u32 mask)
1005{
1006 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1007 unsigned long flags;
1008 int r;
1009
1010 spin_lock_irqsave(&dsi->irq_lock, flags);
1011
1012 r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table,
1013 ARRAY_SIZE(dsi->isr_tables.isr_table));
1014
1015 if (r == 0)
1016 _omap_dsi_set_irqs(dsidev);
1017
1018 spin_unlock_irqrestore(&dsi->irq_lock, flags);
1019
1020 return r;
1021}
1022
1023static int dsi_unregister_isr(struct platform_device *dsidev,
1024 omap_dsi_isr_t isr, void *arg, u32 mask)
1025{
1026 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1027 unsigned long flags;
1028 int r;
1029
1030 spin_lock_irqsave(&dsi->irq_lock, flags);
1031
1032 r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table,
1033 ARRAY_SIZE(dsi->isr_tables.isr_table));
1034
1035 if (r == 0)
1036 _omap_dsi_set_irqs(dsidev);
1037
1038 spin_unlock_irqrestore(&dsi->irq_lock, flags);
1039
1040 return r;
1041}
1042
1043static int dsi_register_isr_vc(struct platform_device *dsidev, int channel,
1044 omap_dsi_isr_t isr, void *arg, u32 mask)
1045{
1046 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1047 unsigned long flags;
1048 int r;
1049
1050 spin_lock_irqsave(&dsi->irq_lock, flags);
1051
1052 r = _dsi_register_isr(isr, arg, mask,
1053 dsi->isr_tables.isr_table_vc[channel],
1054 ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
1055
1056 if (r == 0)
1057 _omap_dsi_set_irqs_vc(dsidev, channel);
1058
1059 spin_unlock_irqrestore(&dsi->irq_lock, flags);
1060
1061 return r;
1062}
1063
1064static int dsi_unregister_isr_vc(struct platform_device *dsidev, int channel,
1065 omap_dsi_isr_t isr, void *arg, u32 mask)
1066{
1067 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1068 unsigned long flags;
1069 int r;
1070
1071 spin_lock_irqsave(&dsi->irq_lock, flags);
1072
1073 r = _dsi_unregister_isr(isr, arg, mask,
1074 dsi->isr_tables.isr_table_vc[channel],
1075 ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
1076
1077 if (r == 0)
1078 _omap_dsi_set_irqs_vc(dsidev, channel);
1079
1080 spin_unlock_irqrestore(&dsi->irq_lock, flags);
1081
1082 return r;
1083}
1084
1085static int dsi_register_isr_cio(struct platform_device *dsidev,
1086 omap_dsi_isr_t isr, void *arg, u32 mask)
1087{
1088 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1089 unsigned long flags;
1090 int r;
1091
1092 spin_lock_irqsave(&dsi->irq_lock, flags);
1093
1094 r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
1095 ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
1096
1097 if (r == 0)
1098 _omap_dsi_set_irqs_cio(dsidev);
1099
1100 spin_unlock_irqrestore(&dsi->irq_lock, flags);
1101
1102 return r;
1103}
1104
1105static int dsi_unregister_isr_cio(struct platform_device *dsidev,
1106 omap_dsi_isr_t isr, void *arg, u32 mask)
1107{
1108 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1109 unsigned long flags;
1110 int r;
1111
1112 spin_lock_irqsave(&dsi->irq_lock, flags);
1113
1114 r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
1115 ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
1116
1117 if (r == 0)
1118 _omap_dsi_set_irqs_cio(dsidev);
1119
1120 spin_unlock_irqrestore(&dsi->irq_lock, flags);
1121
1122 return r;
1123}
1124
1125static u32 dsi_get_errors(struct platform_device *dsidev)
1126{
1127 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1128 unsigned long flags;
1129 u32 e;
1130 spin_lock_irqsave(&dsi->errors_lock, flags);
1131 e = dsi->errors;
1132 dsi->errors = 0;
1133 spin_unlock_irqrestore(&dsi->errors_lock, flags);
1134 return e;
1135}
1136
1137int dsi_runtime_get(struct platform_device *dsidev)
1138{
1139 int r;
1140 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1141
1142 DSSDBG("dsi_runtime_get\n");
1143
1144 r = pm_runtime_get_sync(&dsi->pdev->dev);
1145 WARN_ON(r < 0);
1146 return r < 0 ? r : 0;
1147}
1148
1149void dsi_runtime_put(struct platform_device *dsidev)
1150{
1151 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1152 int r;
1153
1154 DSSDBG("dsi_runtime_put\n");
1155
1156 r = pm_runtime_put_sync(&dsi->pdev->dev);
1157 WARN_ON(r < 0 && r != -ENOSYS);
1158}
1159
1160static int dsi_regulator_init(struct platform_device *dsidev)
1161{
1162 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1163 struct regulator *vdds_dsi;
1164
1165 if (dsi->vdds_dsi_reg != NULL)
1166 return 0;
1167
1168 vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdd");
1169
1170 if (IS_ERR(vdds_dsi)) {
1171 if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
1172 DSSERR("can't get DSI VDD regulator\n");
1173 return PTR_ERR(vdds_dsi);
1174 }
1175
1176 dsi->vdds_dsi_reg = vdds_dsi;
1177
1178 return 0;
1179}
1180
1181/* source clock for DSI PLL. this could also be PCLKFREE */
1182static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
1183 bool enable)
1184{
1185 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1186
1187 if (enable)
1188 clk_prepare_enable(dsi->sys_clk);
1189 else
1190 clk_disable_unprepare(dsi->sys_clk);
1191
1192 if (enable && dsi->pll_locked) {
1193 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1)
1194 DSSERR("cannot lock PLL when enabling clocks\n");
1195 }
1196}
1197
1198static void _dsi_print_reset_status(struct platform_device *dsidev)
1199{
1200 u32 l;
1201 int b0, b1, b2;
1202
1203 /* A dummy read using the SCP interface to any DSIPHY register is
1204 * required after DSIPHY reset to complete the reset of the DSI complex
1205 * I/O. */
1206 l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
1207
1208 if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
1209 b0 = 28;
1210 b1 = 27;
1211 b2 = 26;
1212 } else {
1213 b0 = 24;
1214 b1 = 25;
1215 b2 = 26;
1216 }
1217
1218#define DSI_FLD_GET(fld, start, end)\
1219 FLD_GET(dsi_read_reg(dsidev, DSI_##fld), start, end)
1220
1221 pr_debug("DSI resets: PLL (%d) CIO (%d) PHY (%x%x%x, %d, %d, %d)\n",
1222 DSI_FLD_GET(PLL_STATUS, 0, 0),
1223 DSI_FLD_GET(COMPLEXIO_CFG1, 29, 29),
1224 DSI_FLD_GET(DSIPHY_CFG5, b0, b0),
1225 DSI_FLD_GET(DSIPHY_CFG5, b1, b1),
1226 DSI_FLD_GET(DSIPHY_CFG5, b2, b2),
1227 DSI_FLD_GET(DSIPHY_CFG5, 29, 29),
1228 DSI_FLD_GET(DSIPHY_CFG5, 30, 30),
1229 DSI_FLD_GET(DSIPHY_CFG5, 31, 31));
1230
1231#undef DSI_FLD_GET
1232}
1233
1234static inline int dsi_if_enable(struct platform_device *dsidev, bool enable)
1235{
1236 DSSDBG("dsi_if_enable(%d)\n", enable);
1237
1238 enable = enable ? 1 : 0;
1239 REG_FLD_MOD(dsidev, DSI_CTRL, enable, 0, 0); /* IF_EN */
1240
1241 if (wait_for_bit_change(dsidev, DSI_CTRL, 0, enable) != enable) {
1242 DSSERR("Failed to set dsi_if_enable to %d\n", enable);
1243 return -EIO;
1244 }
1245
1246 return 0;
1247}
1248
1249unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
1250{
1251 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1252
1253 return dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk;
1254}
1255
1256static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev)
1257{
1258 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1259
1260 return dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk;
1261}
1262
1263static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev)
1264{
1265 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1266
1267 return dsi->current_cinfo.clkin4ddr / 16;
1268}
1269
1270static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
1271{
1272 unsigned long r;
1273 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1274
1275 if (dss_get_dsi_clk_source(dsi->module_id) == OMAP_DSS_CLK_SRC_FCK) {
1276 /* DSI FCLK source is DSS_CLK_FCK */
1277 r = clk_get_rate(dsi->dss_clk);
1278 } else {
1279 /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
1280 r = dsi_get_pll_hsdiv_dsi_rate(dsidev);
1281 }
1282
1283 return r;
1284}
1285
1286static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo,
1287 unsigned long lp_clk_min, unsigned long lp_clk_max)
1288{
1289 unsigned long dsi_fclk = cinfo->dsi_pll_hsdiv_dsi_clk;
1290 unsigned lp_clk_div;
1291 unsigned long lp_clk;
1292
1293 lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk_max * 2);
1294 lp_clk = dsi_fclk / 2 / lp_clk_div;
1295
1296 if (lp_clk < lp_clk_min || lp_clk > lp_clk_max)
1297 return -EINVAL;
1298
1299 cinfo->lp_clk_div = lp_clk_div;
1300 cinfo->lp_clk = lp_clk;
1301
1302 return 0;
1303}
1304
1305static int dsi_set_lp_clk_divisor(struct platform_device *dsidev)
1306{
1307 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1308 unsigned long dsi_fclk;
1309 unsigned lp_clk_div;
1310 unsigned long lp_clk;
1311
1312 lp_clk_div = dsi->user_dsi_cinfo.lp_clk_div;
1313
1314 if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max)
1315 return -EINVAL;
1316
1317 dsi_fclk = dsi_fclk_rate(dsidev);
1318
1319 lp_clk = dsi_fclk / 2 / lp_clk_div;
1320
1321 DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
1322 dsi->current_cinfo.lp_clk = lp_clk;
1323 dsi->current_cinfo.lp_clk_div = lp_clk_div;
1324
1325 /* LP_CLK_DIVISOR */
1326 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0);
1327
1328 /* LP_RX_SYNCHRO_ENABLE */
1329 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0, 21, 21);
1330
1331 return 0;
1332}
1333
1334static void dsi_enable_scp_clk(struct platform_device *dsidev)
1335{
1336 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1337
1338 if (dsi->scp_clk_refcount++ == 0)
1339 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 14, 14); /* CIO_CLK_ICG */
1340}
1341
1342static void dsi_disable_scp_clk(struct platform_device *dsidev)
1343{
1344 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1345
1346 WARN_ON(dsi->scp_clk_refcount == 0);
1347 if (--dsi->scp_clk_refcount == 0)
1348 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 14, 14); /* CIO_CLK_ICG */
1349}
1350
1351enum dsi_pll_power_state {
1352 DSI_PLL_POWER_OFF = 0x0,
1353 DSI_PLL_POWER_ON_HSCLK = 0x1,
1354 DSI_PLL_POWER_ON_ALL = 0x2,
1355 DSI_PLL_POWER_ON_DIV = 0x3,
1356};
1357
1358static int dsi_pll_power(struct platform_device *dsidev,
1359 enum dsi_pll_power_state state)
1360{
1361 int t = 0;
1362
1363 /* DSI-PLL power command 0x3 is not working */
1364 if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) &&
1365 state == DSI_PLL_POWER_ON_DIV)
1366 state = DSI_PLL_POWER_ON_ALL;
1367
1368 /* PLL_PWR_CMD */
1369 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, state, 31, 30);
1370
1371 /* PLL_PWR_STATUS */
1372 while (FLD_GET(dsi_read_reg(dsidev, DSI_CLK_CTRL), 29, 28) != state) {
1373 if (++t > 1000) {
1374 DSSERR("Failed to set DSI PLL power mode to %d\n",
1375 state);
1376 return -ENODEV;
1377 }
1378 udelay(1);
1379 }
1380
1381 return 0;
1382}
1383
1384unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
1385{
1386 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1387 return clk_get_rate(dsi->sys_clk);
1388}
1389
1390bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
1391 unsigned long out_min, dsi_hsdiv_calc_func func, void *data)
1392{
1393 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1394 int regm, regm_start, regm_stop;
1395 unsigned long out_max;
1396 unsigned long out;
1397
1398 out_min = out_min ? out_min : 1;
1399 out_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
1400
1401 regm_start = max(DIV_ROUND_UP(pll, out_max), 1ul);
1402 regm_stop = min(pll / out_min, dsi->regm_dispc_max);
1403
1404 for (regm = regm_start; regm <= regm_stop; ++regm) {
1405 out = pll / regm;
1406
1407 if (func(regm, out, data))
1408 return true;
1409 }
1410
1411 return false;
1412}
1413
1414bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
1415 unsigned long pll_min, unsigned long pll_max,
1416 dsi_pll_calc_func func, void *data)
1417{
1418 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1419 int regn, regn_start, regn_stop;
1420 int regm, regm_start, regm_stop;
1421 unsigned long fint, pll;
1422 const unsigned long pll_hw_max = 1800000000;
1423 unsigned long fint_hw_min, fint_hw_max;
1424
1425 fint_hw_min = dsi->fint_min;
1426 fint_hw_max = dsi->fint_max;
1427
1428 regn_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
1429 regn_stop = min(clkin / fint_hw_min, dsi->regn_max);
1430
1431 pll_max = pll_max ? pll_max : ULONG_MAX;
1432
1433 for (regn = regn_start; regn <= regn_stop; ++regn) {
1434 fint = clkin / regn;
1435
1436 regm_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
1437 1ul);
1438 regm_stop = min3(pll_max / fint / 2,
1439 pll_hw_max / fint / 2,
1440 dsi->regm_max);
1441
1442 for (regm = regm_start; regm <= regm_stop; ++regm) {
1443 pll = 2 * regm * fint;
1444
1445 if (func(regn, regm, fint, pll, data))
1446 return true;
1447 }
1448 }
1449
1450 return false;
1451}
1452
1453/* calculate clock rates using dividers in cinfo */
1454static int dsi_calc_clock_rates(struct platform_device *dsidev,
1455 struct dsi_clock_info *cinfo)
1456{
1457 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1458
1459 if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max)
1460 return -EINVAL;
1461
1462 if (cinfo->regm == 0 || cinfo->regm > dsi->regm_max)
1463 return -EINVAL;
1464
1465 if (cinfo->regm_dispc > dsi->regm_dispc_max)
1466 return -EINVAL;
1467
1468 if (cinfo->regm_dsi > dsi->regm_dsi_max)
1469 return -EINVAL;
1470
1471 cinfo->clkin = clk_get_rate(dsi->sys_clk);
1472 cinfo->fint = cinfo->clkin / cinfo->regn;
1473
1474 if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min)
1475 return -EINVAL;
1476
1477 cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
1478
1479 if (cinfo->clkin4ddr > 1800 * 1000 * 1000)
1480 return -EINVAL;
1481
1482 if (cinfo->regm_dispc > 0)
1483 cinfo->dsi_pll_hsdiv_dispc_clk =
1484 cinfo->clkin4ddr / cinfo->regm_dispc;
1485 else
1486 cinfo->dsi_pll_hsdiv_dispc_clk = 0;
1487
1488 if (cinfo->regm_dsi > 0)
1489 cinfo->dsi_pll_hsdiv_dsi_clk =
1490 cinfo->clkin4ddr / cinfo->regm_dsi;
1491 else
1492 cinfo->dsi_pll_hsdiv_dsi_clk = 0;
1493
1494 return 0;
1495}
1496
1497static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo)
1498{
1499 unsigned long max_dsi_fck;
1500
1501 max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
1502
1503 cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck);
1504 cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi;
1505}
1506
1507int dsi_pll_set_clock_div(struct platform_device *dsidev,
1508 struct dsi_clock_info *cinfo)
1509{
1510 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1511 int r = 0;
1512 u32 l;
1513 int f = 0;
1514 u8 regn_start, regn_end, regm_start, regm_end;
1515 u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end;
1516
1517 DSSDBG("DSI PLL clock config starts");
1518
1519 dsi->current_cinfo.clkin = cinfo->clkin;
1520 dsi->current_cinfo.fint = cinfo->fint;
1521 dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr;
1522 dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk =
1523 cinfo->dsi_pll_hsdiv_dispc_clk;
1524 dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk =
1525 cinfo->dsi_pll_hsdiv_dsi_clk;
1526
1527 dsi->current_cinfo.regn = cinfo->regn;
1528 dsi->current_cinfo.regm = cinfo->regm;
1529 dsi->current_cinfo.regm_dispc = cinfo->regm_dispc;
1530 dsi->current_cinfo.regm_dsi = cinfo->regm_dsi;
1531
1532 DSSDBG("DSI Fint %ld\n", cinfo->fint);
1533
1534 DSSDBG("clkin rate %ld\n", cinfo->clkin);
1535
1536 /* DSIPHY == CLKIN4DDR */
1537 DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu = %lu\n",
1538 cinfo->regm,
1539 cinfo->regn,
1540 cinfo->clkin,
1541 cinfo->clkin4ddr);
1542
1543 DSSDBG("Data rate on 1 DSI lane %ld Mbps\n",
1544 cinfo->clkin4ddr / 1000 / 1000 / 2);
1545
1546 DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);
1547
1548 DSSDBG("regm_dispc = %d, %s (%s) = %lu\n", cinfo->regm_dispc,
1549 dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
1550 dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
1551 cinfo->dsi_pll_hsdiv_dispc_clk);
1552 DSSDBG("regm_dsi = %d, %s (%s) = %lu\n", cinfo->regm_dsi,
1553 dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
1554 dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
1555 cinfo->dsi_pll_hsdiv_dsi_clk);
1556
1557 dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, &regn_start, &regn_end);
1558 dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM, &regm_start, &regm_end);
1559 dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DISPC, &regm_dispc_start,
1560 &regm_dispc_end);
1561 dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, &regm_dsi_start,
1562 &regm_dsi_end);
1563
1564 /* DSI_PLL_AUTOMODE = manual */
1565 REG_FLD_MOD(dsidev, DSI_PLL_CONTROL, 0, 0, 0);
1566
1567 l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION1);
1568 l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */
1569 /* DSI_PLL_REGN */
1570 l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end);
1571 /* DSI_PLL_REGM */
1572 l = FLD_MOD(l, cinfo->regm, regm_start, regm_end);
1573 /* DSI_CLOCK_DIV */
1574 l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0,
1575 regm_dispc_start, regm_dispc_end);
1576 /* DSIPROTO_CLOCK_DIV */
1577 l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0,
1578 regm_dsi_start, regm_dsi_end);
1579 dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION1, l);
1580
1581 BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max);
1582
1583 l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
1584
1585 if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) {
1586 f = cinfo->fint < 1000000 ? 0x3 :
1587 cinfo->fint < 1250000 ? 0x4 :
1588 cinfo->fint < 1500000 ? 0x5 :
1589 cinfo->fint < 1750000 ? 0x6 :
1590 0x7;
1591
1592 l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
1593 } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) {
1594 f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4;
1595
1596 l = FLD_MOD(l, f, 4, 1); /* PLL_SELFREQDCO */
1597 }
1598
1599 l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
1600 l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */
1601 l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */
1602 if (dss_has_feature(FEAT_DSI_PLL_REFSEL))
1603 l = FLD_MOD(l, 3, 22, 21); /* REF_SYSCLK = sysclk */
1604 dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
1605
1606 REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
1607
1608 if (wait_for_bit_change(dsidev, DSI_PLL_GO, 0, 0) != 0) {
1609 DSSERR("dsi pll go bit not going down.\n");
1610 r = -EIO;
1611 goto err;
1612 }
1613
1614 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) {
1615 DSSERR("cannot lock PLL\n");
1616 r = -EIO;
1617 goto err;
1618 }
1619
1620 dsi->pll_locked = 1;
1621
1622 l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
1623 l = FLD_MOD(l, 0, 0, 0); /* DSI_PLL_IDLE */
1624 l = FLD_MOD(l, 0, 5, 5); /* DSI_PLL_PLLLPMODE */
1625 l = FLD_MOD(l, 0, 6, 6); /* DSI_PLL_LOWCURRSTBY */
1626 l = FLD_MOD(l, 0, 7, 7); /* DSI_PLL_TIGHTPHASELOCK */
1627 l = FLD_MOD(l, 0, 8, 8); /* DSI_PLL_DRIFTGUARDEN */
1628 l = FLD_MOD(l, 0, 10, 9); /* DSI_PLL_LOCKSEL */
1629 l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
1630 l = FLD_MOD(l, 1, 14, 14); /* DSIPHY_CLKINEN */
1631 l = FLD_MOD(l, 0, 15, 15); /* DSI_BYPASSEN */
1632 l = FLD_MOD(l, 1, 16, 16); /* DSS_CLOCK_EN */
1633 l = FLD_MOD(l, 0, 17, 17); /* DSS_CLOCK_PWDN */
1634 l = FLD_MOD(l, 1, 18, 18); /* DSI_PROTO_CLOCK_EN */
1635 l = FLD_MOD(l, 0, 19, 19); /* DSI_PROTO_CLOCK_PWDN */
1636 l = FLD_MOD(l, 0, 20, 20); /* DSI_HSDIVBYPASS */
1637 dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
1638
1639 DSSDBG("PLL config done\n");
1640err:
1641 return r;
1642}
1643
1644int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
1645 bool enable_hsdiv)
1646{
1647 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1648 int r = 0;
1649 enum dsi_pll_power_state pwstate;
1650
1651 DSSDBG("PLL init\n");
1652
1653 /*
1654 * It seems that on many OMAPs we need to enable both to have a
1655 * functional HSDivider.
1656 */
1657 enable_hsclk = enable_hsdiv = true;
1658
1659 r = dsi_regulator_init(dsidev);
1660 if (r)
1661 return r;
1662
1663 dsi_enable_pll_clock(dsidev, 1);
1664 /*
1665 * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
1666 */
1667 dsi_enable_scp_clk(dsidev);
1668
1669 if (!dsi->vdds_dsi_enabled) {
1670 r = regulator_enable(dsi->vdds_dsi_reg);
1671 if (r)
1672 goto err0;
1673 dsi->vdds_dsi_enabled = true;
1674 }
1675
1676 /* XXX PLL does not come out of reset without this... */
1677 dispc_pck_free_enable(1);
1678
1679 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 0, 1) != 1) {
1680 DSSERR("PLL not coming out of reset.\n");
1681 r = -ENODEV;
1682 dispc_pck_free_enable(0);
1683 goto err1;
1684 }
1685
1686 /* XXX ... but if left on, we get problems when planes do not
1687 * fill the whole display. No idea about this */
1688 dispc_pck_free_enable(0);
1689
1690 if (enable_hsclk && enable_hsdiv)
1691 pwstate = DSI_PLL_POWER_ON_ALL;
1692 else if (enable_hsclk)
1693 pwstate = DSI_PLL_POWER_ON_HSCLK;
1694 else if (enable_hsdiv)
1695 pwstate = DSI_PLL_POWER_ON_DIV;
1696 else
1697 pwstate = DSI_PLL_POWER_OFF;
1698
1699 r = dsi_pll_power(dsidev, pwstate);
1700
1701 if (r)
1702 goto err1;
1703
1704 DSSDBG("PLL init done\n");
1705
1706 return 0;
1707err1:
1708 if (dsi->vdds_dsi_enabled) {
1709 regulator_disable(dsi->vdds_dsi_reg);
1710 dsi->vdds_dsi_enabled = false;
1711 }
1712err0:
1713 dsi_disable_scp_clk(dsidev);
1714 dsi_enable_pll_clock(dsidev, 0);
1715 return r;
1716}
1717
1718void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
1719{
1720 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1721
1722 dsi->pll_locked = 0;
1723 dsi_pll_power(dsidev, DSI_PLL_POWER_OFF);
1724 if (disconnect_lanes) {
1725 WARN_ON(!dsi->vdds_dsi_enabled);
1726 regulator_disable(dsi->vdds_dsi_reg);
1727 dsi->vdds_dsi_enabled = false;
1728 }
1729
1730 dsi_disable_scp_clk(dsidev);
1731 dsi_enable_pll_clock(dsidev, 0);
1732
1733 DSSDBG("PLL uninit done\n");
1734}
1735
1736static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
1737 struct seq_file *s)
1738{
1739 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1740 struct dsi_clock_info *cinfo = &dsi->current_cinfo;
1741 enum omap_dss_clk_source dispc_clk_src, dsi_clk_src;
1742 int dsi_module = dsi->module_id;
1743
1744 dispc_clk_src = dss_get_dispc_clk_source();
1745 dsi_clk_src = dss_get_dsi_clk_source(dsi_module);
1746
1747 if (dsi_runtime_get(dsidev))
1748 return;
1749
1750 seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1);
1751
1752 seq_printf(s, "dsi pll clkin\t%lu\n", cinfo->clkin);
1753
1754 seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
1755
1756 seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n",
1757 cinfo->clkin4ddr, cinfo->regm);
1758
1759 seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16luregm_dispc %u\t(%s)\n",
1760 dss_feat_get_clk_source_name(dsi_module == 0 ?
1761 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
1762 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC),
1763 cinfo->dsi_pll_hsdiv_dispc_clk,
1764 cinfo->regm_dispc,
1765 dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ?
1766 "off" : "on");
1767
1768 seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16luregm_dsi %u\t(%s)\n",
1769 dss_feat_get_clk_source_name(dsi_module == 0 ?
1770 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
1771 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI),
1772 cinfo->dsi_pll_hsdiv_dsi_clk,
1773 cinfo->regm_dsi,
1774 dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ?
1775 "off" : "on");
1776
1777 seq_printf(s, "- DSI%d -\n", dsi_module + 1);
1778
1779 seq_printf(s, "dsi fclk source = %s (%s)\n",
1780 dss_get_generic_clk_source_name(dsi_clk_src),
1781 dss_feat_get_clk_source_name(dsi_clk_src));
1782
1783 seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev));
1784
1785 seq_printf(s, "DDR_CLK\t\t%lu\n",
1786 cinfo->clkin4ddr / 4);
1787
1788 seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev));
1789
1790 seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk);
1791
1792 dsi_runtime_put(dsidev);
1793}
1794
1795void dsi_dump_clocks(struct seq_file *s)
1796{
1797 struct platform_device *dsidev;
1798 int i;
1799
1800 for (i = 0; i < MAX_NUM_DSI; i++) {
1801 dsidev = dsi_get_dsidev_from_id(i);
1802 if (dsidev)
1803 dsi_dump_dsidev_clocks(dsidev, s);
1804 }
1805}
1806
1807#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
1808static void dsi_dump_dsidev_irqs(struct platform_device *dsidev,
1809 struct seq_file *s)
1810{
1811 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1812 unsigned long flags;
1813 struct dsi_irq_stats stats;
1814
1815 spin_lock_irqsave(&dsi->irq_stats_lock, flags);
1816
1817 stats = dsi->irq_stats;
1818 memset(&dsi->irq_stats, 0, sizeof(dsi->irq_stats));
1819 dsi->irq_stats.last_reset = jiffies;
1820
1821 spin_unlock_irqrestore(&dsi->irq_stats_lock, flags);
1822
1823 seq_printf(s, "period %u ms\n",
1824 jiffies_to_msecs(jiffies - stats.last_reset));
1825
1826 seq_printf(s, "irqs %d\n", stats.irq_count);
1827#define PIS(x) \
1828 seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);
1829
1830 seq_printf(s, "-- DSI%d interrupts --\n", dsi->module_id + 1);
1831 PIS(VC0);
1832 PIS(VC1);
1833 PIS(VC2);
1834 PIS(VC3);
1835 PIS(WAKEUP);
1836 PIS(RESYNC);
1837 PIS(PLL_LOCK);
1838 PIS(PLL_UNLOCK);
1839 PIS(PLL_RECALL);
1840 PIS(COMPLEXIO_ERR);
1841 PIS(HS_TX_TIMEOUT);
1842 PIS(LP_RX_TIMEOUT);
1843 PIS(TE_TRIGGER);
1844 PIS(ACK_TRIGGER);
1845 PIS(SYNC_LOST);
1846 PIS(LDO_POWER_GOOD);
1847 PIS(TA_TIMEOUT);
1848#undef PIS
1849
1850#define PIS(x) \
1851 seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \
1852 stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
1853 stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
1854 stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
1855 stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);
1856
1857 seq_printf(s, "-- VC interrupts --\n");
1858 PIS(CS);
1859 PIS(ECC_CORR);
1860 PIS(PACKET_SENT);
1861 PIS(FIFO_TX_OVF);
1862 PIS(FIFO_RX_OVF);
1863 PIS(BTA);
1864 PIS(ECC_NO_CORR);
1865 PIS(FIFO_TX_UDF);
1866 PIS(PP_BUSY_CHANGE);
1867#undef PIS
1868
1869#define PIS(x) \
1870 seq_printf(s, "%-20s %10d\n", #x, \
1871 stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);
1872
1873 seq_printf(s, "-- CIO interrupts --\n");
1874 PIS(ERRSYNCESC1);
1875 PIS(ERRSYNCESC2);
1876 PIS(ERRSYNCESC3);
1877 PIS(ERRESC1);
1878 PIS(ERRESC2);
1879 PIS(ERRESC3);
1880 PIS(ERRCONTROL1);
1881 PIS(ERRCONTROL2);
1882 PIS(ERRCONTROL3);
1883 PIS(STATEULPS1);
1884 PIS(STATEULPS2);
1885 PIS(STATEULPS3);
1886 PIS(ERRCONTENTIONLP0_1);
1887 PIS(ERRCONTENTIONLP1_1);
1888 PIS(ERRCONTENTIONLP0_2);
1889 PIS(ERRCONTENTIONLP1_2);
1890 PIS(ERRCONTENTIONLP0_3);
1891 PIS(ERRCONTENTIONLP1_3);
1892 PIS(ULPSACTIVENOT_ALL0);
1893 PIS(ULPSACTIVENOT_ALL1);
1894#undef PIS
1895}
1896
1897static void dsi1_dump_irqs(struct seq_file *s)
1898{
1899 struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
1900
1901 dsi_dump_dsidev_irqs(dsidev, s);
1902}
1903
1904static void dsi2_dump_irqs(struct seq_file *s)
1905{
1906 struct platform_device *dsidev = dsi_get_dsidev_from_id(1);
1907
1908 dsi_dump_dsidev_irqs(dsidev, s);
1909}
1910#endif
1911
1912static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
1913 struct seq_file *s)
1914{
1915#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r))
1916
1917 if (dsi_runtime_get(dsidev))
1918 return;
1919 dsi_enable_scp_clk(dsidev);
1920
1921 DUMPREG(DSI_REVISION);
1922 DUMPREG(DSI_SYSCONFIG);
1923 DUMPREG(DSI_SYSSTATUS);
1924 DUMPREG(DSI_IRQSTATUS);
1925 DUMPREG(DSI_IRQENABLE);
1926 DUMPREG(DSI_CTRL);
1927 DUMPREG(DSI_COMPLEXIO_CFG1);
1928 DUMPREG(DSI_COMPLEXIO_IRQ_STATUS);
1929 DUMPREG(DSI_COMPLEXIO_IRQ_ENABLE);
1930 DUMPREG(DSI_CLK_CTRL);
1931 DUMPREG(DSI_TIMING1);
1932 DUMPREG(DSI_TIMING2);
1933 DUMPREG(DSI_VM_TIMING1);
1934 DUMPREG(DSI_VM_TIMING2);
1935 DUMPREG(DSI_VM_TIMING3);
1936 DUMPREG(DSI_CLK_TIMING);
1937 DUMPREG(DSI_TX_FIFO_VC_SIZE);
1938 DUMPREG(DSI_RX_FIFO_VC_SIZE);
1939 DUMPREG(DSI_COMPLEXIO_CFG2);
1940 DUMPREG(DSI_RX_FIFO_VC_FULLNESS);
1941 DUMPREG(DSI_VM_TIMING4);
1942 DUMPREG(DSI_TX_FIFO_VC_EMPTINESS);
1943 DUMPREG(DSI_VM_TIMING5);
1944 DUMPREG(DSI_VM_TIMING6);
1945 DUMPREG(DSI_VM_TIMING7);
1946 DUMPREG(DSI_STOPCLK_TIMING);
1947
1948 DUMPREG(DSI_VC_CTRL(0));
1949 DUMPREG(DSI_VC_TE(0));
1950 DUMPREG(DSI_VC_LONG_PACKET_HEADER(0));
1951 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(0));
1952 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(0));
1953 DUMPREG(DSI_VC_IRQSTATUS(0));
1954 DUMPREG(DSI_VC_IRQENABLE(0));
1955
1956 DUMPREG(DSI_VC_CTRL(1));
1957 DUMPREG(DSI_VC_TE(1));
1958 DUMPREG(DSI_VC_LONG_PACKET_HEADER(1));
1959 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(1));
1960 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(1));
1961 DUMPREG(DSI_VC_IRQSTATUS(1));
1962 DUMPREG(DSI_VC_IRQENABLE(1));
1963
1964 DUMPREG(DSI_VC_CTRL(2));
1965 DUMPREG(DSI_VC_TE(2));
1966 DUMPREG(DSI_VC_LONG_PACKET_HEADER(2));
1967 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(2));
1968 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(2));
1969 DUMPREG(DSI_VC_IRQSTATUS(2));
1970 DUMPREG(DSI_VC_IRQENABLE(2));
1971
1972 DUMPREG(DSI_VC_CTRL(3));
1973 DUMPREG(DSI_VC_TE(3));
1974 DUMPREG(DSI_VC_LONG_PACKET_HEADER(3));
1975 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(3));
1976 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(3));
1977 DUMPREG(DSI_VC_IRQSTATUS(3));
1978 DUMPREG(DSI_VC_IRQENABLE(3));
1979
1980 DUMPREG(DSI_DSIPHY_CFG0);
1981 DUMPREG(DSI_DSIPHY_CFG1);
1982 DUMPREG(DSI_DSIPHY_CFG2);
1983 DUMPREG(DSI_DSIPHY_CFG5);
1984
1985 DUMPREG(DSI_PLL_CONTROL);
1986 DUMPREG(DSI_PLL_STATUS);
1987 DUMPREG(DSI_PLL_GO);
1988 DUMPREG(DSI_PLL_CONFIGURATION1);
1989 DUMPREG(DSI_PLL_CONFIGURATION2);
1990
1991 dsi_disable_scp_clk(dsidev);
1992 dsi_runtime_put(dsidev);
1993#undef DUMPREG
1994}
1995
1996static void dsi1_dump_regs(struct seq_file *s)
1997{
1998 struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
1999
2000 dsi_dump_dsidev_regs(dsidev, s);
2001}
2002
2003static void dsi2_dump_regs(struct seq_file *s)
2004{
2005 struct platform_device *dsidev = dsi_get_dsidev_from_id(1);
2006
2007 dsi_dump_dsidev_regs(dsidev, s);
2008}
2009
2010enum dsi_cio_power_state {
2011 DSI_COMPLEXIO_POWER_OFF = 0x0,
2012 DSI_COMPLEXIO_POWER_ON = 0x1,
2013 DSI_COMPLEXIO_POWER_ULPS = 0x2,
2014};
2015
2016static int dsi_cio_power(struct platform_device *dsidev,
2017 enum dsi_cio_power_state state)
2018{
2019 int t = 0;
2020
2021 /* PWR_CMD */
2022 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, state, 28, 27);
2023
2024 /* PWR_STATUS */
2025 while (FLD_GET(dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1),
2026 26, 25) != state) {
2027 if (++t > 1000) {
2028 DSSERR("failed to set complexio power state to "
2029 "%d\n", state);
2030 return -ENODEV;
2031 }
2032 udelay(1);
2033 }
2034
2035 return 0;
2036}
2037
2038static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
2039{
2040 int val;
2041
2042 /* line buffer on OMAP3 is 1024 x 24bits */
2043 /* XXX: for some reason using full buffer size causes
2044 * considerable TX slowdown with update sizes that fill the
2045 * whole buffer */
2046 if (!dss_has_feature(FEAT_DSI_GNQ))
2047 return 1023 * 3;
2048
2049 val = REG_GET(dsidev, DSI_GNQ, 14, 12); /* VP1_LINE_BUFFER_SIZE */
2050
2051 switch (val) {
2052 case 1:
2053 return 512 * 3; /* 512x24 bits */
2054 case 2:
2055 return 682 * 3; /* 682x24 bits */
2056 case 3:
2057 return 853 * 3; /* 853x24 bits */
2058 case 4:
2059 return 1024 * 3; /* 1024x24 bits */
2060 case 5:
2061 return 1194 * 3; /* 1194x24 bits */
2062 case 6:
2063 return 1365 * 3; /* 1365x24 bits */
2064 case 7:
2065 return 1920 * 3; /* 1920x24 bits */
2066 default:
2067 BUG();
2068 return 0;
2069 }
2070}
2071
2072static int dsi_set_lane_config(struct platform_device *dsidev)
2073{
2074 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2075 static const u8 offsets[] = { 0, 4, 8, 12, 16 };
2076 static const enum dsi_lane_function functions[] = {
2077 DSI_LANE_CLK,
2078 DSI_LANE_DATA1,
2079 DSI_LANE_DATA2,
2080 DSI_LANE_DATA3,
2081 DSI_LANE_DATA4,
2082 };
2083 u32 r;
2084 int i;
2085
2086 r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
2087
2088 for (i = 0; i < dsi->num_lanes_used; ++i) {
2089 unsigned offset = offsets[i];
2090 unsigned polarity, lane_number;
2091 unsigned t;
2092
2093 for (t = 0; t < dsi->num_lanes_supported; ++t)
2094 if (dsi->lanes[t].function == functions[i])
2095 break;
2096
2097 if (t == dsi->num_lanes_supported)
2098 return -EINVAL;
2099
2100 lane_number = t;
2101 polarity = dsi->lanes[t].polarity;
2102
2103 r = FLD_MOD(r, lane_number + 1, offset + 2, offset);
2104 r = FLD_MOD(r, polarity, offset + 3, offset + 3);
2105 }
2106
2107 /* clear the unused lanes */
2108 for (; i < dsi->num_lanes_supported; ++i) {
2109 unsigned offset = offsets[i];
2110
2111 r = FLD_MOD(r, 0, offset + 2, offset);
2112 r = FLD_MOD(r, 0, offset + 3, offset + 3);
2113 }
2114
2115 dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);
2116
2117 return 0;
2118}
2119
2120static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns)
2121{
2122 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2123
2124 /* convert time in ns to ddr ticks, rounding up */
2125 unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
2126 return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
2127}
2128
2129static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr)
2130{
2131 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2132
2133 unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
2134 return ddr * 1000 * 1000 / (ddr_clk / 1000);
2135}
2136
2137static void dsi_cio_timings(struct platform_device *dsidev)
2138{
2139 u32 r;
2140 u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
2141 u32 tlpx_half, tclk_trail, tclk_zero;
2142 u32 tclk_prepare;
2143
2144 /* calculate timings */
2145
2146 /* 1 * DDR_CLK = 2 * UI */
2147
2148 /* min 40ns + 4*UI max 85ns + 6*UI */
2149 ths_prepare = ns2ddr(dsidev, 70) + 2;
2150
2151 /* min 145ns + 10*UI */
2152 ths_prepare_ths_zero = ns2ddr(dsidev, 175) + 2;
2153
2154 /* min max(8*UI, 60ns+4*UI) */
2155 ths_trail = ns2ddr(dsidev, 60) + 5;
2156
2157 /* min 100ns */
2158 ths_exit = ns2ddr(dsidev, 145);
2159
2160 /* tlpx min 50n */
2161 tlpx_half = ns2ddr(dsidev, 25);
2162
2163 /* min 60ns */
2164 tclk_trail = ns2ddr(dsidev, 60) + 2;
2165
2166 /* min 38ns, max 95ns */
2167 tclk_prepare = ns2ddr(dsidev, 65);
2168
2169 /* min tclk-prepare + tclk-zero = 300ns */
2170 tclk_zero = ns2ddr(dsidev, 260);
2171
2172 DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
2173 ths_prepare, ddr2ns(dsidev, ths_prepare),
2174 ths_prepare_ths_zero, ddr2ns(dsidev, ths_prepare_ths_zero));
2175 DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
2176 ths_trail, ddr2ns(dsidev, ths_trail),
2177 ths_exit, ddr2ns(dsidev, ths_exit));
2178
2179 DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
2180 "tclk_zero %u (%uns)\n",
2181 tlpx_half, ddr2ns(dsidev, tlpx_half),
2182 tclk_trail, ddr2ns(dsidev, tclk_trail),
2183 tclk_zero, ddr2ns(dsidev, tclk_zero));
2184 DSSDBG("tclk_prepare %u (%uns)\n",
2185 tclk_prepare, ddr2ns(dsidev, tclk_prepare));
2186
2187 /* program timings */
2188
2189 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
2190 r = FLD_MOD(r, ths_prepare, 31, 24);
2191 r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
2192 r = FLD_MOD(r, ths_trail, 15, 8);
2193 r = FLD_MOD(r, ths_exit, 7, 0);
2194 dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r);
2195
2196 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
2197 r = FLD_MOD(r, tlpx_half, 20, 16);
2198 r = FLD_MOD(r, tclk_trail, 15, 8);
2199 r = FLD_MOD(r, tclk_zero, 7, 0);
2200
2201 if (dss_has_feature(FEAT_DSI_PHY_DCC)) {
2202 r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */
2203 r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */
2204 r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */
2205 }
2206
2207 dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);
2208
2209 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
2210 r = FLD_MOD(r, tclk_prepare, 7, 0);
2211 dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r);
2212}
2213
2214/* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */
2215static void dsi_cio_enable_lane_override(struct platform_device *dsidev,
2216 unsigned mask_p, unsigned mask_n)
2217{
2218 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2219 int i;
2220 u32 l;
2221 u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26;
2222
2223 l = 0;
2224
2225 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2226 unsigned p = dsi->lanes[i].polarity;
2227
2228 if (mask_p & (1 << i))
2229 l |= 1 << (i * 2 + (p ? 0 : 1));
2230
2231 if (mask_n & (1 << i))
2232 l |= 1 << (i * 2 + (p ? 1 : 0));
2233 }
2234
2235 /*
2236 * Bits in REGLPTXSCPDAT4TO0DXDY:
2237 * 17: DY0 18: DX0
2238 * 19: DY1 20: DX1
2239 * 21: DY2 22: DX2
2240 * 23: DY3 24: DX3
2241 * 25: DY4 26: DX4
2242 */
2243
2244 /* Set the lane override configuration */
2245
2246 /* REGLPTXSCPDAT4TO0DXDY */
2247 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, l, lptxscp_start, 17);
2248
2249 /* Enable lane override */
2250
2251 /* ENLPTXSCPDAT */
2252 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 1, 27, 27);
2253}
2254
2255static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
2256{
2257 /* Disable lane override */
2258 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 27, 27); /* ENLPTXSCPDAT */
2259 /* Reset the lane override configuration */
2260 /* REGLPTXSCPDAT4TO0DXDY */
2261 REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17);
2262}
2263
2264static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev)
2265{
2266 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2267 int t, i;
2268 bool in_use[DSI_MAX_NR_LANES];
2269 static const u8 offsets_old[] = { 28, 27, 26 };
2270 static const u8 offsets_new[] = { 24, 25, 26, 27, 28 };
2271 const u8 *offsets;
2272
2273 if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC))
2274 offsets = offsets_old;
2275 else
2276 offsets = offsets_new;
2277
2278 for (i = 0; i < dsi->num_lanes_supported; ++i)
2279 in_use[i] = dsi->lanes[i].function != DSI_LANE_UNUSED;
2280
2281 t = 100000;
2282 while (true) {
2283 u32 l;
2284 int ok;
2285
2286 l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
2287
2288 ok = 0;
2289 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2290 if (!in_use[i] || (l & (1 << offsets[i])))
2291 ok++;
2292 }
2293
2294 if (ok == dsi->num_lanes_supported)
2295 break;
2296
2297 if (--t == 0) {
2298 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2299 if (!in_use[i] || (l & (1 << offsets[i])))
2300 continue;
2301
2302 DSSERR("CIO TXCLKESC%d domain not coming " \
2303 "out of reset\n", i);
2304 }
2305 return -EIO;
2306 }
2307 }
2308
2309 return 0;
2310}
2311
2312/* return bitmask of enabled lanes, lane0 being the lsb */
2313static unsigned dsi_get_lane_mask(struct platform_device *dsidev)
2314{
2315 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2316 unsigned mask = 0;
2317 int i;
2318
2319 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2320 if (dsi->lanes[i].function != DSI_LANE_UNUSED)
2321 mask |= 1 << i;
2322 }
2323
2324 return mask;
2325}
2326
2327static int dsi_cio_init(struct platform_device *dsidev)
2328{
2329 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2330 int r;
2331 u32 l;
2332
2333 DSSDBG("DSI CIO init starts");
2334
2335 r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
2336 if (r)
2337 return r;
2338
2339 dsi_enable_scp_clk(dsidev);
2340
2341 /* A dummy read using the SCP interface to any DSIPHY register is
2342 * required after DSIPHY reset to complete the reset of the DSI complex
2343 * I/O. */
2344 dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
2345
2346 if (wait_for_bit_change(dsidev, DSI_DSIPHY_CFG5, 30, 1) != 1) {
2347 DSSERR("CIO SCP Clock domain not coming out of reset.\n");
2348 r = -EIO;
2349 goto err_scp_clk_dom;
2350 }
2351
2352 r = dsi_set_lane_config(dsidev);
2353 if (r)
2354 goto err_scp_clk_dom;
2355
2356 /* set TX STOP MODE timer to maximum for this operation */
2357 l = dsi_read_reg(dsidev, DSI_TIMING1);
2358 l = FLD_MOD(l, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
2359 l = FLD_MOD(l, 1, 14, 14); /* STOP_STATE_X16_IO */
2360 l = FLD_MOD(l, 1, 13, 13); /* STOP_STATE_X4_IO */
2361 l = FLD_MOD(l, 0x1fff, 12, 0); /* STOP_STATE_COUNTER_IO */
2362 dsi_write_reg(dsidev, DSI_TIMING1, l);
2363
2364 if (dsi->ulps_enabled) {
2365 unsigned mask_p;
2366 int i;
2367
2368 DSSDBG("manual ulps exit\n");
2369
2370 /* ULPS is exited by Mark-1 state for 1ms, followed by
2371 * stop state. DSS HW cannot do this via the normal
2372 * ULPS exit sequence, as after reset the DSS HW thinks
2373 * that we are not in ULPS mode, and refuses to send the
2374 * sequence. So we need to send the ULPS exit sequence
2375 * manually by setting positive lines high and negative lines
2376 * low for 1ms.
2377 */
2378
2379 mask_p = 0;
2380
2381 for (i = 0; i < dsi->num_lanes_supported; ++i) {
2382 if (dsi->lanes[i].function == DSI_LANE_UNUSED)
2383 continue;
2384 mask_p |= 1 << i;
2385 }
2386
2387 dsi_cio_enable_lane_override(dsidev, mask_p, 0);
2388 }
2389
2390 r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
2391 if (r)
2392 goto err_cio_pwr;
2393
2394 if (wait_for_bit_change(dsidev, DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
2395 DSSERR("CIO PWR clock domain not coming out of reset.\n");
2396 r = -ENODEV;
2397 goto err_cio_pwr_dom;
2398 }
2399
2400 dsi_if_enable(dsidev, true);
2401 dsi_if_enable(dsidev, false);
2402 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
2403
2404 r = dsi_cio_wait_tx_clk_esc_reset(dsidev);
2405 if (r)
2406 goto err_tx_clk_esc_rst;
2407
2408 if (dsi->ulps_enabled) {
2409 /* Keep Mark-1 state for 1ms (as per DSI spec) */
2410 ktime_t wait = ns_to_ktime(1000 * 1000);
2411 set_current_state(TASK_UNINTERRUPTIBLE);
2412 schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
2413
2414 /* Disable the override. The lanes should be set to Mark-11
2415 * state by the HW */
2416 dsi_cio_disable_lane_override(dsidev);
2417 }
2418
2419 /* FORCE_TX_STOP_MODE_IO */
2420 REG_FLD_MOD(dsidev, DSI_TIMING1, 0, 15, 15);
2421
2422 dsi_cio_timings(dsidev);
2423
2424 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
2425 /* DDR_CLK_ALWAYS_ON */
2426 REG_FLD_MOD(dsidev, DSI_CLK_CTRL,
2427 dsi->vm_timings.ddr_clk_always_on, 13, 13);
2428 }
2429
2430 dsi->ulps_enabled = false;
2431
2432 DSSDBG("CIO init done\n");
2433
2434 return 0;
2435
2436err_tx_clk_esc_rst:
2437 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 20, 20); /* LP_CLK_ENABLE */
2438err_cio_pwr_dom:
2439 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
2440err_cio_pwr:
2441 if (dsi->ulps_enabled)
2442 dsi_cio_disable_lane_override(dsidev);
2443err_scp_clk_dom:
2444 dsi_disable_scp_clk(dsidev);
2445 dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
2446 return r;
2447}
2448
2449static void dsi_cio_uninit(struct platform_device *dsidev)
2450{
2451 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2452
2453 /* DDR_CLK_ALWAYS_ON */
2454 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13);
2455
2456 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
2457 dsi_disable_scp_clk(dsidev);
2458 dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev));
2459}
2460
2461static void dsi_config_tx_fifo(struct platform_device *dsidev,
2462 enum fifo_size size1, enum fifo_size size2,
2463 enum fifo_size size3, enum fifo_size size4)
2464{
2465 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2466 u32 r = 0;
2467 int add = 0;
2468 int i;
2469
2470 dsi->vc[0].tx_fifo_size = size1;
2471 dsi->vc[1].tx_fifo_size = size2;
2472 dsi->vc[2].tx_fifo_size = size3;
2473 dsi->vc[3].tx_fifo_size = size4;
2474
2475 for (i = 0; i < 4; i++) {
2476 u8 v;
2477 int size = dsi->vc[i].tx_fifo_size;
2478
2479 if (add + size > 4) {
2480 DSSERR("Illegal FIFO configuration\n");
2481 BUG();
2482 return;
2483 }
2484
2485 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
2486 r |= v << (8 * i);
2487 /*DSSDBG("TX FIFO vc %d: size %d, add %d\n", i, size, add); */
2488 add += size;
2489 }
2490
2491 dsi_write_reg(dsidev, DSI_TX_FIFO_VC_SIZE, r);
2492}
2493
2494static void dsi_config_rx_fifo(struct platform_device *dsidev,
2495 enum fifo_size size1, enum fifo_size size2,
2496 enum fifo_size size3, enum fifo_size size4)
2497{
2498 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2499 u32 r = 0;
2500 int add = 0;
2501 int i;
2502
2503 dsi->vc[0].rx_fifo_size = size1;
2504 dsi->vc[1].rx_fifo_size = size2;
2505 dsi->vc[2].rx_fifo_size = size3;
2506 dsi->vc[3].rx_fifo_size = size4;
2507
2508 for (i = 0; i < 4; i++) {
2509 u8 v;
2510 int size = dsi->vc[i].rx_fifo_size;
2511
2512 if (add + size > 4) {
2513 DSSERR("Illegal FIFO configuration\n");
2514 BUG();
2515 return;
2516 }
2517
2518 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
2519 r |= v << (8 * i);
2520 /*DSSDBG("RX FIFO vc %d: size %d, add %d\n", i, size, add); */
2521 add += size;
2522 }
2523
2524 dsi_write_reg(dsidev, DSI_RX_FIFO_VC_SIZE, r);
2525}
2526
2527static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev)
2528{
2529 u32 r;
2530
2531 r = dsi_read_reg(dsidev, DSI_TIMING1);
2532 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
2533 dsi_write_reg(dsidev, DSI_TIMING1, r);
2534
2535 if (wait_for_bit_change(dsidev, DSI_TIMING1, 15, 0) != 0) {
2536 DSSERR("TX_STOP bit not going down\n");
2537 return -EIO;
2538 }
2539
2540 return 0;
2541}
2542
2543static bool dsi_vc_is_enabled(struct platform_device *dsidev, int channel)
2544{
2545 return REG_GET(dsidev, DSI_VC_CTRL(channel), 0, 0);
2546}
2547
2548static void dsi_packet_sent_handler_vp(void *data, u32 mask)
2549{
2550 struct dsi_packet_sent_handler_data *vp_data =
2551 (struct dsi_packet_sent_handler_data *) data;
2552 struct dsi_data *dsi = dsi_get_dsidrv_data(vp_data->dsidev);
2553 const int channel = dsi->update_channel;
2554 u8 bit = dsi->te_enabled ? 30 : 31;
2555
2556 if (REG_GET(vp_data->dsidev, DSI_VC_TE(channel), bit, bit) == 0)
2557 complete(vp_data->completion);
2558}
2559
2560static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel)
2561{
2562 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2563 DECLARE_COMPLETION_ONSTACK(completion);
2564 struct dsi_packet_sent_handler_data vp_data = { dsidev, &completion };
2565 int r = 0;
2566 u8 bit;
2567
2568 bit = dsi->te_enabled ? 30 : 31;
2569
2570 r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
2571 &vp_data, DSI_VC_IRQ_PACKET_SENT);
2572 if (r)
2573 goto err0;
2574
2575 /* Wait for completion only if TE_EN/TE_START is still set */
2576 if (REG_GET(dsidev, DSI_VC_TE(channel), bit, bit)) {
2577 if (wait_for_completion_timeout(&completion,
2578 msecs_to_jiffies(10)) == 0) {
2579 DSSERR("Failed to complete previous frame transfer\n");
2580 r = -EIO;
2581 goto err1;
2582 }
2583 }
2584
2585 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
2586 &vp_data, DSI_VC_IRQ_PACKET_SENT);
2587
2588 return 0;
2589err1:
2590 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
2591 &vp_data, DSI_VC_IRQ_PACKET_SENT);
2592err0:
2593 return r;
2594}
2595
2596static void dsi_packet_sent_handler_l4(void *data, u32 mask)
2597{
2598 struct dsi_packet_sent_handler_data *l4_data =
2599 (struct dsi_packet_sent_handler_data *) data;
2600 struct dsi_data *dsi = dsi_get_dsidrv_data(l4_data->dsidev);
2601 const int channel = dsi->update_channel;
2602
2603 if (REG_GET(l4_data->dsidev, DSI_VC_CTRL(channel), 5, 5) == 0)
2604 complete(l4_data->completion);
2605}
2606
2607static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel)
2608{
2609 DECLARE_COMPLETION_ONSTACK(completion);
2610 struct dsi_packet_sent_handler_data l4_data = { dsidev, &completion };
2611 int r = 0;
2612
2613 r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
2614 &l4_data, DSI_VC_IRQ_PACKET_SENT);
2615 if (r)
2616 goto err0;
2617
2618 /* Wait for completion only if TX_FIFO_NOT_EMPTY is still set */
2619 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 5, 5)) {
2620 if (wait_for_completion_timeout(&completion,
2621 msecs_to_jiffies(10)) == 0) {
2622 DSSERR("Failed to complete previous l4 transfer\n");
2623 r = -EIO;
2624 goto err1;
2625 }
2626 }
2627
2628 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
2629 &l4_data, DSI_VC_IRQ_PACKET_SENT);
2630
2631 return 0;
2632err1:
2633 dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
2634 &l4_data, DSI_VC_IRQ_PACKET_SENT);
2635err0:
2636 return r;
2637}
2638
2639static int dsi_sync_vc(struct platform_device *dsidev, int channel)
2640{
2641 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2642
2643 WARN_ON(!dsi_bus_is_locked(dsidev));
2644
2645 WARN_ON(in_interrupt());
2646
2647 if (!dsi_vc_is_enabled(dsidev, channel))
2648 return 0;
2649
2650 switch (dsi->vc[channel].source) {
2651 case DSI_VC_SOURCE_VP:
2652 return dsi_sync_vc_vp(dsidev, channel);
2653 case DSI_VC_SOURCE_L4:
2654 return dsi_sync_vc_l4(dsidev, channel);
2655 default:
2656 BUG();
2657 return -EINVAL;
2658 }
2659}
2660
2661static int dsi_vc_enable(struct platform_device *dsidev, int channel,
2662 bool enable)
2663{
2664 DSSDBG("dsi_vc_enable channel %d, enable %d\n",
2665 channel, enable);
2666
2667 enable = enable ? 1 : 0;
2668
2669 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 0, 0);
2670
2671 if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel),
2672 0, enable) != enable) {
2673 DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
2674 return -EIO;
2675 }
2676
2677 return 0;
2678}
2679
2680static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
2681{
2682 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2683 u32 r;
2684
2685 DSSDBG("Initial config of virtual channel %d", channel);
2686
2687 r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
2688
2689 if (FLD_GET(r, 15, 15)) /* VC_BUSY */
2690 DSSERR("VC(%d) busy when trying to configure it!\n",
2691 channel);
2692
2693 r = FLD_MOD(r, 0, 1, 1); /* SOURCE, 0 = L4 */
2694 r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN */
2695 r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */
2696 r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */
2697 r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
2698 r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
2699 r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
2700 if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH))
2701 r = FLD_MOD(r, 3, 11, 10); /* OCP_WIDTH = 32 bit */
2702
2703 r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
2704 r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
2705
2706 dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r);
2707
2708 dsi->vc[channel].source = DSI_VC_SOURCE_L4;
2709}
2710
2711static int dsi_vc_config_source(struct platform_device *dsidev, int channel,
2712 enum dsi_vc_source source)
2713{
2714 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2715
2716 if (dsi->vc[channel].source == source)
2717 return 0;
2718
2719 DSSDBG("Source config of virtual channel %d", channel);
2720
2721 dsi_sync_vc(dsidev, channel);
2722
2723 dsi_vc_enable(dsidev, channel, 0);
2724
2725 /* VC_BUSY */
2726 if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
2727 DSSERR("vc(%d) busy when trying to config for VP\n", channel);
2728 return -EIO;
2729 }
2730
2731 /* SOURCE, 0 = L4, 1 = video port */
2732 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), source, 1, 1);
2733
2734 /* DCS_CMD_ENABLE */
2735 if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
2736 bool enable = source == DSI_VC_SOURCE_VP;
2737 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 30, 30);
2738 }
2739
2740 dsi_vc_enable(dsidev, channel, 1);
2741
2742 dsi->vc[channel].source = source;
2743
2744 return 0;
2745}
2746
2747static void dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
2748 bool enable)
2749{
2750 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2751 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2752
2753 DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
2754
2755 WARN_ON(!dsi_bus_is_locked(dsidev));
2756
2757 dsi_vc_enable(dsidev, channel, 0);
2758 dsi_if_enable(dsidev, 0);
2759
2760 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 9, 9);
2761
2762 dsi_vc_enable(dsidev, channel, 1);
2763 dsi_if_enable(dsidev, 1);
2764
2765 dsi_force_tx_stop_mode_io(dsidev);
2766
2767 /* start the DDR clock by sending a NULL packet */
2768 if (dsi->vm_timings.ddr_clk_always_on && enable)
2769 dsi_vc_send_null(dssdev, channel);
2770}
2771
2772static void dsi_vc_flush_long_data(struct platform_device *dsidev, int channel)
2773{
2774 while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
2775 u32 val;
2776 val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
2777 DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
2778 (val >> 0) & 0xff,
2779 (val >> 8) & 0xff,
2780 (val >> 16) & 0xff,
2781 (val >> 24) & 0xff);
2782 }
2783}
2784
2785static void dsi_show_rx_ack_with_err(u16 err)
2786{
2787 DSSERR("\tACK with ERROR (%#x):\n", err);
2788 if (err & (1 << 0))
2789 DSSERR("\t\tSoT Error\n");
2790 if (err & (1 << 1))
2791 DSSERR("\t\tSoT Sync Error\n");
2792 if (err & (1 << 2))
2793 DSSERR("\t\tEoT Sync Error\n");
2794 if (err & (1 << 3))
2795 DSSERR("\t\tEscape Mode Entry Command Error\n");
2796 if (err & (1 << 4))
2797 DSSERR("\t\tLP Transmit Sync Error\n");
2798 if (err & (1 << 5))
2799 DSSERR("\t\tHS Receive Timeout Error\n");
2800 if (err & (1 << 6))
2801 DSSERR("\t\tFalse Control Error\n");
2802 if (err & (1 << 7))
2803 DSSERR("\t\t(reserved7)\n");
2804 if (err & (1 << 8))
2805 DSSERR("\t\tECC Error, single-bit (corrected)\n");
2806 if (err & (1 << 9))
2807 DSSERR("\t\tECC Error, multi-bit (not corrected)\n");
2808 if (err & (1 << 10))
2809 DSSERR("\t\tChecksum Error\n");
2810 if (err & (1 << 11))
2811 DSSERR("\t\tData type not recognized\n");
2812 if (err & (1 << 12))
2813 DSSERR("\t\tInvalid VC ID\n");
2814 if (err & (1 << 13))
2815 DSSERR("\t\tInvalid Transmission Length\n");
2816 if (err & (1 << 14))
2817 DSSERR("\t\t(reserved14)\n");
2818 if (err & (1 << 15))
2819 DSSERR("\t\tDSI Protocol Violation\n");
2820}
2821
2822static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev,
2823 int channel)
2824{
2825 /* RX_FIFO_NOT_EMPTY */
2826 while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
2827 u32 val;
2828 u8 dt;
2829 val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
2830 DSSERR("\trawval %#08x\n", val);
2831 dt = FLD_GET(val, 5, 0);
2832 if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) {
2833 u16 err = FLD_GET(val, 23, 8);
2834 dsi_show_rx_ack_with_err(err);
2835 } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE) {
2836 DSSERR("\tDCS short response, 1 byte: %#x\n",
2837 FLD_GET(val, 23, 8));
2838 } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE) {
2839 DSSERR("\tDCS short response, 2 byte: %#x\n",
2840 FLD_GET(val, 23, 8));
2841 } else if (dt == MIPI_DSI_RX_DCS_LONG_READ_RESPONSE) {
2842 DSSERR("\tDCS long response, len %d\n",
2843 FLD_GET(val, 23, 8));
2844 dsi_vc_flush_long_data(dsidev, channel);
2845 } else {
2846 DSSERR("\tunknown datatype 0x%02x\n", dt);
2847 }
2848 }
2849 return 0;
2850}
2851
2852static int dsi_vc_send_bta(struct platform_device *dsidev, int channel)
2853{
2854 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2855
2856 if (dsi->debug_write || dsi->debug_read)
2857 DSSDBG("dsi_vc_send_bta %d\n", channel);
2858
2859 WARN_ON(!dsi_bus_is_locked(dsidev));
2860
2861 /* RX_FIFO_NOT_EMPTY */
2862 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
2863 DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
2864 dsi_vc_flush_receive_data(dsidev, channel);
2865 }
2866
2867 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
2868
2869 /* flush posted write */
2870 dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
2871
2872 return 0;
2873}
2874
2875static int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel)
2876{
2877 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
2878 DECLARE_COMPLETION_ONSTACK(completion);
2879 int r = 0;
2880 u32 err;
2881
2882 r = dsi_register_isr_vc(dsidev, channel, dsi_completion_handler,
2883 &completion, DSI_VC_IRQ_BTA);
2884 if (r)
2885 goto err0;
2886
2887 r = dsi_register_isr(dsidev, dsi_completion_handler, &completion,
2888 DSI_IRQ_ERROR_MASK);
2889 if (r)
2890 goto err1;
2891
2892 r = dsi_vc_send_bta(dsidev, channel);
2893 if (r)
2894 goto err2;
2895
2896 if (wait_for_completion_timeout(&completion,
2897 msecs_to_jiffies(500)) == 0) {
2898 DSSERR("Failed to receive BTA\n");
2899 r = -EIO;
2900 goto err2;
2901 }
2902
2903 err = dsi_get_errors(dsidev);
2904 if (err) {
2905 DSSERR("Error while sending BTA: %x\n", err);
2906 r = -EIO;
2907 goto err2;
2908 }
2909err2:
2910 dsi_unregister_isr(dsidev, dsi_completion_handler, &completion,
2911 DSI_IRQ_ERROR_MASK);
2912err1:
2913 dsi_unregister_isr_vc(dsidev, channel, dsi_completion_handler,
2914 &completion, DSI_VC_IRQ_BTA);
2915err0:
2916 return r;
2917}
2918
2919static inline void dsi_vc_write_long_header(struct platform_device *dsidev,
2920 int channel, u8 data_type, u16 len, u8 ecc)
2921{
2922 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2923 u32 val;
2924 u8 data_id;
2925
2926 WARN_ON(!dsi_bus_is_locked(dsidev));
2927
2928 data_id = data_type | dsi->vc[channel].vc_id << 6;
2929
2930 val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
2931 FLD_VAL(ecc, 31, 24);
2932
2933 dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_HEADER(channel), val);
2934}
2935
2936static inline void dsi_vc_write_long_payload(struct platform_device *dsidev,
2937 int channel, u8 b1, u8 b2, u8 b3, u8 b4)
2938{
2939 u32 val;
2940
2941 val = b4 << 24 | b3 << 16 | b2 << 8 | b1 << 0;
2942
2943/* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
2944 b1, b2, b3, b4, val); */
2945
2946 dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
2947}
2948
2949static int dsi_vc_send_long(struct platform_device *dsidev, int channel,
2950 u8 data_type, u8 *data, u16 len, u8 ecc)
2951{
2952 /*u32 val; */
2953 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
2954 int i;
2955 u8 *p;
2956 int r = 0;
2957 u8 b1, b2, b3, b4;
2958
2959 if (dsi->debug_write)
2960 DSSDBG("dsi_vc_send_long, %d bytes\n", len);
2961
2962 /* len + header */
2963 if (dsi->vc[channel].tx_fifo_size * 32 * 4 < len + 4) {
2964 DSSERR("unable to send long packet: packet too long.\n");
2965 return -EINVAL;
2966 }
2967
2968 dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4);
2969
2970 dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc);
2971
2972 p = data;
2973 for (i = 0; i < len >> 2; i++) {
2974 if (dsi->debug_write)
2975 DSSDBG("\tsending full packet %d\n", i);
2976
2977 b1 = *p++;
2978 b2 = *p++;
2979 b3 = *p++;
2980 b4 = *p++;
2981
2982 dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, b4);
2983 }
2984
2985 i = len % 4;
2986 if (i) {
2987 b1 = 0; b2 = 0; b3 = 0;
2988
2989 if (dsi->debug_write)
2990 DSSDBG("\tsending remainder bytes %d\n", i);
2991
2992 switch (i) {
2993 case 3:
2994 b1 = *p++;
2995 b2 = *p++;
2996 b3 = *p++;
2997 break;
2998 case 2:
2999 b1 = *p++;
3000 b2 = *p++;
3001 break;
3002 case 1:
3003 b1 = *p++;
3004 break;
3005 }
3006
3007 dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, 0);
3008 }
3009
3010 return r;
3011}
3012
3013static int dsi_vc_send_short(struct platform_device *dsidev, int channel,
3014 u8 data_type, u16 data, u8 ecc)
3015{
3016 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3017 u32 r;
3018 u8 data_id;
3019
3020 WARN_ON(!dsi_bus_is_locked(dsidev));
3021
3022 if (dsi->debug_write)
3023 DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
3024 channel,
3025 data_type, data & 0xff, (data >> 8) & 0xff);
3026
3027 dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4);
3028
3029 if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) {
3030 DSSERR("ERROR FIFO FULL, aborting transfer\n");
3031 return -EINVAL;
3032 }
3033
3034 data_id = data_type | dsi->vc[channel].vc_id << 6;
3035
3036 r = (data_id << 0) | (data << 8) | (ecc << 24);
3037
3038 dsi_write_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel), r);
3039
3040 return 0;
3041}
3042
3043static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel)
3044{
3045 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3046
3047 return dsi_vc_send_long(dsidev, channel, MIPI_DSI_NULL_PACKET, NULL,
3048 0, 0);
3049}
3050
3051static int dsi_vc_write_nosync_common(struct platform_device *dsidev,
3052 int channel, u8 *data, int len, enum dss_dsi_content_type type)
3053{
3054 int r;
3055
3056 if (len == 0) {
3057 BUG_ON(type == DSS_DSI_CONTENT_DCS);
3058 r = dsi_vc_send_short(dsidev, channel,
3059 MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM, 0, 0);
3060 } else if (len == 1) {
3061 r = dsi_vc_send_short(dsidev, channel,
3062 type == DSS_DSI_CONTENT_GENERIC ?
3063 MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM :
3064 MIPI_DSI_DCS_SHORT_WRITE, data[0], 0);
3065 } else if (len == 2) {
3066 r = dsi_vc_send_short(dsidev, channel,
3067 type == DSS_DSI_CONTENT_GENERIC ?
3068 MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM :
3069 MIPI_DSI_DCS_SHORT_WRITE_PARAM,
3070 data[0] | (data[1] << 8), 0);
3071 } else {
3072 r = dsi_vc_send_long(dsidev, channel,
3073 type == DSS_DSI_CONTENT_GENERIC ?
3074 MIPI_DSI_GENERIC_LONG_WRITE :
3075 MIPI_DSI_DCS_LONG_WRITE, data, len, 0);
3076 }
3077
3078 return r;
3079}
3080
3081static int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
3082 u8 *data, int len)
3083{
3084 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3085
3086 return dsi_vc_write_nosync_common(dsidev, channel, data, len,
3087 DSS_DSI_CONTENT_DCS);
3088}
3089
3090static int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel,
3091 u8 *data, int len)
3092{
3093 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3094
3095 return dsi_vc_write_nosync_common(dsidev, channel, data, len,
3096 DSS_DSI_CONTENT_GENERIC);
3097}
3098
3099static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel,
3100 u8 *data, int len, enum dss_dsi_content_type type)
3101{
3102 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3103 int r;
3104
3105 r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type);
3106 if (r)
3107 goto err;
3108
3109 r = dsi_vc_send_bta_sync(dssdev, channel);
3110 if (r)
3111 goto err;
3112
3113 /* RX_FIFO_NOT_EMPTY */
3114 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
3115 DSSERR("rx fifo not empty after write, dumping data:\n");
3116 dsi_vc_flush_receive_data(dsidev, channel);
3117 r = -EIO;
3118 goto err;
3119 }
3120
3121 return 0;
3122err:
3123 DSSERR("dsi_vc_write_common(ch %d, cmd 0x%02x, len %d) failed\n",
3124 channel, data[0], len);
3125 return r;
3126}
3127
3128static int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
3129 int len)
3130{
3131 return dsi_vc_write_common(dssdev, channel, data, len,
3132 DSS_DSI_CONTENT_DCS);
3133}
3134
3135static int dsi_vc_generic_write(struct omap_dss_device *dssdev, int channel, u8 *data,
3136 int len)
3137{
3138 return dsi_vc_write_common(dssdev, channel, data, len,
3139 DSS_DSI_CONTENT_GENERIC);
3140}
3141
3142static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev,
3143 int channel, u8 dcs_cmd)
3144{
3145 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3146 int r;
3147
3148 if (dsi->debug_read)
3149 DSSDBG("dsi_vc_dcs_send_read_request(ch%d, dcs_cmd %x)\n",
3150 channel, dcs_cmd);
3151
3152 r = dsi_vc_send_short(dsidev, channel, MIPI_DSI_DCS_READ, dcs_cmd, 0);
3153 if (r) {
3154 DSSERR("dsi_vc_dcs_send_read_request(ch %d, cmd 0x%02x)"
3155 " failed\n", channel, dcs_cmd);
3156 return r;
3157 }
3158
3159 return 0;
3160}
3161
3162static int dsi_vc_generic_send_read_request(struct platform_device *dsidev,
3163 int channel, u8 *reqdata, int reqlen)
3164{
3165 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3166 u16 data;
3167 u8 data_type;
3168 int r;
3169
3170 if (dsi->debug_read)
3171 DSSDBG("dsi_vc_generic_send_read_request(ch %d, reqlen %d)\n",
3172 channel, reqlen);
3173
3174 if (reqlen == 0) {
3175 data_type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM;
3176 data = 0;
3177 } else if (reqlen == 1) {
3178 data_type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
3179 data = reqdata[0];
3180 } else if (reqlen == 2) {
3181 data_type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM;
3182 data = reqdata[0] | (reqdata[1] << 8);
3183 } else {
3184 BUG();
3185 return -EINVAL;
3186 }
3187
3188 r = dsi_vc_send_short(dsidev, channel, data_type, data, 0);
3189 if (r) {
3190 DSSERR("dsi_vc_generic_send_read_request(ch %d, reqlen %d)"
3191 " failed\n", channel, reqlen);
3192 return r;
3193 }
3194
3195 return 0;
3196}
3197
3198static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel,
3199 u8 *buf, int buflen, enum dss_dsi_content_type type)
3200{
3201 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3202 u32 val;
3203 u8 dt;
3204 int r;
3205
3206 /* RX_FIFO_NOT_EMPTY */
3207 if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) {
3208 DSSERR("RX fifo empty when trying to read.\n");
3209 r = -EIO;
3210 goto err;
3211 }
3212
3213 val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
3214 if (dsi->debug_read)
3215 DSSDBG("\theader: %08x\n", val);
3216 dt = FLD_GET(val, 5, 0);
3217 if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) {
3218 u16 err = FLD_GET(val, 23, 8);
3219 dsi_show_rx_ack_with_err(err);
3220 r = -EIO;
3221 goto err;
3222
3223 } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
3224 MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE :
3225 MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE)) {
3226 u8 data = FLD_GET(val, 15, 8);
3227 if (dsi->debug_read)
3228 DSSDBG("\t%s short response, 1 byte: %02x\n",
3229 type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
3230 "DCS", data);
3231
3232 if (buflen < 1) {
3233 r = -EIO;
3234 goto err;
3235 }
3236
3237 buf[0] = data;
3238
3239 return 1;
3240 } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
3241 MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE :
3242 MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE)) {
3243 u16 data = FLD_GET(val, 23, 8);
3244 if (dsi->debug_read)
3245 DSSDBG("\t%s short response, 2 byte: %04x\n",
3246 type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
3247 "DCS", data);
3248
3249 if (buflen < 2) {
3250 r = -EIO;
3251 goto err;
3252 }
3253
3254 buf[0] = data & 0xff;
3255 buf[1] = (data >> 8) & 0xff;
3256
3257 return 2;
3258 } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ?
3259 MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE :
3260 MIPI_DSI_RX_DCS_LONG_READ_RESPONSE)) {
3261 int w;
3262 int len = FLD_GET(val, 23, 8);
3263 if (dsi->debug_read)
3264 DSSDBG("\t%s long response, len %d\n",
3265 type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" :
3266 "DCS", len);
3267
3268 if (len > buflen) {
3269 r = -EIO;
3270 goto err;
3271 }
3272
3273 /* two byte checksum ends the packet, not included in len */
3274 for (w = 0; w < len + 2;) {
3275 int b;
3276 val = dsi_read_reg(dsidev,
3277 DSI_VC_SHORT_PACKET_HEADER(channel));
3278 if (dsi->debug_read)
3279 DSSDBG("\t\t%02x %02x %02x %02x\n",
3280 (val >> 0) & 0xff,
3281 (val >> 8) & 0xff,
3282 (val >> 16) & 0xff,
3283 (val >> 24) & 0xff);
3284
3285 for (b = 0; b < 4; ++b) {
3286 if (w < len)
3287 buf[w] = (val >> (b * 8)) & 0xff;
3288 /* we discard the 2 byte checksum */
3289 ++w;
3290 }
3291 }
3292
3293 return len;
3294 } else {
3295 DSSERR("\tunknown datatype 0x%02x\n", dt);
3296 r = -EIO;
3297 goto err;
3298 }
3299
3300err:
3301 DSSERR("dsi_vc_read_rx_fifo(ch %d type %s) failed\n", channel,
3302 type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : "DCS");
3303
3304 return r;
3305}
3306
3307static int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
3308 u8 *buf, int buflen)
3309{
3310 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3311 int r;
3312
3313 r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd);
3314 if (r)
3315 goto err;
3316
3317 r = dsi_vc_send_bta_sync(dssdev, channel);
3318 if (r)
3319 goto err;
3320
3321 r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen,
3322 DSS_DSI_CONTENT_DCS);
3323 if (r < 0)
3324 goto err;
3325
3326 if (r != buflen) {
3327 r = -EIO;
3328 goto err;
3329 }
3330
3331 return 0;
3332err:
3333 DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n", channel, dcs_cmd);
3334 return r;
3335}
3336
3337static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel,
3338 u8 *reqdata, int reqlen, u8 *buf, int buflen)
3339{
3340 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3341 int r;
3342
3343 r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen);
3344 if (r)
3345 return r;
3346
3347 r = dsi_vc_send_bta_sync(dssdev, channel);
3348 if (r)
3349 return r;
3350
3351 r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen,
3352 DSS_DSI_CONTENT_GENERIC);
3353 if (r < 0)
3354 return r;
3355
3356 if (r != buflen) {
3357 r = -EIO;
3358 return r;
3359 }
3360
3361 return 0;
3362}
3363
3364static int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
3365 u16 len)
3366{
3367 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
3368
3369 return dsi_vc_send_short(dsidev, channel,
3370 MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0);
3371}
3372
3373static int dsi_enter_ulps(struct platform_device *dsidev)
3374{
3375 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3376 DECLARE_COMPLETION_ONSTACK(completion);
3377 int r, i;
3378 unsigned mask;
3379
3380 DSSDBG("Entering ULPS");
3381
3382 WARN_ON(!dsi_bus_is_locked(dsidev));
3383
3384 WARN_ON(dsi->ulps_enabled);
3385
3386 if (dsi->ulps_enabled)
3387 return 0;
3388
3389 /* DDR_CLK_ALWAYS_ON */
3390 if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) {
3391 dsi_if_enable(dsidev, 0);
3392 REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13);
3393 dsi_if_enable(dsidev, 1);
3394 }
3395
3396 dsi_sync_vc(dsidev, 0);
3397 dsi_sync_vc(dsidev, 1);
3398 dsi_sync_vc(dsidev, 2);
3399 dsi_sync_vc(dsidev, 3);
3400
3401 dsi_force_tx_stop_mode_io(dsidev);
3402
3403 dsi_vc_enable(dsidev, 0, false);
3404 dsi_vc_enable(dsidev, 1, false);
3405 dsi_vc_enable(dsidev, 2, false);
3406 dsi_vc_enable(dsidev, 3, false);
3407
3408 if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 16, 16)) { /* HS_BUSY */
3409 DSSERR("HS busy when enabling ULPS\n");
3410 return -EIO;
3411 }
3412
3413 if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 17, 17)) { /* LP_BUSY */
3414 DSSERR("LP busy when enabling ULPS\n");
3415 return -EIO;
3416 }
3417
3418 r = dsi_register_isr_cio(dsidev, dsi_completion_handler, &completion,
3419 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
3420 if (r)
3421 return r;
3422
3423 mask = 0;
3424
3425 for (i = 0; i < dsi->num_lanes_supported; ++i) {
3426 if (dsi->lanes[i].function == DSI_LANE_UNUSED)
3427 continue;
3428 mask |= 1 << i;
3429 }
3430 /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */
3431 /* LANEx_ULPS_SIG2 */
3432 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, mask, 9, 5);
3433
3434 /* flush posted write and wait for SCP interface to finish the write */
3435 dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2);
3436
3437 if (wait_for_completion_timeout(&completion,
3438 msecs_to_jiffies(1000)) == 0) {
3439 DSSERR("ULPS enable timeout\n");
3440 r = -EIO;
3441 goto err;
3442 }
3443
3444 dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
3445 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
3446
3447 /* Reset LANEx_ULPS_SIG2 */
3448 REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, 0, 9, 5);
3449
3450 /* flush posted write and wait for SCP interface to finish the write */
3451 dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2);
3452
3453 dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
3454
3455 dsi_if_enable(dsidev, false);
3456
3457 dsi->ulps_enabled = true;
3458
3459 return 0;
3460
3461err:
3462 dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
3463 DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
3464 return r;
3465}
3466
3467static void dsi_set_lp_rx_timeout(struct platform_device *dsidev,
3468 unsigned ticks, bool x4, bool x16)
3469{
3470 unsigned long fck;
3471 unsigned long total_ticks;
3472 u32 r;
3473
3474 BUG_ON(ticks > 0x1fff);
3475
3476 /* ticks in DSI_FCK */
3477 fck = dsi_fclk_rate(dsidev);
3478
3479 r = dsi_read_reg(dsidev, DSI_TIMING2);
3480 r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */
3481 r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */
3482 r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */
3483 r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */
3484 dsi_write_reg(dsidev, DSI_TIMING2, r);
3485
3486 total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
3487
3488 DSSDBG("LP_RX_TO %lu ticks (%#x%s%s) = %lu ns\n",
3489 total_ticks,
3490 ticks, x4 ? " x4" : "", x16 ? " x16" : "",
3491 (total_ticks * 1000) / (fck / 1000 / 1000));
3492}
3493
3494static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks,
3495 bool x8, bool x16)
3496{
3497 unsigned long fck;
3498 unsigned long total_ticks;
3499 u32 r;
3500
3501 BUG_ON(ticks > 0x1fff);
3502
3503 /* ticks in DSI_FCK */
3504 fck = dsi_fclk_rate(dsidev);
3505
3506 r = dsi_read_reg(dsidev, DSI_TIMING1);
3507 r = FLD_MOD(r, 1, 31, 31); /* TA_TO */
3508 r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* TA_TO_X16 */
3509 r = FLD_MOD(r, x8 ? 1 : 0, 29, 29); /* TA_TO_X8 */
3510 r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */
3511 dsi_write_reg(dsidev, DSI_TIMING1, r);
3512
3513 total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1);
3514
3515 DSSDBG("TA_TO %lu ticks (%#x%s%s) = %lu ns\n",
3516 total_ticks,
3517 ticks, x8 ? " x8" : "", x16 ? " x16" : "",
3518 (total_ticks * 1000) / (fck / 1000 / 1000));
3519}
3520
3521static void dsi_set_stop_state_counter(struct platform_device *dsidev,
3522 unsigned ticks, bool x4, bool x16)
3523{
3524 unsigned long fck;
3525 unsigned long total_ticks;
3526 u32 r;
3527
3528 BUG_ON(ticks > 0x1fff);
3529
3530 /* ticks in DSI_FCK */
3531 fck = dsi_fclk_rate(dsidev);
3532
3533 r = dsi_read_reg(dsidev, DSI_TIMING1);
3534 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
3535 r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* STOP_STATE_X16_IO */
3536 r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* STOP_STATE_X4_IO */
3537 r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */
3538 dsi_write_reg(dsidev, DSI_TIMING1, r);
3539
3540 total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
3541
3542 DSSDBG("STOP_STATE_COUNTER %lu ticks (%#x%s%s) = %lu ns\n",
3543 total_ticks,
3544 ticks, x4 ? " x4" : "", x16 ? " x16" : "",
3545 (total_ticks * 1000) / (fck / 1000 / 1000));
3546}
3547
3548static void dsi_set_hs_tx_timeout(struct platform_device *dsidev,
3549 unsigned ticks, bool x4, bool x16)
3550{
3551 unsigned long fck;
3552 unsigned long total_ticks;
3553 u32 r;
3554
3555 BUG_ON(ticks > 0x1fff);
3556
3557 /* ticks in TxByteClkHS */
3558 fck = dsi_get_txbyteclkhs(dsidev);
3559
3560 r = dsi_read_reg(dsidev, DSI_TIMING2);
3561 r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */
3562 r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* HS_TX_TO_X16 */
3563 r = FLD_MOD(r, x4 ? 1 : 0, 29, 29); /* HS_TX_TO_X8 (4 really) */
3564 r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */
3565 dsi_write_reg(dsidev, DSI_TIMING2, r);
3566
3567 total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
3568
3569 DSSDBG("HS_TX_TO %lu ticks (%#x%s%s) = %lu ns\n",
3570 total_ticks,
3571 ticks, x4 ? " x4" : "", x16 ? " x16" : "",
3572 (total_ticks * 1000) / (fck / 1000 / 1000));
3573}
3574
3575static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
3576{
3577 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3578 int num_line_buffers;
3579
3580 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
3581 int bpp = dsi_get_pixel_size(dsi->pix_fmt);
3582 struct omap_video_timings *timings = &dsi->timings;
3583 /*
3584 * Don't use line buffers if width is greater than the video
3585 * port's line buffer size
3586 */
3587 if (dsi->line_buffer_size <= timings->x_res * bpp / 8)
3588 num_line_buffers = 0;
3589 else
3590 num_line_buffers = 2;
3591 } else {
3592 /* Use maximum number of line buffers in command mode */
3593 num_line_buffers = 2;
3594 }
3595
3596 /* LINE_BUFFER */
3597 REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12);
3598}
3599
3600static void dsi_config_vp_sync_events(struct platform_device *dsidev)
3601{
3602 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3603 bool sync_end;
3604 u32 r;
3605
3606 if (dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE)
3607 sync_end = true;
3608 else
3609 sync_end = false;
3610
3611 r = dsi_read_reg(dsidev, DSI_CTRL);
3612 r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */
3613 r = FLD_MOD(r, 1, 10, 10); /* VP_HSYNC_POL */
3614 r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */
3615 r = FLD_MOD(r, 1, 15, 15); /* VP_VSYNC_START */
3616 r = FLD_MOD(r, sync_end, 16, 16); /* VP_VSYNC_END */
3617 r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */
3618 r = FLD_MOD(r, sync_end, 18, 18); /* VP_HSYNC_END */
3619 dsi_write_reg(dsidev, DSI_CTRL, r);
3620}
3621
3622static void dsi_config_blanking_modes(struct platform_device *dsidev)
3623{
3624 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3625 int blanking_mode = dsi->vm_timings.blanking_mode;
3626 int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode;
3627 int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode;
3628 int hsa_blanking_mode = dsi->vm_timings.hsa_blanking_mode;
3629 u32 r;
3630
3631 /*
3632 * 0 = TX FIFO packets sent or LPS in corresponding blanking periods
3633 * 1 = Long blanking packets are sent in corresponding blanking periods
3634 */
3635 r = dsi_read_reg(dsidev, DSI_CTRL);
3636 r = FLD_MOD(r, blanking_mode, 20, 20); /* BLANKING_MODE */
3637 r = FLD_MOD(r, hfp_blanking_mode, 21, 21); /* HFP_BLANKING */
3638 r = FLD_MOD(r, hbp_blanking_mode, 22, 22); /* HBP_BLANKING */
3639 r = FLD_MOD(r, hsa_blanking_mode, 23, 23); /* HSA_BLANKING */
3640 dsi_write_reg(dsidev, DSI_CTRL, r);
3641}
3642
3643/*
3644 * According to section 'HS Command Mode Interleaving' in OMAP TRM, Scenario 3
3645 * results in maximum transition time for data and clock lanes to enter and
3646 * exit HS mode. Hence, this is the scenario where the least amount of command
3647 * mode data can be interleaved. We program the minimum amount of TXBYTECLKHS
3648 * clock cycles that can be used to interleave command mode data in HS so that
3649 * all scenarios are satisfied.
3650 */
3651static int dsi_compute_interleave_hs(int blank, bool ddr_alwon, int enter_hs,
3652 int exit_hs, int exiths_clk, int ddr_pre, int ddr_post)
3653{
3654 int transition;
3655
3656 /*
3657 * If DDR_CLK_ALWAYS_ON is set, we need to consider HS mode transition
3658 * time of data lanes only, if it isn't set, we need to consider HS
3659 * transition time of both data and clock lanes. HS transition time
3660 * of Scenario 3 is considered.
3661 */
3662 if (ddr_alwon) {
3663 transition = enter_hs + exit_hs + max(enter_hs, 2) + 1;
3664 } else {
3665 int trans1, trans2;
3666 trans1 = ddr_pre + enter_hs + exit_hs + max(enter_hs, 2) + 1;
3667 trans2 = ddr_pre + enter_hs + exiths_clk + ddr_post + ddr_pre +
3668 enter_hs + 1;
3669 transition = max(trans1, trans2);
3670 }
3671
3672 return blank > transition ? blank - transition : 0;
3673}
3674
3675/*
3676 * According to section 'LP Command Mode Interleaving' in OMAP TRM, Scenario 1
3677 * results in maximum transition time for data lanes to enter and exit LP mode.
3678 * Hence, this is the scenario where the least amount of command mode data can
3679 * be interleaved. We program the minimum amount of bytes that can be
3680 * interleaved in LP so that all scenarios are satisfied.
3681 */
3682static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs,
3683 int lp_clk_div, int tdsi_fclk)
3684{
3685 int trans_lp; /* time required for a LP transition, in TXBYTECLKHS */
3686 int tlp_avail; /* time left for interleaving commands, in CLKIN4DDR */
3687 int ttxclkesc; /* period of LP transmit escape clock, in CLKIN4DDR */
3688 int thsbyte_clk = 16; /* Period of TXBYTECLKHS clock, in CLKIN4DDR */
3689 int lp_inter; /* cmd mode data that can be interleaved, in bytes */
3690
3691 /* maximum LP transition time according to Scenario 1 */
3692 trans_lp = exit_hs + max(enter_hs, 2) + 1;
3693
3694 /* CLKIN4DDR = 16 * TXBYTECLKHS */
3695 tlp_avail = thsbyte_clk * (blank - trans_lp);
3696
3697 ttxclkesc = tdsi_fclk * lp_clk_div;
3698
3699 lp_inter = ((tlp_avail - 8 * thsbyte_clk - 5 * tdsi_fclk) / ttxclkesc -
3700 26) / 16;
3701
3702 return max(lp_inter, 0);
3703}
3704
3705static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev)
3706{
3707 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3708 int blanking_mode;
3709 int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode;
3710 int hsa, hfp, hbp, width_bytes, bllp, lp_clk_div;
3711 int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat;
3712 int tclk_trail, ths_exit, exiths_clk;
3713 bool ddr_alwon;
3714 struct omap_video_timings *timings = &dsi->timings;
3715 int bpp = dsi_get_pixel_size(dsi->pix_fmt);
3716 int ndl = dsi->num_lanes_used - 1;
3717 int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.regm_dsi + 1;
3718 int hsa_interleave_hs = 0, hsa_interleave_lp = 0;
3719 int hfp_interleave_hs = 0, hfp_interleave_lp = 0;
3720 int hbp_interleave_hs = 0, hbp_interleave_lp = 0;
3721 int bl_interleave_hs = 0, bl_interleave_lp = 0;
3722 u32 r;
3723
3724 r = dsi_read_reg(dsidev, DSI_CTRL);
3725 blanking_mode = FLD_GET(r, 20, 20);
3726 hfp_blanking_mode = FLD_GET(r, 21, 21);
3727 hbp_blanking_mode = FLD_GET(r, 22, 22);
3728 hsa_blanking_mode = FLD_GET(r, 23, 23);
3729
3730 r = dsi_read_reg(dsidev, DSI_VM_TIMING1);
3731 hbp = FLD_GET(r, 11, 0);
3732 hfp = FLD_GET(r, 23, 12);
3733 hsa = FLD_GET(r, 31, 24);
3734
3735 r = dsi_read_reg(dsidev, DSI_CLK_TIMING);
3736 ddr_clk_post = FLD_GET(r, 7, 0);
3737 ddr_clk_pre = FLD_GET(r, 15, 8);
3738
3739 r = dsi_read_reg(dsidev, DSI_VM_TIMING7);
3740 exit_hs_mode_lat = FLD_GET(r, 15, 0);
3741 enter_hs_mode_lat = FLD_GET(r, 31, 16);
3742
3743 r = dsi_read_reg(dsidev, DSI_CLK_CTRL);
3744 lp_clk_div = FLD_GET(r, 12, 0);
3745 ddr_alwon = FLD_GET(r, 13, 13);
3746
3747 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
3748 ths_exit = FLD_GET(r, 7, 0);
3749
3750 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
3751 tclk_trail = FLD_GET(r, 15, 8);
3752
3753 exiths_clk = ths_exit + tclk_trail;
3754
3755 width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8);
3756 bllp = hbp + hfp + hsa + DIV_ROUND_UP(width_bytes + 6, ndl);
3757
3758 if (!hsa_blanking_mode) {
3759 hsa_interleave_hs = dsi_compute_interleave_hs(hsa, ddr_alwon,
3760 enter_hs_mode_lat, exit_hs_mode_lat,
3761 exiths_clk, ddr_clk_pre, ddr_clk_post);
3762 hsa_interleave_lp = dsi_compute_interleave_lp(hsa,
3763 enter_hs_mode_lat, exit_hs_mode_lat,
3764 lp_clk_div, dsi_fclk_hsdiv);
3765 }
3766
3767 if (!hfp_blanking_mode) {
3768 hfp_interleave_hs = dsi_compute_interleave_hs(hfp, ddr_alwon,
3769 enter_hs_mode_lat, exit_hs_mode_lat,
3770 exiths_clk, ddr_clk_pre, ddr_clk_post);
3771 hfp_interleave_lp = dsi_compute_interleave_lp(hfp,
3772 enter_hs_mode_lat, exit_hs_mode_lat,
3773 lp_clk_div, dsi_fclk_hsdiv);
3774 }
3775
3776 if (!hbp_blanking_mode) {
3777 hbp_interleave_hs = dsi_compute_interleave_hs(hbp, ddr_alwon,
3778 enter_hs_mode_lat, exit_hs_mode_lat,
3779 exiths_clk, ddr_clk_pre, ddr_clk_post);
3780
3781 hbp_interleave_lp = dsi_compute_interleave_lp(hbp,
3782 enter_hs_mode_lat, exit_hs_mode_lat,
3783 lp_clk_div, dsi_fclk_hsdiv);
3784 }
3785
3786 if (!blanking_mode) {
3787 bl_interleave_hs = dsi_compute_interleave_hs(bllp, ddr_alwon,
3788 enter_hs_mode_lat, exit_hs_mode_lat,
3789 exiths_clk, ddr_clk_pre, ddr_clk_post);
3790
3791 bl_interleave_lp = dsi_compute_interleave_lp(bllp,
3792 enter_hs_mode_lat, exit_hs_mode_lat,
3793 lp_clk_div, dsi_fclk_hsdiv);
3794 }
3795
3796 DSSDBG("DSI HS interleaving(TXBYTECLKHS) HSA %d, HFP %d, HBP %d, BLLP %d\n",
3797 hsa_interleave_hs, hfp_interleave_hs, hbp_interleave_hs,
3798 bl_interleave_hs);
3799
3800 DSSDBG("DSI LP interleaving(bytes) HSA %d, HFP %d, HBP %d, BLLP %d\n",
3801 hsa_interleave_lp, hfp_interleave_lp, hbp_interleave_lp,
3802 bl_interleave_lp);
3803
3804 r = dsi_read_reg(dsidev, DSI_VM_TIMING4);
3805 r = FLD_MOD(r, hsa_interleave_hs, 23, 16);
3806 r = FLD_MOD(r, hfp_interleave_hs, 15, 8);
3807 r = FLD_MOD(r, hbp_interleave_hs, 7, 0);
3808 dsi_write_reg(dsidev, DSI_VM_TIMING4, r);
3809
3810 r = dsi_read_reg(dsidev, DSI_VM_TIMING5);
3811 r = FLD_MOD(r, hsa_interleave_lp, 23, 16);
3812 r = FLD_MOD(r, hfp_interleave_lp, 15, 8);
3813 r = FLD_MOD(r, hbp_interleave_lp, 7, 0);
3814 dsi_write_reg(dsidev, DSI_VM_TIMING5, r);
3815
3816 r = dsi_read_reg(dsidev, DSI_VM_TIMING6);
3817 r = FLD_MOD(r, bl_interleave_hs, 31, 15);
3818 r = FLD_MOD(r, bl_interleave_lp, 16, 0);
3819 dsi_write_reg(dsidev, DSI_VM_TIMING6, r);
3820}
3821
3822static int dsi_proto_config(struct platform_device *dsidev)
3823{
3824 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3825 u32 r;
3826 int buswidth = 0;
3827
3828 dsi_config_tx_fifo(dsidev, DSI_FIFO_SIZE_32,
3829 DSI_FIFO_SIZE_32,
3830 DSI_FIFO_SIZE_32,
3831 DSI_FIFO_SIZE_32);
3832
3833 dsi_config_rx_fifo(dsidev, DSI_FIFO_SIZE_32,
3834 DSI_FIFO_SIZE_32,
3835 DSI_FIFO_SIZE_32,
3836 DSI_FIFO_SIZE_32);
3837
3838 /* XXX what values for the timeouts? */
3839 dsi_set_stop_state_counter(dsidev, 0x1000, false, false);
3840 dsi_set_ta_timeout(dsidev, 0x1fff, true, true);
3841 dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true);
3842 dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true);
3843
3844 switch (dsi_get_pixel_size(dsi->pix_fmt)) {
3845 case 16:
3846 buswidth = 0;
3847 break;
3848 case 18:
3849 buswidth = 1;
3850 break;
3851 case 24:
3852 buswidth = 2;
3853 break;
3854 default:
3855 BUG();
3856 return -EINVAL;
3857 }
3858
3859 r = dsi_read_reg(dsidev, DSI_CTRL);
3860 r = FLD_MOD(r, 1, 1, 1); /* CS_RX_EN */
3861 r = FLD_MOD(r, 1, 2, 2); /* ECC_RX_EN */
3862 r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */
3863 r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/
3864 r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */
3865 r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */
3866 r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */
3867 r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */
3868 if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
3869 r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
3870 /* DCS_CMD_CODE, 1=start, 0=continue */
3871 r = FLD_MOD(r, 0, 25, 25);
3872 }
3873
3874 dsi_write_reg(dsidev, DSI_CTRL, r);
3875
3876 dsi_config_vp_num_line_buffers(dsidev);
3877
3878 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
3879 dsi_config_vp_sync_events(dsidev);
3880 dsi_config_blanking_modes(dsidev);
3881 dsi_config_cmd_mode_interleaving(dsidev);
3882 }
3883
3884 dsi_vc_initial_config(dsidev, 0);
3885 dsi_vc_initial_config(dsidev, 1);
3886 dsi_vc_initial_config(dsidev, 2);
3887 dsi_vc_initial_config(dsidev, 3);
3888
3889 return 0;
3890}
3891
3892static void dsi_proto_timings(struct platform_device *dsidev)
3893{
3894 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
3895 unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
3896 unsigned tclk_pre, tclk_post;
3897 unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
3898 unsigned ths_trail, ths_exit;
3899 unsigned ddr_clk_pre, ddr_clk_post;
3900 unsigned enter_hs_mode_lat, exit_hs_mode_lat;
3901 unsigned ths_eot;
3902 int ndl = dsi->num_lanes_used - 1;
3903 u32 r;
3904
3905 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
3906 ths_prepare = FLD_GET(r, 31, 24);
3907 ths_prepare_ths_zero = FLD_GET(r, 23, 16);
3908 ths_zero = ths_prepare_ths_zero - ths_prepare;
3909 ths_trail = FLD_GET(r, 15, 8);
3910 ths_exit = FLD_GET(r, 7, 0);
3911
3912 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
3913 tlpx = FLD_GET(r, 20, 16) * 2;
3914 tclk_trail = FLD_GET(r, 15, 8);
3915 tclk_zero = FLD_GET(r, 7, 0);
3916
3917 r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
3918 tclk_prepare = FLD_GET(r, 7, 0);
3919
3920 /* min 8*UI */
3921 tclk_pre = 20;
3922 /* min 60ns + 52*UI */
3923 tclk_post = ns2ddr(dsidev, 60) + 26;
3924
3925 ths_eot = DIV_ROUND_UP(4, ndl);
3926
3927 ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
3928 4);
3929 ddr_clk_post = DIV_ROUND_UP(tclk_post + ths_trail, 4) + ths_eot;
3930
3931 BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
3932 BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);
3933
3934 r = dsi_read_reg(dsidev, DSI_CLK_TIMING);
3935 r = FLD_MOD(r, ddr_clk_pre, 15, 8);
3936 r = FLD_MOD(r, ddr_clk_post, 7, 0);
3937 dsi_write_reg(dsidev, DSI_CLK_TIMING, r);
3938
3939 DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
3940 ddr_clk_pre,
3941 ddr_clk_post);
3942
3943 enter_hs_mode_lat = 1 + DIV_ROUND_UP(tlpx, 4) +
3944 DIV_ROUND_UP(ths_prepare, 4) +
3945 DIV_ROUND_UP(ths_zero + 3, 4);
3946
3947 exit_hs_mode_lat = DIV_ROUND_UP(ths_trail + ths_exit, 4) + 1 + ths_eot;
3948
3949 r = FLD_VAL(enter_hs_mode_lat, 31, 16) |
3950 FLD_VAL(exit_hs_mode_lat, 15, 0);
3951 dsi_write_reg(dsidev, DSI_VM_TIMING7, r);
3952
3953 DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
3954 enter_hs_mode_lat, exit_hs_mode_lat);
3955
3956 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
3957 /* TODO: Implement a video mode check_timings function */
3958 int hsa = dsi->vm_timings.hsa;
3959 int hfp = dsi->vm_timings.hfp;
3960 int hbp = dsi->vm_timings.hbp;
3961 int vsa = dsi->vm_timings.vsa;
3962 int vfp = dsi->vm_timings.vfp;
3963 int vbp = dsi->vm_timings.vbp;
3964 int window_sync = dsi->vm_timings.window_sync;
3965 bool hsync_end;
3966 struct omap_video_timings *timings = &dsi->timings;
3967 int bpp = dsi_get_pixel_size(dsi->pix_fmt);
3968 int tl, t_he, width_bytes;
3969
3970 hsync_end = dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE;
3971 t_he = hsync_end ?
3972 ((hsa == 0 && ndl == 3) ? 1 : DIV_ROUND_UP(4, ndl)) : 0;
3973
3974 width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8);
3975
3976 /* TL = t_HS + HSA + t_HE + HFP + ceil((WC + 6) / NDL) + HBP */
3977 tl = DIV_ROUND_UP(4, ndl) + (hsync_end ? hsa : 0) + t_he + hfp +
3978 DIV_ROUND_UP(width_bytes + 6, ndl) + hbp;
3979
3980 DSSDBG("HBP: %d, HFP: %d, HSA: %d, TL: %d TXBYTECLKHS\n", hbp,
3981 hfp, hsync_end ? hsa : 0, tl);
3982 DSSDBG("VBP: %d, VFP: %d, VSA: %d, VACT: %d lines\n", vbp, vfp,
3983 vsa, timings->y_res);
3984
3985 r = dsi_read_reg(dsidev, DSI_VM_TIMING1);
3986 r = FLD_MOD(r, hbp, 11, 0); /* HBP */
3987 r = FLD_MOD(r, hfp, 23, 12); /* HFP */
3988 r = FLD_MOD(r, hsync_end ? hsa : 0, 31, 24); /* HSA */
3989 dsi_write_reg(dsidev, DSI_VM_TIMING1, r);
3990
3991 r = dsi_read_reg(dsidev, DSI_VM_TIMING2);
3992 r = FLD_MOD(r, vbp, 7, 0); /* VBP */
3993 r = FLD_MOD(r, vfp, 15, 8); /* VFP */
3994 r = FLD_MOD(r, vsa, 23, 16); /* VSA */
3995 r = FLD_MOD(r, window_sync, 27, 24); /* WINDOW_SYNC */
3996 dsi_write_reg(dsidev, DSI_VM_TIMING2, r);
3997
3998 r = dsi_read_reg(dsidev, DSI_VM_TIMING3);
3999 r = FLD_MOD(r, timings->y_res, 14, 0); /* VACT */
4000 r = FLD_MOD(r, tl, 31, 16); /* TL */
4001 dsi_write_reg(dsidev, DSI_VM_TIMING3, r);
4002 }
4003}
4004
4005static int dsi_configure_pins(struct omap_dss_device *dssdev,
4006 const struct omap_dsi_pin_config *pin_cfg)
4007{
4008 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4009 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4010 int num_pins;
4011 const int *pins;
4012 struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
4013 int num_lanes;
4014 int i;
4015
4016 static const enum dsi_lane_function functions[] = {
4017 DSI_LANE_CLK,
4018 DSI_LANE_DATA1,
4019 DSI_LANE_DATA2,
4020 DSI_LANE_DATA3,
4021 DSI_LANE_DATA4,
4022 };
4023
4024 num_pins = pin_cfg->num_pins;
4025 pins = pin_cfg->pins;
4026
4027 if (num_pins < 4 || num_pins > dsi->num_lanes_supported * 2
4028 || num_pins % 2 != 0)
4029 return -EINVAL;
4030
4031 for (i = 0; i < DSI_MAX_NR_LANES; ++i)
4032 lanes[i].function = DSI_LANE_UNUSED;
4033
4034 num_lanes = 0;
4035
4036 for (i = 0; i < num_pins; i += 2) {
4037 u8 lane, pol;
4038 int dx, dy;
4039
4040 dx = pins[i];
4041 dy = pins[i + 1];
4042
4043 if (dx < 0 || dx >= dsi->num_lanes_supported * 2)
4044 return -EINVAL;
4045
4046 if (dy < 0 || dy >= dsi->num_lanes_supported * 2)
4047 return -EINVAL;
4048
4049 if (dx & 1) {
4050 if (dy != dx - 1)
4051 return -EINVAL;
4052 pol = 1;
4053 } else {
4054 if (dy != dx + 1)
4055 return -EINVAL;
4056 pol = 0;
4057 }
4058
4059 lane = dx / 2;
4060
4061 lanes[lane].function = functions[i / 2];
4062 lanes[lane].polarity = pol;
4063 num_lanes++;
4064 }
4065
4066 memcpy(dsi->lanes, lanes, sizeof(dsi->lanes));
4067 dsi->num_lanes_used = num_lanes;
4068
4069 return 0;
4070}
4071
4072static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
4073{
4074 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4075 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4076 struct omap_overlay_manager *mgr = dsi->output.manager;
4077 int bpp = dsi_get_pixel_size(dsi->pix_fmt);
4078 struct omap_dss_device *out = &dsi->output;
4079 u8 data_type;
4080 u16 word_count;
4081 int r;
4082
4083 if (out == NULL || out->manager == NULL) {
4084 DSSERR("failed to enable display: no output/manager\n");
4085 return -ENODEV;
4086 }
4087
4088 r = dsi_display_init_dispc(dsidev, mgr);
4089 if (r)
4090 goto err_init_dispc;
4091
4092 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
4093 switch (dsi->pix_fmt) {
4094 case OMAP_DSS_DSI_FMT_RGB888:
4095 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24;
4096 break;
4097 case OMAP_DSS_DSI_FMT_RGB666:
4098 data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
4099 break;
4100 case OMAP_DSS_DSI_FMT_RGB666_PACKED:
4101 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18;
4102 break;
4103 case OMAP_DSS_DSI_FMT_RGB565:
4104 data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
4105 break;
4106 default:
4107 r = -EINVAL;
4108 goto err_pix_fmt;
4109 }
4110
4111 dsi_if_enable(dsidev, false);
4112 dsi_vc_enable(dsidev, channel, false);
4113
4114 /* MODE, 1 = video mode */
4115 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4);
4116
4117 word_count = DIV_ROUND_UP(dsi->timings.x_res * bpp, 8);
4118
4119 dsi_vc_write_long_header(dsidev, channel, data_type,
4120 word_count, 0);
4121
4122 dsi_vc_enable(dsidev, channel, true);
4123 dsi_if_enable(dsidev, true);
4124 }
4125
4126 r = dss_mgr_enable(mgr);
4127 if (r)
4128 goto err_mgr_enable;
4129
4130 return 0;
4131
4132err_mgr_enable:
4133 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
4134 dsi_if_enable(dsidev, false);
4135 dsi_vc_enable(dsidev, channel, false);
4136 }
4137err_pix_fmt:
4138 dsi_display_uninit_dispc(dsidev, mgr);
4139err_init_dispc:
4140 return r;
4141}
4142
4143static void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
4144{
4145 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4146 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4147 struct omap_overlay_manager *mgr = dsi->output.manager;
4148
4149 if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
4150 dsi_if_enable(dsidev, false);
4151 dsi_vc_enable(dsidev, channel, false);
4152
4153 /* MODE, 0 = command mode */
4154 REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4);
4155
4156 dsi_vc_enable(dsidev, channel, true);
4157 dsi_if_enable(dsidev, true);
4158 }
4159
4160 dss_mgr_disable(mgr);
4161
4162 dsi_display_uninit_dispc(dsidev, mgr);
4163}
4164
4165static void dsi_update_screen_dispc(struct platform_device *dsidev)
4166{
4167 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4168 struct omap_overlay_manager *mgr = dsi->output.manager;
4169 unsigned bytespp;
4170 unsigned bytespl;
4171 unsigned bytespf;
4172 unsigned total_len;
4173 unsigned packet_payload;
4174 unsigned packet_len;
4175 u32 l;
4176 int r;
4177 const unsigned channel = dsi->update_channel;
4178 const unsigned line_buf_size = dsi->line_buffer_size;
4179 u16 w = dsi->timings.x_res;
4180 u16 h = dsi->timings.y_res;
4181
4182 DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h);
4183
4184 dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP);
4185
4186 bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8;
4187 bytespl = w * bytespp;
4188 bytespf = bytespl * h;
4189
4190 /* NOTE: packet_payload has to be equal to N * bytespl, where N is
4191 * number of lines in a packet. See errata about VP_CLK_RATIO */
4192
4193 if (bytespf < line_buf_size)
4194 packet_payload = bytespf;
4195 else
4196 packet_payload = (line_buf_size) / bytespl * bytespl;
4197
4198 packet_len = packet_payload + 1; /* 1 byte for DCS cmd */
4199 total_len = (bytespf / packet_payload) * packet_len;
4200
4201 if (bytespf % packet_payload)
4202 total_len += (bytespf % packet_payload) + 1;
4203
4204 l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
4205 dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
4206
4207 dsi_vc_write_long_header(dsidev, channel, MIPI_DSI_DCS_LONG_WRITE,
4208 packet_len, 0);
4209
4210 if (dsi->te_enabled)
4211 l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
4212 else
4213 l = FLD_MOD(l, 1, 31, 31); /* TE_START */
4214 dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
4215
4216 /* We put SIDLEMODE to no-idle for the duration of the transfer,
4217 * because DSS interrupts are not capable of waking up the CPU and the
4218 * framedone interrupt could be delayed for quite a long time. I think
4219 * the same goes for any DSS interrupts, but for some reason I have not
4220 * seen the problem anywhere else than here.
4221 */
4222 dispc_disable_sidle();
4223
4224 dsi_perf_mark_start(dsidev);
4225
4226 r = schedule_delayed_work(&dsi->framedone_timeout_work,
4227 msecs_to_jiffies(250));
4228 BUG_ON(r == 0);
4229
4230 dss_mgr_set_timings(mgr, &dsi->timings);
4231
4232 dss_mgr_start_update(mgr);
4233
4234 if (dsi->te_enabled) {
4235 /* disable LP_RX_TO, so that we can receive TE. Time to wait
4236 * for TE is longer than the timer allows */
4237 REG_FLD_MOD(dsidev, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
4238
4239 dsi_vc_send_bta(dsidev, channel);
4240
4241#ifdef DSI_CATCH_MISSING_TE
4242 mod_timer(&dsi->te_timer, jiffies + msecs_to_jiffies(250));
4243#endif
4244 }
4245}
4246
4247#ifdef DSI_CATCH_MISSING_TE
4248static void dsi_te_timeout(unsigned long arg)
4249{
4250 DSSERR("TE not received for 250ms!\n");
4251}
4252#endif
4253
4254static void dsi_handle_framedone(struct platform_device *dsidev, int error)
4255{
4256 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4257
4258 /* SIDLEMODE back to smart-idle */
4259 dispc_enable_sidle();
4260
4261 if (dsi->te_enabled) {
4262 /* enable LP_RX_TO again after the TE */
4263 REG_FLD_MOD(dsidev, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
4264 }
4265
4266 dsi->framedone_callback(error, dsi->framedone_data);
4267
4268 if (!error)
4269 dsi_perf_show(dsidev, "DISPC");
4270}
4271
4272static void dsi_framedone_timeout_work_callback(struct work_struct *work)
4273{
4274 struct dsi_data *dsi = container_of(work, struct dsi_data,
4275 framedone_timeout_work.work);
4276 /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after
4277 * 250ms which would conflict with this timeout work. What should be
4278 * done is first cancel the transfer on the HW, and then cancel the
4279 * possibly scheduled framedone work. However, cancelling the transfer
4280 * on the HW is buggy, and would probably require resetting the whole
4281 * DSI */
4282
4283 DSSERR("Framedone not received for 250ms!\n");
4284
4285 dsi_handle_framedone(dsi->pdev, -ETIMEDOUT);
4286}
4287
4288static void dsi_framedone_irq_callback(void *data)
4289{
4290 struct platform_device *dsidev = (struct platform_device *) data;
4291 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4292
4293 /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
4294 * turns itself off. However, DSI still has the pixels in its buffers,
4295 * and is sending the data.
4296 */
4297
4298 cancel_delayed_work(&dsi->framedone_timeout_work);
4299
4300 dsi_handle_framedone(dsidev, 0);
4301}
4302
4303static int dsi_update(struct omap_dss_device *dssdev, int channel,
4304 void (*callback)(int, void *), void *data)
4305{
4306 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4307 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4308 u16 dw, dh;
4309
4310 dsi_perf_mark_setup(dsidev);
4311
4312 dsi->update_channel = channel;
4313
4314 dsi->framedone_callback = callback;
4315 dsi->framedone_data = data;
4316
4317 dw = dsi->timings.x_res;
4318 dh = dsi->timings.y_res;
4319
4320#ifdef DSI_PERF_MEASURE
4321 dsi->update_bytes = dw * dh *
4322 dsi_get_pixel_size(dsi->pix_fmt) / 8;
4323#endif
4324 dsi_update_screen_dispc(dsidev);
4325
4326 return 0;
4327}
4328
4329/* Display funcs */
4330
4331static int dsi_configure_dispc_clocks(struct platform_device *dsidev)
4332{
4333 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4334 struct dispc_clock_info dispc_cinfo;
4335 int r;
4336 unsigned long fck;
4337
4338 fck = dsi_get_pll_hsdiv_dispc_rate(dsidev);
4339
4340 dispc_cinfo.lck_div = dsi->user_dispc_cinfo.lck_div;
4341 dispc_cinfo.pck_div = dsi->user_dispc_cinfo.pck_div;
4342
4343 r = dispc_calc_clock_rates(fck, &dispc_cinfo);
4344 if (r) {
4345 DSSERR("Failed to calc dispc clocks\n");
4346 return r;
4347 }
4348
4349 dsi->mgr_config.clock_info = dispc_cinfo;
4350
4351 return 0;
4352}
4353
4354static int dsi_display_init_dispc(struct platform_device *dsidev,
4355 struct omap_overlay_manager *mgr)
4356{
4357 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4358 int r;
4359
4360 dss_select_lcd_clk_source(mgr->id, dsi->module_id == 0 ?
4361 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
4362 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC);
4363
4364 if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
4365 r = dss_mgr_register_framedone_handler(mgr,
4366 dsi_framedone_irq_callback, dsidev);
4367 if (r) {
4368 DSSERR("can't register FRAMEDONE handler\n");
4369 goto err;
4370 }
4371
4372 dsi->mgr_config.stallmode = true;
4373 dsi->mgr_config.fifohandcheck = true;
4374 } else {
4375 dsi->mgr_config.stallmode = false;
4376 dsi->mgr_config.fifohandcheck = false;
4377 }
4378
4379 /*
4380 * override interlace, logic level and edge related parameters in
4381 * omap_video_timings with default values
4382 */
4383 dsi->timings.interlace = false;
4384 dsi->timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
4385 dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
4386 dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
4387 dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
4388 dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
4389
4390 dss_mgr_set_timings(mgr, &dsi->timings);
4391
4392 r = dsi_configure_dispc_clocks(dsidev);
4393 if (r)
4394 goto err1;
4395
4396 dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
4397 dsi->mgr_config.video_port_width =
4398 dsi_get_pixel_size(dsi->pix_fmt);
4399 dsi->mgr_config.lcden_sig_polarity = 0;
4400
4401 dss_mgr_set_lcd_config(mgr, &dsi->mgr_config);
4402
4403 return 0;
4404err1:
4405 if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
4406 dss_mgr_unregister_framedone_handler(mgr,
4407 dsi_framedone_irq_callback, dsidev);
4408err:
4409 dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
4410 return r;
4411}
4412
4413static void dsi_display_uninit_dispc(struct platform_device *dsidev,
4414 struct omap_overlay_manager *mgr)
4415{
4416 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4417
4418 if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
4419 dss_mgr_unregister_framedone_handler(mgr,
4420 dsi_framedone_irq_callback, dsidev);
4421
4422 dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
4423}
4424
4425static int dsi_configure_dsi_clocks(struct platform_device *dsidev)
4426{
4427 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4428 struct dsi_clock_info cinfo;
4429 int r;
4430
4431 cinfo = dsi->user_dsi_cinfo;
4432
4433 r = dsi_calc_clock_rates(dsidev, &cinfo);
4434 if (r) {
4435 DSSERR("Failed to calc dsi clocks\n");
4436 return r;
4437 }
4438
4439 r = dsi_pll_set_clock_div(dsidev, &cinfo);
4440 if (r) {
4441 DSSERR("Failed to set dsi clocks\n");
4442 return r;
4443 }
4444
4445 return 0;
4446}
4447
4448static int dsi_display_init_dsi(struct platform_device *dsidev)
4449{
4450 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4451 int r;
4452
4453 r = dsi_pll_init(dsidev, true, true);
4454 if (r)
4455 goto err0;
4456
4457 r = dsi_configure_dsi_clocks(dsidev);
4458 if (r)
4459 goto err1;
4460
4461 dss_select_dsi_clk_source(dsi->module_id, dsi->module_id == 0 ?
4462 OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
4463 OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI);
4464
4465 DSSDBG("PLL OK\n");
4466
4467 r = dsi_cio_init(dsidev);
4468 if (r)
4469 goto err2;
4470
4471 _dsi_print_reset_status(dsidev);
4472
4473 dsi_proto_timings(dsidev);
4474 dsi_set_lp_clk_divisor(dsidev);
4475
4476 if (1)
4477 _dsi_print_reset_status(dsidev);
4478
4479 r = dsi_proto_config(dsidev);
4480 if (r)
4481 goto err3;
4482
4483 /* enable interface */
4484 dsi_vc_enable(dsidev, 0, 1);
4485 dsi_vc_enable(dsidev, 1, 1);
4486 dsi_vc_enable(dsidev, 2, 1);
4487 dsi_vc_enable(dsidev, 3, 1);
4488 dsi_if_enable(dsidev, 1);
4489 dsi_force_tx_stop_mode_io(dsidev);
4490
4491 return 0;
4492err3:
4493 dsi_cio_uninit(dsidev);
4494err2:
4495 dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
4496err1:
4497 dsi_pll_uninit(dsidev, true);
4498err0:
4499 return r;
4500}
4501
4502static void dsi_display_uninit_dsi(struct platform_device *dsidev,
4503 bool disconnect_lanes, bool enter_ulps)
4504{
4505 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4506
4507 if (enter_ulps && !dsi->ulps_enabled)
4508 dsi_enter_ulps(dsidev);
4509
4510 /* disable interface */
4511 dsi_if_enable(dsidev, 0);
4512 dsi_vc_enable(dsidev, 0, 0);
4513 dsi_vc_enable(dsidev, 1, 0);
4514 dsi_vc_enable(dsidev, 2, 0);
4515 dsi_vc_enable(dsidev, 3, 0);
4516
4517 dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
4518 dsi_cio_uninit(dsidev);
4519 dsi_pll_uninit(dsidev, disconnect_lanes);
4520}
4521
4522static int dsi_display_enable(struct omap_dss_device *dssdev)
4523{
4524 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4525 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4526 int r = 0;
4527
4528 DSSDBG("dsi_display_enable\n");
4529
4530 WARN_ON(!dsi_bus_is_locked(dsidev));
4531
4532 mutex_lock(&dsi->lock);
4533
4534 r = dsi_runtime_get(dsidev);
4535 if (r)
4536 goto err_get_dsi;
4537
4538 dsi_enable_pll_clock(dsidev, 1);
4539
4540 _dsi_initialize_irq(dsidev);
4541
4542 r = dsi_display_init_dsi(dsidev);
4543 if (r)
4544 goto err_init_dsi;
4545
4546 mutex_unlock(&dsi->lock);
4547
4548 return 0;
4549
4550err_init_dsi:
4551 dsi_enable_pll_clock(dsidev, 0);
4552 dsi_runtime_put(dsidev);
4553err_get_dsi:
4554 mutex_unlock(&dsi->lock);
4555 DSSDBG("dsi_display_enable FAILED\n");
4556 return r;
4557}
4558
4559static void dsi_display_disable(struct omap_dss_device *dssdev,
4560 bool disconnect_lanes, bool enter_ulps)
4561{
4562 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4563 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4564
4565 DSSDBG("dsi_display_disable\n");
4566
4567 WARN_ON(!dsi_bus_is_locked(dsidev));
4568
4569 mutex_lock(&dsi->lock);
4570
4571 dsi_sync_vc(dsidev, 0);
4572 dsi_sync_vc(dsidev, 1);
4573 dsi_sync_vc(dsidev, 2);
4574 dsi_sync_vc(dsidev, 3);
4575
4576 dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps);
4577
4578 dsi_runtime_put(dsidev);
4579 dsi_enable_pll_clock(dsidev, 0);
4580
4581 mutex_unlock(&dsi->lock);
4582}
4583
4584static int dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
4585{
4586 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
4587 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
4588
4589 dsi->te_enabled = enable;
4590 return 0;
4591}
4592
4593#ifdef PRINT_VERBOSE_VM_TIMINGS
4594static void print_dsi_vm(const char *str,
4595 const struct omap_dss_dsi_videomode_timings *t)
4596{
4597 unsigned long byteclk = t->hsclk / 4;
4598 int bl, wc, pps, tot;
4599
4600 wc = DIV_ROUND_UP(t->hact * t->bitspp, 8);
4601 pps = DIV_ROUND_UP(wc + 6, t->ndl); /* pixel packet size */
4602 bl = t->hss + t->hsa + t->hse + t->hbp + t->hfp;
4603 tot = bl + pps;
4604
4605#define TO_DSI_T(x) ((u32)div64_u64((u64)x * 1000000000llu, byteclk))
4606
4607 pr_debug("%s bck %lu, %u/%u/%u/%u/%u/%u = %u+%u = %u, "
4608 "%u/%u/%u/%u/%u/%u = %u + %u = %u\n",
4609 str,
4610 byteclk,
4611 t->hss, t->hsa, t->hse, t->hbp, pps, t->hfp,
4612 bl, pps, tot,
4613 TO_DSI_T(t->hss),
4614 TO_DSI_T(t->hsa),
4615 TO_DSI_T(t->hse),
4616 TO_DSI_T(t->hbp),
4617 TO_DSI_T(pps),
4618 TO_DSI_T(t->hfp),
4619
4620 TO_DSI_T(bl),
4621 TO_DSI_T(pps),
4622
4623 TO_DSI_T(tot));
4624#undef TO_DSI_T
4625}
4626
4627static void print_dispc_vm(const char *str, const struct omap_video_timings *t)
4628{
4629 unsigned long pck = t->pixelclock;
4630 int hact, bl, tot;
4631
4632 hact = t->x_res;
4633 bl = t->hsw + t->hbp + t->hfp;
4634 tot = hact + bl;
4635
4636#define TO_DISPC_T(x) ((u32)div64_u64((u64)x * 1000000000llu, pck))
4637
4638 pr_debug("%s pck %lu, %u/%u/%u/%u = %u+%u = %u, "
4639 "%u/%u/%u/%u = %u + %u = %u\n",
4640 str,
4641 pck,
4642 t->hsw, t->hbp, hact, t->hfp,
4643 bl, hact, tot,
4644 TO_DISPC_T(t->hsw),
4645 TO_DISPC_T(t->hbp),
4646 TO_DISPC_T(hact),
4647 TO_DISPC_T(t->hfp),
4648 TO_DISPC_T(bl),
4649 TO_DISPC_T(hact),
4650 TO_DISPC_T(tot));
4651#undef TO_DISPC_T
4652}
4653
4654/* note: this is not quite accurate */
4655static void print_dsi_dispc_vm(const char *str,
4656 const struct omap_dss_dsi_videomode_timings *t)
4657{
4658 struct omap_video_timings vm = { 0 };
4659 unsigned long byteclk = t->hsclk / 4;
4660 unsigned long pck;
4661 u64 dsi_tput;
4662 int dsi_hact, dsi_htot;
4663
4664 dsi_tput = (u64)byteclk * t->ndl * 8;
4665 pck = (u32)div64_u64(dsi_tput, t->bitspp);
4666 dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(t->hact * t->bitspp, 8) + 6, t->ndl);
4667 dsi_htot = t->hss + t->hsa + t->hse + t->hbp + dsi_hact + t->hfp;
4668
4669 vm.pixelclock = pck;
4670 vm.hsw = div64_u64((u64)(t->hsa + t->hse) * pck, byteclk);
4671 vm.hbp = div64_u64((u64)t->hbp * pck, byteclk);
4672 vm.hfp = div64_u64((u64)t->hfp * pck, byteclk);
4673 vm.x_res = t->hact;
4674
4675 print_dispc_vm(str, &vm);
4676}
4677#endif /* PRINT_VERBOSE_VM_TIMINGS */
4678
4679static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
4680 unsigned long pck, void *data)
4681{
4682 struct dsi_clk_calc_ctx *ctx = data;
4683 struct omap_video_timings *t = &ctx->dispc_vm;
4684
4685 ctx->dispc_cinfo.lck_div = lckd;
4686 ctx->dispc_cinfo.pck_div = pckd;
4687 ctx->dispc_cinfo.lck = lck;
4688 ctx->dispc_cinfo.pck = pck;
4689
4690 *t = *ctx->config->timings;
4691 t->pixelclock = pck;
4692 t->x_res = ctx->config->timings->x_res;
4693 t->y_res = ctx->config->timings->y_res;
4694 t->hsw = t->hfp = t->hbp = t->vsw = 1;
4695 t->vfp = t->vbp = 0;
4696
4697 return true;
4698}
4699
4700static bool dsi_cm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
4701 void *data)
4702{
4703 struct dsi_clk_calc_ctx *ctx = data;
4704
4705 ctx->dsi_cinfo.regm_dispc = regm_dispc;
4706 ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
4707
4708 return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max,
4709 dsi_cm_calc_dispc_cb, ctx);
4710}
4711
4712static bool dsi_cm_calc_pll_cb(int regn, int regm, unsigned long fint,
4713 unsigned long pll, void *data)
4714{
4715 struct dsi_clk_calc_ctx *ctx = data;
4716
4717 ctx->dsi_cinfo.regn = regn;
4718 ctx->dsi_cinfo.regm = regm;
4719 ctx->dsi_cinfo.fint = fint;
4720 ctx->dsi_cinfo.clkin4ddr = pll;
4721
4722 return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
4723 dsi_cm_calc_hsdiv_cb, ctx);
4724}
4725
4726static bool dsi_cm_calc(struct dsi_data *dsi,
4727 const struct omap_dss_dsi_config *cfg,
4728 struct dsi_clk_calc_ctx *ctx)
4729{
4730 unsigned long clkin;
4731 int bitspp, ndl;
4732 unsigned long pll_min, pll_max;
4733 unsigned long pck, txbyteclk;
4734
4735 clkin = clk_get_rate(dsi->sys_clk);
4736 bitspp = dsi_get_pixel_size(cfg->pixel_format);
4737 ndl = dsi->num_lanes_used - 1;
4738
4739 /*
4740 * Here we should calculate minimum txbyteclk to be able to send the
4741 * frame in time, and also to handle TE. That's not very simple, though,
4742 * especially as we go to LP between each pixel packet due to HW
4743 * "feature". So let's just estimate very roughly and multiply by 1.5.
4744 */
4745 pck = cfg->timings->pixelclock;
4746 pck = pck * 3 / 2;
4747 txbyteclk = pck * bitspp / 8 / ndl;
4748
4749 memset(ctx, 0, sizeof(*ctx));
4750 ctx->dsidev = dsi->pdev;
4751 ctx->config = cfg;
4752 ctx->req_pck_min = pck;
4753 ctx->req_pck_nom = pck;
4754 ctx->req_pck_max = pck * 3 / 2;
4755 ctx->dsi_cinfo.clkin = clkin;
4756
4757 pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4);
4758 pll_max = cfg->hs_clk_max * 4;
4759
4760 return dsi_pll_calc(dsi->pdev, clkin,
4761 pll_min, pll_max,
4762 dsi_cm_calc_pll_cb, ctx);
4763}
4764
4765static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx)
4766{
4767 struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev);
4768 const struct omap_dss_dsi_config *cfg = ctx->config;
4769 int bitspp = dsi_get_pixel_size(cfg->pixel_format);
4770 int ndl = dsi->num_lanes_used - 1;
4771 unsigned long hsclk = ctx->dsi_cinfo.clkin4ddr / 4;
4772 unsigned long byteclk = hsclk / 4;
4773
4774 unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max;
4775 int xres;
4776 int panel_htot, panel_hbl; /* pixels */
4777 int dispc_htot, dispc_hbl; /* pixels */
4778 int dsi_htot, dsi_hact, dsi_hbl, hss, hse; /* byteclks */
4779 int hfp, hsa, hbp;
4780 const struct omap_video_timings *req_vm;
4781 struct omap_video_timings *dispc_vm;
4782 struct omap_dss_dsi_videomode_timings *dsi_vm;
4783 u64 dsi_tput, dispc_tput;
4784
4785 dsi_tput = (u64)byteclk * ndl * 8;
4786
4787 req_vm = cfg->timings;
4788 req_pck_min = ctx->req_pck_min;
4789 req_pck_max = ctx->req_pck_max;
4790 req_pck_nom = ctx->req_pck_nom;
4791
4792 dispc_pck = ctx->dispc_cinfo.pck;
4793 dispc_tput = (u64)dispc_pck * bitspp;
4794
4795 xres = req_vm->x_res;
4796
4797 panel_hbl = req_vm->hfp + req_vm->hbp + req_vm->hsw;
4798 panel_htot = xres + panel_hbl;
4799
4800 dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(xres * bitspp, 8) + 6, ndl);
4801
4802 /*
4803 * When there are no line buffers, DISPC and DSI must have the
4804 * same tput. Otherwise DISPC tput needs to be higher than DSI's.
4805 */
4806 if (dsi->line_buffer_size < xres * bitspp / 8) {
4807 if (dispc_tput != dsi_tput)
4808 return false;
4809 } else {
4810 if (dispc_tput < dsi_tput)
4811 return false;
4812 }
4813
4814 /* DSI tput must be over the min requirement */
4815 if (dsi_tput < (u64)bitspp * req_pck_min)
4816 return false;
4817
4818 /* When non-burst mode, DSI tput must be below max requirement. */
4819 if (cfg->trans_mode != OMAP_DSS_DSI_BURST_MODE) {
4820 if (dsi_tput > (u64)bitspp * req_pck_max)
4821 return false;
4822 }
4823
4824 hss = DIV_ROUND_UP(4, ndl);
4825
4826 if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) {
4827 if (ndl == 3 && req_vm->hsw == 0)
4828 hse = 1;
4829 else
4830 hse = DIV_ROUND_UP(4, ndl);
4831 } else {
4832 hse = 0;
4833 }
4834
4835 /* DSI htot to match the panel's nominal pck */
4836 dsi_htot = div64_u64((u64)panel_htot * byteclk, req_pck_nom);
4837
4838 /* fail if there would be no time for blanking */
4839 if (dsi_htot < hss + hse + dsi_hact)
4840 return false;
4841
4842 /* total DSI blanking needed to achieve panel's TL */
4843 dsi_hbl = dsi_htot - dsi_hact;
4844
4845 /* DISPC htot to match the DSI TL */
4846 dispc_htot = div64_u64((u64)dsi_htot * dispc_pck, byteclk);
4847
4848 /* verify that the DSI and DISPC TLs are the same */
4849 if ((u64)dsi_htot * dispc_pck != (u64)dispc_htot * byteclk)
4850 return false;
4851
4852 dispc_hbl = dispc_htot - xres;
4853
4854 /* setup DSI videomode */
4855
4856 dsi_vm = &ctx->dsi_vm;
4857 memset(dsi_vm, 0, sizeof(*dsi_vm));
4858
4859 dsi_vm->hsclk = hsclk;
4860
4861 dsi_vm->ndl = ndl;
4862 dsi_vm->bitspp = bitspp;
4863
4864 if (cfg->trans_mode != OMAP_DSS_DSI_PULSE_MODE) {
4865 hsa = 0;
4866 } else if (ndl == 3 && req_vm->hsw == 0) {
4867 hsa = 0;
4868 } else {
4869 hsa = div64_u64((u64)req_vm->hsw * byteclk, req_pck_nom);
4870 hsa = max(hsa - hse, 1);
4871 }
4872
4873 hbp = div64_u64((u64)req_vm->hbp * byteclk, req_pck_nom);
4874 hbp = max(hbp, 1);
4875
4876 hfp = dsi_hbl - (hss + hsa + hse + hbp);
4877 if (hfp < 1) {
4878 int t;
4879 /* we need to take cycles from hbp */
4880
4881 t = 1 - hfp;
4882 hbp = max(hbp - t, 1);
4883 hfp = dsi_hbl - (hss + hsa + hse + hbp);
4884
4885 if (hfp < 1 && hsa > 0) {
4886 /* we need to take cycles from hsa */
4887 t = 1 - hfp;
4888 hsa = max(hsa - t, 1);
4889 hfp = dsi_hbl - (hss + hsa + hse + hbp);
4890 }
4891 }
4892
4893 if (hfp < 1)
4894 return false;
4895
4896 dsi_vm->hss = hss;
4897 dsi_vm->hsa = hsa;
4898 dsi_vm->hse = hse;
4899 dsi_vm->hbp = hbp;
4900 dsi_vm->hact = xres;
4901 dsi_vm->hfp = hfp;
4902
4903 dsi_vm->vsa = req_vm->vsw;
4904 dsi_vm->vbp = req_vm->vbp;
4905 dsi_vm->vact = req_vm->y_res;
4906 dsi_vm->vfp = req_vm->vfp;
4907
4908 dsi_vm->trans_mode = cfg->trans_mode;
4909
4910 dsi_vm->blanking_mode = 0;
4911 dsi_vm->hsa_blanking_mode = 1;
4912 dsi_vm->hfp_blanking_mode = 1;
4913 dsi_vm->hbp_blanking_mode = 1;
4914
4915 dsi_vm->ddr_clk_always_on = cfg->ddr_clk_always_on;
4916 dsi_vm->window_sync = 4;
4917
4918 /* setup DISPC videomode */
4919
4920 dispc_vm = &ctx->dispc_vm;
4921 *dispc_vm = *req_vm;
4922 dispc_vm->pixelclock = dispc_pck;
4923
4924 if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) {
4925 hsa = div64_u64((u64)req_vm->hsw * dispc_pck,
4926 req_pck_nom);
4927 hsa = max(hsa, 1);
4928 } else {
4929 hsa = 1;
4930 }
4931
4932 hbp = div64_u64((u64)req_vm->hbp * dispc_pck, req_pck_nom);
4933 hbp = max(hbp, 1);
4934
4935 hfp = dispc_hbl - hsa - hbp;
4936 if (hfp < 1) {
4937 int t;
4938 /* we need to take cycles from hbp */
4939
4940 t = 1 - hfp;
4941 hbp = max(hbp - t, 1);
4942 hfp = dispc_hbl - hsa - hbp;
4943
4944 if (hfp < 1) {
4945 /* we need to take cycles from hsa */
4946 t = 1 - hfp;
4947 hsa = max(hsa - t, 1);
4948 hfp = dispc_hbl - hsa - hbp;
4949 }
4950 }
4951
4952 if (hfp < 1)
4953 return false;
4954
4955 dispc_vm->hfp = hfp;
4956 dispc_vm->hsw = hsa;
4957 dispc_vm->hbp = hbp;
4958
4959 return true;
4960}
4961
4962
4963static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
4964 unsigned long pck, void *data)
4965{
4966 struct dsi_clk_calc_ctx *ctx = data;
4967
4968 ctx->dispc_cinfo.lck_div = lckd;
4969 ctx->dispc_cinfo.pck_div = pckd;
4970 ctx->dispc_cinfo.lck = lck;
4971 ctx->dispc_cinfo.pck = pck;
4972
4973 if (dsi_vm_calc_blanking(ctx) == false)
4974 return false;
4975
4976#ifdef PRINT_VERBOSE_VM_TIMINGS
4977 print_dispc_vm("dispc", &ctx->dispc_vm);
4978 print_dsi_vm("dsi ", &ctx->dsi_vm);
4979 print_dispc_vm("req ", ctx->config->timings);
4980 print_dsi_dispc_vm("act ", &ctx->dsi_vm);
4981#endif
4982
4983 return true;
4984}
4985
4986static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
4987 void *data)
4988{
4989 struct dsi_clk_calc_ctx *ctx = data;
4990 unsigned long pck_max;
4991
4992 ctx->dsi_cinfo.regm_dispc = regm_dispc;
4993 ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
4994
4995 /*
4996 * In burst mode we can let the dispc pck be arbitrarily high, but it
4997 * limits our scaling abilities. So for now, don't aim too high.
4998 */
4999
5000 if (ctx->config->trans_mode == OMAP_DSS_DSI_BURST_MODE)
5001 pck_max = ctx->req_pck_max + 10000000;
5002 else
5003 pck_max = ctx->req_pck_max;
5004
5005 return dispc_div_calc(dispc, ctx->req_pck_min, pck_max,
5006 dsi_vm_calc_dispc_cb, ctx);
5007}
5008
5009static bool dsi_vm_calc_pll_cb(int regn, int regm, unsigned long fint,
5010 unsigned long pll, void *data)
5011{
5012 struct dsi_clk_calc_ctx *ctx = data;
5013
5014 ctx->dsi_cinfo.regn = regn;
5015 ctx->dsi_cinfo.regm = regm;
5016 ctx->dsi_cinfo.fint = fint;
5017 ctx->dsi_cinfo.clkin4ddr = pll;
5018
5019 return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
5020 dsi_vm_calc_hsdiv_cb, ctx);
5021}
5022
5023static bool dsi_vm_calc(struct dsi_data *dsi,
5024 const struct omap_dss_dsi_config *cfg,
5025 struct dsi_clk_calc_ctx *ctx)
5026{
5027 const struct omap_video_timings *t = cfg->timings;
5028 unsigned long clkin;
5029 unsigned long pll_min;
5030 unsigned long pll_max;
5031 int ndl = dsi->num_lanes_used - 1;
5032 int bitspp = dsi_get_pixel_size(cfg->pixel_format);
5033 unsigned long byteclk_min;
5034
5035 clkin = clk_get_rate(dsi->sys_clk);
5036
5037 memset(ctx, 0, sizeof(*ctx));
5038 ctx->dsidev = dsi->pdev;
5039 ctx->config = cfg;
5040
5041 ctx->dsi_cinfo.clkin = clkin;
5042
5043 /* these limits should come from the panel driver */
5044 ctx->req_pck_min = t->pixelclock - 1000;
5045 ctx->req_pck_nom = t->pixelclock;
5046 ctx->req_pck_max = t->pixelclock + 1000;
5047
5048 byteclk_min = div64_u64((u64)ctx->req_pck_min * bitspp, ndl * 8);
5049 pll_min = max(cfg->hs_clk_min * 4, byteclk_min * 4 * 4);
5050
5051 if (cfg->trans_mode == OMAP_DSS_DSI_BURST_MODE) {
5052 pll_max = cfg->hs_clk_max * 4;
5053 } else {
5054 unsigned long byteclk_max;
5055 byteclk_max = div64_u64((u64)ctx->req_pck_max * bitspp,
5056 ndl * 8);
5057
5058 pll_max = byteclk_max * 4 * 4;
5059 }
5060
5061 return dsi_pll_calc(dsi->pdev, clkin,
5062 pll_min, pll_max,
5063 dsi_vm_calc_pll_cb, ctx);
5064}
5065
5066static int dsi_set_config(struct omap_dss_device *dssdev,
5067 const struct omap_dss_dsi_config *config)
5068{
5069 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
5070 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5071 struct dsi_clk_calc_ctx ctx;
5072 bool ok;
5073 int r;
5074
5075 mutex_lock(&dsi->lock);
5076
5077 dsi->pix_fmt = config->pixel_format;
5078 dsi->mode = config->mode;
5079
5080 if (config->mode == OMAP_DSS_DSI_VIDEO_MODE)
5081 ok = dsi_vm_calc(dsi, config, &ctx);
5082 else
5083 ok = dsi_cm_calc(dsi, config, &ctx);
5084
5085 if (!ok) {
5086 DSSERR("failed to find suitable DSI clock settings\n");
5087 r = -EINVAL;
5088 goto err;
5089 }
5090
5091 dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo);
5092
5093 r = dsi_lp_clock_calc(&ctx.dsi_cinfo, config->lp_clk_min,
5094 config->lp_clk_max);
5095 if (r) {
5096 DSSERR("failed to find suitable DSI LP clock settings\n");
5097 goto err;
5098 }
5099
5100 dsi->user_dsi_cinfo = ctx.dsi_cinfo;
5101 dsi->user_dispc_cinfo = ctx.dispc_cinfo;
5102
5103 dsi->timings = ctx.dispc_vm;
5104 dsi->vm_timings = ctx.dsi_vm;
5105
5106 mutex_unlock(&dsi->lock);
5107
5108 return 0;
5109err:
5110 mutex_unlock(&dsi->lock);
5111
5112 return r;
5113}
5114
5115/*
5116 * Return a hardcoded channel for the DSI output. This should work for
5117 * current use cases, but this can be later expanded to either resolve
5118 * the channel in some more dynamic manner, or get the channel as a user
5119 * parameter.
5120 */
5121static enum omap_channel dsi_get_channel(int module_id)
5122{
5123 switch (omapdss_get_version()) {
5124 case OMAPDSS_VER_OMAP24xx:
5125 DSSWARN("DSI not supported\n");
5126 return OMAP_DSS_CHANNEL_LCD;
5127
5128 case OMAPDSS_VER_OMAP34xx_ES1:
5129 case OMAPDSS_VER_OMAP34xx_ES3:
5130 case OMAPDSS_VER_OMAP3630:
5131 case OMAPDSS_VER_AM35xx:
5132 return OMAP_DSS_CHANNEL_LCD;
5133
5134 case OMAPDSS_VER_OMAP4430_ES1:
5135 case OMAPDSS_VER_OMAP4430_ES2:
5136 case OMAPDSS_VER_OMAP4:
5137 switch (module_id) {
5138 case 0:
5139 return OMAP_DSS_CHANNEL_LCD;
5140 case 1:
5141 return OMAP_DSS_CHANNEL_LCD2;
5142 default:
5143 DSSWARN("unsupported module id\n");
5144 return OMAP_DSS_CHANNEL_LCD;
5145 }
5146
5147 case OMAPDSS_VER_OMAP5:
5148 switch (module_id) {
5149 case 0:
5150 return OMAP_DSS_CHANNEL_LCD;
5151 case 1:
5152 return OMAP_DSS_CHANNEL_LCD3;
5153 default:
5154 DSSWARN("unsupported module id\n");
5155 return OMAP_DSS_CHANNEL_LCD;
5156 }
5157
5158 default:
5159 DSSWARN("unsupported DSS version\n");
5160 return OMAP_DSS_CHANNEL_LCD;
5161 }
5162}
5163
5164static int dsi_request_vc(struct omap_dss_device *dssdev, int *channel)
5165{
5166 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
5167 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5168 int i;
5169
5170 for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
5171 if (!dsi->vc[i].dssdev) {
5172 dsi->vc[i].dssdev = dssdev;
5173 *channel = i;
5174 return 0;
5175 }
5176 }
5177
5178 DSSERR("cannot get VC for display %s", dssdev->name);
5179 return -ENOSPC;
5180}
5181
5182static int dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
5183{
5184 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
5185 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5186
5187 if (vc_id < 0 || vc_id > 3) {
5188 DSSERR("VC ID out of range\n");
5189 return -EINVAL;
5190 }
5191
5192 if (channel < 0 || channel > 3) {
5193 DSSERR("Virtual Channel out of range\n");
5194 return -EINVAL;
5195 }
5196
5197 if (dsi->vc[channel].dssdev != dssdev) {
5198 DSSERR("Virtual Channel not allocated to display %s\n",
5199 dssdev->name);
5200 return -EINVAL;
5201 }
5202
5203 dsi->vc[channel].vc_id = vc_id;
5204
5205 return 0;
5206}
5207
5208static void dsi_release_vc(struct omap_dss_device *dssdev, int channel)
5209{
5210 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
5211 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5212
5213 if ((channel >= 0 && channel <= 3) &&
5214 dsi->vc[channel].dssdev == dssdev) {
5215 dsi->vc[channel].dssdev = NULL;
5216 dsi->vc[channel].vc_id = 0;
5217 }
5218}
5219
5220void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
5221{
5222 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 7, 1) != 1)
5223 DSSERR("%s (%s) not active\n",
5224 dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
5225 dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC));
5226}
5227
5228void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
5229{
5230 if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 8, 1) != 1)
5231 DSSERR("%s (%s) not active\n",
5232 dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
5233 dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
5234}
5235
5236static void dsi_calc_clock_param_ranges(struct platform_device *dsidev)
5237{
5238 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5239
5240 dsi->regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
5241 dsi->regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
5242 dsi->regm_dispc_max =
5243 dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
5244 dsi->regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
5245 dsi->fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
5246 dsi->fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
5247 dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
5248}
5249
5250static int dsi_get_clocks(struct platform_device *dsidev)
5251{
5252 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5253 struct clk *clk;
5254
5255 clk = devm_clk_get(&dsidev->dev, "fck");
5256 if (IS_ERR(clk)) {
5257 DSSERR("can't get fck\n");
5258 return PTR_ERR(clk);
5259 }
5260
5261 dsi->dss_clk = clk;
5262
5263 clk = devm_clk_get(&dsidev->dev, "sys_clk");
5264 if (IS_ERR(clk)) {
5265 DSSERR("can't get sys_clk\n");
5266 return PTR_ERR(clk);
5267 }
5268
5269 dsi->sys_clk = clk;
5270
5271 return 0;
5272}
5273
5274static int dsi_connect(struct omap_dss_device *dssdev,
5275 struct omap_dss_device *dst)
5276{
5277 struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
5278 struct omap_overlay_manager *mgr;
5279 int r;
5280
5281 r = dsi_regulator_init(dsidev);
5282 if (r)
5283 return r;
5284
5285 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
5286 if (!mgr)
5287 return -ENODEV;
5288
5289 r = dss_mgr_connect(mgr, dssdev);
5290 if (r)
5291 return r;
5292
5293 r = omapdss_output_set_device(dssdev, dst);
5294 if (r) {
5295 DSSERR("failed to connect output to new device: %s\n",
5296 dssdev->name);
5297 dss_mgr_disconnect(mgr, dssdev);
5298 return r;
5299 }
5300
5301 return 0;
5302}
5303
5304static void dsi_disconnect(struct omap_dss_device *dssdev,
5305 struct omap_dss_device *dst)
5306{
5307 WARN_ON(dst != dssdev->dst);
5308
5309 if (dst != dssdev->dst)
5310 return;
5311
5312 omapdss_output_unset_device(dssdev);
5313
5314 if (dssdev->manager)
5315 dss_mgr_disconnect(dssdev->manager, dssdev);
5316}
5317
5318static const struct omapdss_dsi_ops dsi_ops = {
5319 .connect = dsi_connect,
5320 .disconnect = dsi_disconnect,
5321
5322 .bus_lock = dsi_bus_lock,
5323 .bus_unlock = dsi_bus_unlock,
5324
5325 .enable = dsi_display_enable,
5326 .disable = dsi_display_disable,
5327
5328 .enable_hs = dsi_vc_enable_hs,
5329
5330 .configure_pins = dsi_configure_pins,
5331 .set_config = dsi_set_config,
5332
5333 .enable_video_output = dsi_enable_video_output,
5334 .disable_video_output = dsi_disable_video_output,
5335
5336 .update = dsi_update,
5337
5338 .enable_te = dsi_enable_te,
5339
5340 .request_vc = dsi_request_vc,
5341 .set_vc_id = dsi_set_vc_id,
5342 .release_vc = dsi_release_vc,
5343
5344 .dcs_write = dsi_vc_dcs_write,
5345 .dcs_write_nosync = dsi_vc_dcs_write_nosync,
5346 .dcs_read = dsi_vc_dcs_read,
5347
5348 .gen_write = dsi_vc_generic_write,
5349 .gen_write_nosync = dsi_vc_generic_write_nosync,
5350 .gen_read = dsi_vc_generic_read,
5351
5352 .bta_sync = dsi_vc_send_bta_sync,
5353
5354 .set_max_rx_packet_size = dsi_vc_set_max_rx_packet_size,
5355};
5356
5357static void dsi_init_output(struct platform_device *dsidev)
5358{
5359 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5360 struct omap_dss_device *out = &dsi->output;
5361
5362 out->dev = &dsidev->dev;
5363 out->id = dsi->module_id == 0 ?
5364 OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
5365
5366 out->output_type = OMAP_DISPLAY_TYPE_DSI;
5367 out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1";
5368 out->dispc_channel = dsi_get_channel(dsi->module_id);
5369 out->ops.dsi = &dsi_ops;
5370 out->owner = THIS_MODULE;
5371
5372 omapdss_register_output(out);
5373}
5374
5375static void dsi_uninit_output(struct platform_device *dsidev)
5376{
5377 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5378 struct omap_dss_device *out = &dsi->output;
5379
5380 omapdss_unregister_output(out);
5381}
5382
5383static int dsi_probe_of(struct platform_device *pdev)
5384{
5385 struct device_node *node = pdev->dev.of_node;
5386 struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
5387 struct property *prop;
5388 u32 lane_arr[10];
5389 int len, num_pins;
5390 int r, i;
5391 struct device_node *ep;
5392 struct omap_dsi_pin_config pin_cfg;
5393
5394 ep = omapdss_of_get_first_endpoint(node);
5395 if (!ep)
5396 return 0;
5397
5398 prop = of_find_property(ep, "lanes", &len);
5399 if (prop == NULL) {
5400 dev_err(&pdev->dev, "failed to find lane data\n");
5401 r = -EINVAL;
5402 goto err;
5403 }
5404
5405 num_pins = len / sizeof(u32);
5406
5407 if (num_pins < 4 || num_pins % 2 != 0 ||
5408 num_pins > dsi->num_lanes_supported * 2) {
5409 dev_err(&pdev->dev, "bad number of lanes\n");
5410 r = -EINVAL;
5411 goto err;
5412 }
5413
5414 r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins);
5415 if (r) {
5416 dev_err(&pdev->dev, "failed to read lane data\n");
5417 goto err;
5418 }
5419
5420 pin_cfg.num_pins = num_pins;
5421 for (i = 0; i < num_pins; ++i)
5422 pin_cfg.pins[i] = (int)lane_arr[i];
5423
5424 r = dsi_configure_pins(&dsi->output, &pin_cfg);
5425 if (r) {
5426 dev_err(&pdev->dev, "failed to configure pins");
5427 goto err;
5428 }
5429
5430 of_node_put(ep);
5431
5432 return 0;
5433
5434err:
5435 of_node_put(ep);
5436 return r;
5437}
5438
5439/* DSI1 HW IP initialisation */
5440static int omap_dsihw_probe(struct platform_device *dsidev)
5441{
5442 u32 rev;
5443 int r, i;
5444 struct dsi_data *dsi;
5445 struct resource *dsi_mem;
5446 struct resource *res;
5447 struct resource temp_res;
5448
5449 dsi = devm_kzalloc(&dsidev->dev, sizeof(*dsi), GFP_KERNEL);
5450 if (!dsi)
5451 return -ENOMEM;
5452
5453 dsi->pdev = dsidev;
5454 dev_set_drvdata(&dsidev->dev, dsi);
5455
5456 spin_lock_init(&dsi->irq_lock);
5457 spin_lock_init(&dsi->errors_lock);
5458 dsi->errors = 0;
5459
5460#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
5461 spin_lock_init(&dsi->irq_stats_lock);
5462 dsi->irq_stats.last_reset = jiffies;
5463#endif
5464
5465 mutex_init(&dsi->lock);
5466 sema_init(&dsi->bus_lock, 1);
5467
5468 INIT_DEFERRABLE_WORK(&dsi->framedone_timeout_work,
5469 dsi_framedone_timeout_work_callback);
5470
5471#ifdef DSI_CATCH_MISSING_TE
5472 init_timer(&dsi->te_timer);
5473 dsi->te_timer.function = dsi_te_timeout;
5474 dsi->te_timer.data = 0;
5475#endif
5476
5477 res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "proto");
5478 if (!res) {
5479 res = platform_get_resource(dsidev, IORESOURCE_MEM, 0);
5480 if (!res) {
5481 DSSERR("can't get IORESOURCE_MEM DSI\n");
5482 return -EINVAL;
5483 }
5484
5485 temp_res.start = res->start;
5486 temp_res.end = temp_res.start + DSI_PROTO_SZ - 1;
5487 res = &temp_res;
5488 }
5489
5490 dsi_mem = res;
5491
5492 dsi->proto_base = devm_ioremap(&dsidev->dev, res->start,
5493 resource_size(res));
5494 if (!dsi->proto_base) {
5495 DSSERR("can't ioremap DSI protocol engine\n");
5496 return -ENOMEM;
5497 }
5498
5499 res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "phy");
5500 if (!res) {
5501 res = platform_get_resource(dsidev, IORESOURCE_MEM, 0);
5502 if (!res) {
5503 DSSERR("can't get IORESOURCE_MEM DSI\n");
5504 return -EINVAL;
5505 }
5506
5507 temp_res.start = res->start + DSI_PHY_OFFSET;
5508 temp_res.end = temp_res.start + DSI_PHY_SZ - 1;
5509 res = &temp_res;
5510 }
5511
5512 dsi->phy_base = devm_ioremap(&dsidev->dev, res->start,
5513 resource_size(res));
5514 if (!dsi->proto_base) {
5515 DSSERR("can't ioremap DSI PHY\n");
5516 return -ENOMEM;
5517 }
5518
5519 res = platform_get_resource_byname(dsidev, IORESOURCE_MEM, "pll");
5520 if (!res) {
5521 res = platform_get_resource(dsidev, IORESOURCE_MEM, 0);
5522 if (!res) {
5523 DSSERR("can't get IORESOURCE_MEM DSI\n");
5524 return -EINVAL;
5525 }
5526
5527 temp_res.start = res->start + DSI_PLL_OFFSET;
5528 temp_res.end = temp_res.start + DSI_PLL_SZ - 1;
5529 res = &temp_res;
5530 }
5531
5532 dsi->pll_base = devm_ioremap(&dsidev->dev, res->start,
5533 resource_size(res));
5534 if (!dsi->proto_base) {
5535 DSSERR("can't ioremap DSI PLL\n");
5536 return -ENOMEM;
5537 }
5538
5539 dsi->irq = platform_get_irq(dsi->pdev, 0);
5540 if (dsi->irq < 0) {
5541 DSSERR("platform_get_irq failed\n");
5542 return -ENODEV;
5543 }
5544
5545 r = devm_request_irq(&dsidev->dev, dsi->irq, omap_dsi_irq_handler,
5546 IRQF_SHARED, dev_name(&dsidev->dev), dsi->pdev);
5547 if (r < 0) {
5548 DSSERR("request_irq failed\n");
5549 return r;
5550 }
5551
5552 if (dsidev->dev.of_node) {
5553 const struct of_device_id *match;
5554 const struct dsi_module_id_data *d;
5555
5556 match = of_match_node(dsi_of_match, dsidev->dev.of_node);
5557 if (!match) {
5558 DSSERR("unsupported DSI module\n");
5559 return -ENODEV;
5560 }
5561
5562 d = match->data;
5563
5564 while (d->address != 0 && d->address != dsi_mem->start)
5565 d++;
5566
5567 if (d->address == 0) {
5568 DSSERR("unsupported DSI module\n");
5569 return -ENODEV;
5570 }
5571
5572 dsi->module_id = d->id;
5573 } else {
5574 dsi->module_id = dsidev->id;
5575 }
5576
5577 /* DSI VCs initialization */
5578 for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
5579 dsi->vc[i].source = DSI_VC_SOURCE_L4;
5580 dsi->vc[i].dssdev = NULL;
5581 dsi->vc[i].vc_id = 0;
5582 }
5583
5584 dsi_calc_clock_param_ranges(dsidev);
5585
5586 r = dsi_get_clocks(dsidev);
5587 if (r)
5588 return r;
5589
5590 pm_runtime_enable(&dsidev->dev);
5591
5592 r = dsi_runtime_get(dsidev);
5593 if (r)
5594 goto err_runtime_get;
5595
5596 rev = dsi_read_reg(dsidev, DSI_REVISION);
5597 dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
5598 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
5599
5600 /* DSI on OMAP3 doesn't have register DSI_GNQ, set number
5601 * of data to 3 by default */
5602 if (dss_has_feature(FEAT_DSI_GNQ))
5603 /* NB_DATA_LANES */
5604 dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9);
5605 else
5606 dsi->num_lanes_supported = 3;
5607
5608 dsi->line_buffer_size = dsi_get_line_buf_size(dsidev);
5609
5610 dsi_init_output(dsidev);
5611
5612 if (dsidev->dev.of_node) {
5613 r = dsi_probe_of(dsidev);
5614 if (r) {
5615 DSSERR("Invalid DSI DT data\n");
5616 goto err_probe_of;
5617 }
5618
5619 r = of_platform_populate(dsidev->dev.of_node, NULL, NULL,
5620 &dsidev->dev);
5621 if (r)
5622 DSSERR("Failed to populate DSI child devices: %d\n", r);
5623 }
5624
5625 dsi_runtime_put(dsidev);
5626
5627 if (dsi->module_id == 0)
5628 dss_debugfs_create_file("dsi1_regs", dsi1_dump_regs);
5629 else if (dsi->module_id == 1)
5630 dss_debugfs_create_file("dsi2_regs", dsi2_dump_regs);
5631
5632#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
5633 if (dsi->module_id == 0)
5634 dss_debugfs_create_file("dsi1_irqs", dsi1_dump_irqs);
5635 else if (dsi->module_id == 1)
5636 dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs);
5637#endif
5638
5639 return 0;
5640
5641err_probe_of:
5642 dsi_uninit_output(dsidev);
5643 dsi_runtime_put(dsidev);
5644
5645err_runtime_get:
5646 pm_runtime_disable(&dsidev->dev);
5647 return r;
5648}
5649
5650static int dsi_unregister_child(struct device *dev, void *data)
5651{
5652 struct platform_device *pdev = to_platform_device(dev);
5653 platform_device_unregister(pdev);
5654 return 0;
5655}
5656
5657static int __exit omap_dsihw_remove(struct platform_device *dsidev)
5658{
5659 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
5660
5661 device_for_each_child(&dsidev->dev, NULL, dsi_unregister_child);
5662
5663 WARN_ON(dsi->scp_clk_refcount > 0);
5664
5665 dsi_uninit_output(dsidev);
5666
5667 pm_runtime_disable(&dsidev->dev);
5668
5669 if (dsi->vdds_dsi_reg != NULL && dsi->vdds_dsi_enabled) {
5670 regulator_disable(dsi->vdds_dsi_reg);
5671 dsi->vdds_dsi_enabled = false;
5672 }
5673
5674 return 0;
5675}
5676
5677static int dsi_runtime_suspend(struct device *dev)
5678{
5679 struct platform_device *pdev = to_platform_device(dev);
5680 struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
5681
5682 dsi->is_enabled = false;
5683 /* ensure the irq handler sees the is_enabled value */
5684 smp_wmb();
5685 /* wait for current handler to finish before turning the DSI off */
5686 synchronize_irq(dsi->irq);
5687
5688 dispc_runtime_put();
5689
5690 return 0;
5691}
5692
5693static int dsi_runtime_resume(struct device *dev)
5694{
5695 struct platform_device *pdev = to_platform_device(dev);
5696 struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
5697 int r;
5698
5699 r = dispc_runtime_get();
5700 if (r)
5701 return r;
5702
5703 dsi->is_enabled = true;
5704 /* ensure the irq handler sees the is_enabled value */
5705 smp_wmb();
5706
5707 return 0;
5708}
5709
5710static const struct dev_pm_ops dsi_pm_ops = {
5711 .runtime_suspend = dsi_runtime_suspend,
5712 .runtime_resume = dsi_runtime_resume,
5713};
5714
5715static const struct dsi_module_id_data dsi_of_data_omap3[] = {
5716 { .address = 0x4804fc00, .id = 0, },
5717 { },
5718};
5719
5720static const struct dsi_module_id_data dsi_of_data_omap4[] = {
5721 { .address = 0x58004000, .id = 0, },
5722 { .address = 0x58005000, .id = 1, },
5723 { },
5724};
5725
5726static const struct of_device_id dsi_of_match[] = {
5727 { .compatible = "ti,omap3-dsi", .data = dsi_of_data_omap3, },
5728 { .compatible = "ti,omap4-dsi", .data = dsi_of_data_omap4, },
5729 {},
5730};
5731
5732static struct platform_driver omap_dsihw_driver = {
5733 .probe = omap_dsihw_probe,
5734 .remove = __exit_p(omap_dsihw_remove),
5735 .driver = {
5736 .name = "omapdss_dsi",
5737 .owner = THIS_MODULE,
5738 .pm = &dsi_pm_ops,
5739 .of_match_table = dsi_of_match,
5740 },
5741};
5742
5743int __init dsi_init_platform_driver(void)
5744{
5745 return platform_driver_register(&omap_dsihw_driver);
5746}
5747
5748void __exit dsi_uninit_platform_driver(void)
5749{
5750 platform_driver_unregister(&omap_dsihw_driver);
5751}
diff --git a/drivers/video/fbdev/omap2/dss/dss-of.c b/drivers/video/fbdev/omap2/dss/dss-of.c
new file mode 100644
index 000000000000..a4b20aaf6142
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/dss-of.c
@@ -0,0 +1,159 @@
1/*
2 * Copyright (C) 2013 Texas Instruments
3 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#include <linux/device.h>
16#include <linux/err.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/seq_file.h>
20
21#include <video/omapdss.h>
22
23struct device_node *
24omapdss_of_get_next_port(const struct device_node *parent,
25 struct device_node *prev)
26{
27 struct device_node *port = NULL;
28
29 if (!parent)
30 return NULL;
31
32 if (!prev) {
33 struct device_node *ports;
34 /*
35 * It's the first call, we have to find a port subnode
36 * within this node or within an optional 'ports' node.
37 */
38 ports = of_get_child_by_name(parent, "ports");
39 if (ports)
40 parent = ports;
41
42 port = of_get_child_by_name(parent, "port");
43
44 /* release the 'ports' node */
45 of_node_put(ports);
46 } else {
47 struct device_node *ports;
48
49 ports = of_get_parent(prev);
50 if (!ports)
51 return NULL;
52
53 do {
54 port = of_get_next_child(ports, prev);
55 if (!port) {
56 of_node_put(ports);
57 return NULL;
58 }
59 prev = port;
60 } while (of_node_cmp(port->name, "port") != 0);
61 }
62
63 return port;
64}
65EXPORT_SYMBOL_GPL(omapdss_of_get_next_port);
66
67struct device_node *
68omapdss_of_get_next_endpoint(const struct device_node *parent,
69 struct device_node *prev)
70{
71 struct device_node *ep = NULL;
72
73 if (!parent)
74 return NULL;
75
76 do {
77 ep = of_get_next_child(parent, prev);
78 if (!ep)
79 return NULL;
80 prev = ep;
81 } while (of_node_cmp(ep->name, "endpoint") != 0);
82
83 return ep;
84}
85EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint);
86
87static struct device_node *
88omapdss_of_get_remote_device_node(const struct device_node *node)
89{
90 struct device_node *np;
91 int i;
92
93 np = of_parse_phandle(node, "remote-endpoint", 0);
94
95 if (!np)
96 return NULL;
97
98 np = of_get_next_parent(np);
99
100 for (i = 0; i < 3 && np; ++i) {
101 struct property *prop;
102
103 prop = of_find_property(np, "compatible", NULL);
104
105 if (prop)
106 return np;
107
108 np = of_get_next_parent(np);
109 }
110
111 return NULL;
112}
113
114struct device_node *
115omapdss_of_get_first_endpoint(const struct device_node *parent)
116{
117 struct device_node *port, *ep;
118
119 port = omapdss_of_get_next_port(parent, NULL);
120
121 if (!port)
122 return NULL;
123
124 ep = omapdss_of_get_next_endpoint(port, NULL);
125
126 of_node_put(port);
127
128 return ep;
129}
130EXPORT_SYMBOL_GPL(omapdss_of_get_first_endpoint);
131
132struct omap_dss_device *
133omapdss_of_find_source_for_first_ep(struct device_node *node)
134{
135 struct device_node *ep;
136 struct device_node *src_node;
137 struct omap_dss_device *src;
138
139 ep = omapdss_of_get_first_endpoint(node);
140 if (!ep)
141 return ERR_PTR(-EINVAL);
142
143 src_node = omapdss_of_get_remote_device_node(ep);
144
145 of_node_put(ep);
146
147 if (!src_node)
148 return ERR_PTR(-EINVAL);
149
150 src = omap_dss_find_output_by_node(src_node);
151
152 of_node_put(src_node);
153
154 if (!src)
155 return ERR_PTR(-EPROBE_DEFER);
156
157 return src;
158}
159EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
diff --git a/drivers/video/fbdev/omap2/dss/dss.c b/drivers/video/fbdev/omap2/dss/dss.c
new file mode 100644
index 000000000000..d55266c0e029
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/dss.c
@@ -0,0 +1,972 @@
1/*
2 * linux/drivers/video/omap2/dss/dss.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 "DSS"
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/io.h>
28#include <linux/export.h>
29#include <linux/err.h>
30#include <linux/delay.h>
31#include <linux/seq_file.h>
32#include <linux/clk.h>
33#include <linux/platform_device.h>
34#include <linux/pm_runtime.h>
35#include <linux/gfp.h>
36#include <linux/sizes.h>
37#include <linux/of.h>
38
39#include <video/omapdss.h>
40
41#include "dss.h"
42#include "dss_features.h"
43
44#define DSS_SZ_REGS SZ_512
45
46struct dss_reg {
47 u16 idx;
48};
49
50#define DSS_REG(idx) ((const struct dss_reg) { idx })
51
52#define DSS_REVISION DSS_REG(0x0000)
53#define DSS_SYSCONFIG DSS_REG(0x0010)
54#define DSS_SYSSTATUS DSS_REG(0x0014)
55#define DSS_CONTROL DSS_REG(0x0040)
56#define DSS_SDI_CONTROL DSS_REG(0x0044)
57#define DSS_PLL_CONTROL DSS_REG(0x0048)
58#define DSS_SDI_STATUS DSS_REG(0x005C)
59
60#define REG_GET(idx, start, end) \
61 FLD_GET(dss_read_reg(idx), start, end)
62
63#define REG_FLD_MOD(idx, val, start, end) \
64 dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
65
66static int dss_runtime_get(void);
67static void dss_runtime_put(void);
68
69struct dss_features {
70 u8 fck_div_max;
71 u8 dss_fck_multiplier;
72 const char *parent_clk_name;
73 int (*dpi_select_source)(enum omap_channel channel);
74};
75
76static struct {
77 struct platform_device *pdev;
78 void __iomem *base;
79
80 struct clk *parent_clk;
81 struct clk *dss_clk;
82 unsigned long dss_clk_rate;
83
84 unsigned long cache_req_pck;
85 unsigned long cache_prate;
86 struct dispc_clock_info cache_dispc_cinfo;
87
88 enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI];
89 enum omap_dss_clk_source dispc_clk_source;
90 enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
91
92 bool ctx_valid;
93 u32 ctx[DSS_SZ_REGS / sizeof(u32)];
94
95 const struct dss_features *feat;
96} dss;
97
98static const char * const dss_generic_clk_source_names[] = {
99 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC",
100 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI",
101 [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK",
102 [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DSI_PLL2_HSDIV_DISPC",
103 [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DSI_PLL2_HSDIV_DSI",
104};
105
106static inline void dss_write_reg(const struct dss_reg idx, u32 val)
107{
108 __raw_writel(val, dss.base + idx.idx);
109}
110
111static inline u32 dss_read_reg(const struct dss_reg idx)
112{
113 return __raw_readl(dss.base + idx.idx);
114}
115
116#define SR(reg) \
117 dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
118#define RR(reg) \
119 dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
120
121static void dss_save_context(void)
122{
123 DSSDBG("dss_save_context\n");
124
125 SR(CONTROL);
126
127 if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
128 OMAP_DISPLAY_TYPE_SDI) {
129 SR(SDI_CONTROL);
130 SR(PLL_CONTROL);
131 }
132
133 dss.ctx_valid = true;
134
135 DSSDBG("context saved\n");
136}
137
138static void dss_restore_context(void)
139{
140 DSSDBG("dss_restore_context\n");
141
142 if (!dss.ctx_valid)
143 return;
144
145 RR(CONTROL);
146
147 if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
148 OMAP_DISPLAY_TYPE_SDI) {
149 RR(SDI_CONTROL);
150 RR(PLL_CONTROL);
151 }
152
153 DSSDBG("context restored\n");
154}
155
156#undef SR
157#undef RR
158
159void dss_sdi_init(int datapairs)
160{
161 u32 l;
162
163 BUG_ON(datapairs > 3 || datapairs < 1);
164
165 l = dss_read_reg(DSS_SDI_CONTROL);
166 l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */
167 l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */
168 l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */
169 dss_write_reg(DSS_SDI_CONTROL, l);
170
171 l = dss_read_reg(DSS_PLL_CONTROL);
172 l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */
173 l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */
174 l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */
175 dss_write_reg(DSS_PLL_CONTROL, l);
176}
177
178int dss_sdi_enable(void)
179{
180 unsigned long timeout;
181
182 dispc_pck_free_enable(1);
183
184 /* Reset SDI PLL */
185 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
186 udelay(1); /* wait 2x PCLK */
187
188 /* Lock SDI PLL */
189 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
190
191 /* Waiting for PLL lock request to complete */
192 timeout = jiffies + msecs_to_jiffies(500);
193 while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
194 if (time_after_eq(jiffies, timeout)) {
195 DSSERR("PLL lock request timed out\n");
196 goto err1;
197 }
198 }
199
200 /* Clearing PLL_GO bit */
201 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
202
203 /* Waiting for PLL to lock */
204 timeout = jiffies + msecs_to_jiffies(500);
205 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
206 if (time_after_eq(jiffies, timeout)) {
207 DSSERR("PLL lock timed out\n");
208 goto err1;
209 }
210 }
211
212 dispc_lcd_enable_signal(1);
213
214 /* Waiting for SDI reset to complete */
215 timeout = jiffies + msecs_to_jiffies(500);
216 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
217 if (time_after_eq(jiffies, timeout)) {
218 DSSERR("SDI reset timed out\n");
219 goto err2;
220 }
221 }
222
223 return 0;
224
225 err2:
226 dispc_lcd_enable_signal(0);
227 err1:
228 /* Reset SDI PLL */
229 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
230
231 dispc_pck_free_enable(0);
232
233 return -ETIMEDOUT;
234}
235
236void dss_sdi_disable(void)
237{
238 dispc_lcd_enable_signal(0);
239
240 dispc_pck_free_enable(0);
241
242 /* Reset SDI PLL */
243 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
244}
245
246const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
247{
248 return dss_generic_clk_source_names[clk_src];
249}
250
251void dss_dump_clocks(struct seq_file *s)
252{
253 const char *fclk_name, *fclk_real_name;
254 unsigned long fclk_rate;
255
256 if (dss_runtime_get())
257 return;
258
259 seq_printf(s, "- DSS -\n");
260
261 fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
262 fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
263 fclk_rate = clk_get_rate(dss.dss_clk);
264
265 seq_printf(s, "%s (%s) = %lu\n",
266 fclk_name, fclk_real_name,
267 fclk_rate);
268
269 dss_runtime_put();
270}
271
272static void dss_dump_regs(struct seq_file *s)
273{
274#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
275
276 if (dss_runtime_get())
277 return;
278
279 DUMPREG(DSS_REVISION);
280 DUMPREG(DSS_SYSCONFIG);
281 DUMPREG(DSS_SYSSTATUS);
282 DUMPREG(DSS_CONTROL);
283
284 if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
285 OMAP_DISPLAY_TYPE_SDI) {
286 DUMPREG(DSS_SDI_CONTROL);
287 DUMPREG(DSS_PLL_CONTROL);
288 DUMPREG(DSS_SDI_STATUS);
289 }
290
291 dss_runtime_put();
292#undef DUMPREG
293}
294
295static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
296{
297 struct platform_device *dsidev;
298 int b;
299 u8 start, end;
300
301 switch (clk_src) {
302 case OMAP_DSS_CLK_SRC_FCK:
303 b = 0;
304 break;
305 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
306 b = 1;
307 dsidev = dsi_get_dsidev_from_id(0);
308 dsi_wait_pll_hsdiv_dispc_active(dsidev);
309 break;
310 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
311 b = 2;
312 dsidev = dsi_get_dsidev_from_id(1);
313 dsi_wait_pll_hsdiv_dispc_active(dsidev);
314 break;
315 default:
316 BUG();
317 return;
318 }
319
320 dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end);
321
322 REG_FLD_MOD(DSS_CONTROL, b, start, end); /* DISPC_CLK_SWITCH */
323
324 dss.dispc_clk_source = clk_src;
325}
326
327void dss_select_dsi_clk_source(int dsi_module,
328 enum omap_dss_clk_source clk_src)
329{
330 struct platform_device *dsidev;
331 int b, pos;
332
333 switch (clk_src) {
334 case OMAP_DSS_CLK_SRC_FCK:
335 b = 0;
336 break;
337 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
338 BUG_ON(dsi_module != 0);
339 b = 1;
340 dsidev = dsi_get_dsidev_from_id(0);
341 dsi_wait_pll_hsdiv_dsi_active(dsidev);
342 break;
343 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
344 BUG_ON(dsi_module != 1);
345 b = 1;
346 dsidev = dsi_get_dsidev_from_id(1);
347 dsi_wait_pll_hsdiv_dsi_active(dsidev);
348 break;
349 default:
350 BUG();
351 return;
352 }
353
354 pos = dsi_module == 0 ? 1 : 10;
355 REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* DSIx_CLK_SWITCH */
356
357 dss.dsi_clk_source[dsi_module] = clk_src;
358}
359
360void dss_select_lcd_clk_source(enum omap_channel channel,
361 enum omap_dss_clk_source clk_src)
362{
363 struct platform_device *dsidev;
364 int b, ix, pos;
365
366 if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
367 dss_select_dispc_clk_source(clk_src);
368 return;
369 }
370
371 switch (clk_src) {
372 case OMAP_DSS_CLK_SRC_FCK:
373 b = 0;
374 break;
375 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
376 BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
377 b = 1;
378 dsidev = dsi_get_dsidev_from_id(0);
379 dsi_wait_pll_hsdiv_dispc_active(dsidev);
380 break;
381 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
382 BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 &&
383 channel != OMAP_DSS_CHANNEL_LCD3);
384 b = 1;
385 dsidev = dsi_get_dsidev_from_id(1);
386 dsi_wait_pll_hsdiv_dispc_active(dsidev);
387 break;
388 default:
389 BUG();
390 return;
391 }
392
393 pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
394 (channel == OMAP_DSS_CHANNEL_LCD2 ? 12 : 19);
395 REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* LCDx_CLK_SWITCH */
396
397 ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
398 (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
399 dss.lcd_clk_source[ix] = clk_src;
400}
401
402enum omap_dss_clk_source dss_get_dispc_clk_source(void)
403{
404 return dss.dispc_clk_source;
405}
406
407enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)
408{
409 return dss.dsi_clk_source[dsi_module];
410}
411
412enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
413{
414 if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
415 int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
416 (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
417 return dss.lcd_clk_source[ix];
418 } else {
419 /* LCD_CLK source is the same as DISPC_FCLK source for
420 * OMAP2 and OMAP3 */
421 return dss.dispc_clk_source;
422 }
423}
424
425bool dss_div_calc(unsigned long pck, unsigned long fck_min,
426 dss_div_calc_func func, void *data)
427{
428 int fckd, fckd_start, fckd_stop;
429 unsigned long fck;
430 unsigned long fck_hw_max;
431 unsigned long fckd_hw_max;
432 unsigned long prate;
433 unsigned m;
434
435 fck_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
436
437 if (dss.parent_clk == NULL) {
438 unsigned pckd;
439
440 pckd = fck_hw_max / pck;
441
442 fck = pck * pckd;
443
444 fck = clk_round_rate(dss.dss_clk, fck);
445
446 return func(fck, data);
447 }
448
449 fckd_hw_max = dss.feat->fck_div_max;
450
451 m = dss.feat->dss_fck_multiplier;
452 prate = clk_get_rate(dss.parent_clk);
453
454 fck_min = fck_min ? fck_min : 1;
455
456 fckd_start = min(prate * m / fck_min, fckd_hw_max);
457 fckd_stop = max(DIV_ROUND_UP(prate * m, fck_hw_max), 1ul);
458
459 for (fckd = fckd_start; fckd >= fckd_stop; --fckd) {
460 fck = DIV_ROUND_UP(prate, fckd) * m;
461
462 if (func(fck, data))
463 return true;
464 }
465
466 return false;
467}
468
469int dss_set_fck_rate(unsigned long rate)
470{
471 int r;
472
473 DSSDBG("set fck to %lu\n", rate);
474
475 r = clk_set_rate(dss.dss_clk, rate);
476 if (r)
477 return r;
478
479 dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
480
481 WARN_ONCE(dss.dss_clk_rate != rate,
482 "clk rate mismatch: %lu != %lu", dss.dss_clk_rate,
483 rate);
484
485 return 0;
486}
487
488unsigned long dss_get_dispc_clk_rate(void)
489{
490 return dss.dss_clk_rate;
491}
492
493static int dss_setup_default_clock(void)
494{
495 unsigned long max_dss_fck, prate;
496 unsigned long fck;
497 unsigned fck_div;
498 int r;
499
500 max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
501
502 if (dss.parent_clk == NULL) {
503 fck = clk_round_rate(dss.dss_clk, max_dss_fck);
504 } else {
505 prate = clk_get_rate(dss.parent_clk);
506
507 fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier,
508 max_dss_fck);
509 fck = DIV_ROUND_UP(prate, fck_div) * dss.feat->dss_fck_multiplier;
510 }
511
512 r = dss_set_fck_rate(fck);
513 if (r)
514 return r;
515
516 return 0;
517}
518
519void dss_set_venc_output(enum omap_dss_venc_type type)
520{
521 int l = 0;
522
523 if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
524 l = 0;
525 else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
526 l = 1;
527 else
528 BUG();
529
530 /* venc out selection. 0 = comp, 1 = svideo */
531 REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
532}
533
534void dss_set_dac_pwrdn_bgz(bool enable)
535{
536 REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
537}
538
539void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src)
540{
541 enum omap_display_type dp;
542 dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
543
544 /* Complain about invalid selections */
545 WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC));
546 WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI));
547
548 /* Select only if we have options */
549 if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI))
550 REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */
551}
552
553enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
554{
555 enum omap_display_type displays;
556
557 displays = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
558 if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0)
559 return DSS_VENC_TV_CLK;
560
561 if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0)
562 return DSS_HDMI_M_PCLK;
563
564 return REG_GET(DSS_CONTROL, 15, 15);
565}
566
567static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
568{
569 if (channel != OMAP_DSS_CHANNEL_LCD)
570 return -EINVAL;
571
572 return 0;
573}
574
575static int dss_dpi_select_source_omap4(enum omap_channel channel)
576{
577 int val;
578
579 switch (channel) {
580 case OMAP_DSS_CHANNEL_LCD2:
581 val = 0;
582 break;
583 case OMAP_DSS_CHANNEL_DIGIT:
584 val = 1;
585 break;
586 default:
587 return -EINVAL;
588 }
589
590 REG_FLD_MOD(DSS_CONTROL, val, 17, 17);
591
592 return 0;
593}
594
595static int dss_dpi_select_source_omap5(enum omap_channel channel)
596{
597 int val;
598
599 switch (channel) {
600 case OMAP_DSS_CHANNEL_LCD:
601 val = 1;
602 break;
603 case OMAP_DSS_CHANNEL_LCD2:
604 val = 2;
605 break;
606 case OMAP_DSS_CHANNEL_LCD3:
607 val = 3;
608 break;
609 case OMAP_DSS_CHANNEL_DIGIT:
610 val = 0;
611 break;
612 default:
613 return -EINVAL;
614 }
615
616 REG_FLD_MOD(DSS_CONTROL, val, 17, 16);
617
618 return 0;
619}
620
621int dss_dpi_select_source(enum omap_channel channel)
622{
623 return dss.feat->dpi_select_source(channel);
624}
625
626static int dss_get_clocks(void)
627{
628 struct clk *clk;
629
630 clk = devm_clk_get(&dss.pdev->dev, "fck");
631 if (IS_ERR(clk)) {
632 DSSERR("can't get clock fck\n");
633 return PTR_ERR(clk);
634 }
635
636 dss.dss_clk = clk;
637
638 if (dss.feat->parent_clk_name) {
639 clk = clk_get(NULL, dss.feat->parent_clk_name);
640 if (IS_ERR(clk)) {
641 DSSERR("Failed to get %s\n", dss.feat->parent_clk_name);
642 return PTR_ERR(clk);
643 }
644 } else {
645 clk = NULL;
646 }
647
648 dss.parent_clk = clk;
649
650 return 0;
651}
652
653static void dss_put_clocks(void)
654{
655 if (dss.parent_clk)
656 clk_put(dss.parent_clk);
657}
658
659static int dss_runtime_get(void)
660{
661 int r;
662
663 DSSDBG("dss_runtime_get\n");
664
665 r = pm_runtime_get_sync(&dss.pdev->dev);
666 WARN_ON(r < 0);
667 return r < 0 ? r : 0;
668}
669
670static void dss_runtime_put(void)
671{
672 int r;
673
674 DSSDBG("dss_runtime_put\n");
675
676 r = pm_runtime_put_sync(&dss.pdev->dev);
677 WARN_ON(r < 0 && r != -ENOSYS && r != -EBUSY);
678}
679
680/* DEBUGFS */
681#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
682void dss_debug_dump_clocks(struct seq_file *s)
683{
684 dss_dump_clocks(s);
685 dispc_dump_clocks(s);
686#ifdef CONFIG_OMAP2_DSS_DSI
687 dsi_dump_clocks(s);
688#endif
689}
690#endif
691
692static const struct dss_features omap24xx_dss_feats __initconst = {
693 /*
694 * fck div max is really 16, but the divider range has gaps. The range
695 * from 1 to 6 has no gaps, so let's use that as a max.
696 */
697 .fck_div_max = 6,
698 .dss_fck_multiplier = 2,
699 .parent_clk_name = "core_ck",
700 .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
701};
702
703static const struct dss_features omap34xx_dss_feats __initconst = {
704 .fck_div_max = 16,
705 .dss_fck_multiplier = 2,
706 .parent_clk_name = "dpll4_ck",
707 .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
708};
709
710static const struct dss_features omap3630_dss_feats __initconst = {
711 .fck_div_max = 32,
712 .dss_fck_multiplier = 1,
713 .parent_clk_name = "dpll4_ck",
714 .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
715};
716
717static const struct dss_features omap44xx_dss_feats __initconst = {
718 .fck_div_max = 32,
719 .dss_fck_multiplier = 1,
720 .parent_clk_name = "dpll_per_x2_ck",
721 .dpi_select_source = &dss_dpi_select_source_omap4,
722};
723
724static const struct dss_features omap54xx_dss_feats __initconst = {
725 .fck_div_max = 64,
726 .dss_fck_multiplier = 1,
727 .parent_clk_name = "dpll_per_x2_ck",
728 .dpi_select_source = &dss_dpi_select_source_omap5,
729};
730
731static int __init dss_init_features(struct platform_device *pdev)
732{
733 const struct dss_features *src;
734 struct dss_features *dst;
735
736 dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
737 if (!dst) {
738 dev_err(&pdev->dev, "Failed to allocate local DSS Features\n");
739 return -ENOMEM;
740 }
741
742 switch (omapdss_get_version()) {
743 case OMAPDSS_VER_OMAP24xx:
744 src = &omap24xx_dss_feats;
745 break;
746
747 case OMAPDSS_VER_OMAP34xx_ES1:
748 case OMAPDSS_VER_OMAP34xx_ES3:
749 case OMAPDSS_VER_AM35xx:
750 src = &omap34xx_dss_feats;
751 break;
752
753 case OMAPDSS_VER_OMAP3630:
754 src = &omap3630_dss_feats;
755 break;
756
757 case OMAPDSS_VER_OMAP4430_ES1:
758 case OMAPDSS_VER_OMAP4430_ES2:
759 case OMAPDSS_VER_OMAP4:
760 src = &omap44xx_dss_feats;
761 break;
762
763 case OMAPDSS_VER_OMAP5:
764 src = &omap54xx_dss_feats;
765 break;
766
767 default:
768 return -ENODEV;
769 }
770
771 memcpy(dst, src, sizeof(*dst));
772 dss.feat = dst;
773
774 return 0;
775}
776
777static int __init dss_init_ports(struct platform_device *pdev)
778{
779 struct device_node *parent = pdev->dev.of_node;
780 struct device_node *port;
781 int r;
782
783 if (parent == NULL)
784 return 0;
785
786 port = omapdss_of_get_next_port(parent, NULL);
787 if (!port) {
788#ifdef CONFIG_OMAP2_DSS_DPI
789 dpi_init_port(pdev, parent);
790#endif
791 return 0;
792 }
793
794 do {
795 u32 reg;
796
797 r = of_property_read_u32(port, "reg", &reg);
798 if (r)
799 reg = 0;
800
801#ifdef CONFIG_OMAP2_DSS_DPI
802 if (reg == 0)
803 dpi_init_port(pdev, port);
804#endif
805
806#ifdef CONFIG_OMAP2_DSS_SDI
807 if (reg == 1)
808 sdi_init_port(pdev, port);
809#endif
810
811 } while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
812
813 return 0;
814}
815
816static void dss_uninit_ports(void)
817{
818#ifdef CONFIG_OMAP2_DSS_DPI
819 dpi_uninit_port();
820#endif
821
822#ifdef CONFIG_OMAP2_DSS_SDI
823 sdi_uninit_port();
824#endif
825}
826
827/* DSS HW IP initialisation */
828static int __init omap_dsshw_probe(struct platform_device *pdev)
829{
830 struct resource *dss_mem;
831 u32 rev;
832 int r;
833
834 dss.pdev = pdev;
835
836 r = dss_init_features(dss.pdev);
837 if (r)
838 return r;
839
840 dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
841 if (!dss_mem) {
842 DSSERR("can't get IORESOURCE_MEM DSS\n");
843 return -EINVAL;
844 }
845
846 dss.base = devm_ioremap(&pdev->dev, dss_mem->start,
847 resource_size(dss_mem));
848 if (!dss.base) {
849 DSSERR("can't ioremap DSS\n");
850 return -ENOMEM;
851 }
852
853 r = dss_get_clocks();
854 if (r)
855 return r;
856
857 r = dss_setup_default_clock();
858 if (r)
859 goto err_setup_clocks;
860
861 pm_runtime_enable(&pdev->dev);
862
863 r = dss_runtime_get();
864 if (r)
865 goto err_runtime_get;
866
867 dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
868
869 /* Select DPLL */
870 REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
871
872 dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
873
874#ifdef CONFIG_OMAP2_DSS_VENC
875 REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
876 REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
877 REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
878#endif
879 dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
880 dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
881 dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
882 dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
883 dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
884
885 dss_init_ports(pdev);
886
887 rev = dss_read_reg(DSS_REVISION);
888 printk(KERN_INFO "OMAP DSS rev %d.%d\n",
889 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
890
891 dss_runtime_put();
892
893 dss_debugfs_create_file("dss", dss_dump_regs);
894
895 return 0;
896
897err_runtime_get:
898 pm_runtime_disable(&pdev->dev);
899err_setup_clocks:
900 dss_put_clocks();
901 return r;
902}
903
904static int __exit omap_dsshw_remove(struct platform_device *pdev)
905{
906 dss_uninit_ports();
907
908 pm_runtime_disable(&pdev->dev);
909
910 dss_put_clocks();
911
912 return 0;
913}
914
915static int dss_runtime_suspend(struct device *dev)
916{
917 dss_save_context();
918 dss_set_min_bus_tput(dev, 0);
919 return 0;
920}
921
922static int dss_runtime_resume(struct device *dev)
923{
924 int r;
925 /*
926 * Set an arbitrarily high tput request to ensure OPP100.
927 * What we should really do is to make a request to stay in OPP100,
928 * without any tput requirements, but that is not currently possible
929 * via the PM layer.
930 */
931
932 r = dss_set_min_bus_tput(dev, 1000000000);
933 if (r)
934 return r;
935
936 dss_restore_context();
937 return 0;
938}
939
940static const struct dev_pm_ops dss_pm_ops = {
941 .runtime_suspend = dss_runtime_suspend,
942 .runtime_resume = dss_runtime_resume,
943};
944
945static const struct of_device_id dss_of_match[] = {
946 { .compatible = "ti,omap2-dss", },
947 { .compatible = "ti,omap3-dss", },
948 { .compatible = "ti,omap4-dss", },
949 {},
950};
951
952MODULE_DEVICE_TABLE(of, dss_of_match);
953
954static struct platform_driver omap_dsshw_driver = {
955 .remove = __exit_p(omap_dsshw_remove),
956 .driver = {
957 .name = "omapdss_dss",
958 .owner = THIS_MODULE,
959 .pm = &dss_pm_ops,
960 .of_match_table = dss_of_match,
961 },
962};
963
964int __init dss_init_platform_driver(void)
965{
966 return platform_driver_probe(&omap_dsshw_driver, omap_dsshw_probe);
967}
968
969void dss_uninit_platform_driver(void)
970{
971 platform_driver_unregister(&omap_dsshw_driver);
972}
diff --git a/drivers/video/fbdev/omap2/dss/dss.h b/drivers/video/fbdev/omap2/dss/dss.h
new file mode 100644
index 000000000000..560078fcb198
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/dss.h
@@ -0,0 +1,438 @@
1/*
2 * linux/drivers/video/omap2/dss/dss.h
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#ifndef __OMAP2_DSS_H
24#define __OMAP2_DSS_H
25
26#include <linux/interrupt.h>
27
28#ifdef pr_fmt
29#undef pr_fmt
30#endif
31
32#ifdef DSS_SUBSYS_NAME
33#define pr_fmt(fmt) DSS_SUBSYS_NAME ": " fmt
34#else
35#define pr_fmt(fmt) fmt
36#endif
37
38#define DSSDBG(format, ...) \
39 pr_debug(format, ## __VA_ARGS__)
40
41#ifdef DSS_SUBSYS_NAME
42#define DSSERR(format, ...) \
43 printk(KERN_ERR "omapdss " DSS_SUBSYS_NAME " error: " format, \
44 ## __VA_ARGS__)
45#else
46#define DSSERR(format, ...) \
47 printk(KERN_ERR "omapdss error: " format, ## __VA_ARGS__)
48#endif
49
50#ifdef DSS_SUBSYS_NAME
51#define DSSINFO(format, ...) \
52 printk(KERN_INFO "omapdss " DSS_SUBSYS_NAME ": " format, \
53 ## __VA_ARGS__)
54#else
55#define DSSINFO(format, ...) \
56 printk(KERN_INFO "omapdss: " format, ## __VA_ARGS__)
57#endif
58
59#ifdef DSS_SUBSYS_NAME
60#define DSSWARN(format, ...) \
61 printk(KERN_WARNING "omapdss " DSS_SUBSYS_NAME ": " format, \
62 ## __VA_ARGS__)
63#else
64#define DSSWARN(format, ...) \
65 printk(KERN_WARNING "omapdss: " format, ## __VA_ARGS__)
66#endif
67
68/* OMAP TRM gives bitfields as start:end, where start is the higher bit
69 number. For example 7:0 */
70#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
71#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
72#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
73#define FLD_MOD(orig, val, start, end) \
74 (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
75
76enum dss_io_pad_mode {
77 DSS_IO_PAD_MODE_RESET,
78 DSS_IO_PAD_MODE_RFBI,
79 DSS_IO_PAD_MODE_BYPASS,
80};
81
82enum dss_hdmi_venc_clk_source_select {
83 DSS_VENC_TV_CLK = 0,
84 DSS_HDMI_M_PCLK = 1,
85};
86
87enum dss_dsi_content_type {
88 DSS_DSI_CONTENT_DCS,
89 DSS_DSI_CONTENT_GENERIC,
90};
91
92enum dss_writeback_channel {
93 DSS_WB_LCD1_MGR = 0,
94 DSS_WB_LCD2_MGR = 1,
95 DSS_WB_TV_MGR = 2,
96 DSS_WB_OVL0 = 3,
97 DSS_WB_OVL1 = 4,
98 DSS_WB_OVL2 = 5,
99 DSS_WB_OVL3 = 6,
100 DSS_WB_LCD3_MGR = 7,
101};
102
103struct dispc_clock_info {
104 /* rates that we get with dividers below */
105 unsigned long lck;
106 unsigned long pck;
107
108 /* dividers */
109 u16 lck_div;
110 u16 pck_div;
111};
112
113struct dsi_clock_info {
114 /* rates that we get with dividers below */
115 unsigned long fint;
116 unsigned long clkin4ddr;
117 unsigned long clkin;
118 unsigned long dsi_pll_hsdiv_dispc_clk; /* OMAP3: DSI1_PLL_CLK
119 * OMAP4: PLLx_CLK1 */
120 unsigned long dsi_pll_hsdiv_dsi_clk; /* OMAP3: DSI2_PLL_CLK
121 * OMAP4: PLLx_CLK2 */
122 unsigned long lp_clk;
123
124 /* dividers */
125 u16 regn;
126 u16 regm;
127 u16 regm_dispc; /* OMAP3: REGM3
128 * OMAP4: REGM4 */
129 u16 regm_dsi; /* OMAP3: REGM4
130 * OMAP4: REGM5 */
131 u16 lp_clk_div;
132};
133
134struct dss_lcd_mgr_config {
135 enum dss_io_pad_mode io_pad_mode;
136
137 bool stallmode;
138 bool fifohandcheck;
139
140 struct dispc_clock_info clock_info;
141
142 int video_port_width;
143
144 int lcden_sig_polarity;
145};
146
147struct seq_file;
148struct platform_device;
149
150/* core */
151struct platform_device *dss_get_core_pdev(void);
152int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask);
153void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask);
154int dss_set_min_bus_tput(struct device *dev, unsigned long tput);
155int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *));
156
157/* display */
158int dss_suspend_all_devices(void);
159int dss_resume_all_devices(void);
160void dss_disable_all_devices(void);
161
162int display_init_sysfs(struct platform_device *pdev);
163void display_uninit_sysfs(struct platform_device *pdev);
164
165/* manager */
166int dss_init_overlay_managers(void);
167void dss_uninit_overlay_managers(void);
168int dss_init_overlay_managers_sysfs(struct platform_device *pdev);
169void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev);
170int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
171 const struct omap_overlay_manager_info *info);
172int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
173 const struct omap_video_timings *timings);
174int dss_mgr_check(struct omap_overlay_manager *mgr,
175 struct omap_overlay_manager_info *info,
176 const struct omap_video_timings *mgr_timings,
177 const struct dss_lcd_mgr_config *config,
178 struct omap_overlay_info **overlay_infos);
179
180static inline bool dss_mgr_is_lcd(enum omap_channel id)
181{
182 if (id == OMAP_DSS_CHANNEL_LCD || id == OMAP_DSS_CHANNEL_LCD2 ||
183 id == OMAP_DSS_CHANNEL_LCD3)
184 return true;
185 else
186 return false;
187}
188
189int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
190 struct platform_device *pdev);
191void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr);
192
193/* overlay */
194void dss_init_overlays(struct platform_device *pdev);
195void dss_uninit_overlays(struct platform_device *pdev);
196void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
197int dss_ovl_simple_check(struct omap_overlay *ovl,
198 const struct omap_overlay_info *info);
199int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
200 const struct omap_video_timings *mgr_timings);
201bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
202 enum omap_color_mode mode);
203int dss_overlay_kobj_init(struct omap_overlay *ovl,
204 struct platform_device *pdev);
205void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
206
207/* DSS */
208int dss_init_platform_driver(void) __init;
209void dss_uninit_platform_driver(void);
210
211unsigned long dss_get_dispc_clk_rate(void);
212int dss_dpi_select_source(enum omap_channel channel);
213void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
214enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
215const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
216void dss_dump_clocks(struct seq_file *s);
217
218#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
219void dss_debug_dump_clocks(struct seq_file *s);
220#endif
221
222void dss_sdi_init(int datapairs);
223int dss_sdi_enable(void);
224void dss_sdi_disable(void);
225
226void dss_select_dsi_clk_source(int dsi_module,
227 enum omap_dss_clk_source clk_src);
228void dss_select_lcd_clk_source(enum omap_channel channel,
229 enum omap_dss_clk_source clk_src);
230enum omap_dss_clk_source dss_get_dispc_clk_source(void);
231enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module);
232enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel);
233
234void dss_set_venc_output(enum omap_dss_venc_type type);
235void dss_set_dac_pwrdn_bgz(bool enable);
236
237int dss_set_fck_rate(unsigned long rate);
238
239typedef bool (*dss_div_calc_func)(unsigned long fck, void *data);
240bool dss_div_calc(unsigned long pck, unsigned long fck_min,
241 dss_div_calc_func func, void *data);
242
243/* SDI */
244int sdi_init_platform_driver(void) __init;
245void sdi_uninit_platform_driver(void) __exit;
246
247int sdi_init_port(struct platform_device *pdev, struct device_node *port) __init;
248void sdi_uninit_port(void) __exit;
249
250/* DSI */
251
252typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint,
253 unsigned long pll, void *data);
254typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc,
255 void *data);
256
257#ifdef CONFIG_OMAP2_DSS_DSI
258
259struct dentry;
260struct file_operations;
261
262int dsi_init_platform_driver(void) __init;
263void dsi_uninit_platform_driver(void) __exit;
264
265int dsi_runtime_get(struct platform_device *dsidev);
266void dsi_runtime_put(struct platform_device *dsidev);
267
268void dsi_dump_clocks(struct seq_file *s);
269
270void dsi_irq_handler(void);
271u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
272
273unsigned long dsi_get_pll_clkin(struct platform_device *dsidev);
274
275bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
276 unsigned long out_min, dsi_hsdiv_calc_func func, void *data);
277bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
278 unsigned long pll_min, unsigned long pll_max,
279 dsi_pll_calc_func func, void *data);
280
281unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
282int dsi_pll_set_clock_div(struct platform_device *dsidev,
283 struct dsi_clock_info *cinfo);
284int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
285 bool enable_hsdiv);
286void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
287void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
288void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
289struct platform_device *dsi_get_dsidev_from_id(int module);
290#else
291static inline int dsi_runtime_get(struct platform_device *dsidev)
292{
293 return 0;
294}
295static inline void dsi_runtime_put(struct platform_device *dsidev)
296{
297}
298static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
299{
300 WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__);
301 return 0;
302}
303static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
304{
305 WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
306 return 0;
307}
308static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,
309 struct dsi_clock_info *cinfo)
310{
311 WARN("%s: DSI not compiled in\n", __func__);
312 return -ENODEV;
313}
314static inline int dsi_pll_init(struct platform_device *dsidev,
315 bool enable_hsclk, bool enable_hsdiv)
316{
317 WARN("%s: DSI not compiled in\n", __func__);
318 return -ENODEV;
319}
320static inline void dsi_pll_uninit(struct platform_device *dsidev,
321 bool disconnect_lanes)
322{
323}
324static inline void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
325{
326}
327static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
328{
329}
330static inline struct platform_device *dsi_get_dsidev_from_id(int module)
331{
332 return NULL;
333}
334
335static inline unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
336{
337 return 0;
338}
339
340static inline bool dsi_hsdiv_calc(struct platform_device *dsidev,
341 unsigned long pll, unsigned long out_min,
342 dsi_hsdiv_calc_func func, void *data)
343{
344 return false;
345}
346
347static inline bool dsi_pll_calc(struct platform_device *dsidev,
348 unsigned long clkin,
349 unsigned long pll_min, unsigned long pll_max,
350 dsi_pll_calc_func func, void *data)
351{
352 return false;
353}
354
355#endif
356
357/* DPI */
358int dpi_init_platform_driver(void) __init;
359void dpi_uninit_platform_driver(void) __exit;
360
361int dpi_init_port(struct platform_device *pdev, struct device_node *port) __init;
362void dpi_uninit_port(void) __exit;
363
364/* DISPC */
365int dispc_init_platform_driver(void) __init;
366void dispc_uninit_platform_driver(void) __exit;
367void dispc_dump_clocks(struct seq_file *s);
368
369void dispc_enable_sidle(void);
370void dispc_disable_sidle(void);
371
372void dispc_lcd_enable_signal(bool enable);
373void dispc_pck_free_enable(bool enable);
374void dispc_enable_fifomerge(bool enable);
375void dispc_enable_gamma_table(bool enable);
376void dispc_set_loadmode(enum omap_dss_load_mode mode);
377
378typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck,
379 unsigned long pck, void *data);
380bool dispc_div_calc(unsigned long dispc,
381 unsigned long pck_min, unsigned long pck_max,
382 dispc_div_calc_func func, void *data);
383
384bool dispc_mgr_timings_ok(enum omap_channel channel,
385 const struct omap_video_timings *timings);
386unsigned long dispc_fclk_rate(void);
387int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
388 struct dispc_clock_info *cinfo);
389
390
391void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high);
392void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
393 u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
394 bool manual_update);
395
396unsigned long dispc_mgr_lclk_rate(enum omap_channel channel);
397unsigned long dispc_mgr_pclk_rate(enum omap_channel channel);
398unsigned long dispc_core_clk_rate(void);
399void dispc_mgr_set_clock_div(enum omap_channel channel,
400 const struct dispc_clock_info *cinfo);
401int dispc_mgr_get_clock_div(enum omap_channel channel,
402 struct dispc_clock_info *cinfo);
403void dispc_set_tv_pclk(unsigned long pclk);
404
405u32 dispc_wb_get_framedone_irq(void);
406bool dispc_wb_go_busy(void);
407void dispc_wb_go(void);
408void dispc_wb_enable(bool enable);
409bool dispc_wb_is_enabled(void);
410void dispc_wb_set_channel_in(enum dss_writeback_channel channel);
411int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
412 bool mem_to_mem, const struct omap_video_timings *timings);
413
414/* VENC */
415int venc_init_platform_driver(void) __init;
416void venc_uninit_platform_driver(void) __exit;
417
418/* HDMI */
419int hdmi4_init_platform_driver(void) __init;
420void hdmi4_uninit_platform_driver(void) __exit;
421
422/* RFBI */
423int rfbi_init_platform_driver(void) __init;
424void rfbi_uninit_platform_driver(void) __exit;
425
426
427#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
428static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
429{
430 int b;
431 for (b = 0; b < 32; ++b) {
432 if (irqstatus & (1 << b))
433 irq_arr[b]++;
434 }
435}
436#endif
437
438#endif
diff --git a/drivers/video/fbdev/omap2/dss/dss_features.c b/drivers/video/fbdev/omap2/dss/dss_features.c
new file mode 100644
index 000000000000..7f8969191dc6
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/dss_features.c
@@ -0,0 +1,935 @@
1/*
2 * linux/drivers/video/omap2/dss/dss_features.c
3 *
4 * Copyright (C) 2010 Texas Instruments
5 * Author: Archit Taneja <archit@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/types.h>
23#include <linux/err.h>
24#include <linux/slab.h>
25
26#include <video/omapdss.h>
27
28#include "dss.h"
29#include "dss_features.h"
30
31/* Defines a generic omap register field */
32struct dss_reg_field {
33 u8 start, end;
34};
35
36struct dss_param_range {
37 int min, max;
38};
39
40struct omap_dss_features {
41 const struct dss_reg_field *reg_fields;
42 const int num_reg_fields;
43
44 const enum dss_feat_id *features;
45 const int num_features;
46
47 const int num_mgrs;
48 const int num_ovls;
49 const int num_wbs;
50 const enum omap_display_type *supported_displays;
51 const enum omap_dss_output_id *supported_outputs;
52 const enum omap_color_mode *supported_color_modes;
53 const enum omap_overlay_caps *overlay_caps;
54 const char * const *clksrc_names;
55 const struct dss_param_range *dss_params;
56
57 const enum omap_dss_rotation_type supported_rotation_types;
58
59 const u32 buffer_size_unit;
60 const u32 burst_size_unit;
61};
62
63/* This struct is assigned to one of the below during initialization */
64static const struct omap_dss_features *omap_current_dss_features;
65
66static const struct dss_reg_field omap2_dss_reg_fields[] = {
67 [FEAT_REG_FIRHINC] = { 11, 0 },
68 [FEAT_REG_FIRVINC] = { 27, 16 },
69 [FEAT_REG_FIFOLOWTHRESHOLD] = { 8, 0 },
70 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 24, 16 },
71 [FEAT_REG_FIFOSIZE] = { 8, 0 },
72 [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
73 [FEAT_REG_VERTICALACCU] = { 25, 16 },
74 [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
75 [FEAT_REG_DSIPLL_REGN] = { 0, 0 },
76 [FEAT_REG_DSIPLL_REGM] = { 0, 0 },
77 [FEAT_REG_DSIPLL_REGM_DISPC] = { 0, 0 },
78 [FEAT_REG_DSIPLL_REGM_DSI] = { 0, 0 },
79};
80
81static const struct dss_reg_field omap3_dss_reg_fields[] = {
82 [FEAT_REG_FIRHINC] = { 12, 0 },
83 [FEAT_REG_FIRVINC] = { 28, 16 },
84 [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 },
85 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 },
86 [FEAT_REG_FIFOSIZE] = { 10, 0 },
87 [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
88 [FEAT_REG_VERTICALACCU] = { 25, 16 },
89 [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
90 [FEAT_REG_DSIPLL_REGN] = { 7, 1 },
91 [FEAT_REG_DSIPLL_REGM] = { 18, 8 },
92 [FEAT_REG_DSIPLL_REGM_DISPC] = { 22, 19 },
93 [FEAT_REG_DSIPLL_REGM_DSI] = { 26, 23 },
94};
95
96static const struct dss_reg_field omap4_dss_reg_fields[] = {
97 [FEAT_REG_FIRHINC] = { 12, 0 },
98 [FEAT_REG_FIRVINC] = { 28, 16 },
99 [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
100 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
101 [FEAT_REG_FIFOSIZE] = { 15, 0 },
102 [FEAT_REG_HORIZONTALACCU] = { 10, 0 },
103 [FEAT_REG_VERTICALACCU] = { 26, 16 },
104 [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 },
105 [FEAT_REG_DSIPLL_REGN] = { 8, 1 },
106 [FEAT_REG_DSIPLL_REGM] = { 20, 9 },
107 [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
108 [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
109};
110
111static const struct dss_reg_field omap5_dss_reg_fields[] = {
112 [FEAT_REG_FIRHINC] = { 12, 0 },
113 [FEAT_REG_FIRVINC] = { 28, 16 },
114 [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
115 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
116 [FEAT_REG_FIFOSIZE] = { 15, 0 },
117 [FEAT_REG_HORIZONTALACCU] = { 10, 0 },
118 [FEAT_REG_VERTICALACCU] = { 26, 16 },
119 [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 },
120 [FEAT_REG_DSIPLL_REGN] = { 8, 1 },
121 [FEAT_REG_DSIPLL_REGM] = { 20, 9 },
122 [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
123 [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
124};
125
126static const enum omap_display_type omap2_dss_supported_displays[] = {
127 /* OMAP_DSS_CHANNEL_LCD */
128 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI,
129
130 /* OMAP_DSS_CHANNEL_DIGIT */
131 OMAP_DISPLAY_TYPE_VENC,
132};
133
134static const enum omap_display_type omap3430_dss_supported_displays[] = {
135 /* OMAP_DSS_CHANNEL_LCD */
136 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
137 OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI,
138
139 /* OMAP_DSS_CHANNEL_DIGIT */
140 OMAP_DISPLAY_TYPE_VENC,
141};
142
143static const enum omap_display_type omap3630_dss_supported_displays[] = {
144 /* OMAP_DSS_CHANNEL_LCD */
145 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
146 OMAP_DISPLAY_TYPE_DSI,
147
148 /* OMAP_DSS_CHANNEL_DIGIT */
149 OMAP_DISPLAY_TYPE_VENC,
150};
151
152static const enum omap_display_type omap4_dss_supported_displays[] = {
153 /* OMAP_DSS_CHANNEL_LCD */
154 OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI,
155
156 /* OMAP_DSS_CHANNEL_DIGIT */
157 OMAP_DISPLAY_TYPE_VENC | OMAP_DISPLAY_TYPE_HDMI,
158
159 /* OMAP_DSS_CHANNEL_LCD2 */
160 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
161 OMAP_DISPLAY_TYPE_DSI,
162};
163
164static const enum omap_display_type omap5_dss_supported_displays[] = {
165 /* OMAP_DSS_CHANNEL_LCD */
166 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
167 OMAP_DISPLAY_TYPE_DSI,
168
169 /* OMAP_DSS_CHANNEL_DIGIT */
170 OMAP_DISPLAY_TYPE_HDMI | OMAP_DISPLAY_TYPE_DPI,
171
172 /* OMAP_DSS_CHANNEL_LCD2 */
173 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
174 OMAP_DISPLAY_TYPE_DSI,
175};
176
177static const enum omap_dss_output_id omap2_dss_supported_outputs[] = {
178 /* OMAP_DSS_CHANNEL_LCD */
179 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
180
181 /* OMAP_DSS_CHANNEL_DIGIT */
182 OMAP_DSS_OUTPUT_VENC,
183};
184
185static const enum omap_dss_output_id omap3430_dss_supported_outputs[] = {
186 /* OMAP_DSS_CHANNEL_LCD */
187 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
188 OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1,
189
190 /* OMAP_DSS_CHANNEL_DIGIT */
191 OMAP_DSS_OUTPUT_VENC,
192};
193
194static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = {
195 /* OMAP_DSS_CHANNEL_LCD */
196 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
197 OMAP_DSS_OUTPUT_DSI1,
198
199 /* OMAP_DSS_CHANNEL_DIGIT */
200 OMAP_DSS_OUTPUT_VENC,
201};
202
203static const enum omap_dss_output_id omap4_dss_supported_outputs[] = {
204 /* OMAP_DSS_CHANNEL_LCD */
205 OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1,
206
207 /* OMAP_DSS_CHANNEL_DIGIT */
208 OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI,
209
210 /* OMAP_DSS_CHANNEL_LCD2 */
211 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
212 OMAP_DSS_OUTPUT_DSI2,
213};
214
215static const enum omap_dss_output_id omap5_dss_supported_outputs[] = {
216 /* OMAP_DSS_CHANNEL_LCD */
217 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
218 OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2,
219
220 /* OMAP_DSS_CHANNEL_DIGIT */
221 OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI,
222
223 /* OMAP_DSS_CHANNEL_LCD2 */
224 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
225 OMAP_DSS_OUTPUT_DSI1,
226
227 /* OMAP_DSS_CHANNEL_LCD3 */
228 OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
229 OMAP_DSS_OUTPUT_DSI2,
230};
231
232static const enum omap_color_mode omap2_dss_supported_color_modes[] = {
233 /* OMAP_DSS_GFX */
234 OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
235 OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
236 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
237 OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P,
238
239 /* OMAP_DSS_VIDEO1 */
240 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
241 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
242 OMAP_DSS_COLOR_UYVY,
243
244 /* OMAP_DSS_VIDEO2 */
245 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
246 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
247 OMAP_DSS_COLOR_UYVY,
248};
249
250static const enum omap_color_mode omap3_dss_supported_color_modes[] = {
251 /* OMAP_DSS_GFX */
252 OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
253 OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
254 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
255 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
256 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
257 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
258
259 /* OMAP_DSS_VIDEO1 */
260 OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
261 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
262 OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
263
264 /* OMAP_DSS_VIDEO2 */
265 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
266 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
267 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
268 OMAP_DSS_COLOR_UYVY | OMAP_DSS_COLOR_ARGB32 |
269 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
270};
271
272static const enum omap_color_mode omap4_dss_supported_color_modes[] = {
273 /* OMAP_DSS_GFX */
274 OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
275 OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
276 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
277 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
278 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
279 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32 |
280 OMAP_DSS_COLOR_ARGB16_1555 | OMAP_DSS_COLOR_RGBX16 |
281 OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_XRGB16_1555,
282
283 /* OMAP_DSS_VIDEO1 */
284 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
285 OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
286 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
287 OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
288 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
289 OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
290 OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
291 OMAP_DSS_COLOR_RGBX32,
292
293 /* OMAP_DSS_VIDEO2 */
294 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
295 OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
296 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
297 OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
298 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
299 OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
300 OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
301 OMAP_DSS_COLOR_RGBX32,
302
303 /* OMAP_DSS_VIDEO3 */
304 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
305 OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
306 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
307 OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
308 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
309 OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
310 OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
311 OMAP_DSS_COLOR_RGBX32,
312
313 /* OMAP_DSS_WB */
314 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
315 OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
316 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
317 OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
318 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
319 OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
320 OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
321 OMAP_DSS_COLOR_RGBX32,
322};
323
324static const enum omap_overlay_caps omap2_dss_overlay_caps[] = {
325 /* OMAP_DSS_GFX */
326 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
327
328 /* OMAP_DSS_VIDEO1 */
329 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
330 OMAP_DSS_OVL_CAP_REPLICATION,
331
332 /* OMAP_DSS_VIDEO2 */
333 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
334 OMAP_DSS_OVL_CAP_REPLICATION,
335};
336
337static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = {
338 /* OMAP_DSS_GFX */
339 OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS |
340 OMAP_DSS_OVL_CAP_REPLICATION,
341
342 /* OMAP_DSS_VIDEO1 */
343 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
344 OMAP_DSS_OVL_CAP_REPLICATION,
345
346 /* OMAP_DSS_VIDEO2 */
347 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
348 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
349};
350
351static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = {
352 /* OMAP_DSS_GFX */
353 OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
354 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
355
356 /* OMAP_DSS_VIDEO1 */
357 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
358 OMAP_DSS_OVL_CAP_REPLICATION,
359
360 /* OMAP_DSS_VIDEO2 */
361 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
362 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS |
363 OMAP_DSS_OVL_CAP_REPLICATION,
364};
365
366static const enum omap_overlay_caps omap4_dss_overlay_caps[] = {
367 /* OMAP_DSS_GFX */
368 OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
369 OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS |
370 OMAP_DSS_OVL_CAP_REPLICATION,
371
372 /* OMAP_DSS_VIDEO1 */
373 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
374 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
375 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
376
377 /* OMAP_DSS_VIDEO2 */
378 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
379 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
380 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
381
382 /* OMAP_DSS_VIDEO3 */
383 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
384 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
385 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
386};
387
388static const char * const omap2_dss_clk_source_names[] = {
389 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "N/A",
390 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "N/A",
391 [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCLK1",
392};
393
394static const char * const omap3_dss_clk_source_names[] = {
395 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI1_PLL_FCLK",
396 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI2_PLL_FCLK",
397 [OMAP_DSS_CLK_SRC_FCK] = "DSS1_ALWON_FCLK",
398};
399
400static const char * const omap4_dss_clk_source_names[] = {
401 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "PLL1_CLK1",
402 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "PLL1_CLK2",
403 [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCLK",
404 [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "PLL2_CLK1",
405 [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2",
406};
407
408static const char * const omap5_dss_clk_source_names[] = {
409 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1",
410 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2",
411 [OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK",
412 [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1",
413 [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2",
414};
415
416static const struct dss_param_range omap2_dss_param_range[] = {
417 [FEAT_PARAM_DSS_FCK] = { 0, 133000000 },
418 [FEAT_PARAM_DSS_PCD] = { 2, 255 },
419 [FEAT_PARAM_DSIPLL_REGN] = { 0, 0 },
420 [FEAT_PARAM_DSIPLL_REGM] = { 0, 0 },
421 [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, 0 },
422 [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, 0 },
423 [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 },
424 [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 },
425 [FEAT_PARAM_DOWNSCALE] = { 1, 2 },
426 /*
427 * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC
428 * scaler cannot scale a image with width more than 768.
429 */
430 [FEAT_PARAM_LINEWIDTH] = { 1, 768 },
431};
432
433static const struct dss_param_range omap3_dss_param_range[] = {
434 [FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
435 [FEAT_PARAM_DSS_PCD] = { 1, 255 },
436 [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 7) - 1 },
437 [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 11) - 1 },
438 [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 4) - 1 },
439 [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 },
440 [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 },
441 [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1},
442 [FEAT_PARAM_DSI_FCK] = { 0, 173000000 },
443 [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
444 [FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
445};
446
447static const struct dss_param_range omap4_dss_param_range[] = {
448 [FEAT_PARAM_DSS_FCK] = { 0, 186000000 },
449 [FEAT_PARAM_DSS_PCD] = { 1, 255 },
450 [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
451 [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
452 [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
453 [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
454 [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
455 [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
456 [FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
457 [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
458 [FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
459};
460
461static const struct dss_param_range omap5_dss_param_range[] = {
462 [FEAT_PARAM_DSS_FCK] = { 0, 209250000 },
463 [FEAT_PARAM_DSS_PCD] = { 1, 255 },
464 [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
465 [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
466 [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
467 [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
468 [FEAT_PARAM_DSIPLL_FINT] = { 150000, 52000000 },
469 [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
470 [FEAT_PARAM_DSI_FCK] = { 0, 209250000 },
471 [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
472 [FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
473};
474
475static const enum dss_feat_id omap2_dss_feat_list[] = {
476 FEAT_LCDENABLEPOL,
477 FEAT_LCDENABLESIGNAL,
478 FEAT_PCKFREEENABLE,
479 FEAT_FUNCGATED,
480 FEAT_ROWREPEATENABLE,
481 FEAT_RESIZECONF,
482};
483
484static const enum dss_feat_id omap3430_dss_feat_list[] = {
485 FEAT_LCDENABLEPOL,
486 FEAT_LCDENABLESIGNAL,
487 FEAT_PCKFREEENABLE,
488 FEAT_FUNCGATED,
489 FEAT_LINEBUFFERSPLIT,
490 FEAT_ROWREPEATENABLE,
491 FEAT_RESIZECONF,
492 FEAT_DSI_PLL_FREQSEL,
493 FEAT_DSI_REVERSE_TXCLKESC,
494 FEAT_VENC_REQUIRES_TV_DAC_CLK,
495 FEAT_CPR,
496 FEAT_PRELOAD,
497 FEAT_FIR_COEF_V,
498 FEAT_ALPHA_FIXED_ZORDER,
499 FEAT_FIFO_MERGE,
500 FEAT_OMAP3_DSI_FIFO_BUG,
501 FEAT_DPI_USES_VDDS_DSI,
502};
503
504static const enum dss_feat_id am35xx_dss_feat_list[] = {
505 FEAT_LCDENABLEPOL,
506 FEAT_LCDENABLESIGNAL,
507 FEAT_PCKFREEENABLE,
508 FEAT_FUNCGATED,
509 FEAT_LINEBUFFERSPLIT,
510 FEAT_ROWREPEATENABLE,
511 FEAT_RESIZECONF,
512 FEAT_DSI_PLL_FREQSEL,
513 FEAT_DSI_REVERSE_TXCLKESC,
514 FEAT_VENC_REQUIRES_TV_DAC_CLK,
515 FEAT_CPR,
516 FEAT_PRELOAD,
517 FEAT_FIR_COEF_V,
518 FEAT_ALPHA_FIXED_ZORDER,
519 FEAT_FIFO_MERGE,
520 FEAT_OMAP3_DSI_FIFO_BUG,
521};
522
523static const enum dss_feat_id omap3630_dss_feat_list[] = {
524 FEAT_LCDENABLEPOL,
525 FEAT_LCDENABLESIGNAL,
526 FEAT_PCKFREEENABLE,
527 FEAT_FUNCGATED,
528 FEAT_LINEBUFFERSPLIT,
529 FEAT_ROWREPEATENABLE,
530 FEAT_RESIZECONF,
531 FEAT_DSI_PLL_PWR_BUG,
532 FEAT_DSI_PLL_FREQSEL,
533 FEAT_CPR,
534 FEAT_PRELOAD,
535 FEAT_FIR_COEF_V,
536 FEAT_ALPHA_FIXED_ZORDER,
537 FEAT_FIFO_MERGE,
538 FEAT_OMAP3_DSI_FIFO_BUG,
539 FEAT_DPI_USES_VDDS_DSI,
540};
541
542static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = {
543 FEAT_MGR_LCD2,
544 FEAT_CORE_CLK_DIV,
545 FEAT_LCD_CLK_SRC,
546 FEAT_DSI_DCS_CMD_CONFIG_VC,
547 FEAT_DSI_VC_OCP_WIDTH,
548 FEAT_DSI_GNQ,
549 FEAT_HANDLE_UV_SEPARATE,
550 FEAT_ATTR2,
551 FEAT_CPR,
552 FEAT_PRELOAD,
553 FEAT_FIR_COEF_V,
554 FEAT_ALPHA_FREE_ZORDER,
555 FEAT_FIFO_MERGE,
556 FEAT_BURST_2D,
557};
558
559static const enum dss_feat_id omap4430_es2_0_1_2_dss_feat_list[] = {
560 FEAT_MGR_LCD2,
561 FEAT_CORE_CLK_DIV,
562 FEAT_LCD_CLK_SRC,
563 FEAT_DSI_DCS_CMD_CONFIG_VC,
564 FEAT_DSI_VC_OCP_WIDTH,
565 FEAT_DSI_GNQ,
566 FEAT_HDMI_CTS_SWMODE,
567 FEAT_HANDLE_UV_SEPARATE,
568 FEAT_ATTR2,
569 FEAT_CPR,
570 FEAT_PRELOAD,
571 FEAT_FIR_COEF_V,
572 FEAT_ALPHA_FREE_ZORDER,
573 FEAT_FIFO_MERGE,
574 FEAT_BURST_2D,
575};
576
577static const enum dss_feat_id omap4_dss_feat_list[] = {
578 FEAT_MGR_LCD2,
579 FEAT_CORE_CLK_DIV,
580 FEAT_LCD_CLK_SRC,
581 FEAT_DSI_DCS_CMD_CONFIG_VC,
582 FEAT_DSI_VC_OCP_WIDTH,
583 FEAT_DSI_GNQ,
584 FEAT_HDMI_CTS_SWMODE,
585 FEAT_HDMI_AUDIO_USE_MCLK,
586 FEAT_HANDLE_UV_SEPARATE,
587 FEAT_ATTR2,
588 FEAT_CPR,
589 FEAT_PRELOAD,
590 FEAT_FIR_COEF_V,
591 FEAT_ALPHA_FREE_ZORDER,
592 FEAT_FIFO_MERGE,
593 FEAT_BURST_2D,
594};
595
596static const enum dss_feat_id omap5_dss_feat_list[] = {
597 FEAT_MGR_LCD2,
598 FEAT_CORE_CLK_DIV,
599 FEAT_LCD_CLK_SRC,
600 FEAT_DSI_DCS_CMD_CONFIG_VC,
601 FEAT_DSI_VC_OCP_WIDTH,
602 FEAT_DSI_GNQ,
603 FEAT_HDMI_CTS_SWMODE,
604 FEAT_HDMI_AUDIO_USE_MCLK,
605 FEAT_HANDLE_UV_SEPARATE,
606 FEAT_ATTR2,
607 FEAT_CPR,
608 FEAT_PRELOAD,
609 FEAT_FIR_COEF_V,
610 FEAT_ALPHA_FREE_ZORDER,
611 FEAT_FIFO_MERGE,
612 FEAT_BURST_2D,
613 FEAT_DSI_PLL_SELFREQDCO,
614 FEAT_DSI_PLL_REFSEL,
615 FEAT_DSI_PHY_DCC,
616 FEAT_MFLAG,
617};
618
619/* OMAP2 DSS Features */
620static const struct omap_dss_features omap2_dss_features = {
621 .reg_fields = omap2_dss_reg_fields,
622 .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields),
623
624 .features = omap2_dss_feat_list,
625 .num_features = ARRAY_SIZE(omap2_dss_feat_list),
626
627 .num_mgrs = 2,
628 .num_ovls = 3,
629 .supported_displays = omap2_dss_supported_displays,
630 .supported_outputs = omap2_dss_supported_outputs,
631 .supported_color_modes = omap2_dss_supported_color_modes,
632 .overlay_caps = omap2_dss_overlay_caps,
633 .clksrc_names = omap2_dss_clk_source_names,
634 .dss_params = omap2_dss_param_range,
635 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
636 .buffer_size_unit = 1,
637 .burst_size_unit = 8,
638};
639
640/* OMAP3 DSS Features */
641static const struct omap_dss_features omap3430_dss_features = {
642 .reg_fields = omap3_dss_reg_fields,
643 .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
644
645 .features = omap3430_dss_feat_list,
646 .num_features = ARRAY_SIZE(omap3430_dss_feat_list),
647
648 .num_mgrs = 2,
649 .num_ovls = 3,
650 .supported_displays = omap3430_dss_supported_displays,
651 .supported_outputs = omap3430_dss_supported_outputs,
652 .supported_color_modes = omap3_dss_supported_color_modes,
653 .overlay_caps = omap3430_dss_overlay_caps,
654 .clksrc_names = omap3_dss_clk_source_names,
655 .dss_params = omap3_dss_param_range,
656 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
657 .buffer_size_unit = 1,
658 .burst_size_unit = 8,
659};
660
661/*
662 * AM35xx DSS Features. This is basically OMAP3 DSS Features without the
663 * vdds_dsi regulator.
664 */
665static const struct omap_dss_features am35xx_dss_features = {
666 .reg_fields = omap3_dss_reg_fields,
667 .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
668
669 .features = am35xx_dss_feat_list,
670 .num_features = ARRAY_SIZE(am35xx_dss_feat_list),
671
672 .num_mgrs = 2,
673 .num_ovls = 3,
674 .supported_displays = omap3430_dss_supported_displays,
675 .supported_outputs = omap3430_dss_supported_outputs,
676 .supported_color_modes = omap3_dss_supported_color_modes,
677 .overlay_caps = omap3430_dss_overlay_caps,
678 .clksrc_names = omap3_dss_clk_source_names,
679 .dss_params = omap3_dss_param_range,
680 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
681 .buffer_size_unit = 1,
682 .burst_size_unit = 8,
683};
684
685static const struct omap_dss_features omap3630_dss_features = {
686 .reg_fields = omap3_dss_reg_fields,
687 .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
688
689 .features = omap3630_dss_feat_list,
690 .num_features = ARRAY_SIZE(omap3630_dss_feat_list),
691
692 .num_mgrs = 2,
693 .num_ovls = 3,
694 .supported_displays = omap3630_dss_supported_displays,
695 .supported_outputs = omap3630_dss_supported_outputs,
696 .supported_color_modes = omap3_dss_supported_color_modes,
697 .overlay_caps = omap3630_dss_overlay_caps,
698 .clksrc_names = omap3_dss_clk_source_names,
699 .dss_params = omap3_dss_param_range,
700 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB,
701 .buffer_size_unit = 1,
702 .burst_size_unit = 8,
703};
704
705/* OMAP4 DSS Features */
706/* For OMAP4430 ES 1.0 revision */
707static const struct omap_dss_features omap4430_es1_0_dss_features = {
708 .reg_fields = omap4_dss_reg_fields,
709 .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
710
711 .features = omap4430_es1_0_dss_feat_list,
712 .num_features = ARRAY_SIZE(omap4430_es1_0_dss_feat_list),
713
714 .num_mgrs = 3,
715 .num_ovls = 4,
716 .num_wbs = 1,
717 .supported_displays = omap4_dss_supported_displays,
718 .supported_outputs = omap4_dss_supported_outputs,
719 .supported_color_modes = omap4_dss_supported_color_modes,
720 .overlay_caps = omap4_dss_overlay_caps,
721 .clksrc_names = omap4_dss_clk_source_names,
722 .dss_params = omap4_dss_param_range,
723 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
724 .buffer_size_unit = 16,
725 .burst_size_unit = 16,
726};
727
728/* For OMAP4430 ES 2.0, 2.1 and 2.2 revisions */
729static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = {
730 .reg_fields = omap4_dss_reg_fields,
731 .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
732
733 .features = omap4430_es2_0_1_2_dss_feat_list,
734 .num_features = ARRAY_SIZE(omap4430_es2_0_1_2_dss_feat_list),
735
736 .num_mgrs = 3,
737 .num_ovls = 4,
738 .num_wbs = 1,
739 .supported_displays = omap4_dss_supported_displays,
740 .supported_outputs = omap4_dss_supported_outputs,
741 .supported_color_modes = omap4_dss_supported_color_modes,
742 .overlay_caps = omap4_dss_overlay_caps,
743 .clksrc_names = omap4_dss_clk_source_names,
744 .dss_params = omap4_dss_param_range,
745 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
746 .buffer_size_unit = 16,
747 .burst_size_unit = 16,
748};
749
750/* For all the other OMAP4 versions */
751static const struct omap_dss_features omap4_dss_features = {
752 .reg_fields = omap4_dss_reg_fields,
753 .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
754
755 .features = omap4_dss_feat_list,
756 .num_features = ARRAY_SIZE(omap4_dss_feat_list),
757
758 .num_mgrs = 3,
759 .num_ovls = 4,
760 .num_wbs = 1,
761 .supported_displays = omap4_dss_supported_displays,
762 .supported_outputs = omap4_dss_supported_outputs,
763 .supported_color_modes = omap4_dss_supported_color_modes,
764 .overlay_caps = omap4_dss_overlay_caps,
765 .clksrc_names = omap4_dss_clk_source_names,
766 .dss_params = omap4_dss_param_range,
767 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
768 .buffer_size_unit = 16,
769 .burst_size_unit = 16,
770};
771
772/* OMAP5 DSS Features */
773static const struct omap_dss_features omap5_dss_features = {
774 .reg_fields = omap5_dss_reg_fields,
775 .num_reg_fields = ARRAY_SIZE(omap5_dss_reg_fields),
776
777 .features = omap5_dss_feat_list,
778 .num_features = ARRAY_SIZE(omap5_dss_feat_list),
779
780 .num_mgrs = 3,
781 .num_ovls = 4,
782 .supported_displays = omap5_dss_supported_displays,
783 .supported_outputs = omap5_dss_supported_outputs,
784 .supported_color_modes = omap4_dss_supported_color_modes,
785 .overlay_caps = omap4_dss_overlay_caps,
786 .clksrc_names = omap5_dss_clk_source_names,
787 .dss_params = omap5_dss_param_range,
788 .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER,
789 .buffer_size_unit = 16,
790 .burst_size_unit = 16,
791};
792
793/* Functions returning values related to a DSS feature */
794int dss_feat_get_num_mgrs(void)
795{
796 return omap_current_dss_features->num_mgrs;
797}
798EXPORT_SYMBOL(dss_feat_get_num_mgrs);
799
800int dss_feat_get_num_ovls(void)
801{
802 return omap_current_dss_features->num_ovls;
803}
804EXPORT_SYMBOL(dss_feat_get_num_ovls);
805
806int dss_feat_get_num_wbs(void)
807{
808 return omap_current_dss_features->num_wbs;
809}
810
811unsigned long dss_feat_get_param_min(enum dss_range_param param)
812{
813 return omap_current_dss_features->dss_params[param].min;
814}
815
816unsigned long dss_feat_get_param_max(enum dss_range_param param)
817{
818 return omap_current_dss_features->dss_params[param].max;
819}
820
821enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel)
822{
823 return omap_current_dss_features->supported_displays[channel];
824}
825EXPORT_SYMBOL(dss_feat_get_supported_displays);
826
827enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel)
828{
829 return omap_current_dss_features->supported_outputs[channel];
830}
831EXPORT_SYMBOL(dss_feat_get_supported_outputs);
832
833enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane)
834{
835 return omap_current_dss_features->supported_color_modes[plane];
836}
837EXPORT_SYMBOL(dss_feat_get_supported_color_modes);
838
839enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane)
840{
841 return omap_current_dss_features->overlay_caps[plane];
842}
843
844bool dss_feat_color_mode_supported(enum omap_plane plane,
845 enum omap_color_mode color_mode)
846{
847 return omap_current_dss_features->supported_color_modes[plane] &
848 color_mode;
849}
850
851const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id)
852{
853 return omap_current_dss_features->clksrc_names[id];
854}
855
856u32 dss_feat_get_buffer_size_unit(void)
857{
858 return omap_current_dss_features->buffer_size_unit;
859}
860
861u32 dss_feat_get_burst_size_unit(void)
862{
863 return omap_current_dss_features->burst_size_unit;
864}
865
866/* DSS has_feature check */
867bool dss_has_feature(enum dss_feat_id id)
868{
869 int i;
870 const enum dss_feat_id *features = omap_current_dss_features->features;
871 const int num_features = omap_current_dss_features->num_features;
872
873 for (i = 0; i < num_features; i++) {
874 if (features[i] == id)
875 return true;
876 }
877
878 return false;
879}
880
881void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end)
882{
883 if (id >= omap_current_dss_features->num_reg_fields)
884 BUG();
885
886 *start = omap_current_dss_features->reg_fields[id].start;
887 *end = omap_current_dss_features->reg_fields[id].end;
888}
889
890bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type)
891{
892 return omap_current_dss_features->supported_rotation_types & rot_type;
893}
894
895void dss_features_init(enum omapdss_version version)
896{
897 switch (version) {
898 case OMAPDSS_VER_OMAP24xx:
899 omap_current_dss_features = &omap2_dss_features;
900 break;
901
902 case OMAPDSS_VER_OMAP34xx_ES1:
903 case OMAPDSS_VER_OMAP34xx_ES3:
904 omap_current_dss_features = &omap3430_dss_features;
905 break;
906
907 case OMAPDSS_VER_OMAP3630:
908 omap_current_dss_features = &omap3630_dss_features;
909 break;
910
911 case OMAPDSS_VER_OMAP4430_ES1:
912 omap_current_dss_features = &omap4430_es1_0_dss_features;
913 break;
914
915 case OMAPDSS_VER_OMAP4430_ES2:
916 omap_current_dss_features = &omap4430_es2_0_1_2_dss_features;
917 break;
918
919 case OMAPDSS_VER_OMAP4:
920 omap_current_dss_features = &omap4_dss_features;
921 break;
922
923 case OMAPDSS_VER_OMAP5:
924 omap_current_dss_features = &omap5_dss_features;
925 break;
926
927 case OMAPDSS_VER_AM35xx:
928 omap_current_dss_features = &am35xx_dss_features;
929 break;
930
931 default:
932 DSSWARN("Unsupported OMAP version");
933 break;
934 }
935}
diff --git a/drivers/video/fbdev/omap2/dss/dss_features.h b/drivers/video/fbdev/omap2/dss/dss_features.h
new file mode 100644
index 000000000000..e3ef3b714896
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/dss_features.h
@@ -0,0 +1,117 @@
1/*
2 * linux/drivers/video/omap2/dss/dss_features.h
3 *
4 * Copyright (C) 2010 Texas Instruments
5 * Author: Archit Taneja <archit@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifndef __OMAP2_DSS_FEATURES_H
21#define __OMAP2_DSS_FEATURES_H
22
23#define MAX_DSS_MANAGERS 4
24#define MAX_DSS_OVERLAYS 4
25#define MAX_DSS_LCD_MANAGERS 3
26#define MAX_NUM_DSI 2
27
28/* DSS has feature id */
29enum dss_feat_id {
30 FEAT_LCDENABLEPOL,
31 FEAT_LCDENABLESIGNAL,
32 FEAT_PCKFREEENABLE,
33 FEAT_FUNCGATED,
34 FEAT_MGR_LCD2,
35 FEAT_MGR_LCD3,
36 FEAT_LINEBUFFERSPLIT,
37 FEAT_ROWREPEATENABLE,
38 FEAT_RESIZECONF,
39 /* Independent core clk divider */
40 FEAT_CORE_CLK_DIV,
41 FEAT_LCD_CLK_SRC,
42 /* DSI-PLL power command 0x3 is not working */
43 FEAT_DSI_PLL_PWR_BUG,
44 FEAT_DSI_PLL_FREQSEL,
45 FEAT_DSI_DCS_CMD_CONFIG_VC,
46 FEAT_DSI_VC_OCP_WIDTH,
47 FEAT_DSI_REVERSE_TXCLKESC,
48 FEAT_DSI_GNQ,
49 FEAT_DPI_USES_VDDS_DSI,
50 FEAT_HDMI_CTS_SWMODE,
51 FEAT_HDMI_AUDIO_USE_MCLK,
52 FEAT_HANDLE_UV_SEPARATE,
53 FEAT_ATTR2,
54 FEAT_VENC_REQUIRES_TV_DAC_CLK,
55 FEAT_CPR,
56 FEAT_PRELOAD,
57 FEAT_FIR_COEF_V,
58 FEAT_ALPHA_FIXED_ZORDER,
59 FEAT_ALPHA_FREE_ZORDER,
60 FEAT_FIFO_MERGE,
61 /* An unknown HW bug causing the normal FIFO thresholds not to work */
62 FEAT_OMAP3_DSI_FIFO_BUG,
63 FEAT_BURST_2D,
64 FEAT_DSI_PLL_SELFREQDCO,
65 FEAT_DSI_PLL_REFSEL,
66 FEAT_DSI_PHY_DCC,
67 FEAT_MFLAG,
68};
69
70/* DSS register field id */
71enum dss_feat_reg_field {
72 FEAT_REG_FIRHINC,
73 FEAT_REG_FIRVINC,
74 FEAT_REG_FIFOHIGHTHRESHOLD,
75 FEAT_REG_FIFOLOWTHRESHOLD,
76 FEAT_REG_FIFOSIZE,
77 FEAT_REG_HORIZONTALACCU,
78 FEAT_REG_VERTICALACCU,
79 FEAT_REG_DISPC_CLK_SWITCH,
80 FEAT_REG_DSIPLL_REGN,
81 FEAT_REG_DSIPLL_REGM,
82 FEAT_REG_DSIPLL_REGM_DISPC,
83 FEAT_REG_DSIPLL_REGM_DSI,
84};
85
86enum dss_range_param {
87 FEAT_PARAM_DSS_FCK,
88 FEAT_PARAM_DSS_PCD,
89 FEAT_PARAM_DSIPLL_REGN,
90 FEAT_PARAM_DSIPLL_REGM,
91 FEAT_PARAM_DSIPLL_REGM_DISPC,
92 FEAT_PARAM_DSIPLL_REGM_DSI,
93 FEAT_PARAM_DSIPLL_FINT,
94 FEAT_PARAM_DSIPLL_LPDIV,
95 FEAT_PARAM_DSI_FCK,
96 FEAT_PARAM_DOWNSCALE,
97 FEAT_PARAM_LINEWIDTH,
98};
99
100/* DSS Feature Functions */
101int dss_feat_get_num_wbs(void);
102unsigned long dss_feat_get_param_min(enum dss_range_param param);
103unsigned long dss_feat_get_param_max(enum dss_range_param param);
104enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane);
105bool dss_feat_color_mode_supported(enum omap_plane plane,
106 enum omap_color_mode color_mode);
107const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id);
108
109u32 dss_feat_get_buffer_size_unit(void); /* in bytes */
110u32 dss_feat_get_burst_size_unit(void); /* in bytes */
111
112bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type);
113
114bool dss_has_feature(enum dss_feat_id id);
115void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
116void dss_features_init(enum omapdss_version version);
117#endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi.h b/drivers/video/fbdev/omap2/dss/hdmi.h
new file mode 100644
index 000000000000..e25681ff5a70
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/hdmi.h
@@ -0,0 +1,444 @@
1/*
2 * HDMI driver definition for TI OMAP4 Processor.
3 *
4 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef _HDMI_H
20#define _HDMI_H
21
22#include <linux/delay.h>
23#include <linux/io.h>
24#include <linux/platform_device.h>
25#include <video/omapdss.h>
26
27#include "dss.h"
28
29/* HDMI Wrapper */
30
31#define HDMI_WP_REVISION 0x0
32#define HDMI_WP_SYSCONFIG 0x10
33#define HDMI_WP_IRQSTATUS_RAW 0x24
34#define HDMI_WP_IRQSTATUS 0x28
35#define HDMI_WP_IRQENABLE_SET 0x2C
36#define HDMI_WP_IRQENABLE_CLR 0x30
37#define HDMI_WP_IRQWAKEEN 0x34
38#define HDMI_WP_PWR_CTRL 0x40
39#define HDMI_WP_DEBOUNCE 0x44
40#define HDMI_WP_VIDEO_CFG 0x50
41#define HDMI_WP_VIDEO_SIZE 0x60
42#define HDMI_WP_VIDEO_TIMING_H 0x68
43#define HDMI_WP_VIDEO_TIMING_V 0x6C
44#define HDMI_WP_CLK 0x70
45#define HDMI_WP_AUDIO_CFG 0x80
46#define HDMI_WP_AUDIO_CFG2 0x84
47#define HDMI_WP_AUDIO_CTRL 0x88
48#define HDMI_WP_AUDIO_DATA 0x8C
49
50/* HDMI WP IRQ flags */
51#define HDMI_IRQ_CORE (1 << 0)
52#define HDMI_IRQ_OCP_TIMEOUT (1 << 4)
53#define HDMI_IRQ_AUDIO_FIFO_UNDERFLOW (1 << 8)
54#define HDMI_IRQ_AUDIO_FIFO_OVERFLOW (1 << 9)
55#define HDMI_IRQ_AUDIO_FIFO_SAMPLE_REQ (1 << 10)
56#define HDMI_IRQ_VIDEO_VSYNC (1 << 16)
57#define HDMI_IRQ_VIDEO_FRAME_DONE (1 << 17)
58#define HDMI_IRQ_PHY_LINE5V_ASSERT (1 << 24)
59#define HDMI_IRQ_LINK_CONNECT (1 << 25)
60#define HDMI_IRQ_LINK_DISCONNECT (1 << 26)
61#define HDMI_IRQ_PLL_LOCK (1 << 29)
62#define HDMI_IRQ_PLL_UNLOCK (1 << 30)
63#define HDMI_IRQ_PLL_RECAL (1 << 31)
64
65/* HDMI PLL */
66
67#define PLLCTRL_PLL_CONTROL 0x0
68#define PLLCTRL_PLL_STATUS 0x4
69#define PLLCTRL_PLL_GO 0x8
70#define PLLCTRL_CFG1 0xC
71#define PLLCTRL_CFG2 0x10
72#define PLLCTRL_CFG3 0x14
73#define PLLCTRL_SSC_CFG1 0x18
74#define PLLCTRL_SSC_CFG2 0x1C
75#define PLLCTRL_CFG4 0x20
76
77/* HDMI PHY */
78
79#define HDMI_TXPHY_TX_CTRL 0x0
80#define HDMI_TXPHY_DIGITAL_CTRL 0x4
81#define HDMI_TXPHY_POWER_CTRL 0x8
82#define HDMI_TXPHY_PAD_CFG_CTRL 0xC
83
84enum hdmi_pll_pwr {
85 HDMI_PLLPWRCMD_ALLOFF = 0,
86 HDMI_PLLPWRCMD_PLLONLY = 1,
87 HDMI_PLLPWRCMD_BOTHON_ALLCLKS = 2,
88 HDMI_PLLPWRCMD_BOTHON_NOPHYCLK = 3
89};
90
91enum hdmi_phy_pwr {
92 HDMI_PHYPWRCMD_OFF = 0,
93 HDMI_PHYPWRCMD_LDOON = 1,
94 HDMI_PHYPWRCMD_TXON = 2
95};
96
97enum hdmi_core_hdmi_dvi {
98 HDMI_DVI = 0,
99 HDMI_HDMI = 1
100};
101
102enum hdmi_clk_refsel {
103 HDMI_REFSEL_PCLK = 0,
104 HDMI_REFSEL_REF1 = 1,
105 HDMI_REFSEL_REF2 = 2,
106 HDMI_REFSEL_SYSCLK = 3
107};
108
109enum hdmi_packing_mode {
110 HDMI_PACK_10b_RGB_YUV444 = 0,
111 HDMI_PACK_24b_RGB_YUV444_YUV422 = 1,
112 HDMI_PACK_20b_YUV422 = 2,
113 HDMI_PACK_ALREADYPACKED = 7
114};
115
116enum hdmi_stereo_channels {
117 HDMI_AUDIO_STEREO_NOCHANNELS = 0,
118 HDMI_AUDIO_STEREO_ONECHANNEL = 1,
119 HDMI_AUDIO_STEREO_TWOCHANNELS = 2,
120 HDMI_AUDIO_STEREO_THREECHANNELS = 3,
121 HDMI_AUDIO_STEREO_FOURCHANNELS = 4
122};
123
124enum hdmi_audio_type {
125 HDMI_AUDIO_TYPE_LPCM = 0,
126 HDMI_AUDIO_TYPE_IEC = 1
127};
128
129enum hdmi_audio_justify {
130 HDMI_AUDIO_JUSTIFY_LEFT = 0,
131 HDMI_AUDIO_JUSTIFY_RIGHT = 1
132};
133
134enum hdmi_audio_sample_order {
135 HDMI_AUDIO_SAMPLE_RIGHT_FIRST = 0,
136 HDMI_AUDIO_SAMPLE_LEFT_FIRST = 1
137};
138
139enum hdmi_audio_samples_perword {
140 HDMI_AUDIO_ONEWORD_ONESAMPLE = 0,
141 HDMI_AUDIO_ONEWORD_TWOSAMPLES = 1
142};
143
144enum hdmi_audio_sample_size {
145 HDMI_AUDIO_SAMPLE_16BITS = 0,
146 HDMI_AUDIO_SAMPLE_24BITS = 1
147};
148
149enum hdmi_audio_transf_mode {
150 HDMI_AUDIO_TRANSF_DMA = 0,
151 HDMI_AUDIO_TRANSF_IRQ = 1
152};
153
154enum hdmi_audio_blk_strt_end_sig {
155 HDMI_AUDIO_BLOCK_SIG_STARTEND_ON = 0,
156 HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF = 1
157};
158
159enum hdmi_core_audio_layout {
160 HDMI_AUDIO_LAYOUT_2CH = 0,
161 HDMI_AUDIO_LAYOUT_8CH = 1
162};
163
164enum hdmi_core_cts_mode {
165 HDMI_AUDIO_CTS_MODE_HW = 0,
166 HDMI_AUDIO_CTS_MODE_SW = 1
167};
168
169enum hdmi_audio_mclk_mode {
170 HDMI_AUDIO_MCLK_128FS = 0,
171 HDMI_AUDIO_MCLK_256FS = 1,
172 HDMI_AUDIO_MCLK_384FS = 2,
173 HDMI_AUDIO_MCLK_512FS = 3,
174 HDMI_AUDIO_MCLK_768FS = 4,
175 HDMI_AUDIO_MCLK_1024FS = 5,
176 HDMI_AUDIO_MCLK_1152FS = 6,
177 HDMI_AUDIO_MCLK_192FS = 7
178};
179
180/* INFOFRAME_AVI_ and INFOFRAME_AUDIO_ definitions */
181enum hdmi_core_infoframe {
182 HDMI_INFOFRAME_AVI_DB1Y_RGB = 0,
183 HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1,
184 HDMI_INFOFRAME_AVI_DB1Y_YUV444 = 2,
185 HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF = 0,
186 HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_ON = 1,
187 HDMI_INFOFRAME_AVI_DB1B_NO = 0,
188 HDMI_INFOFRAME_AVI_DB1B_VERT = 1,
189 HDMI_INFOFRAME_AVI_DB1B_HORI = 2,
190 HDMI_INFOFRAME_AVI_DB1B_VERTHORI = 3,
191 HDMI_INFOFRAME_AVI_DB1S_0 = 0,
192 HDMI_INFOFRAME_AVI_DB1S_1 = 1,
193 HDMI_INFOFRAME_AVI_DB1S_2 = 2,
194 HDMI_INFOFRAME_AVI_DB2C_NO = 0,
195 HDMI_INFOFRAME_AVI_DB2C_ITU601 = 1,
196 HDMI_INFOFRAME_AVI_DB2C_ITU709 = 2,
197 HDMI_INFOFRAME_AVI_DB2C_EC_EXTENDED = 3,
198 HDMI_INFOFRAME_AVI_DB2M_NO = 0,
199 HDMI_INFOFRAME_AVI_DB2M_43 = 1,
200 HDMI_INFOFRAME_AVI_DB2M_169 = 2,
201 HDMI_INFOFRAME_AVI_DB2R_SAME = 8,
202 HDMI_INFOFRAME_AVI_DB2R_43 = 9,
203 HDMI_INFOFRAME_AVI_DB2R_169 = 10,
204 HDMI_INFOFRAME_AVI_DB2R_149 = 11,
205 HDMI_INFOFRAME_AVI_DB3ITC_NO = 0,
206 HDMI_INFOFRAME_AVI_DB3ITC_YES = 1,
207 HDMI_INFOFRAME_AVI_DB3EC_XVYUV601 = 0,
208 HDMI_INFOFRAME_AVI_DB3EC_XVYUV709 = 1,
209 HDMI_INFOFRAME_AVI_DB3Q_DEFAULT = 0,
210 HDMI_INFOFRAME_AVI_DB3Q_LR = 1,
211 HDMI_INFOFRAME_AVI_DB3Q_FR = 2,
212 HDMI_INFOFRAME_AVI_DB3SC_NO = 0,
213 HDMI_INFOFRAME_AVI_DB3SC_HORI = 1,
214 HDMI_INFOFRAME_AVI_DB3SC_VERT = 2,
215 HDMI_INFOFRAME_AVI_DB3SC_HORIVERT = 3,
216 HDMI_INFOFRAME_AVI_DB5PR_NO = 0,
217 HDMI_INFOFRAME_AVI_DB5PR_2 = 1,
218 HDMI_INFOFRAME_AVI_DB5PR_3 = 2,
219 HDMI_INFOFRAME_AVI_DB5PR_4 = 3,
220 HDMI_INFOFRAME_AVI_DB5PR_5 = 4,
221 HDMI_INFOFRAME_AVI_DB5PR_6 = 5,
222 HDMI_INFOFRAME_AVI_DB5PR_7 = 6,
223 HDMI_INFOFRAME_AVI_DB5PR_8 = 7,
224 HDMI_INFOFRAME_AVI_DB5PR_9 = 8,
225 HDMI_INFOFRAME_AVI_DB5PR_10 = 9,
226};
227
228struct hdmi_cm {
229 int code;
230 int mode;
231};
232
233struct hdmi_video_format {
234 enum hdmi_packing_mode packing_mode;
235 u32 y_res; /* Line per panel */
236 u32 x_res; /* pixel per line */
237};
238
239struct hdmi_config {
240 struct omap_video_timings timings;
241 struct hdmi_cm cm;
242};
243
244/* HDMI PLL structure */
245struct hdmi_pll_info {
246 u16 regn;
247 u16 regm;
248 u32 regmf;
249 u16 regm2;
250 u16 regsd;
251 u16 dcofreq;
252 enum hdmi_clk_refsel refsel;
253};
254
255struct hdmi_audio_format {
256 enum hdmi_stereo_channels stereo_channels;
257 u8 active_chnnls_msk;
258 enum hdmi_audio_type type;
259 enum hdmi_audio_justify justification;
260 enum hdmi_audio_sample_order sample_order;
261 enum hdmi_audio_samples_perword samples_per_word;
262 enum hdmi_audio_sample_size sample_size;
263 enum hdmi_audio_blk_strt_end_sig en_sig_blk_strt_end;
264};
265
266struct hdmi_audio_dma {
267 u8 transfer_size;
268 u8 block_size;
269 enum hdmi_audio_transf_mode mode;
270 u16 fifo_threshold;
271};
272
273struct hdmi_core_audio_i2s_config {
274 u8 in_length_bits;
275 u8 justification;
276 u8 sck_edge_mode;
277 u8 vbit;
278 u8 direction;
279 u8 shift;
280 u8 active_sds;
281};
282
283struct hdmi_core_audio_config {
284 struct hdmi_core_audio_i2s_config i2s_cfg;
285 struct snd_aes_iec958 *iec60958_cfg;
286 bool fs_override;
287 u32 n;
288 u32 cts;
289 u32 aud_par_busclk;
290 enum hdmi_core_audio_layout layout;
291 enum hdmi_core_cts_mode cts_mode;
292 bool use_mclk;
293 enum hdmi_audio_mclk_mode mclk_mode;
294 bool en_acr_pkt;
295 bool en_dsd_audio;
296 bool en_parallel_aud_input;
297 bool en_spdif;
298};
299
300/*
301 * Refer to section 8.2 in HDMI 1.3 specification for
302 * details about infoframe databytes
303 */
304struct hdmi_core_infoframe_avi {
305 /* Y0, Y1 rgb,yCbCr */
306 u8 db1_format;
307 /* A0 Active information Present */
308 u8 db1_active_info;
309 /* B0, B1 Bar info data valid */
310 u8 db1_bar_info_dv;
311 /* S0, S1 scan information */
312 u8 db1_scan_info;
313 /* C0, C1 colorimetry */
314 u8 db2_colorimetry;
315 /* M0, M1 Aspect ratio (4:3, 16:9) */
316 u8 db2_aspect_ratio;
317 /* R0...R3 Active format aspect ratio */
318 u8 db2_active_fmt_ar;
319 /* ITC IT content. */
320 u8 db3_itc;
321 /* EC0, EC1, EC2 Extended colorimetry */
322 u8 db3_ec;
323 /* Q1, Q0 Quantization range */
324 u8 db3_q_range;
325 /* SC1, SC0 Non-uniform picture scaling */
326 u8 db3_nup_scaling;
327 /* VIC0..6 Video format identification */
328 u8 db4_videocode;
329 /* PR0..PR3 Pixel repetition factor */
330 u8 db5_pixel_repeat;
331 /* Line number end of top bar */
332 u16 db6_7_line_eoftop;
333 /* Line number start of bottom bar */
334 u16 db8_9_line_sofbottom;
335 /* Pixel number end of left bar */
336 u16 db10_11_pixel_eofleft;
337 /* Pixel number start of right bar */
338 u16 db12_13_pixel_sofright;
339};
340
341struct hdmi_wp_data {
342 void __iomem *base;
343};
344
345struct hdmi_pll_data {
346 void __iomem *base;
347
348 struct hdmi_pll_info info;
349};
350
351struct hdmi_phy_data {
352 void __iomem *base;
353
354 int irq;
355};
356
357struct hdmi_core_data {
358 void __iomem *base;
359
360 struct hdmi_core_infoframe_avi avi_cfg;
361};
362
363static inline void hdmi_write_reg(void __iomem *base_addr, const u16 idx,
364 u32 val)
365{
366 __raw_writel(val, base_addr + idx);
367}
368
369static inline u32 hdmi_read_reg(void __iomem *base_addr, const u16 idx)
370{
371 return __raw_readl(base_addr + idx);
372}
373
374#define REG_FLD_MOD(base, idx, val, start, end) \
375 hdmi_write_reg(base, idx, FLD_MOD(hdmi_read_reg(base, idx),\
376 val, start, end))
377#define REG_GET(base, idx, start, end) \
378 FLD_GET(hdmi_read_reg(base, idx), start, end)
379
380static inline int hdmi_wait_for_bit_change(void __iomem *base_addr,
381 const u32 idx, int b2, int b1, u32 val)
382{
383 u32 t = 0, v;
384 while (val != (v = REG_GET(base_addr, idx, b2, b1))) {
385 if (t++ > 10000)
386 return v;
387 udelay(1);
388 }
389 return v;
390}
391
392/* HDMI wrapper funcs */
393int hdmi_wp_video_start(struct hdmi_wp_data *wp);
394void hdmi_wp_video_stop(struct hdmi_wp_data *wp);
395void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s);
396u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp);
397void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus);
398void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask);
399void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask);
400int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val);
401int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val);
402void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
403 struct hdmi_video_format *video_fmt);
404void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
405 struct omap_video_timings *timings);
406void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
407 struct omap_video_timings *timings);
408void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
409 struct omap_video_timings *timings, struct hdmi_config *param);
410int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp);
411
412/* HDMI PLL funcs */
413int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
414void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
415void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s);
416void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy);
417int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll);
418
419/* HDMI PHY funcs */
420int hdmi_phy_enable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp,
421 struct hdmi_config *cfg);
422void hdmi_phy_disable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp);
423void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s);
424int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy);
425
426/* HDMI common funcs */
427const struct hdmi_config *hdmi_default_timing(void);
428const struct hdmi_config *hdmi_get_timings(int mode, int code);
429struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing);
430
431#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
432int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts);
433int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable);
434int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable);
435void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
436 struct hdmi_audio_format *aud_fmt);
437void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
438 struct hdmi_audio_dma *aud_dma);
439static inline bool hdmi_mode_has_audio(int mode)
440{
441 return mode == HDMI_HDMI ? true : false;
442}
443#endif
444#endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c
new file mode 100644
index 000000000000..f5f7944a1fd1
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/hdmi4.c
@@ -0,0 +1,703 @@
1/*
2 * HDMI interface DSS driver for TI's OMAP4 family of SoCs.
3 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
4 * Authors: Yong Zhi
5 * Mythri pk <mythripk@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#define DSS_SUBSYS_NAME "HDMI"
21
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/err.h>
25#include <linux/io.h>
26#include <linux/interrupt.h>
27#include <linux/mutex.h>
28#include <linux/delay.h>
29#include <linux/string.h>
30#include <linux/platform_device.h>
31#include <linux/pm_runtime.h>
32#include <linux/clk.h>
33#include <linux/gpio.h>
34#include <linux/regulator/consumer.h>
35#include <video/omapdss.h>
36
37#include "hdmi4_core.h"
38#include "dss.h"
39#include "dss_features.h"
40
41static struct {
42 struct mutex lock;
43 struct platform_device *pdev;
44
45 struct hdmi_wp_data wp;
46 struct hdmi_pll_data pll;
47 struct hdmi_phy_data phy;
48 struct hdmi_core_data core;
49
50 struct hdmi_config cfg;
51
52 struct clk *sys_clk;
53 struct regulator *vdda_hdmi_dac_reg;
54
55 bool core_enabled;
56
57 struct omap_dss_device output;
58} hdmi;
59
60static int hdmi_runtime_get(void)
61{
62 int r;
63
64 DSSDBG("hdmi_runtime_get\n");
65
66 r = pm_runtime_get_sync(&hdmi.pdev->dev);
67 WARN_ON(r < 0);
68 if (r < 0)
69 return r;
70
71 return 0;
72}
73
74static void hdmi_runtime_put(void)
75{
76 int r;
77
78 DSSDBG("hdmi_runtime_put\n");
79
80 r = pm_runtime_put_sync(&hdmi.pdev->dev);
81 WARN_ON(r < 0 && r != -ENOSYS);
82}
83
84static int hdmi_init_regulator(void)
85{
86 struct regulator *reg;
87
88 if (hdmi.vdda_hdmi_dac_reg != NULL)
89 return 0;
90
91 reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
92
93 if (IS_ERR(reg)) {
94 if (PTR_ERR(reg) != -EPROBE_DEFER)
95 DSSERR("can't get VDDA regulator\n");
96 return PTR_ERR(reg);
97 }
98
99 hdmi.vdda_hdmi_dac_reg = reg;
100
101 return 0;
102}
103
104static int hdmi_power_on_core(struct omap_dss_device *dssdev)
105{
106 int r;
107
108 r = regulator_enable(hdmi.vdda_hdmi_dac_reg);
109 if (r)
110 return r;
111
112 r = hdmi_runtime_get();
113 if (r)
114 goto err_runtime_get;
115
116 /* Make selection of HDMI in DSS */
117 dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
118
119 hdmi.core_enabled = true;
120
121 return 0;
122
123err_runtime_get:
124 regulator_disable(hdmi.vdda_hdmi_dac_reg);
125
126 return r;
127}
128
129static void hdmi_power_off_core(struct omap_dss_device *dssdev)
130{
131 hdmi.core_enabled = false;
132
133 hdmi_runtime_put();
134 regulator_disable(hdmi.vdda_hdmi_dac_reg);
135}
136
137static int hdmi_power_on_full(struct omap_dss_device *dssdev)
138{
139 int r;
140 struct omap_video_timings *p;
141 struct omap_overlay_manager *mgr = hdmi.output.manager;
142 unsigned long phy;
143
144 r = hdmi_power_on_core(dssdev);
145 if (r)
146 return r;
147
148 p = &hdmi.cfg.timings;
149
150 DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
151
152 /* the functions below use kHz pixel clock. TODO: change to Hz */
153 phy = p->pixelclock / 1000;
154
155 hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
156
157 /* config the PLL and PHY hdmi_set_pll_pwrfirst */
158 r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
159 if (r) {
160 DSSDBG("Failed to lock PLL\n");
161 goto err_pll_enable;
162 }
163
164 r = hdmi_phy_enable(&hdmi.phy, &hdmi.wp, &hdmi.cfg);
165 if (r) {
166 DSSDBG("Failed to start PHY\n");
167 goto err_phy_enable;
168 }
169
170 hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
171
172 /* bypass TV gamma table */
173 dispc_enable_gamma_table(0);
174
175 /* tv size */
176 dss_mgr_set_timings(mgr, p);
177
178 r = hdmi_wp_video_start(&hdmi.wp);
179 if (r)
180 goto err_vid_enable;
181
182 r = dss_mgr_enable(mgr);
183 if (r)
184 goto err_mgr_enable;
185
186 return 0;
187
188err_mgr_enable:
189 hdmi_wp_video_stop(&hdmi.wp);
190err_vid_enable:
191 hdmi_phy_disable(&hdmi.phy, &hdmi.wp);
192err_phy_enable:
193 hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
194err_pll_enable:
195 hdmi_power_off_core(dssdev);
196 return -EIO;
197}
198
199static void hdmi_power_off_full(struct omap_dss_device *dssdev)
200{
201 struct omap_overlay_manager *mgr = hdmi.output.manager;
202
203 dss_mgr_disable(mgr);
204
205 hdmi_wp_video_stop(&hdmi.wp);
206 hdmi_phy_disable(&hdmi.phy, &hdmi.wp);
207 hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
208
209 hdmi_power_off_core(dssdev);
210}
211
212static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
213 struct omap_video_timings *timings)
214{
215 struct omap_dss_device *out = &hdmi.output;
216
217 if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
218 return -EINVAL;
219
220 return 0;
221}
222
223static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
224 struct omap_video_timings *timings)
225{
226 struct hdmi_cm cm;
227 const struct hdmi_config *t;
228
229 mutex_lock(&hdmi.lock);
230
231 cm = hdmi_get_code(timings);
232 hdmi.cfg.cm = cm;
233
234 t = hdmi_get_timings(cm.mode, cm.code);
235 if (t != NULL) {
236 hdmi.cfg = *t;
237
238 dispc_set_tv_pclk(t->timings.pixelclock);
239 } else {
240 hdmi.cfg.timings = *timings;
241 hdmi.cfg.cm.code = 0;
242 hdmi.cfg.cm.mode = HDMI_DVI;
243
244 dispc_set_tv_pclk(timings->pixelclock);
245 }
246
247 DSSDBG("using mode: %s, code %d\n", hdmi.cfg.cm.mode == HDMI_DVI ?
248 "DVI" : "HDMI", hdmi.cfg.cm.code);
249
250 mutex_unlock(&hdmi.lock);
251}
252
253static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
254 struct omap_video_timings *timings)
255{
256 const struct hdmi_config *cfg;
257 struct hdmi_cm cm = hdmi.cfg.cm;
258
259 cfg = hdmi_get_timings(cm.mode, cm.code);
260 if (cfg == NULL)
261 cfg = hdmi_default_timing();
262
263 memcpy(timings, &cfg->timings, sizeof(cfg->timings));
264}
265
266static void hdmi_dump_regs(struct seq_file *s)
267{
268 mutex_lock(&hdmi.lock);
269
270 if (hdmi_runtime_get()) {
271 mutex_unlock(&hdmi.lock);
272 return;
273 }
274
275 hdmi_wp_dump(&hdmi.wp, s);
276 hdmi_pll_dump(&hdmi.pll, s);
277 hdmi_phy_dump(&hdmi.phy, s);
278 hdmi4_core_dump(&hdmi.core, s);
279
280 hdmi_runtime_put();
281 mutex_unlock(&hdmi.lock);
282}
283
284static int read_edid(u8 *buf, int len)
285{
286 int r;
287
288 mutex_lock(&hdmi.lock);
289
290 r = hdmi_runtime_get();
291 BUG_ON(r);
292
293 r = hdmi4_read_edid(&hdmi.core, buf, len);
294
295 hdmi_runtime_put();
296 mutex_unlock(&hdmi.lock);
297
298 return r;
299}
300
301static int hdmi_display_enable(struct omap_dss_device *dssdev)
302{
303 struct omap_dss_device *out = &hdmi.output;
304 int r = 0;
305
306 DSSDBG("ENTER hdmi_display_enable\n");
307
308 mutex_lock(&hdmi.lock);
309
310 if (out == NULL || out->manager == NULL) {
311 DSSERR("failed to enable display: no output/manager\n");
312 r = -ENODEV;
313 goto err0;
314 }
315
316 r = hdmi_power_on_full(dssdev);
317 if (r) {
318 DSSERR("failed to power on device\n");
319 goto err0;
320 }
321
322 mutex_unlock(&hdmi.lock);
323 return 0;
324
325err0:
326 mutex_unlock(&hdmi.lock);
327 return r;
328}
329
330static void hdmi_display_disable(struct omap_dss_device *dssdev)
331{
332 DSSDBG("Enter hdmi_display_disable\n");
333
334 mutex_lock(&hdmi.lock);
335
336 hdmi_power_off_full(dssdev);
337
338 mutex_unlock(&hdmi.lock);
339}
340
341static int hdmi_core_enable(struct omap_dss_device *dssdev)
342{
343 int r = 0;
344
345 DSSDBG("ENTER omapdss_hdmi_core_enable\n");
346
347 mutex_lock(&hdmi.lock);
348
349 r = hdmi_power_on_core(dssdev);
350 if (r) {
351 DSSERR("failed to power on device\n");
352 goto err0;
353 }
354
355 mutex_unlock(&hdmi.lock);
356 return 0;
357
358err0:
359 mutex_unlock(&hdmi.lock);
360 return r;
361}
362
363static void hdmi_core_disable(struct omap_dss_device *dssdev)
364{
365 DSSDBG("Enter omapdss_hdmi_core_disable\n");
366
367 mutex_lock(&hdmi.lock);
368
369 hdmi_power_off_core(dssdev);
370
371 mutex_unlock(&hdmi.lock);
372}
373
374static int hdmi_get_clocks(struct platform_device *pdev)
375{
376 struct clk *clk;
377
378 clk = devm_clk_get(&pdev->dev, "sys_clk");
379 if (IS_ERR(clk)) {
380 DSSERR("can't get sys_clk\n");
381 return PTR_ERR(clk);
382 }
383
384 hdmi.sys_clk = clk;
385
386 return 0;
387}
388
389static int hdmi_connect(struct omap_dss_device *dssdev,
390 struct omap_dss_device *dst)
391{
392 struct omap_overlay_manager *mgr;
393 int r;
394
395 r = hdmi_init_regulator();
396 if (r)
397 return r;
398
399 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
400 if (!mgr)
401 return -ENODEV;
402
403 r = dss_mgr_connect(mgr, dssdev);
404 if (r)
405 return r;
406
407 r = omapdss_output_set_device(dssdev, dst);
408 if (r) {
409 DSSERR("failed to connect output to new device: %s\n",
410 dst->name);
411 dss_mgr_disconnect(mgr, dssdev);
412 return r;
413 }
414
415 return 0;
416}
417
418static void hdmi_disconnect(struct omap_dss_device *dssdev,
419 struct omap_dss_device *dst)
420{
421 WARN_ON(dst != dssdev->dst);
422
423 if (dst != dssdev->dst)
424 return;
425
426 omapdss_output_unset_device(dssdev);
427
428 if (dssdev->manager)
429 dss_mgr_disconnect(dssdev->manager, dssdev);
430}
431
432static int hdmi_read_edid(struct omap_dss_device *dssdev,
433 u8 *edid, int len)
434{
435 bool need_enable;
436 int r;
437
438 need_enable = hdmi.core_enabled == false;
439
440 if (need_enable) {
441 r = hdmi_core_enable(dssdev);
442 if (r)
443 return r;
444 }
445
446 r = read_edid(edid, len);
447
448 if (need_enable)
449 hdmi_core_disable(dssdev);
450
451 return r;
452}
453
454#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
455static int hdmi_audio_enable(struct omap_dss_device *dssdev)
456{
457 int r;
458
459 mutex_lock(&hdmi.lock);
460
461 if (!hdmi_mode_has_audio(hdmi.cfg.cm.mode)) {
462 r = -EPERM;
463 goto err;
464 }
465
466 r = hdmi_wp_audio_enable(&hdmi.wp, true);
467 if (r)
468 goto err;
469
470 mutex_unlock(&hdmi.lock);
471 return 0;
472
473err:
474 mutex_unlock(&hdmi.lock);
475 return r;
476}
477
478static void hdmi_audio_disable(struct omap_dss_device *dssdev)
479{
480 hdmi_wp_audio_enable(&hdmi.wp, false);
481}
482
483static int hdmi_audio_start(struct omap_dss_device *dssdev)
484{
485 return hdmi4_audio_start(&hdmi.core, &hdmi.wp);
486}
487
488static void hdmi_audio_stop(struct omap_dss_device *dssdev)
489{
490 hdmi4_audio_stop(&hdmi.core, &hdmi.wp);
491}
492
493static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
494{
495 bool r;
496
497 mutex_lock(&hdmi.lock);
498
499 r = hdmi_mode_has_audio(hdmi.cfg.cm.mode);
500
501 mutex_unlock(&hdmi.lock);
502 return r;
503}
504
505static int hdmi_audio_config(struct omap_dss_device *dssdev,
506 struct omap_dss_audio *audio)
507{
508 int r;
509 u32 pclk = hdmi.cfg.timings.pixelclock;
510
511 mutex_lock(&hdmi.lock);
512
513 if (!hdmi_mode_has_audio(hdmi.cfg.cm.mode)) {
514 r = -EPERM;
515 goto err;
516 }
517
518 r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, audio, pclk);
519 if (r)
520 goto err;
521
522 mutex_unlock(&hdmi.lock);
523 return 0;
524
525err:
526 mutex_unlock(&hdmi.lock);
527 return r;
528}
529#else
530static int hdmi_audio_enable(struct omap_dss_device *dssdev)
531{
532 return -EPERM;
533}
534
535static void hdmi_audio_disable(struct omap_dss_device *dssdev)
536{
537}
538
539static int hdmi_audio_start(struct omap_dss_device *dssdev)
540{
541 return -EPERM;
542}
543
544static void hdmi_audio_stop(struct omap_dss_device *dssdev)
545{
546}
547
548static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
549{
550 return false;
551}
552
553static int hdmi_audio_config(struct omap_dss_device *dssdev,
554 struct omap_dss_audio *audio)
555{
556 return -EPERM;
557}
558#endif
559
560static const struct omapdss_hdmi_ops hdmi_ops = {
561 .connect = hdmi_connect,
562 .disconnect = hdmi_disconnect,
563
564 .enable = hdmi_display_enable,
565 .disable = hdmi_display_disable,
566
567 .check_timings = hdmi_display_check_timing,
568 .set_timings = hdmi_display_set_timing,
569 .get_timings = hdmi_display_get_timings,
570
571 .read_edid = hdmi_read_edid,
572
573 .audio_enable = hdmi_audio_enable,
574 .audio_disable = hdmi_audio_disable,
575 .audio_start = hdmi_audio_start,
576 .audio_stop = hdmi_audio_stop,
577 .audio_supported = hdmi_audio_supported,
578 .audio_config = hdmi_audio_config,
579};
580
581static void hdmi_init_output(struct platform_device *pdev)
582{
583 struct omap_dss_device *out = &hdmi.output;
584
585 out->dev = &pdev->dev;
586 out->id = OMAP_DSS_OUTPUT_HDMI;
587 out->output_type = OMAP_DISPLAY_TYPE_HDMI;
588 out->name = "hdmi.0";
589 out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
590 out->ops.hdmi = &hdmi_ops;
591 out->owner = THIS_MODULE;
592
593 omapdss_register_output(out);
594}
595
596static void __exit hdmi_uninit_output(struct platform_device *pdev)
597{
598 struct omap_dss_device *out = &hdmi.output;
599
600 omapdss_unregister_output(out);
601}
602
603/* HDMI HW IP initialisation */
604static int omapdss_hdmihw_probe(struct platform_device *pdev)
605{
606 int r;
607
608 hdmi.pdev = pdev;
609
610 mutex_init(&hdmi.lock);
611
612 r = hdmi_wp_init(pdev, &hdmi.wp);
613 if (r)
614 return r;
615
616 r = hdmi_pll_init(pdev, &hdmi.pll);
617 if (r)
618 return r;
619
620 r = hdmi_phy_init(pdev, &hdmi.phy);
621 if (r)
622 return r;
623
624 r = hdmi4_core_init(pdev, &hdmi.core);
625 if (r)
626 return r;
627
628 r = hdmi_get_clocks(pdev);
629 if (r) {
630 DSSERR("can't get clocks\n");
631 return r;
632 }
633
634 pm_runtime_enable(&pdev->dev);
635
636 hdmi_init_output(pdev);
637
638 dss_debugfs_create_file("hdmi", hdmi_dump_regs);
639
640 return 0;
641}
642
643static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
644{
645 hdmi_uninit_output(pdev);
646
647 pm_runtime_disable(&pdev->dev);
648
649 return 0;
650}
651
652static int hdmi_runtime_suspend(struct device *dev)
653{
654 clk_disable_unprepare(hdmi.sys_clk);
655
656 dispc_runtime_put();
657
658 return 0;
659}
660
661static int hdmi_runtime_resume(struct device *dev)
662{
663 int r;
664
665 r = dispc_runtime_get();
666 if (r < 0)
667 return r;
668
669 clk_prepare_enable(hdmi.sys_clk);
670
671 return 0;
672}
673
674static const struct dev_pm_ops hdmi_pm_ops = {
675 .runtime_suspend = hdmi_runtime_suspend,
676 .runtime_resume = hdmi_runtime_resume,
677};
678
679static const struct of_device_id hdmi_of_match[] = {
680 { .compatible = "ti,omap4-hdmi", },
681 {},
682};
683
684static struct platform_driver omapdss_hdmihw_driver = {
685 .probe = omapdss_hdmihw_probe,
686 .remove = __exit_p(omapdss_hdmihw_remove),
687 .driver = {
688 .name = "omapdss_hdmi",
689 .owner = THIS_MODULE,
690 .pm = &hdmi_pm_ops,
691 .of_match_table = hdmi_of_match,
692 },
693};
694
695int __init hdmi4_init_platform_driver(void)
696{
697 return platform_driver_register(&omapdss_hdmihw_driver);
698}
699
700void __exit hdmi4_uninit_platform_driver(void)
701{
702 platform_driver_unregister(&omapdss_hdmihw_driver);
703}
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.c b/drivers/video/fbdev/omap2/dss/hdmi4_core.c
new file mode 100644
index 000000000000..2eb04dcf807c
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.c
@@ -0,0 +1,1036 @@
1/*
2 * ti_hdmi_4xxx_ip.c
3 *
4 * HDMI TI81xx, TI38xx, TI OMAP4 etc IP driver Library
5 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
6 * Authors: Yong Zhi
7 * Mythri pk <mythripk@ti.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#define DSS_SUBSYS_NAME "HDMICORE"
23
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/err.h>
27#include <linux/io.h>
28#include <linux/interrupt.h>
29#include <linux/mutex.h>
30#include <linux/delay.h>
31#include <linux/platform_device.h>
32#include <linux/string.h>
33#include <linux/seq_file.h>
34#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
35#include <sound/asound.h>
36#include <sound/asoundef.h>
37#endif
38
39#include "hdmi4_core.h"
40#include "dss_features.h"
41
42#define HDMI_CORE_AV 0x500
43
44static inline void __iomem *hdmi_av_base(struct hdmi_core_data *core)
45{
46 return core->base + HDMI_CORE_AV;
47}
48
49static int hdmi_core_ddc_init(struct hdmi_core_data *core)
50{
51 void __iomem *base = core->base;
52
53 /* Turn on CLK for DDC */
54 REG_FLD_MOD(base, HDMI_CORE_AV_DPD, 0x7, 2, 0);
55
56 /* IN_PROG */
57 if (REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 1) {
58 /* Abort transaction */
59 REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xf, 3, 0);
60 /* IN_PROG */
61 if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
62 4, 4, 0) != 0) {
63 DSSERR("Timeout aborting DDC transaction\n");
64 return -ETIMEDOUT;
65 }
66 }
67
68 /* Clk SCL Devices */
69 REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xA, 3, 0);
70
71 /* HDMI_CORE_DDC_STATUS_IN_PROG */
72 if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
73 4, 4, 0) != 0) {
74 DSSERR("Timeout starting SCL clock\n");
75 return -ETIMEDOUT;
76 }
77
78 /* Clear FIFO */
79 REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x9, 3, 0);
80
81 /* HDMI_CORE_DDC_STATUS_IN_PROG */
82 if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
83 4, 4, 0) != 0) {
84 DSSERR("Timeout clearing DDC fifo\n");
85 return -ETIMEDOUT;
86 }
87
88 return 0;
89}
90
91static int hdmi_core_ddc_edid(struct hdmi_core_data *core,
92 u8 *pedid, int ext)
93{
94 void __iomem *base = core->base;
95 u32 i;
96 char checksum;
97 u32 offset = 0;
98
99 /* HDMI_CORE_DDC_STATUS_IN_PROG */
100 if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS,
101 4, 4, 0) != 0) {
102 DSSERR("Timeout waiting DDC to be ready\n");
103 return -ETIMEDOUT;
104 }
105
106 if (ext % 2 != 0)
107 offset = 0x80;
108
109 /* Load Segment Address Register */
110 REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, ext / 2, 7, 0);
111
112 /* Load Slave Address Register */
113 REG_FLD_MOD(base, HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1);
114
115 /* Load Offset Address Register */
116 REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, offset, 7, 0);
117
118 /* Load Byte Count */
119 REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, 0x80, 7, 0);
120 REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT2, 0x0, 1, 0);
121
122 /* Set DDC_CMD */
123 if (ext)
124 REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x4, 3, 0);
125 else
126 REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x2, 3, 0);
127
128 /* HDMI_CORE_DDC_STATUS_BUS_LOW */
129 if (REG_GET(base, HDMI_CORE_DDC_STATUS, 6, 6) == 1) {
130 DSSERR("I2C Bus Low?\n");
131 return -EIO;
132 }
133 /* HDMI_CORE_DDC_STATUS_NO_ACK */
134 if (REG_GET(base, HDMI_CORE_DDC_STATUS, 5, 5) == 1) {
135 DSSERR("I2C No Ack\n");
136 return -EIO;
137 }
138
139 for (i = 0; i < 0x80; ++i) {
140 int t;
141
142 /* IN_PROG */
143 if (REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 0) {
144 DSSERR("operation stopped when reading edid\n");
145 return -EIO;
146 }
147
148 t = 0;
149 /* FIFO_EMPTY */
150 while (REG_GET(base, HDMI_CORE_DDC_STATUS, 2, 2) == 1) {
151 if (t++ > 10000) {
152 DSSERR("timeout reading edid\n");
153 return -ETIMEDOUT;
154 }
155 udelay(1);
156 }
157
158 pedid[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0);
159 }
160
161 checksum = 0;
162 for (i = 0; i < 0x80; ++i)
163 checksum += pedid[i];
164
165 if (checksum != 0) {
166 DSSERR("E-EDID checksum failed!!\n");
167 return -EIO;
168 }
169
170 return 0;
171}
172
173int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len)
174{
175 int r, l;
176
177 if (len < 128)
178 return -EINVAL;
179
180 r = hdmi_core_ddc_init(core);
181 if (r)
182 return r;
183
184 r = hdmi_core_ddc_edid(core, edid, 0);
185 if (r)
186 return r;
187
188 l = 128;
189
190 if (len >= 128 * 2 && edid[0x7e] > 0) {
191 r = hdmi_core_ddc_edid(core, edid + 0x80, 1);
192 if (r)
193 return r;
194 l += 128;
195 }
196
197 return l;
198}
199
200static void hdmi_core_init(struct hdmi_core_video_config *video_cfg,
201 struct hdmi_core_infoframe_avi *avi_cfg,
202 struct hdmi_core_packet_enable_repeat *repeat_cfg)
203{
204 DSSDBG("Enter hdmi_core_init\n");
205
206 /* video core */
207 video_cfg->ip_bus_width = HDMI_INPUT_8BIT;
208 video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT;
209 video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE;
210 video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE;
211 video_cfg->hdmi_dvi = HDMI_DVI;
212 video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK;
213
214 /* info frame */
215 avi_cfg->db1_format = 0;
216 avi_cfg->db1_active_info = 0;
217 avi_cfg->db1_bar_info_dv = 0;
218 avi_cfg->db1_scan_info = 0;
219 avi_cfg->db2_colorimetry = 0;
220 avi_cfg->db2_aspect_ratio = 0;
221 avi_cfg->db2_active_fmt_ar = 0;
222 avi_cfg->db3_itc = 0;
223 avi_cfg->db3_ec = 0;
224 avi_cfg->db3_q_range = 0;
225 avi_cfg->db3_nup_scaling = 0;
226 avi_cfg->db4_videocode = 0;
227 avi_cfg->db5_pixel_repeat = 0;
228 avi_cfg->db6_7_line_eoftop = 0;
229 avi_cfg->db8_9_line_sofbottom = 0;
230 avi_cfg->db10_11_pixel_eofleft = 0;
231 avi_cfg->db12_13_pixel_sofright = 0;
232
233 /* packet enable and repeat */
234 repeat_cfg->audio_pkt = 0;
235 repeat_cfg->audio_pkt_repeat = 0;
236 repeat_cfg->avi_infoframe = 0;
237 repeat_cfg->avi_infoframe_repeat = 0;
238 repeat_cfg->gen_cntrl_pkt = 0;
239 repeat_cfg->gen_cntrl_pkt_repeat = 0;
240 repeat_cfg->generic_pkt = 0;
241 repeat_cfg->generic_pkt_repeat = 0;
242}
243
244static void hdmi_core_powerdown_disable(struct hdmi_core_data *core)
245{
246 DSSDBG("Enter hdmi_core_powerdown_disable\n");
247 REG_FLD_MOD(core->base, HDMI_CORE_SYS_SYS_CTRL1, 0x0, 0, 0);
248}
249
250static void hdmi_core_swreset_release(struct hdmi_core_data *core)
251{
252 DSSDBG("Enter hdmi_core_swreset_release\n");
253 REG_FLD_MOD(core->base, HDMI_CORE_SYS_SRST, 0x0, 0, 0);
254}
255
256static void hdmi_core_swreset_assert(struct hdmi_core_data *core)
257{
258 DSSDBG("Enter hdmi_core_swreset_assert\n");
259 REG_FLD_MOD(core->base, HDMI_CORE_SYS_SRST, 0x1, 0, 0);
260}
261
262/* HDMI_CORE_VIDEO_CONFIG */
263static void hdmi_core_video_config(struct hdmi_core_data *core,
264 struct hdmi_core_video_config *cfg)
265{
266 u32 r = 0;
267 void __iomem *core_sys_base = core->base;
268 void __iomem *core_av_base = hdmi_av_base(core);
269
270 /* sys_ctrl1 default configuration not tunable */
271 r = hdmi_read_reg(core_sys_base, HDMI_CORE_SYS_SYS_CTRL1);
272 r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_VEN_FOLLOWVSYNC, 5, 5);
273 r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_HEN_FOLLOWHSYNC, 4, 4);
274 r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_BSEL_24BITBUS, 2, 2);
275 r = FLD_MOD(r, HDMI_CORE_SYS_SYS_CTRL1_EDGE_RISINGEDGE, 1, 1);
276 hdmi_write_reg(core_sys_base, HDMI_CORE_SYS_SYS_CTRL1, r);
277
278 REG_FLD_MOD(core_sys_base,
279 HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6);
280
281 /* Vid_Mode */
282 r = hdmi_read_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE);
283
284 /* dither truncation configuration */
285 if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) {
286 r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6);
287 r = FLD_MOD(r, 1, 5, 5);
288 } else {
289 r = FLD_MOD(r, cfg->op_dither_truc, 7, 6);
290 r = FLD_MOD(r, 0, 5, 5);
291 }
292 hdmi_write_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE, r);
293
294 /* HDMI_Ctrl */
295 r = hdmi_read_reg(core_av_base, HDMI_CORE_AV_HDMI_CTRL);
296 r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6);
297 r = FLD_MOD(r, cfg->pkt_mode, 5, 3);
298 r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0);
299 hdmi_write_reg(core_av_base, HDMI_CORE_AV_HDMI_CTRL, r);
300
301 /* TMDS_CTRL */
302 REG_FLD_MOD(core_sys_base,
303 HDMI_CORE_SYS_TMDS_CTRL, cfg->tclk_sel_clkmult, 6, 5);
304}
305
306static void hdmi_core_aux_infoframe_avi_config(struct hdmi_core_data *core)
307{
308 u32 val;
309 char sum = 0, checksum = 0;
310 void __iomem *av_base = hdmi_av_base(core);
311 struct hdmi_core_infoframe_avi info_avi = core->avi_cfg;
312
313 sum += 0x82 + 0x002 + 0x00D;
314 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_TYPE, 0x082);
315 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_VERS, 0x002);
316 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_LEN, 0x00D);
317
318 val = (info_avi.db1_format << 5) |
319 (info_avi.db1_active_info << 4) |
320 (info_avi.db1_bar_info_dv << 2) |
321 (info_avi.db1_scan_info);
322 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(0), val);
323 sum += val;
324
325 val = (info_avi.db2_colorimetry << 6) |
326 (info_avi.db2_aspect_ratio << 4) |
327 (info_avi.db2_active_fmt_ar);
328 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(1), val);
329 sum += val;
330
331 val = (info_avi.db3_itc << 7) |
332 (info_avi.db3_ec << 4) |
333 (info_avi.db3_q_range << 2) |
334 (info_avi.db3_nup_scaling);
335 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(2), val);
336 sum += val;
337
338 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(3),
339 info_avi.db4_videocode);
340 sum += info_avi.db4_videocode;
341
342 val = info_avi.db5_pixel_repeat;
343 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(4), val);
344 sum += val;
345
346 val = info_avi.db6_7_line_eoftop & 0x00FF;
347 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(5), val);
348 sum += val;
349
350 val = ((info_avi.db6_7_line_eoftop >> 8) & 0x00FF);
351 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(6), val);
352 sum += val;
353
354 val = info_avi.db8_9_line_sofbottom & 0x00FF;
355 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(7), val);
356 sum += val;
357
358 val = ((info_avi.db8_9_line_sofbottom >> 8) & 0x00FF);
359 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(8), val);
360 sum += val;
361
362 val = info_avi.db10_11_pixel_eofleft & 0x00FF;
363 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(9), val);
364 sum += val;
365
366 val = ((info_avi.db10_11_pixel_eofleft >> 8) & 0x00FF);
367 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(10), val);
368 sum += val;
369
370 val = info_avi.db12_13_pixel_sofright & 0x00FF;
371 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(11), val);
372 sum += val;
373
374 val = ((info_avi.db12_13_pixel_sofright >> 8) & 0x00FF);
375 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(12), val);
376 sum += val;
377
378 checksum = 0x100 - sum;
379 hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_CHSUM, checksum);
380}
381
382static void hdmi_core_av_packet_config(struct hdmi_core_data *core,
383 struct hdmi_core_packet_enable_repeat repeat_cfg)
384{
385 /* enable/repeat the infoframe */
386 hdmi_write_reg(hdmi_av_base(core), HDMI_CORE_AV_PB_CTRL1,
387 (repeat_cfg.audio_pkt << 5) |
388 (repeat_cfg.audio_pkt_repeat << 4) |
389 (repeat_cfg.avi_infoframe << 1) |
390 (repeat_cfg.avi_infoframe_repeat));
391
392 /* enable/repeat the packet */
393 hdmi_write_reg(hdmi_av_base(core), HDMI_CORE_AV_PB_CTRL2,
394 (repeat_cfg.gen_cntrl_pkt << 3) |
395 (repeat_cfg.gen_cntrl_pkt_repeat << 2) |
396 (repeat_cfg.generic_pkt << 1) |
397 (repeat_cfg.generic_pkt_repeat));
398}
399
400void hdmi4_configure(struct hdmi_core_data *core,
401 struct hdmi_wp_data *wp, struct hdmi_config *cfg)
402{
403 /* HDMI */
404 struct omap_video_timings video_timing;
405 struct hdmi_video_format video_format;
406 /* HDMI core */
407 struct hdmi_core_infoframe_avi *avi_cfg = &core->avi_cfg;
408 struct hdmi_core_video_config v_core_cfg;
409 struct hdmi_core_packet_enable_repeat repeat_cfg;
410
411 hdmi_core_init(&v_core_cfg, avi_cfg, &repeat_cfg);
412
413 hdmi_wp_init_vid_fmt_timings(&video_format, &video_timing, cfg);
414
415 hdmi_wp_video_config_timing(wp, &video_timing);
416
417 /* video config */
418 video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422;
419
420 hdmi_wp_video_config_format(wp, &video_format);
421
422 hdmi_wp_video_config_interface(wp, &video_timing);
423
424 /*
425 * configure core video part
426 * set software reset in the core
427 */
428 hdmi_core_swreset_assert(core);
429
430 /* power down off */
431 hdmi_core_powerdown_disable(core);
432
433 v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL;
434 v_core_cfg.hdmi_dvi = cfg->cm.mode;
435
436 hdmi_core_video_config(core, &v_core_cfg);
437
438 /* release software reset in the core */
439 hdmi_core_swreset_release(core);
440
441 /*
442 * configure packet
443 * info frame video see doc CEA861-D page 65
444 */
445 avi_cfg->db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB;
446 avi_cfg->db1_active_info =
447 HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF;
448 avi_cfg->db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO;
449 avi_cfg->db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0;
450 avi_cfg->db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO;
451 avi_cfg->db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO;
452 avi_cfg->db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME;
453 avi_cfg->db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO;
454 avi_cfg->db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601;
455 avi_cfg->db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT;
456 avi_cfg->db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO;
457 avi_cfg->db4_videocode = cfg->cm.code;
458 avi_cfg->db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO;
459 avi_cfg->db6_7_line_eoftop = 0;
460 avi_cfg->db8_9_line_sofbottom = 0;
461 avi_cfg->db10_11_pixel_eofleft = 0;
462 avi_cfg->db12_13_pixel_sofright = 0;
463
464 hdmi_core_aux_infoframe_avi_config(core);
465
466 /* enable/repeat the infoframe */
467 repeat_cfg.avi_infoframe = HDMI_PACKETENABLE;
468 repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON;
469 /* wakeup */
470 repeat_cfg.audio_pkt = HDMI_PACKETENABLE;
471 repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON;
472 hdmi_core_av_packet_config(core, repeat_cfg);
473}
474
475void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s)
476{
477 int i;
478
479#define CORE_REG(i, name) name(i)
480#define DUMPCORE(r) seq_printf(s, "%-35s %08x\n", #r,\
481 hdmi_read_reg(core->base, r))
482#define DUMPCOREAV(r) seq_printf(s, "%-35s %08x\n", #r,\
483 hdmi_read_reg(hdmi_av_base(core), r))
484#define DUMPCOREAV2(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \
485 (i < 10) ? 32 - (int)strlen(#r) : 31 - (int)strlen(#r), " ", \
486 hdmi_read_reg(hdmi_av_base(core), CORE_REG(i, r)))
487
488 DUMPCORE(HDMI_CORE_SYS_VND_IDL);
489 DUMPCORE(HDMI_CORE_SYS_DEV_IDL);
490 DUMPCORE(HDMI_CORE_SYS_DEV_IDH);
491 DUMPCORE(HDMI_CORE_SYS_DEV_REV);
492 DUMPCORE(HDMI_CORE_SYS_SRST);
493 DUMPCORE(HDMI_CORE_SYS_SYS_CTRL1);
494 DUMPCORE(HDMI_CORE_SYS_SYS_STAT);
495 DUMPCORE(HDMI_CORE_SYS_SYS_CTRL3);
496 DUMPCORE(HDMI_CORE_SYS_DE_DLY);
497 DUMPCORE(HDMI_CORE_SYS_DE_CTRL);
498 DUMPCORE(HDMI_CORE_SYS_DE_TOP);
499 DUMPCORE(HDMI_CORE_SYS_DE_CNTL);
500 DUMPCORE(HDMI_CORE_SYS_DE_CNTH);
501 DUMPCORE(HDMI_CORE_SYS_DE_LINL);
502 DUMPCORE(HDMI_CORE_SYS_DE_LINH_1);
503 DUMPCORE(HDMI_CORE_SYS_HRES_L);
504 DUMPCORE(HDMI_CORE_SYS_HRES_H);
505 DUMPCORE(HDMI_CORE_SYS_VRES_L);
506 DUMPCORE(HDMI_CORE_SYS_VRES_H);
507 DUMPCORE(HDMI_CORE_SYS_IADJUST);
508 DUMPCORE(HDMI_CORE_SYS_POLDETECT);
509 DUMPCORE(HDMI_CORE_SYS_HWIDTH1);
510 DUMPCORE(HDMI_CORE_SYS_HWIDTH2);
511 DUMPCORE(HDMI_CORE_SYS_VWIDTH);
512 DUMPCORE(HDMI_CORE_SYS_VID_CTRL);
513 DUMPCORE(HDMI_CORE_SYS_VID_ACEN);
514 DUMPCORE(HDMI_CORE_SYS_VID_MODE);
515 DUMPCORE(HDMI_CORE_SYS_VID_BLANK1);
516 DUMPCORE(HDMI_CORE_SYS_VID_BLANK3);
517 DUMPCORE(HDMI_CORE_SYS_VID_BLANK1);
518 DUMPCORE(HDMI_CORE_SYS_DC_HEADER);
519 DUMPCORE(HDMI_CORE_SYS_VID_DITHER);
520 DUMPCORE(HDMI_CORE_SYS_RGB2XVYCC_CT);
521 DUMPCORE(HDMI_CORE_SYS_R2Y_COEFF_LOW);
522 DUMPCORE(HDMI_CORE_SYS_R2Y_COEFF_UP);
523 DUMPCORE(HDMI_CORE_SYS_G2Y_COEFF_LOW);
524 DUMPCORE(HDMI_CORE_SYS_G2Y_COEFF_UP);
525 DUMPCORE(HDMI_CORE_SYS_B2Y_COEFF_LOW);
526 DUMPCORE(HDMI_CORE_SYS_B2Y_COEFF_UP);
527 DUMPCORE(HDMI_CORE_SYS_R2CB_COEFF_LOW);
528 DUMPCORE(HDMI_CORE_SYS_R2CB_COEFF_UP);
529 DUMPCORE(HDMI_CORE_SYS_G2CB_COEFF_LOW);
530 DUMPCORE(HDMI_CORE_SYS_G2CB_COEFF_UP);
531 DUMPCORE(HDMI_CORE_SYS_B2CB_COEFF_LOW);
532 DUMPCORE(HDMI_CORE_SYS_B2CB_COEFF_UP);
533 DUMPCORE(HDMI_CORE_SYS_R2CR_COEFF_LOW);
534 DUMPCORE(HDMI_CORE_SYS_R2CR_COEFF_UP);
535 DUMPCORE(HDMI_CORE_SYS_G2CR_COEFF_LOW);
536 DUMPCORE(HDMI_CORE_SYS_G2CR_COEFF_UP);
537 DUMPCORE(HDMI_CORE_SYS_B2CR_COEFF_LOW);
538 DUMPCORE(HDMI_CORE_SYS_B2CR_COEFF_UP);
539 DUMPCORE(HDMI_CORE_SYS_RGB_OFFSET_LOW);
540 DUMPCORE(HDMI_CORE_SYS_RGB_OFFSET_UP);
541 DUMPCORE(HDMI_CORE_SYS_Y_OFFSET_LOW);
542 DUMPCORE(HDMI_CORE_SYS_Y_OFFSET_UP);
543 DUMPCORE(HDMI_CORE_SYS_CBCR_OFFSET_LOW);
544 DUMPCORE(HDMI_CORE_SYS_CBCR_OFFSET_UP);
545 DUMPCORE(HDMI_CORE_SYS_INTR_STATE);
546 DUMPCORE(HDMI_CORE_SYS_INTR1);
547 DUMPCORE(HDMI_CORE_SYS_INTR2);
548 DUMPCORE(HDMI_CORE_SYS_INTR3);
549 DUMPCORE(HDMI_CORE_SYS_INTR4);
550 DUMPCORE(HDMI_CORE_SYS_INTR_UNMASK1);
551 DUMPCORE(HDMI_CORE_SYS_INTR_UNMASK2);
552 DUMPCORE(HDMI_CORE_SYS_INTR_UNMASK3);
553 DUMPCORE(HDMI_CORE_SYS_INTR_UNMASK4);
554 DUMPCORE(HDMI_CORE_SYS_INTR_CTRL);
555 DUMPCORE(HDMI_CORE_SYS_TMDS_CTRL);
556
557 DUMPCORE(HDMI_CORE_DDC_ADDR);
558 DUMPCORE(HDMI_CORE_DDC_SEGM);
559 DUMPCORE(HDMI_CORE_DDC_OFFSET);
560 DUMPCORE(HDMI_CORE_DDC_COUNT1);
561 DUMPCORE(HDMI_CORE_DDC_COUNT2);
562 DUMPCORE(HDMI_CORE_DDC_STATUS);
563 DUMPCORE(HDMI_CORE_DDC_CMD);
564 DUMPCORE(HDMI_CORE_DDC_DATA);
565
566 DUMPCOREAV(HDMI_CORE_AV_ACR_CTRL);
567 DUMPCOREAV(HDMI_CORE_AV_FREQ_SVAL);
568 DUMPCOREAV(HDMI_CORE_AV_N_SVAL1);
569 DUMPCOREAV(HDMI_CORE_AV_N_SVAL2);
570 DUMPCOREAV(HDMI_CORE_AV_N_SVAL3);
571 DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL1);
572 DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL2);
573 DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL3);
574 DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL1);
575 DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL2);
576 DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL3);
577 DUMPCOREAV(HDMI_CORE_AV_AUD_MODE);
578 DUMPCOREAV(HDMI_CORE_AV_SPDIF_CTRL);
579 DUMPCOREAV(HDMI_CORE_AV_HW_SPDIF_FS);
580 DUMPCOREAV(HDMI_CORE_AV_SWAP_I2S);
581 DUMPCOREAV(HDMI_CORE_AV_SPDIF_ERTH);
582 DUMPCOREAV(HDMI_CORE_AV_I2S_IN_MAP);
583 DUMPCOREAV(HDMI_CORE_AV_I2S_IN_CTRL);
584 DUMPCOREAV(HDMI_CORE_AV_I2S_CHST0);
585 DUMPCOREAV(HDMI_CORE_AV_I2S_CHST1);
586 DUMPCOREAV(HDMI_CORE_AV_I2S_CHST2);
587 DUMPCOREAV(HDMI_CORE_AV_I2S_CHST4);
588 DUMPCOREAV(HDMI_CORE_AV_I2S_CHST5);
589 DUMPCOREAV(HDMI_CORE_AV_ASRC);
590 DUMPCOREAV(HDMI_CORE_AV_I2S_IN_LEN);
591 DUMPCOREAV(HDMI_CORE_AV_HDMI_CTRL);
592 DUMPCOREAV(HDMI_CORE_AV_AUDO_TXSTAT);
593 DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_1);
594 DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_2);
595 DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_3);
596 DUMPCOREAV(HDMI_CORE_AV_TEST_TXCTRL);
597 DUMPCOREAV(HDMI_CORE_AV_DPD);
598 DUMPCOREAV(HDMI_CORE_AV_PB_CTRL1);
599 DUMPCOREAV(HDMI_CORE_AV_PB_CTRL2);
600 DUMPCOREAV(HDMI_CORE_AV_AVI_TYPE);
601 DUMPCOREAV(HDMI_CORE_AV_AVI_VERS);
602 DUMPCOREAV(HDMI_CORE_AV_AVI_LEN);
603 DUMPCOREAV(HDMI_CORE_AV_AVI_CHSUM);
604
605 for (i = 0; i < HDMI_CORE_AV_AVI_DBYTE_NELEMS; i++)
606 DUMPCOREAV2(i, HDMI_CORE_AV_AVI_DBYTE);
607
608 DUMPCOREAV(HDMI_CORE_AV_SPD_TYPE);
609 DUMPCOREAV(HDMI_CORE_AV_SPD_VERS);
610 DUMPCOREAV(HDMI_CORE_AV_SPD_LEN);
611 DUMPCOREAV(HDMI_CORE_AV_SPD_CHSUM);
612
613 for (i = 0; i < HDMI_CORE_AV_SPD_DBYTE_NELEMS; i++)
614 DUMPCOREAV2(i, HDMI_CORE_AV_SPD_DBYTE);
615
616 DUMPCOREAV(HDMI_CORE_AV_AUDIO_TYPE);
617 DUMPCOREAV(HDMI_CORE_AV_AUDIO_VERS);
618 DUMPCOREAV(HDMI_CORE_AV_AUDIO_LEN);
619 DUMPCOREAV(HDMI_CORE_AV_AUDIO_CHSUM);
620
621 for (i = 0; i < HDMI_CORE_AV_AUD_DBYTE_NELEMS; i++)
622 DUMPCOREAV2(i, HDMI_CORE_AV_AUD_DBYTE);
623
624 DUMPCOREAV(HDMI_CORE_AV_MPEG_TYPE);
625 DUMPCOREAV(HDMI_CORE_AV_MPEG_VERS);
626 DUMPCOREAV(HDMI_CORE_AV_MPEG_LEN);
627 DUMPCOREAV(HDMI_CORE_AV_MPEG_CHSUM);
628
629 for (i = 0; i < HDMI_CORE_AV_MPEG_DBYTE_NELEMS; i++)
630 DUMPCOREAV2(i, HDMI_CORE_AV_MPEG_DBYTE);
631
632 for (i = 0; i < HDMI_CORE_AV_GEN_DBYTE_NELEMS; i++)
633 DUMPCOREAV2(i, HDMI_CORE_AV_GEN_DBYTE);
634
635 DUMPCOREAV(HDMI_CORE_AV_CP_BYTE1);
636
637 for (i = 0; i < HDMI_CORE_AV_GEN2_DBYTE_NELEMS; i++)
638 DUMPCOREAV2(i, HDMI_CORE_AV_GEN2_DBYTE);
639
640 DUMPCOREAV(HDMI_CORE_AV_CEC_ADDR_ID);
641}
642
643#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
644static void hdmi_core_audio_config(struct hdmi_core_data *core,
645 struct hdmi_core_audio_config *cfg)
646{
647 u32 r;
648 void __iomem *av_base = hdmi_av_base(core);
649
650 /*
651 * Parameters for generation of Audio Clock Recovery packets
652 */
653 REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0);
654 REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0);
655 REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0);
656
657 if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) {
658 REG_FLD_MOD(av_base, HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0);
659 REG_FLD_MOD(av_base,
660 HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0);
661 REG_FLD_MOD(av_base,
662 HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0);
663 } else {
664 REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_1,
665 cfg->aud_par_busclk, 7, 0);
666 REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_2,
667 (cfg->aud_par_busclk >> 8), 7, 0);
668 REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_3,
669 (cfg->aud_par_busclk >> 16), 7, 0);
670 }
671
672 /* Set ACR clock divisor */
673 REG_FLD_MOD(av_base,
674 HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0);
675
676 r = hdmi_read_reg(av_base, HDMI_CORE_AV_ACR_CTRL);
677 /*
678 * Use TMDS clock for ACR packets. For devices that use
679 * the MCLK, this is the first part of the MCLK initialization.
680 */
681 r = FLD_MOD(r, 0, 2, 2);
682
683 r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1);
684 r = FLD_MOD(r, cfg->cts_mode, 0, 0);
685 hdmi_write_reg(av_base, HDMI_CORE_AV_ACR_CTRL, r);
686
687 /* For devices using MCLK, this completes its initialization. */
688 if (cfg->use_mclk)
689 REG_FLD_MOD(av_base, HDMI_CORE_AV_ACR_CTRL, 1, 2, 2);
690
691 /* Override of SPDIF sample frequency with value in I2S_CHST4 */
692 REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL,
693 cfg->fs_override, 1, 1);
694
695 /*
696 * Set IEC-60958-3 channel status word. It is passed to the IP
697 * just as it is received. The user of the driver is responsible
698 * for its contents.
699 */
700 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST0,
701 cfg->iec60958_cfg->status[0]);
702 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST1,
703 cfg->iec60958_cfg->status[1]);
704 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST2,
705 cfg->iec60958_cfg->status[2]);
706 /* yes, this is correct: status[3] goes to CHST4 register */
707 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST4,
708 cfg->iec60958_cfg->status[3]);
709 /* yes, this is correct: status[4] goes to CHST5 register */
710 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5,
711 cfg->iec60958_cfg->status[4]);
712
713 /* set I2S parameters */
714 r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL);
715 r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6);
716 r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4);
717 r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2);
718 r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1);
719 r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0);
720 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL, r);
721
722 REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_IN_LEN,
723 cfg->i2s_cfg.in_length_bits, 3, 0);
724
725 /* Audio channels and mode parameters */
726 REG_FLD_MOD(av_base, HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1);
727 r = hdmi_read_reg(av_base, HDMI_CORE_AV_AUD_MODE);
728 r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4);
729 r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3);
730 r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2);
731 r = FLD_MOD(r, cfg->en_spdif, 1, 1);
732 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r);
733
734 /* Audio channel mappings */
735 /* TODO: Make channel mapping dynamic. For now, map channels
736 * in the ALSA order: FL/FR/RL/RR/C/LFE/SL/SR. Remapping is needed as
737 * HDMI speaker order is different. See CEA-861 Section 6.6.2.
738 */
739 hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_MAP, 0x78);
740 REG_FLD_MOD(av_base, HDMI_CORE_AV_SWAP_I2S, 1, 5, 5);
741}
742
743static void hdmi_core_audio_infoframe_cfg(struct hdmi_core_data *core,
744 struct snd_cea_861_aud_if *info_aud)
745{
746 u8 sum = 0, checksum = 0;
747 void __iomem *av_base = hdmi_av_base(core);
748
749 /*
750 * Set audio info frame type, version and length as
751 * described in HDMI 1.4a Section 8.2.2 specification.
752 * Checksum calculation is defined in Section 5.3.5.
753 */
754 hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_TYPE, 0x84);
755 hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_VERS, 0x01);
756 hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_LEN, 0x0a);
757 sum += 0x84 + 0x001 + 0x00a;
758
759 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0),
760 info_aud->db1_ct_cc);
761 sum += info_aud->db1_ct_cc;
762
763 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1),
764 info_aud->db2_sf_ss);
765 sum += info_aud->db2_sf_ss;
766
767 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), info_aud->db3);
768 sum += info_aud->db3;
769
770 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), info_aud->db4_ca);
771 sum += info_aud->db4_ca;
772
773 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4),
774 info_aud->db5_dminh_lsv);
775 sum += info_aud->db5_dminh_lsv;
776
777 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(5), 0x00);
778 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(6), 0x00);
779 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(7), 0x00);
780 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(8), 0x00);
781 hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(9), 0x00);
782
783 checksum = 0x100 - sum;
784 hdmi_write_reg(av_base,
785 HDMI_CORE_AV_AUDIO_CHSUM, checksum);
786
787 /*
788 * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing
789 * is available.
790 */
791}
792
793int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
794 struct omap_dss_audio *audio, u32 pclk)
795{
796 struct hdmi_audio_format audio_format;
797 struct hdmi_audio_dma audio_dma;
798 struct hdmi_core_audio_config acore;
799 int err, n, cts, channel_count;
800 unsigned int fs_nr;
801 bool word_length_16b = false;
802
803 if (!audio || !audio->iec || !audio->cea || !core)
804 return -EINVAL;
805
806 acore.iec60958_cfg = audio->iec;
807 /*
808 * In the IEC-60958 status word, check if the audio sample word length
809 * is 16-bit as several optimizations can be performed in such case.
810 */
811 if (!(audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24))
812 if (audio->iec->status[4] & IEC958_AES4_CON_WORDLEN_20_16)
813 word_length_16b = true;
814
815 /* I2S configuration. See Phillips' specification */
816 if (word_length_16b)
817 acore.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT;
818 else
819 acore.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
820 /*
821 * The I2S input word length is twice the lenght given in the IEC-60958
822 * status word. If the word size is greater than
823 * 20 bits, increment by one.
824 */
825 acore.i2s_cfg.in_length_bits = audio->iec->status[4]
826 & IEC958_AES4_CON_WORDLEN;
827 if (audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24)
828 acore.i2s_cfg.in_length_bits++;
829 acore.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING;
830 acore.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM;
831 acore.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST;
832 acore.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT;
833
834 /* convert sample frequency to a number */
835 switch (audio->iec->status[3] & IEC958_AES3_CON_FS) {
836 case IEC958_AES3_CON_FS_32000:
837 fs_nr = 32000;
838 break;
839 case IEC958_AES3_CON_FS_44100:
840 fs_nr = 44100;
841 break;
842 case IEC958_AES3_CON_FS_48000:
843 fs_nr = 48000;
844 break;
845 case IEC958_AES3_CON_FS_88200:
846 fs_nr = 88200;
847 break;
848 case IEC958_AES3_CON_FS_96000:
849 fs_nr = 96000;
850 break;
851 case IEC958_AES3_CON_FS_176400:
852 fs_nr = 176400;
853 break;
854 case IEC958_AES3_CON_FS_192000:
855 fs_nr = 192000;
856 break;
857 default:
858 return -EINVAL;
859 }
860
861 err = hdmi_compute_acr(pclk, fs_nr, &n, &cts);
862
863 /* Audio clock regeneration settings */
864 acore.n = n;
865 acore.cts = cts;
866 if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) {
867 acore.aud_par_busclk = 0;
868 acore.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
869 acore.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK);
870 } else {
871 acore.aud_par_busclk = (((128 * 31) - 1) << 8);
872 acore.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
873 acore.use_mclk = true;
874 }
875
876 if (acore.use_mclk)
877 acore.mclk_mode = HDMI_AUDIO_MCLK_128FS;
878
879 /* Audio channels settings */
880 channel_count = (audio->cea->db1_ct_cc &
881 CEA861_AUDIO_INFOFRAME_DB1CC) + 1;
882
883 switch (channel_count) {
884 case 2:
885 audio_format.active_chnnls_msk = 0x03;
886 break;
887 case 3:
888 audio_format.active_chnnls_msk = 0x07;
889 break;
890 case 4:
891 audio_format.active_chnnls_msk = 0x0f;
892 break;
893 case 5:
894 audio_format.active_chnnls_msk = 0x1f;
895 break;
896 case 6:
897 audio_format.active_chnnls_msk = 0x3f;
898 break;
899 case 7:
900 audio_format.active_chnnls_msk = 0x7f;
901 break;
902 case 8:
903 audio_format.active_chnnls_msk = 0xff;
904 break;
905 default:
906 return -EINVAL;
907 }
908
909 /*
910 * the HDMI IP needs to enable four stereo channels when transmitting
911 * more than 2 audio channels
912 */
913 if (channel_count == 2) {
914 audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL;
915 acore.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN;
916 acore.layout = HDMI_AUDIO_LAYOUT_2CH;
917 } else {
918 audio_format.stereo_channels = HDMI_AUDIO_STEREO_FOURCHANNELS;
919 acore.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN |
920 HDMI_AUDIO_I2S_SD1_EN | HDMI_AUDIO_I2S_SD2_EN |
921 HDMI_AUDIO_I2S_SD3_EN;
922 acore.layout = HDMI_AUDIO_LAYOUT_8CH;
923 }
924
925 acore.en_spdif = false;
926 /* use sample frequency from channel status word */
927 acore.fs_override = true;
928 /* enable ACR packets */
929 acore.en_acr_pkt = true;
930 /* disable direct streaming digital audio */
931 acore.en_dsd_audio = false;
932 /* use parallel audio interface */
933 acore.en_parallel_aud_input = true;
934
935 /* DMA settings */
936 if (word_length_16b)
937 audio_dma.transfer_size = 0x10;
938 else
939 audio_dma.transfer_size = 0x20;
940 audio_dma.block_size = 0xC0;
941 audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
942 audio_dma.fifo_threshold = 0x20; /* in number of samples */
943
944 /* audio FIFO format settings */
945 if (word_length_16b) {
946 audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
947 audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
948 audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
949 } else {
950 audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE;
951 audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS;
952 audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
953 }
954 audio_format.type = HDMI_AUDIO_TYPE_LPCM;
955 audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
956 /* disable start/stop signals of IEC 60958 blocks */
957 audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
958
959 /* configure DMA and audio FIFO format*/
960 hdmi_wp_audio_config_dma(wp, &audio_dma);
961 hdmi_wp_audio_config_format(wp, &audio_format);
962
963 /* configure the core*/
964 hdmi_core_audio_config(core, &acore);
965
966 /* configure CEA 861 audio infoframe*/
967 hdmi_core_audio_infoframe_cfg(core, audio->cea);
968
969 return 0;
970}
971
972int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp)
973{
974 REG_FLD_MOD(hdmi_av_base(core),
975 HDMI_CORE_AV_AUD_MODE, true, 0, 0);
976
977 hdmi_wp_audio_core_req_enable(wp, true);
978
979 return 0;
980}
981
982void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp)
983{
984 REG_FLD_MOD(hdmi_av_base(core),
985 HDMI_CORE_AV_AUD_MODE, false, 0, 0);
986
987 hdmi_wp_audio_core_req_enable(wp, false);
988}
989
990int hdmi4_audio_get_dma_port(u32 *offset, u32 *size)
991{
992 if (!offset || !size)
993 return -EINVAL;
994 *offset = HDMI_WP_AUDIO_DATA;
995 *size = 4;
996 return 0;
997}
998
999#endif
1000
1001#define CORE_OFFSET 0x400
1002#define CORE_SIZE 0xc00
1003
1004int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
1005{
1006 struct resource *res;
1007 struct resource temp_res;
1008
1009 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
1010 if (!res) {
1011 DSSDBG("can't get CORE mem resource by name\n");
1012 /*
1013 * if hwmod/DT doesn't have the memory resource information
1014 * split into HDMI sub blocks by name, we try again by getting
1015 * the platform's first resource. this code will be removed when
1016 * the driver can get the mem resources by name
1017 */
1018 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1019 if (!res) {
1020 DSSERR("can't get CORE mem resource\n");
1021 return -EINVAL;
1022 }
1023
1024 temp_res.start = res->start + CORE_OFFSET;
1025 temp_res.end = temp_res.start + CORE_SIZE - 1;
1026 res = &temp_res;
1027 }
1028
1029 core->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
1030 if (!core->base) {
1031 DSSERR("can't ioremap CORE\n");
1032 return -ENOMEM;
1033 }
1034
1035 return 0;
1036}
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.h b/drivers/video/fbdev/omap2/dss/hdmi4_core.h
new file mode 100644
index 000000000000..bb646896fa82
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.h
@@ -0,0 +1,276 @@
1/*
2 * HDMI header definition for OMAP4 HDMI core IP
3 *
4 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef _HDMI4_CORE_H_
20#define _HDMI4_CORE_H_
21
22#include "hdmi.h"
23
24/* OMAP4 HDMI IP Core System */
25
26#define HDMI_CORE_SYS_VND_IDL 0x0
27#define HDMI_CORE_SYS_DEV_IDL 0x8
28#define HDMI_CORE_SYS_DEV_IDH 0xC
29#define HDMI_CORE_SYS_DEV_REV 0x10
30#define HDMI_CORE_SYS_SRST 0x14
31#define HDMI_CORE_SYS_SYS_CTRL1 0x20
32#define HDMI_CORE_SYS_SYS_STAT 0x24
33#define HDMI_CORE_SYS_SYS_CTRL3 0x28
34#define HDMI_CORE_SYS_DCTL 0x34
35#define HDMI_CORE_SYS_DE_DLY 0xC8
36#define HDMI_CORE_SYS_DE_CTRL 0xCC
37#define HDMI_CORE_SYS_DE_TOP 0xD0
38#define HDMI_CORE_SYS_DE_CNTL 0xD8
39#define HDMI_CORE_SYS_DE_CNTH 0xDC
40#define HDMI_CORE_SYS_DE_LINL 0xE0
41#define HDMI_CORE_SYS_DE_LINH_1 0xE4
42#define HDMI_CORE_SYS_HRES_L 0xE8
43#define HDMI_CORE_SYS_HRES_H 0xEC
44#define HDMI_CORE_SYS_VRES_L 0xF0
45#define HDMI_CORE_SYS_VRES_H 0xF4
46#define HDMI_CORE_SYS_IADJUST 0xF8
47#define HDMI_CORE_SYS_POLDETECT 0xFC
48#define HDMI_CORE_SYS_HWIDTH1 0x110
49#define HDMI_CORE_SYS_HWIDTH2 0x114
50#define HDMI_CORE_SYS_VWIDTH 0x11C
51#define HDMI_CORE_SYS_VID_CTRL 0x120
52#define HDMI_CORE_SYS_VID_ACEN 0x124
53#define HDMI_CORE_SYS_VID_MODE 0x128
54#define HDMI_CORE_SYS_VID_BLANK1 0x12C
55#define HDMI_CORE_SYS_VID_BLANK2 0x130
56#define HDMI_CORE_SYS_VID_BLANK3 0x134
57#define HDMI_CORE_SYS_DC_HEADER 0x138
58#define HDMI_CORE_SYS_VID_DITHER 0x13C
59#define HDMI_CORE_SYS_RGB2XVYCC_CT 0x140
60#define HDMI_CORE_SYS_R2Y_COEFF_LOW 0x144
61#define HDMI_CORE_SYS_R2Y_COEFF_UP 0x148
62#define HDMI_CORE_SYS_G2Y_COEFF_LOW 0x14C
63#define HDMI_CORE_SYS_G2Y_COEFF_UP 0x150
64#define HDMI_CORE_SYS_B2Y_COEFF_LOW 0x154
65#define HDMI_CORE_SYS_B2Y_COEFF_UP 0x158
66#define HDMI_CORE_SYS_R2CB_COEFF_LOW 0x15C
67#define HDMI_CORE_SYS_R2CB_COEFF_UP 0x160
68#define HDMI_CORE_SYS_G2CB_COEFF_LOW 0x164
69#define HDMI_CORE_SYS_G2CB_COEFF_UP 0x168
70#define HDMI_CORE_SYS_B2CB_COEFF_LOW 0x16C
71#define HDMI_CORE_SYS_B2CB_COEFF_UP 0x170
72#define HDMI_CORE_SYS_R2CR_COEFF_LOW 0x174
73#define HDMI_CORE_SYS_R2CR_COEFF_UP 0x178
74#define HDMI_CORE_SYS_G2CR_COEFF_LOW 0x17C
75#define HDMI_CORE_SYS_G2CR_COEFF_UP 0x180
76#define HDMI_CORE_SYS_B2CR_COEFF_LOW 0x184
77#define HDMI_CORE_SYS_B2CR_COEFF_UP 0x188
78#define HDMI_CORE_SYS_RGB_OFFSET_LOW 0x18C
79#define HDMI_CORE_SYS_RGB_OFFSET_UP 0x190
80#define HDMI_CORE_SYS_Y_OFFSET_LOW 0x194
81#define HDMI_CORE_SYS_Y_OFFSET_UP 0x198
82#define HDMI_CORE_SYS_CBCR_OFFSET_LOW 0x19C
83#define HDMI_CORE_SYS_CBCR_OFFSET_UP 0x1A0
84#define HDMI_CORE_SYS_INTR_STATE 0x1C0
85#define HDMI_CORE_SYS_INTR1 0x1C4
86#define HDMI_CORE_SYS_INTR2 0x1C8
87#define HDMI_CORE_SYS_INTR3 0x1CC
88#define HDMI_CORE_SYS_INTR4 0x1D0
89#define HDMI_CORE_SYS_INTR_UNMASK1 0x1D4
90#define HDMI_CORE_SYS_INTR_UNMASK2 0x1D8
91#define HDMI_CORE_SYS_INTR_UNMASK3 0x1DC
92#define HDMI_CORE_SYS_INTR_UNMASK4 0x1E0
93#define HDMI_CORE_SYS_INTR_CTRL 0x1E4
94#define HDMI_CORE_SYS_TMDS_CTRL 0x208
95
96/* value definitions for HDMI_CORE_SYS_SYS_CTRL1 fields */
97#define HDMI_CORE_SYS_SYS_CTRL1_VEN_FOLLOWVSYNC 0x1
98#define HDMI_CORE_SYS_SYS_CTRL1_HEN_FOLLOWHSYNC 0x1
99#define HDMI_CORE_SYS_SYS_CTRL1_BSEL_24BITBUS 0x1
100#define HDMI_CORE_SYS_SYS_CTRL1_EDGE_RISINGEDGE 0x1
101
102/* HDMI DDC E-DID */
103#define HDMI_CORE_DDC_ADDR 0x3B4
104#define HDMI_CORE_DDC_SEGM 0x3B8
105#define HDMI_CORE_DDC_OFFSET 0x3BC
106#define HDMI_CORE_DDC_COUNT1 0x3C0
107#define HDMI_CORE_DDC_COUNT2 0x3C4
108#define HDMI_CORE_DDC_STATUS 0x3C8
109#define HDMI_CORE_DDC_CMD 0x3CC
110#define HDMI_CORE_DDC_DATA 0x3D0
111
112/* HDMI IP Core Audio Video */
113
114#define HDMI_CORE_AV_ACR_CTRL 0x4
115#define HDMI_CORE_AV_FREQ_SVAL 0x8
116#define HDMI_CORE_AV_N_SVAL1 0xC
117#define HDMI_CORE_AV_N_SVAL2 0x10
118#define HDMI_CORE_AV_N_SVAL3 0x14
119#define HDMI_CORE_AV_CTS_SVAL1 0x18
120#define HDMI_CORE_AV_CTS_SVAL2 0x1C
121#define HDMI_CORE_AV_CTS_SVAL3 0x20
122#define HDMI_CORE_AV_CTS_HVAL1 0x24
123#define HDMI_CORE_AV_CTS_HVAL2 0x28
124#define HDMI_CORE_AV_CTS_HVAL3 0x2C
125#define HDMI_CORE_AV_AUD_MODE 0x50
126#define HDMI_CORE_AV_SPDIF_CTRL 0x54
127#define HDMI_CORE_AV_HW_SPDIF_FS 0x60
128#define HDMI_CORE_AV_SWAP_I2S 0x64
129#define HDMI_CORE_AV_SPDIF_ERTH 0x6C
130#define HDMI_CORE_AV_I2S_IN_MAP 0x70
131#define HDMI_CORE_AV_I2S_IN_CTRL 0x74
132#define HDMI_CORE_AV_I2S_CHST0 0x78
133#define HDMI_CORE_AV_I2S_CHST1 0x7C
134#define HDMI_CORE_AV_I2S_CHST2 0x80
135#define HDMI_CORE_AV_I2S_CHST4 0x84
136#define HDMI_CORE_AV_I2S_CHST5 0x88
137#define HDMI_CORE_AV_ASRC 0x8C
138#define HDMI_CORE_AV_I2S_IN_LEN 0x90
139#define HDMI_CORE_AV_HDMI_CTRL 0xBC
140#define HDMI_CORE_AV_AUDO_TXSTAT 0xC0
141#define HDMI_CORE_AV_AUD_PAR_BUSCLK_1 0xCC
142#define HDMI_CORE_AV_AUD_PAR_BUSCLK_2 0xD0
143#define HDMI_CORE_AV_AUD_PAR_BUSCLK_3 0xD4
144#define HDMI_CORE_AV_TEST_TXCTRL 0xF0
145#define HDMI_CORE_AV_DPD 0xF4
146#define HDMI_CORE_AV_PB_CTRL1 0xF8
147#define HDMI_CORE_AV_PB_CTRL2 0xFC
148#define HDMI_CORE_AV_AVI_TYPE 0x100
149#define HDMI_CORE_AV_AVI_VERS 0x104
150#define HDMI_CORE_AV_AVI_LEN 0x108
151#define HDMI_CORE_AV_AVI_CHSUM 0x10C
152#define HDMI_CORE_AV_AVI_DBYTE(n) (n * 4 + 0x110)
153#define HDMI_CORE_AV_SPD_TYPE 0x180
154#define HDMI_CORE_AV_SPD_VERS 0x184
155#define HDMI_CORE_AV_SPD_LEN 0x188
156#define HDMI_CORE_AV_SPD_CHSUM 0x18C
157#define HDMI_CORE_AV_SPD_DBYTE(n) (n * 4 + 0x190)
158#define HDMI_CORE_AV_AUDIO_TYPE 0x200
159#define HDMI_CORE_AV_AUDIO_VERS 0x204
160#define HDMI_CORE_AV_AUDIO_LEN 0x208
161#define HDMI_CORE_AV_AUDIO_CHSUM 0x20C
162#define HDMI_CORE_AV_AUD_DBYTE(n) (n * 4 + 0x210)
163#define HDMI_CORE_AV_MPEG_TYPE 0x280
164#define HDMI_CORE_AV_MPEG_VERS 0x284
165#define HDMI_CORE_AV_MPEG_LEN 0x288
166#define HDMI_CORE_AV_MPEG_CHSUM 0x28C
167#define HDMI_CORE_AV_MPEG_DBYTE(n) (n * 4 + 0x290)
168#define HDMI_CORE_AV_GEN_DBYTE(n) (n * 4 + 0x300)
169#define HDMI_CORE_AV_CP_BYTE1 0x37C
170#define HDMI_CORE_AV_GEN2_DBYTE(n) (n * 4 + 0x380)
171#define HDMI_CORE_AV_CEC_ADDR_ID 0x3FC
172
173#define HDMI_CORE_AV_SPD_DBYTE_ELSIZE 0x4
174#define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE 0x4
175#define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE 0x4
176#define HDMI_CORE_AV_GEN_DBYTE_ELSIZE 0x4
177
178#define HDMI_CORE_AV_AVI_DBYTE_NELEMS 15
179#define HDMI_CORE_AV_SPD_DBYTE_NELEMS 27
180#define HDMI_CORE_AV_AUD_DBYTE_NELEMS 10
181#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS 27
182#define HDMI_CORE_AV_GEN_DBYTE_NELEMS 31
183#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS 31
184
185enum hdmi_core_inputbus_width {
186 HDMI_INPUT_8BIT = 0,
187 HDMI_INPUT_10BIT = 1,
188 HDMI_INPUT_12BIT = 2
189};
190
191enum hdmi_core_dither_trunc {
192 HDMI_OUTPUTTRUNCATION_8BIT = 0,
193 HDMI_OUTPUTTRUNCATION_10BIT = 1,
194 HDMI_OUTPUTTRUNCATION_12BIT = 2,
195 HDMI_OUTPUTDITHER_8BIT = 3,
196 HDMI_OUTPUTDITHER_10BIT = 4,
197 HDMI_OUTPUTDITHER_12BIT = 5
198};
199
200enum hdmi_core_deepcolor_ed {
201 HDMI_DEEPCOLORPACKECTDISABLE = 0,
202 HDMI_DEEPCOLORPACKECTENABLE = 1
203};
204
205enum hdmi_core_packet_mode {
206 HDMI_PACKETMODERESERVEDVALUE = 0,
207 HDMI_PACKETMODE24BITPERPIXEL = 4,
208 HDMI_PACKETMODE30BITPERPIXEL = 5,
209 HDMI_PACKETMODE36BITPERPIXEL = 6,
210 HDMI_PACKETMODE48BITPERPIXEL = 7
211};
212
213enum hdmi_core_tclkselclkmult {
214 HDMI_FPLL05IDCK = 0,
215 HDMI_FPLL10IDCK = 1,
216 HDMI_FPLL20IDCK = 2,
217 HDMI_FPLL40IDCK = 3
218};
219
220enum hdmi_core_packet_ctrl {
221 HDMI_PACKETENABLE = 1,
222 HDMI_PACKETDISABLE = 0,
223 HDMI_PACKETREPEATON = 1,
224 HDMI_PACKETREPEATOFF = 0
225};
226
227enum hdmi_audio_i2s_config {
228 HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0,
229 HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1,
230 HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0,
231 HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1,
232 HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0,
233 HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1,
234 HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0,
235 HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1,
236 HDMI_AUDIO_I2S_SD0_EN = 1,
237 HDMI_AUDIO_I2S_SD1_EN = 1 << 1,
238 HDMI_AUDIO_I2S_SD2_EN = 1 << 2,
239 HDMI_AUDIO_I2S_SD3_EN = 1 << 3,
240};
241
242struct hdmi_core_video_config {
243 enum hdmi_core_inputbus_width ip_bus_width;
244 enum hdmi_core_dither_trunc op_dither_truc;
245 enum hdmi_core_deepcolor_ed deep_color_pkt;
246 enum hdmi_core_packet_mode pkt_mode;
247 enum hdmi_core_hdmi_dvi hdmi_dvi;
248 enum hdmi_core_tclkselclkmult tclk_sel_clkmult;
249};
250
251struct hdmi_core_packet_enable_repeat {
252 u32 audio_pkt;
253 u32 audio_pkt_repeat;
254 u32 avi_infoframe;
255 u32 avi_infoframe_repeat;
256 u32 gen_cntrl_pkt;
257 u32 gen_cntrl_pkt_repeat;
258 u32 generic_pkt;
259 u32 generic_pkt_repeat;
260};
261
262int hdmi4_read_edid(struct hdmi_core_data *core, u8 *edid, int len);
263void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
264 struct hdmi_config *cfg);
265void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s);
266int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
267
268#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
269int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
270void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
271int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
272 struct omap_dss_audio *audio, u32 pclk);
273int hdmi4_audio_get_dma_port(u32 *offset, u32 *size);
274#endif
275
276#endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_common.c b/drivers/video/fbdev/omap2/dss/hdmi_common.c
new file mode 100644
index 000000000000..0b12a3f62fe1
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/hdmi_common.c
@@ -0,0 +1,425 @@
1
2/*
3 * Logic for the below structure :
4 * user enters the CEA or VESA timings by specifying the HDMI/DVI code.
5 * There is a correspondence between CEA/VESA timing and code, please
6 * refer to section 6.3 in HDMI 1.3 specification for timing code.
7 *
8 * In the below structure, cea_vesa_timings corresponds to all OMAP4
9 * supported CEA and VESA timing values.code_cea corresponds to the CEA
10 * code, It is used to get the timing from cea_vesa_timing array.Similarly
11 * with code_vesa. Code_index is used for back mapping, that is once EDID
12 * is read from the TV, EDID is parsed to find the timing values and then
13 * map it to corresponding CEA or VESA index.
14 */
15
16#define DSS_SUBSYS_NAME "HDMI"
17
18#include <linux/kernel.h>
19#include <linux/err.h>
20#include <video/omapdss.h>
21
22#include "hdmi.h"
23
24static const struct hdmi_config cea_timings[] = {
25 {
26 { 640, 480, 25200000, 96, 16, 48, 2, 10, 33,
27 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
28 false, },
29 { 1, HDMI_HDMI },
30 },
31 {
32 { 720, 480, 27027000, 62, 16, 60, 6, 9, 30,
33 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
34 false, },
35 { 2, HDMI_HDMI },
36 },
37 {
38 { 1280, 720, 74250000, 40, 110, 220, 5, 5, 20,
39 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
40 false, },
41 { 4, HDMI_HDMI },
42 },
43 {
44 { 1920, 540, 74250000, 44, 88, 148, 5, 2, 15,
45 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
46 true, },
47 { 5, HDMI_HDMI },
48 },
49 {
50 { 1440, 240, 27027000, 124, 38, 114, 3, 4, 15,
51 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
52 true, },
53 { 6, HDMI_HDMI },
54 },
55 {
56 { 1920, 1080, 148500000, 44, 88, 148, 5, 4, 36,
57 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
58 false, },
59 { 16, HDMI_HDMI },
60 },
61 {
62 { 720, 576, 27000000, 64, 12, 68, 5, 5, 39,
63 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
64 false, },
65 { 17, HDMI_HDMI },
66 },
67 {
68 { 1280, 720, 74250000, 40, 440, 220, 5, 5, 20,
69 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
70 false, },
71 { 19, HDMI_HDMI },
72 },
73 {
74 { 1920, 540, 74250000, 44, 528, 148, 5, 2, 15,
75 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
76 true, },
77 { 20, HDMI_HDMI },
78 },
79 {
80 { 1440, 288, 27000000, 126, 24, 138, 3, 2, 19,
81 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
82 true, },
83 { 21, HDMI_HDMI },
84 },
85 {
86 { 1440, 576, 54000000, 128, 24, 136, 5, 5, 39,
87 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
88 false, },
89 { 29, HDMI_HDMI },
90 },
91 {
92 { 1920, 1080, 148500000, 44, 528, 148, 5, 4, 36,
93 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
94 false, },
95 { 31, HDMI_HDMI },
96 },
97 {
98 { 1920, 1080, 74250000, 44, 638, 148, 5, 4, 36,
99 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
100 false, },
101 { 32, HDMI_HDMI },
102 },
103 {
104 { 2880, 480, 108108000, 248, 64, 240, 6, 9, 30,
105 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
106 false, },
107 { 35, HDMI_HDMI },
108 },
109 {
110 { 2880, 576, 108000000, 256, 48, 272, 5, 5, 39,
111 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
112 false, },
113 { 37, HDMI_HDMI },
114 },
115};
116
117static const struct hdmi_config vesa_timings[] = {
118/* VESA From Here */
119 {
120 { 640, 480, 25175000, 96, 16, 48, 2, 11, 31,
121 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
122 false, },
123 { 4, HDMI_DVI },
124 },
125 {
126 { 800, 600, 40000000, 128, 40, 88, 4, 1, 23,
127 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
128 false, },
129 { 9, HDMI_DVI },
130 },
131 {
132 { 848, 480, 33750000, 112, 16, 112, 8, 6, 23,
133 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
134 false, },
135 { 0xE, HDMI_DVI },
136 },
137 {
138 { 1280, 768, 79500000, 128, 64, 192, 7, 3, 20,
139 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
140 false, },
141 { 0x17, HDMI_DVI },
142 },
143 {
144 { 1280, 800, 83500000, 128, 72, 200, 6, 3, 22,
145 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
146 false, },
147 { 0x1C, HDMI_DVI },
148 },
149 {
150 { 1360, 768, 85500000, 112, 64, 256, 6, 3, 18,
151 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
152 false, },
153 { 0x27, HDMI_DVI },
154 },
155 {
156 { 1280, 960, 108000000, 112, 96, 312, 3, 1, 36,
157 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
158 false, },
159 { 0x20, HDMI_DVI },
160 },
161 {
162 { 1280, 1024, 108000000, 112, 48, 248, 3, 1, 38,
163 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
164 false, },
165 { 0x23, HDMI_DVI },
166 },
167 {
168 { 1024, 768, 65000000, 136, 24, 160, 6, 3, 29,
169 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW,
170 false, },
171 { 0x10, HDMI_DVI },
172 },
173 {
174 { 1400, 1050, 121750000, 144, 88, 232, 4, 3, 32,
175 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
176 false, },
177 { 0x2A, HDMI_DVI },
178 },
179 {
180 { 1440, 900, 106500000, 152, 80, 232, 6, 3, 25,
181 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
182 false, },
183 { 0x2F, HDMI_DVI },
184 },
185 {
186 { 1680, 1050, 146250000, 176 , 104, 280, 6, 3, 30,
187 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW,
188 false, },
189 { 0x3A, HDMI_DVI },
190 },
191 {
192 { 1366, 768, 85500000, 143, 70, 213, 3, 3, 24,
193 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
194 false, },
195 { 0x51, HDMI_DVI },
196 },
197 {
198 { 1920, 1080, 148500000, 44, 148, 80, 5, 4, 36,
199 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
200 false, },
201 { 0x52, HDMI_DVI },
202 },
203 {
204 { 1280, 768, 68250000, 32, 48, 80, 7, 3, 12,
205 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
206 false, },
207 { 0x16, HDMI_DVI },
208 },
209 {
210 { 1400, 1050, 101000000, 32, 48, 80, 4, 3, 23,
211 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
212 false, },
213 { 0x29, HDMI_DVI },
214 },
215 {
216 { 1680, 1050, 119000000, 32, 48, 80, 6, 3, 21,
217 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
218 false, },
219 { 0x39, HDMI_DVI },
220 },
221 {
222 { 1280, 800, 79500000, 32, 48, 80, 6, 3, 14,
223 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
224 false, },
225 { 0x1B, HDMI_DVI },
226 },
227 {
228 { 1280, 720, 74250000, 40, 110, 220, 5, 5, 20,
229 OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH,
230 false, },
231 { 0x55, HDMI_DVI },
232 },
233 {
234 { 1920, 1200, 154000000, 32, 48, 80, 6, 3, 26,
235 OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH,
236 false, },
237 { 0x44, HDMI_DVI },
238 },
239};
240
241const struct hdmi_config *hdmi_default_timing(void)
242{
243 return &vesa_timings[0];
244}
245
246static const struct hdmi_config *hdmi_find_timing(int code,
247 const struct hdmi_config *timings_arr, int len)
248{
249 int i;
250
251 for (i = 0; i < len; i++) {
252 if (timings_arr[i].cm.code == code)
253 return &timings_arr[i];
254 }
255
256 return NULL;
257}
258
259const struct hdmi_config *hdmi_get_timings(int mode, int code)
260{
261 const struct hdmi_config *arr;
262 int len;
263
264 if (mode == HDMI_DVI) {
265 arr = vesa_timings;
266 len = ARRAY_SIZE(vesa_timings);
267 } else {
268 arr = cea_timings;
269 len = ARRAY_SIZE(cea_timings);
270 }
271
272 return hdmi_find_timing(code, arr, len);
273}
274
275static bool hdmi_timings_compare(struct omap_video_timings *timing1,
276 const struct omap_video_timings *timing2)
277{
278 int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync;
279
280 if ((DIV_ROUND_CLOSEST(timing2->pixelclock, 1000000) ==
281 DIV_ROUND_CLOSEST(timing1->pixelclock, 1000000)) &&
282 (timing2->x_res == timing1->x_res) &&
283 (timing2->y_res == timing1->y_res)) {
284
285 timing2_hsync = timing2->hfp + timing2->hsw + timing2->hbp;
286 timing1_hsync = timing1->hfp + timing1->hsw + timing1->hbp;
287 timing2_vsync = timing2->vfp + timing2->vsw + timing2->vbp;
288 timing1_vsync = timing1->vfp + timing1->vsw + timing1->vbp;
289
290 DSSDBG("timing1_hsync = %d timing1_vsync = %d"\
291 "timing2_hsync = %d timing2_vsync = %d\n",
292 timing1_hsync, timing1_vsync,
293 timing2_hsync, timing2_vsync);
294
295 if ((timing1_hsync == timing2_hsync) &&
296 (timing1_vsync == timing2_vsync)) {
297 return true;
298 }
299 }
300 return false;
301}
302
303struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing)
304{
305 int i;
306 struct hdmi_cm cm = {-1};
307 DSSDBG("hdmi_get_code\n");
308
309 for (i = 0; i < ARRAY_SIZE(cea_timings); i++) {
310 if (hdmi_timings_compare(timing, &cea_timings[i].timings)) {
311 cm = cea_timings[i].cm;
312 goto end;
313 }
314 }
315 for (i = 0; i < ARRAY_SIZE(vesa_timings); i++) {
316 if (hdmi_timings_compare(timing, &vesa_timings[i].timings)) {
317 cm = vesa_timings[i].cm;
318 goto end;
319 }
320 }
321
322end:
323 return cm;
324}
325
326#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
327int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
328{
329 u32 deep_color;
330 bool deep_color_correct = false;
331
332 if (n == NULL || cts == NULL)
333 return -EINVAL;
334
335 /* TODO: When implemented, query deep color mode here. */
336 deep_color = 100;
337
338 /*
339 * When using deep color, the default N value (as in the HDMI
340 * specification) yields to an non-integer CTS. Hence, we
341 * modify it while keeping the restrictions described in
342 * section 7.2.1 of the HDMI 1.4a specification.
343 */
344 switch (sample_freq) {
345 case 32000:
346 case 48000:
347 case 96000:
348 case 192000:
349 if (deep_color == 125)
350 if (pclk == 27027000 || pclk == 74250000)
351 deep_color_correct = true;
352 if (deep_color == 150)
353 if (pclk == 27027000)
354 deep_color_correct = true;
355 break;
356 case 44100:
357 case 88200:
358 case 176400:
359 if (deep_color == 125)
360 if (pclk == 27027000)
361 deep_color_correct = true;
362 break;
363 default:
364 return -EINVAL;
365 }
366
367 if (deep_color_correct) {
368 switch (sample_freq) {
369 case 32000:
370 *n = 8192;
371 break;
372 case 44100:
373 *n = 12544;
374 break;
375 case 48000:
376 *n = 8192;
377 break;
378 case 88200:
379 *n = 25088;
380 break;
381 case 96000:
382 *n = 16384;
383 break;
384 case 176400:
385 *n = 50176;
386 break;
387 case 192000:
388 *n = 32768;
389 break;
390 default:
391 return -EINVAL;
392 }
393 } else {
394 switch (sample_freq) {
395 case 32000:
396 *n = 4096;
397 break;
398 case 44100:
399 *n = 6272;
400 break;
401 case 48000:
402 *n = 6144;
403 break;
404 case 88200:
405 *n = 12544;
406 break;
407 case 96000:
408 *n = 12288;
409 break;
410 case 176400:
411 *n = 25088;
412 break;
413 case 192000:
414 *n = 24576;
415 break;
416 default:
417 return -EINVAL;
418 }
419 }
420 /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
421 *cts = (pclk/1000) * (*n / 128) * deep_color / (sample_freq / 10);
422
423 return 0;
424}
425#endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_phy.c b/drivers/video/fbdev/omap2/dss/hdmi_phy.c
new file mode 100644
index 000000000000..dd376ce8da01
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/hdmi_phy.c
@@ -0,0 +1,160 @@
1/*
2 * HDMI PHY
3 *
4 * Copyright (C) 2013 Texas Instruments Incorporated
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10
11#include <linux/kernel.h>
12#include <linux/err.h>
13#include <linux/io.h>
14#include <linux/platform_device.h>
15#include <video/omapdss.h>
16
17#include "dss.h"
18#include "hdmi.h"
19
20void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s)
21{
22#define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\
23 hdmi_read_reg(phy->base, r))
24
25 DUMPPHY(HDMI_TXPHY_TX_CTRL);
26 DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL);
27 DUMPPHY(HDMI_TXPHY_POWER_CTRL);
28 DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL);
29}
30
31static irqreturn_t hdmi_irq_handler(int irq, void *data)
32{
33 struct hdmi_wp_data *wp = data;
34 u32 irqstatus;
35
36 irqstatus = hdmi_wp_get_irqstatus(wp);
37 hdmi_wp_set_irqstatus(wp, irqstatus);
38
39 if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
40 irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
41 /*
42 * If we get both connect and disconnect interrupts at the same
43 * time, turn off the PHY, clear interrupts, and restart, which
44 * raises connect interrupt if a cable is connected, or nothing
45 * if cable is not connected.
46 */
47 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
48
49 hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
50 HDMI_IRQ_LINK_DISCONNECT);
51
52 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
53 } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
54 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
55 } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
56 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
57 }
58
59 return IRQ_HANDLED;
60}
61
62int hdmi_phy_enable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp,
63 struct hdmi_config *cfg)
64{
65 u16 r = 0;
66 u32 irqstatus;
67
68 hdmi_wp_clear_irqenable(wp, 0xffffffff);
69
70 irqstatus = hdmi_wp_get_irqstatus(wp);
71 hdmi_wp_set_irqstatus(wp, irqstatus);
72
73 r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
74 if (r)
75 return r;
76
77 /*
78 * Read address 0 in order to get the SCP reset done completed
79 * Dummy access performed to make sure reset is done
80 */
81 hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL);
82
83 /*
84 * Write to phy address 0 to configure the clock
85 * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
86 */
87 REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, 0x1, 31, 30);
88
89 /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
90 hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
91
92 /* Setup max LDO voltage */
93 REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
94
95 /* Write to phy address 3 to change the polarity control */
96 REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27);
97
98 r = request_threaded_irq(phy->irq, NULL, hdmi_irq_handler,
99 IRQF_ONESHOT, "OMAP HDMI", wp);
100 if (r) {
101 DSSERR("HDMI IRQ request failed\n");
102 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
103 return r;
104 }
105
106 hdmi_wp_set_irqenable(wp,
107 HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
108
109 return 0;
110}
111
112void hdmi_phy_disable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp)
113{
114 free_irq(phy->irq, wp);
115
116 hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
117}
118
119#define PHY_OFFSET 0x300
120#define PHY_SIZE 0x100
121
122int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy)
123{
124 struct resource *res;
125 struct resource temp_res;
126
127 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
128 if (!res) {
129 DSSDBG("can't get PHY mem resource by name\n");
130 /*
131 * if hwmod/DT doesn't have the memory resource information
132 * split into HDMI sub blocks by name, we try again by getting
133 * the platform's first resource. this code will be removed when
134 * the driver can get the mem resources by name
135 */
136 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
137 if (!res) {
138 DSSERR("can't get PHY mem resource\n");
139 return -EINVAL;
140 }
141
142 temp_res.start = res->start + PHY_OFFSET;
143 temp_res.end = temp_res.start + PHY_SIZE - 1;
144 res = &temp_res;
145 }
146
147 phy->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
148 if (!phy->base) {
149 DSSERR("can't ioremap TX PHY\n");
150 return -ENOMEM;
151 }
152
153 phy->irq = platform_get_irq(pdev, 0);
154 if (phy->irq < 0) {
155 DSSERR("platform_get_irq failed\n");
156 return -ENODEV;
157 }
158
159 return 0;
160}
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
new file mode 100644
index 000000000000..5fc71215c303
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
@@ -0,0 +1,232 @@
1/*
2 * HDMI PLL
3 *
4 * Copyright (C) 2013 Texas Instruments Incorporated
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10
11#define DSS_SUBSYS_NAME "HDMIPLL"
12
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/err.h>
16#include <linux/io.h>
17#include <linux/platform_device.h>
18#include <video/omapdss.h>
19
20#include "dss.h"
21#include "hdmi.h"
22
23#define HDMI_DEFAULT_REGN 16
24#define HDMI_DEFAULT_REGM2 1
25
26void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
27{
28#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
29 hdmi_read_reg(pll->base, r))
30
31 DUMPPLL(PLLCTRL_PLL_CONTROL);
32 DUMPPLL(PLLCTRL_PLL_STATUS);
33 DUMPPLL(PLLCTRL_PLL_GO);
34 DUMPPLL(PLLCTRL_CFG1);
35 DUMPPLL(PLLCTRL_CFG2);
36 DUMPPLL(PLLCTRL_CFG3);
37 DUMPPLL(PLLCTRL_SSC_CFG1);
38 DUMPPLL(PLLCTRL_SSC_CFG2);
39 DUMPPLL(PLLCTRL_CFG4);
40}
41
42void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy)
43{
44 struct hdmi_pll_info *pi = &pll->info;
45 unsigned long refclk;
46 u32 mf;
47
48 /* use our funky units */
49 clkin /= 10000;
50
51 /*
52 * Input clock is predivided by N + 1
53 * out put of which is reference clk
54 */
55
56 pi->regn = HDMI_DEFAULT_REGN;
57
58 refclk = clkin / pi->regn;
59
60 pi->regm2 = HDMI_DEFAULT_REGM2;
61
62 /*
63 * multiplier is pixel_clk/ref_clk
64 * Multiplying by 100 to avoid fractional part removal
65 */
66 pi->regm = phy * pi->regm2 / refclk;
67
68 /*
69 * fractional multiplier is remainder of the difference between
70 * multiplier and actual phy(required pixel clock thus should be
71 * multiplied by 2^18(262144) divided by the reference clock
72 */
73 mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
74 pi->regmf = pi->regm2 * mf / refclk;
75
76 /*
77 * Dcofreq should be set to 1 if required pixel clock
78 * is greater than 1000MHz
79 */
80 pi->dcofreq = phy > 1000 * 100;
81 pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
82
83 /* Set the reference clock to sysclk reference */
84 pi->refsel = HDMI_REFSEL_SYSCLK;
85
86 DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
87 DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
88}
89
90
91static int hdmi_pll_config(struct hdmi_pll_data *pll)
92{
93 u32 r;
94 struct hdmi_pll_info *fmt = &pll->info;
95
96 /* PLL start always use manual mode */
97 REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0);
98
99 r = hdmi_read_reg(pll->base, PLLCTRL_CFG1);
100 r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */
101 r = FLD_MOD(r, fmt->regn - 1, 8, 1); /* CFG1_PLL_REGN */
102 hdmi_write_reg(pll->base, PLLCTRL_CFG1, r);
103
104 r = hdmi_read_reg(pll->base, PLLCTRL_CFG2);
105
106 r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
107 r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */
108 r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
109 r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */
110
111 if (fmt->dcofreq) {
112 /* divider programming for frequency beyond 1000Mhz */
113 REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10);
114 r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
115 } else {
116 r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
117 }
118
119 hdmi_write_reg(pll->base, PLLCTRL_CFG2, r);
120
121 r = hdmi_read_reg(pll->base, PLLCTRL_CFG4);
122 r = FLD_MOD(r, fmt->regm2, 24, 18);
123 r = FLD_MOD(r, fmt->regmf, 17, 0);
124 hdmi_write_reg(pll->base, PLLCTRL_CFG4, r);
125
126 /* go now */
127 REG_FLD_MOD(pll->base, PLLCTRL_PLL_GO, 0x1, 0, 0);
128
129 /* wait for bit change */
130 if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO,
131 0, 0, 1) != 1) {
132 DSSERR("PLL GO bit not set\n");
133 return -ETIMEDOUT;
134 }
135
136 /* Wait till the lock bit is set in PLL status */
137 if (hdmi_wait_for_bit_change(pll->base,
138 PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
139 DSSERR("cannot lock PLL\n");
140 DSSERR("CFG1 0x%x\n",
141 hdmi_read_reg(pll->base, PLLCTRL_CFG1));
142 DSSERR("CFG2 0x%x\n",
143 hdmi_read_reg(pll->base, PLLCTRL_CFG2));
144 DSSERR("CFG4 0x%x\n",
145 hdmi_read_reg(pll->base, PLLCTRL_CFG4));
146 return -ETIMEDOUT;
147 }
148
149 DSSDBG("PLL locked!\n");
150
151 return 0;
152}
153
154static int hdmi_pll_reset(struct hdmi_pll_data *pll)
155{
156 /* SYSRESET controlled by power FSM */
157 REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 3, 3);
158
159 /* READ 0x0 reset is in progress */
160 if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1)
161 != 1) {
162 DSSERR("Failed to sysreset PLL\n");
163 return -ETIMEDOUT;
164 }
165
166 return 0;
167}
168
169int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
170{
171 u16 r = 0;
172
173 r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
174 if (r)
175 return r;
176
177 r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
178 if (r)
179 return r;
180
181 r = hdmi_pll_reset(pll);
182 if (r)
183 return r;
184
185 r = hdmi_pll_config(pll);
186 if (r)
187 return r;
188
189 return 0;
190}
191
192void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
193{
194 hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
195}
196
197#define PLL_OFFSET 0x200
198#define PLL_SIZE 0x100
199
200int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
201{
202 struct resource *res;
203 struct resource temp_res;
204
205 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll");
206 if (!res) {
207 DSSDBG("can't get PLL mem resource by name\n");
208 /*
209 * if hwmod/DT doesn't have the memory resource information
210 * split into HDMI sub blocks by name, we try again by getting
211 * the platform's first resource. this code will be removed when
212 * the driver can get the mem resources by name
213 */
214 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
215 if (!res) {
216 DSSERR("can't get PLL mem resource\n");
217 return -EINVAL;
218 }
219
220 temp_res.start = res->start + PLL_OFFSET;
221 temp_res.end = temp_res.start + PLL_SIZE - 1;
222 res = &temp_res;
223 }
224
225 pll->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
226 if (!pll->base) {
227 DSSERR("can't ioremap PLLCTRL\n");
228 return -ENOMEM;
229 }
230
231 return 0;
232}
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_wp.c b/drivers/video/fbdev/omap2/dss/hdmi_wp.c
new file mode 100644
index 000000000000..f5f4ccf50d90
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/hdmi_wp.c
@@ -0,0 +1,275 @@
1/*
2 * HDMI wrapper
3 *
4 * Copyright (C) 2013 Texas Instruments Incorporated
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10
11#define DSS_SUBSYS_NAME "HDMIWP"
12
13#include <linux/kernel.h>
14#include <linux/err.h>
15#include <linux/io.h>
16#include <linux/platform_device.h>
17#include <video/omapdss.h>
18
19#include "dss.h"
20#include "hdmi.h"
21
22void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s)
23{
24#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, hdmi_read_reg(wp->base, r))
25
26 DUMPREG(HDMI_WP_REVISION);
27 DUMPREG(HDMI_WP_SYSCONFIG);
28 DUMPREG(HDMI_WP_IRQSTATUS_RAW);
29 DUMPREG(HDMI_WP_IRQSTATUS);
30 DUMPREG(HDMI_WP_IRQENABLE_SET);
31 DUMPREG(HDMI_WP_IRQENABLE_CLR);
32 DUMPREG(HDMI_WP_IRQWAKEEN);
33 DUMPREG(HDMI_WP_PWR_CTRL);
34 DUMPREG(HDMI_WP_DEBOUNCE);
35 DUMPREG(HDMI_WP_VIDEO_CFG);
36 DUMPREG(HDMI_WP_VIDEO_SIZE);
37 DUMPREG(HDMI_WP_VIDEO_TIMING_H);
38 DUMPREG(HDMI_WP_VIDEO_TIMING_V);
39 DUMPREG(HDMI_WP_CLK);
40 DUMPREG(HDMI_WP_AUDIO_CFG);
41 DUMPREG(HDMI_WP_AUDIO_CFG2);
42 DUMPREG(HDMI_WP_AUDIO_CTRL);
43 DUMPREG(HDMI_WP_AUDIO_DATA);
44}
45
46u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp)
47{
48 return hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
49}
50
51void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus)
52{
53 hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, irqstatus);
54 /* flush posted write */
55 hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
56}
57
58void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask)
59{
60 hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_SET, mask);
61}
62
63void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask)
64{
65 hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_CLR, mask);
66}
67
68/* PHY_PWR_CMD */
69int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val)
70{
71 /* Return if already the state */
72 if (REG_GET(wp->base, HDMI_WP_PWR_CTRL, 5, 4) == val)
73 return 0;
74
75 /* Command for power control of HDMI PHY */
76 REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 7, 6);
77
78 /* Status of the power control of HDMI PHY */
79 if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 5, 4, val)
80 != val) {
81 DSSERR("Failed to set PHY power mode to %d\n", val);
82 return -ETIMEDOUT;
83 }
84
85 return 0;
86}
87
88/* PLL_PWR_CMD */
89int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val)
90{
91 /* Command for power control of HDMI PLL */
92 REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 3, 2);
93
94 /* wait till PHY_PWR_STATUS is set */
95 if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 1, 0, val)
96 != val) {
97 DSSERR("Failed to set PLL_PWR_STATUS\n");
98 return -ETIMEDOUT;
99 }
100
101 return 0;
102}
103
104int hdmi_wp_video_start(struct hdmi_wp_data *wp)
105{
106 REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, true, 31, 31);
107
108 return 0;
109}
110
111void hdmi_wp_video_stop(struct hdmi_wp_data *wp)
112{
113 REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31);
114}
115
116void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
117 struct hdmi_video_format *video_fmt)
118{
119 u32 l = 0;
120
121 REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, video_fmt->packing_mode,
122 10, 8);
123
124 l |= FLD_VAL(video_fmt->y_res, 31, 16);
125 l |= FLD_VAL(video_fmt->x_res, 15, 0);
126 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_SIZE, l);
127}
128
129void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
130 struct omap_video_timings *timings)
131{
132 u32 r;
133 bool vsync_pol, hsync_pol;
134 DSSDBG("Enter hdmi_wp_video_config_interface\n");
135
136 vsync_pol = timings->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
137 hsync_pol = timings->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
138
139 r = hdmi_read_reg(wp->base, HDMI_WP_VIDEO_CFG);
140 r = FLD_MOD(r, vsync_pol, 7, 7);
141 r = FLD_MOD(r, hsync_pol, 6, 6);
142 r = FLD_MOD(r, timings->interlace, 3, 3);
143 r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */
144 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_CFG, r);
145}
146
147void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
148 struct omap_video_timings *timings)
149{
150 u32 timing_h = 0;
151 u32 timing_v = 0;
152
153 DSSDBG("Enter hdmi_wp_video_config_timing\n");
154
155 timing_h |= FLD_VAL(timings->hbp, 31, 20);
156 timing_h |= FLD_VAL(timings->hfp, 19, 8);
157 timing_h |= FLD_VAL(timings->hsw, 7, 0);
158 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h);
159
160 timing_v |= FLD_VAL(timings->vbp, 31, 20);
161 timing_v |= FLD_VAL(timings->vfp, 19, 8);
162 timing_v |= FLD_VAL(timings->vsw, 7, 0);
163 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_V, timing_v);
164}
165
166void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
167 struct omap_video_timings *timings, struct hdmi_config *param)
168{
169 DSSDBG("Enter hdmi_wp_video_init_format\n");
170
171 video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
172 video_fmt->y_res = param->timings.y_res;
173 video_fmt->x_res = param->timings.x_res;
174 if (param->timings.interlace)
175 video_fmt->y_res /= 2;
176
177 timings->hbp = param->timings.hbp;
178 timings->hfp = param->timings.hfp;
179 timings->hsw = param->timings.hsw;
180 timings->vbp = param->timings.vbp;
181 timings->vfp = param->timings.vfp;
182 timings->vsw = param->timings.vsw;
183 timings->vsync_level = param->timings.vsync_level;
184 timings->hsync_level = param->timings.hsync_level;
185 timings->interlace = param->timings.interlace;
186}
187
188#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
189void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
190 struct hdmi_audio_format *aud_fmt)
191{
192 u32 r;
193
194 DSSDBG("Enter hdmi_wp_audio_config_format\n");
195
196 r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
197 r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
198 r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
199 r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
200 r = FLD_MOD(r, aud_fmt->type, 4, 4);
201 r = FLD_MOD(r, aud_fmt->justification, 3, 3);
202 r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
203 r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
204 r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
205 hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG, r);
206}
207
208void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
209 struct hdmi_audio_dma *aud_dma)
210{
211 u32 r;
212
213 DSSDBG("Enter hdmi_wp_audio_config_dma\n");
214
215 r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG2);
216 r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
217 r = FLD_MOD(r, aud_dma->block_size, 7, 0);
218 hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG2, r);
219
220 r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CTRL);
221 r = FLD_MOD(r, aud_dma->mode, 9, 9);
222 r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
223 hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CTRL, r);
224}
225
226int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable)
227{
228 REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 31, 31);
229
230 return 0;
231}
232
233int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)
234{
235 REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 30, 30);
236
237 return 0;
238}
239#endif
240
241#define WP_SIZE 0x200
242
243int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
244{
245 struct resource *res;
246 struct resource temp_res;
247
248 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wp");
249 if (!res) {
250 DSSDBG("can't get WP mem resource by name\n");
251 /*
252 * if hwmod/DT doesn't have the memory resource information
253 * split into HDMI sub blocks by name, we try again by getting
254 * the platform's first resource. this code will be removed when
255 * the driver can get the mem resources by name
256 */
257 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
258 if (!res) {
259 DSSERR("can't get WP mem resource\n");
260 return -EINVAL;
261 }
262
263 temp_res.start = res->start;
264 temp_res.end = temp_res.start + WP_SIZE - 1;
265 res = &temp_res;
266 }
267
268 wp->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
269 if (!wp->base) {
270 DSSERR("can't ioremap HDMI WP\n");
271 return -ENOMEM;
272 }
273
274 return 0;
275}
diff --git a/drivers/video/fbdev/omap2/dss/manager-sysfs.c b/drivers/video/fbdev/omap2/dss/manager-sysfs.c
new file mode 100644
index 000000000000..37b59fe28dc8
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/manager-sysfs.c
@@ -0,0 +1,529 @@
1/*
2 * Copyright (C) 2009 Nokia Corporation
3 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
4 *
5 * Some code and ideas taken from drivers/video/omap/ driver
6 * by Imre Deak.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#define DSS_SUBSYS_NAME "MANAGER"
22
23#include <linux/kernel.h>
24#include <linux/slab.h>
25#include <linux/module.h>
26#include <linux/platform_device.h>
27#include <linux/jiffies.h>
28
29#include <video/omapdss.h>
30
31#include "dss.h"
32#include "dss_features.h"
33
34static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
35{
36 return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
37}
38
39static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
40{
41 struct omap_dss_device *dssdev = mgr->get_device(mgr);
42
43 return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ?
44 dssdev->name : "<none>");
45}
46
47static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
48 const char *buf, size_t size)
49{
50 int r = 0;
51 size_t len = size;
52 struct omap_dss_device *dssdev = NULL;
53 struct omap_dss_device *old_dssdev;
54
55 int match(struct omap_dss_device *dssdev, void *data)
56 {
57 const char *str = data;
58 return sysfs_streq(dssdev->name, str);
59 }
60
61 if (buf[size-1] == '\n')
62 --len;
63
64 if (len > 0)
65 dssdev = omap_dss_find_device((void *)buf, match);
66
67 if (len > 0 && dssdev == NULL)
68 return -EINVAL;
69
70 if (dssdev) {
71 DSSDBG("display %s found\n", dssdev->name);
72
73 if (omapdss_device_is_connected(dssdev)) {
74 DSSERR("new display is already connected\n");
75 r = -EINVAL;
76 goto put_device;
77 }
78
79 if (omapdss_device_is_enabled(dssdev)) {
80 DSSERR("new display is not disabled\n");
81 r = -EINVAL;
82 goto put_device;
83 }
84 }
85
86 old_dssdev = mgr->get_device(mgr);
87 if (old_dssdev) {
88 if (omapdss_device_is_enabled(old_dssdev)) {
89 DSSERR("old display is not disabled\n");
90 r = -EINVAL;
91 goto put_device;
92 }
93
94 old_dssdev->driver->disconnect(old_dssdev);
95 }
96
97 if (dssdev) {
98 r = dssdev->driver->connect(dssdev);
99 if (r) {
100 DSSERR("failed to connect new device\n");
101 goto put_device;
102 }
103
104 old_dssdev = mgr->get_device(mgr);
105 if (old_dssdev != dssdev) {
106 DSSERR("failed to connect device to this manager\n");
107 dssdev->driver->disconnect(dssdev);
108 goto put_device;
109 }
110
111 r = mgr->apply(mgr);
112 if (r) {
113 DSSERR("failed to apply dispc config\n");
114 goto put_device;
115 }
116 }
117
118put_device:
119 if (dssdev)
120 omap_dss_put_device(dssdev);
121
122 return r ? r : size;
123}
124
125static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
126 char *buf)
127{
128 struct omap_overlay_manager_info info;
129
130 mgr->get_manager_info(mgr, &info);
131
132 return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color);
133}
134
135static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
136 const char *buf, size_t size)
137{
138 struct omap_overlay_manager_info info;
139 u32 color;
140 int r;
141
142 r = kstrtouint(buf, 0, &color);
143 if (r)
144 return r;
145
146 mgr->get_manager_info(mgr, &info);
147
148 info.default_color = color;
149
150 r = mgr->set_manager_info(mgr, &info);
151 if (r)
152 return r;
153
154 r = mgr->apply(mgr);
155 if (r)
156 return r;
157
158 return size;
159}
160
161static const char *trans_key_type_str[] = {
162 "gfx-destination",
163 "video-source",
164};
165
166static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
167 char *buf)
168{
169 enum omap_dss_trans_key_type key_type;
170 struct omap_overlay_manager_info info;
171
172 mgr->get_manager_info(mgr, &info);
173
174 key_type = info.trans_key_type;
175 BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
176
177 return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
178}
179
180static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
181 const char *buf, size_t size)
182{
183 enum omap_dss_trans_key_type key_type;
184 struct omap_overlay_manager_info info;
185 int r;
186
187 for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
188 key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
189 if (sysfs_streq(buf, trans_key_type_str[key_type]))
190 break;
191 }
192
193 if (key_type == ARRAY_SIZE(trans_key_type_str))
194 return -EINVAL;
195
196 mgr->get_manager_info(mgr, &info);
197
198 info.trans_key_type = key_type;
199
200 r = mgr->set_manager_info(mgr, &info);
201 if (r)
202 return r;
203
204 r = mgr->apply(mgr);
205 if (r)
206 return r;
207
208 return size;
209}
210
211static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
212 char *buf)
213{
214 struct omap_overlay_manager_info info;
215
216 mgr->get_manager_info(mgr, &info);
217
218 return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key);
219}
220
221static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
222 const char *buf, size_t size)
223{
224 struct omap_overlay_manager_info info;
225 u32 key_value;
226 int r;
227
228 r = kstrtouint(buf, 0, &key_value);
229 if (r)
230 return r;
231
232 mgr->get_manager_info(mgr, &info);
233
234 info.trans_key = key_value;
235
236 r = mgr->set_manager_info(mgr, &info);
237 if (r)
238 return r;
239
240 r = mgr->apply(mgr);
241 if (r)
242 return r;
243
244 return size;
245}
246
247static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
248 char *buf)
249{
250 struct omap_overlay_manager_info info;
251
252 mgr->get_manager_info(mgr, &info);
253
254 return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled);
255}
256
257static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
258 const char *buf, size_t size)
259{
260 struct omap_overlay_manager_info info;
261 bool enable;
262 int r;
263
264 r = strtobool(buf, &enable);
265 if (r)
266 return r;
267
268 mgr->get_manager_info(mgr, &info);
269
270 info.trans_enabled = enable;
271
272 r = mgr->set_manager_info(mgr, &info);
273 if (r)
274 return r;
275
276 r = mgr->apply(mgr);
277 if (r)
278 return r;
279
280 return size;
281}
282
283static ssize_t manager_alpha_blending_enabled_show(
284 struct omap_overlay_manager *mgr, char *buf)
285{
286 struct omap_overlay_manager_info info;
287
288 if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
289 return -ENODEV;
290
291 mgr->get_manager_info(mgr, &info);
292
293 return snprintf(buf, PAGE_SIZE, "%d\n",
294 info.partial_alpha_enabled);
295}
296
297static ssize_t manager_alpha_blending_enabled_store(
298 struct omap_overlay_manager *mgr,
299 const char *buf, size_t size)
300{
301 struct omap_overlay_manager_info info;
302 bool enable;
303 int r;
304
305 if(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
306 return -ENODEV;
307
308 r = strtobool(buf, &enable);
309 if (r)
310 return r;
311
312 mgr->get_manager_info(mgr, &info);
313
314 info.partial_alpha_enabled = enable;
315
316 r = mgr->set_manager_info(mgr, &info);
317 if (r)
318 return r;
319
320 r = mgr->apply(mgr);
321 if (r)
322 return r;
323
324 return size;
325}
326
327static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr,
328 char *buf)
329{
330 struct omap_overlay_manager_info info;
331
332 mgr->get_manager_info(mgr, &info);
333
334 return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable);
335}
336
337static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr,
338 const char *buf, size_t size)
339{
340 struct omap_overlay_manager_info info;
341 int r;
342 bool enable;
343
344 if (!dss_has_feature(FEAT_CPR))
345 return -ENODEV;
346
347 r = strtobool(buf, &enable);
348 if (r)
349 return r;
350
351 mgr->get_manager_info(mgr, &info);
352
353 if (info.cpr_enable == enable)
354 return size;
355
356 info.cpr_enable = enable;
357
358 r = mgr->set_manager_info(mgr, &info);
359 if (r)
360 return r;
361
362 r = mgr->apply(mgr);
363 if (r)
364 return r;
365
366 return size;
367}
368
369static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr,
370 char *buf)
371{
372 struct omap_overlay_manager_info info;
373
374 mgr->get_manager_info(mgr, &info);
375
376 return snprintf(buf, PAGE_SIZE,
377 "%d %d %d %d %d %d %d %d %d\n",
378 info.cpr_coefs.rr,
379 info.cpr_coefs.rg,
380 info.cpr_coefs.rb,
381 info.cpr_coefs.gr,
382 info.cpr_coefs.gg,
383 info.cpr_coefs.gb,
384 info.cpr_coefs.br,
385 info.cpr_coefs.bg,
386 info.cpr_coefs.bb);
387}
388
389static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr,
390 const char *buf, size_t size)
391{
392 struct omap_overlay_manager_info info;
393 struct omap_dss_cpr_coefs coefs;
394 int r, i;
395 s16 *arr;
396
397 if (!dss_has_feature(FEAT_CPR))
398 return -ENODEV;
399
400 if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd",
401 &coefs.rr, &coefs.rg, &coefs.rb,
402 &coefs.gr, &coefs.gg, &coefs.gb,
403 &coefs.br, &coefs.bg, &coefs.bb) != 9)
404 return -EINVAL;
405
406 arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb,
407 coefs.gr, coefs.gg, coefs.gb,
408 coefs.br, coefs.bg, coefs.bb };
409
410 for (i = 0; i < 9; ++i) {
411 if (arr[i] < -512 || arr[i] > 511)
412 return -EINVAL;
413 }
414
415 mgr->get_manager_info(mgr, &info);
416
417 info.cpr_coefs = coefs;
418
419 r = mgr->set_manager_info(mgr, &info);
420 if (r)
421 return r;
422
423 r = mgr->apply(mgr);
424 if (r)
425 return r;
426
427 return size;
428}
429
430struct manager_attribute {
431 struct attribute attr;
432 ssize_t (*show)(struct omap_overlay_manager *, char *);
433 ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
434};
435
436#define MANAGER_ATTR(_name, _mode, _show, _store) \
437 struct manager_attribute manager_attr_##_name = \
438 __ATTR(_name, _mode, _show, _store)
439
440static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
441static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
442 manager_display_show, manager_display_store);
443static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
444 manager_default_color_show, manager_default_color_store);
445static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
446 manager_trans_key_type_show, manager_trans_key_type_store);
447static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
448 manager_trans_key_value_show, manager_trans_key_value_store);
449static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
450 manager_trans_key_enabled_show,
451 manager_trans_key_enabled_store);
452static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
453 manager_alpha_blending_enabled_show,
454 manager_alpha_blending_enabled_store);
455static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR,
456 manager_cpr_enable_show,
457 manager_cpr_enable_store);
458static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR,
459 manager_cpr_coef_show,
460 manager_cpr_coef_store);
461
462
463static struct attribute *manager_sysfs_attrs[] = {
464 &manager_attr_name.attr,
465 &manager_attr_display.attr,
466 &manager_attr_default_color.attr,
467 &manager_attr_trans_key_type.attr,
468 &manager_attr_trans_key_value.attr,
469 &manager_attr_trans_key_enabled.attr,
470 &manager_attr_alpha_blending_enabled.attr,
471 &manager_attr_cpr_enable.attr,
472 &manager_attr_cpr_coef.attr,
473 NULL
474};
475
476static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
477 char *buf)
478{
479 struct omap_overlay_manager *manager;
480 struct manager_attribute *manager_attr;
481
482 manager = container_of(kobj, struct omap_overlay_manager, kobj);
483 manager_attr = container_of(attr, struct manager_attribute, attr);
484
485 if (!manager_attr->show)
486 return -ENOENT;
487
488 return manager_attr->show(manager, buf);
489}
490
491static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
492 const char *buf, size_t size)
493{
494 struct omap_overlay_manager *manager;
495 struct manager_attribute *manager_attr;
496
497 manager = container_of(kobj, struct omap_overlay_manager, kobj);
498 manager_attr = container_of(attr, struct manager_attribute, attr);
499
500 if (!manager_attr->store)
501 return -ENOENT;
502
503 return manager_attr->store(manager, buf, size);
504}
505
506static const struct sysfs_ops manager_sysfs_ops = {
507 .show = manager_attr_show,
508 .store = manager_attr_store,
509};
510
511static struct kobj_type manager_ktype = {
512 .sysfs_ops = &manager_sysfs_ops,
513 .default_attrs = manager_sysfs_attrs,
514};
515
516int dss_manager_kobj_init(struct omap_overlay_manager *mgr,
517 struct platform_device *pdev)
518{
519 return kobject_init_and_add(&mgr->kobj, &manager_ktype,
520 &pdev->dev.kobj, "manager%d", mgr->id);
521}
522
523void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr)
524{
525 kobject_del(&mgr->kobj);
526 kobject_put(&mgr->kobj);
527
528 memset(&mgr->kobj, 0, sizeof(mgr->kobj));
529}
diff --git a/drivers/video/fbdev/omap2/dss/manager.c b/drivers/video/fbdev/omap2/dss/manager.c
new file mode 100644
index 000000000000..1aac9b4191a9
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/manager.c
@@ -0,0 +1,263 @@
1/*
2 * linux/drivers/video/omap2/dss/manager.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 "MANAGER"
24
25#include <linux/kernel.h>
26#include <linux/slab.h>
27#include <linux/module.h>
28#include <linux/platform_device.h>
29#include <linux/jiffies.h>
30
31#include <video/omapdss.h>
32
33#include "dss.h"
34#include "dss_features.h"
35
36static int num_managers;
37static struct omap_overlay_manager *managers;
38
39int dss_init_overlay_managers(void)
40{
41 int i;
42
43 num_managers = dss_feat_get_num_mgrs();
44
45 managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers,
46 GFP_KERNEL);
47
48 BUG_ON(managers == NULL);
49
50 for (i = 0; i < num_managers; ++i) {
51 struct omap_overlay_manager *mgr = &managers[i];
52
53 switch (i) {
54 case 0:
55 mgr->name = "lcd";
56 mgr->id = OMAP_DSS_CHANNEL_LCD;
57 break;
58 case 1:
59 mgr->name = "tv";
60 mgr->id = OMAP_DSS_CHANNEL_DIGIT;
61 break;
62 case 2:
63 mgr->name = "lcd2";
64 mgr->id = OMAP_DSS_CHANNEL_LCD2;
65 break;
66 case 3:
67 mgr->name = "lcd3";
68 mgr->id = OMAP_DSS_CHANNEL_LCD3;
69 break;
70 }
71
72 mgr->caps = 0;
73 mgr->supported_displays =
74 dss_feat_get_supported_displays(mgr->id);
75 mgr->supported_outputs =
76 dss_feat_get_supported_outputs(mgr->id);
77
78 INIT_LIST_HEAD(&mgr->overlays);
79 }
80
81 return 0;
82}
83
84int dss_init_overlay_managers_sysfs(struct platform_device *pdev)
85{
86 int i, r;
87
88 for (i = 0; i < num_managers; ++i) {
89 struct omap_overlay_manager *mgr = &managers[i];
90
91 r = dss_manager_kobj_init(mgr, pdev);
92 if (r)
93 DSSERR("failed to create sysfs file\n");
94 }
95
96 return 0;
97}
98
99void dss_uninit_overlay_managers(void)
100{
101 kfree(managers);
102 managers = NULL;
103 num_managers = 0;
104}
105
106void dss_uninit_overlay_managers_sysfs(struct platform_device *pdev)
107{
108 int i;
109
110 for (i = 0; i < num_managers; ++i) {
111 struct omap_overlay_manager *mgr = &managers[i];
112
113 dss_manager_kobj_uninit(mgr);
114 }
115}
116
117int omap_dss_get_num_overlay_managers(void)
118{
119 return num_managers;
120}
121EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
122
123struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
124{
125 if (num >= num_managers)
126 return NULL;
127
128 return &managers[num];
129}
130EXPORT_SYMBOL(omap_dss_get_overlay_manager);
131
132int dss_mgr_simple_check(struct omap_overlay_manager *mgr,
133 const struct omap_overlay_manager_info *info)
134{
135 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) {
136 /*
137 * OMAP3 supports only graphics source transparency color key
138 * and alpha blending simultaneously. See TRM 15.4.2.4.2.2
139 * Alpha Mode.
140 */
141 if (info->partial_alpha_enabled && info->trans_enabled
142 && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) {
143 DSSERR("check_manager: illegal transparency key\n");
144 return -EINVAL;
145 }
146 }
147
148 return 0;
149}
150
151static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr,
152 struct omap_overlay_info **overlay_infos)
153{
154 struct omap_overlay *ovl1, *ovl2;
155 struct omap_overlay_info *info1, *info2;
156
157 list_for_each_entry(ovl1, &mgr->overlays, list) {
158 info1 = overlay_infos[ovl1->id];
159
160 if (info1 == NULL)
161 continue;
162
163 list_for_each_entry(ovl2, &mgr->overlays, list) {
164 if (ovl1 == ovl2)
165 continue;
166
167 info2 = overlay_infos[ovl2->id];
168
169 if (info2 == NULL)
170 continue;
171
172 if (info1->zorder == info2->zorder) {
173 DSSERR("overlays %d and %d have the same "
174 "zorder %d\n",
175 ovl1->id, ovl2->id, info1->zorder);
176 return -EINVAL;
177 }
178 }
179 }
180
181 return 0;
182}
183
184int dss_mgr_check_timings(struct omap_overlay_manager *mgr,
185 const struct omap_video_timings *timings)
186{
187 if (!dispc_mgr_timings_ok(mgr->id, timings)) {
188 DSSERR("check_manager: invalid timings\n");
189 return -EINVAL;
190 }
191
192 return 0;
193}
194
195static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr,
196 const struct dss_lcd_mgr_config *config)
197{
198 struct dispc_clock_info cinfo = config->clock_info;
199 int dl = config->video_port_width;
200 bool stallmode = config->stallmode;
201 bool fifohandcheck = config->fifohandcheck;
202
203 if (cinfo.lck_div < 1 || cinfo.lck_div > 255)
204 return -EINVAL;
205
206 if (cinfo.pck_div < 1 || cinfo.pck_div > 255)
207 return -EINVAL;
208
209 if (dl != 12 && dl != 16 && dl != 18 && dl != 24)
210 return -EINVAL;
211
212 /* fifohandcheck should be used only with stallmode */
213 if (stallmode == false && fifohandcheck == true)
214 return -EINVAL;
215
216 /*
217 * io pad mode can be only checked by using dssdev connected to the
218 * manager. Ignore checking these for now, add checks when manager
219 * is capable of holding information related to the connected interface
220 */
221
222 return 0;
223}
224
225int dss_mgr_check(struct omap_overlay_manager *mgr,
226 struct omap_overlay_manager_info *info,
227 const struct omap_video_timings *mgr_timings,
228 const struct dss_lcd_mgr_config *lcd_config,
229 struct omap_overlay_info **overlay_infos)
230{
231 struct omap_overlay *ovl;
232 int r;
233
234 if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) {
235 r = dss_mgr_check_zorder(mgr, overlay_infos);
236 if (r)
237 return r;
238 }
239
240 r = dss_mgr_check_timings(mgr, mgr_timings);
241 if (r)
242 return r;
243
244 r = dss_mgr_check_lcd_config(mgr, lcd_config);
245 if (r)
246 return r;
247
248 list_for_each_entry(ovl, &mgr->overlays, list) {
249 struct omap_overlay_info *oi;
250 int r;
251
252 oi = overlay_infos[ovl->id];
253
254 if (oi == NULL)
255 continue;
256
257 r = dss_ovl_check(ovl, oi, mgr_timings);
258 if (r)
259 return r;
260 }
261
262 return 0;
263}
diff --git a/drivers/video/fbdev/omap2/dss/output.c b/drivers/video/fbdev/omap2/dss/output.c
new file mode 100644
index 000000000000..2ab3afa615e8
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/output.c
@@ -0,0 +1,254 @@
1/*
2 * Copyright (C) 2012 Texas Instruments Ltd
3 * Author: Archit Taneja <archit@ti.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/platform_device.h>
21#include <linux/slab.h>
22
23#include <video/omapdss.h>
24
25#include "dss.h"
26
27static LIST_HEAD(output_list);
28static DEFINE_MUTEX(output_lock);
29
30int omapdss_output_set_device(struct omap_dss_device *out,
31 struct omap_dss_device *dssdev)
32{
33 int r;
34
35 mutex_lock(&output_lock);
36
37 if (out->dst) {
38 DSSERR("output already has device %s connected to it\n",
39 out->dst->name);
40 r = -EINVAL;
41 goto err;
42 }
43
44 if (out->output_type != dssdev->type) {
45 DSSERR("output type and display type don't match\n");
46 r = -EINVAL;
47 goto err;
48 }
49
50 out->dst = dssdev;
51 dssdev->src = out;
52
53 mutex_unlock(&output_lock);
54
55 return 0;
56err:
57 mutex_unlock(&output_lock);
58
59 return r;
60}
61EXPORT_SYMBOL(omapdss_output_set_device);
62
63int omapdss_output_unset_device(struct omap_dss_device *out)
64{
65 int r;
66
67 mutex_lock(&output_lock);
68
69 if (!out->dst) {
70 DSSERR("output doesn't have a device connected to it\n");
71 r = -EINVAL;
72 goto err;
73 }
74
75 if (out->dst->state != OMAP_DSS_DISPLAY_DISABLED) {
76 DSSERR("device %s is not disabled, cannot unset device\n",
77 out->dst->name);
78 r = -EINVAL;
79 goto err;
80 }
81
82 out->dst->src = NULL;
83 out->dst = NULL;
84
85 mutex_unlock(&output_lock);
86
87 return 0;
88err:
89 mutex_unlock(&output_lock);
90
91 return r;
92}
93EXPORT_SYMBOL(omapdss_output_unset_device);
94
95int omapdss_register_output(struct omap_dss_device *out)
96{
97 list_add_tail(&out->list, &output_list);
98 return 0;
99}
100EXPORT_SYMBOL(omapdss_register_output);
101
102void omapdss_unregister_output(struct omap_dss_device *out)
103{
104 list_del(&out->list);
105}
106EXPORT_SYMBOL(omapdss_unregister_output);
107
108struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id)
109{
110 struct omap_dss_device *out;
111
112 list_for_each_entry(out, &output_list, list) {
113 if (out->id == id)
114 return out;
115 }
116
117 return NULL;
118}
119EXPORT_SYMBOL(omap_dss_get_output);
120
121struct omap_dss_device *omap_dss_find_output(const char *name)
122{
123 struct omap_dss_device *out;
124
125 list_for_each_entry(out, &output_list, list) {
126 if (strcmp(out->name, name) == 0)
127 return omap_dss_get_device(out);
128 }
129
130 return NULL;
131}
132EXPORT_SYMBOL(omap_dss_find_output);
133
134struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node)
135{
136 struct omap_dss_device *out;
137
138 list_for_each_entry(out, &output_list, list) {
139 if (out->dev->of_node == node)
140 return omap_dss_get_device(out);
141 }
142
143 return NULL;
144}
145EXPORT_SYMBOL(omap_dss_find_output_by_node);
146
147struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev)
148{
149 while (dssdev->src)
150 dssdev = dssdev->src;
151
152 if (dssdev->id != 0)
153 return omap_dss_get_device(dssdev);
154
155 return NULL;
156}
157EXPORT_SYMBOL(omapdss_find_output_from_display);
158
159struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev)
160{
161 struct omap_dss_device *out;
162 struct omap_overlay_manager *mgr;
163
164 out = omapdss_find_output_from_display(dssdev);
165
166 if (out == NULL)
167 return NULL;
168
169 mgr = out->manager;
170
171 omap_dss_put_device(out);
172
173 return mgr;
174}
175EXPORT_SYMBOL(omapdss_find_mgr_from_display);
176
177static const struct dss_mgr_ops *dss_mgr_ops;
178
179int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops)
180{
181 if (dss_mgr_ops)
182 return -EBUSY;
183
184 dss_mgr_ops = mgr_ops;
185
186 return 0;
187}
188EXPORT_SYMBOL(dss_install_mgr_ops);
189
190void dss_uninstall_mgr_ops(void)
191{
192 dss_mgr_ops = NULL;
193}
194EXPORT_SYMBOL(dss_uninstall_mgr_ops);
195
196int dss_mgr_connect(struct omap_overlay_manager *mgr,
197 struct omap_dss_device *dst)
198{
199 return dss_mgr_ops->connect(mgr, dst);
200}
201EXPORT_SYMBOL(dss_mgr_connect);
202
203void dss_mgr_disconnect(struct omap_overlay_manager *mgr,
204 struct omap_dss_device *dst)
205{
206 dss_mgr_ops->disconnect(mgr, dst);
207}
208EXPORT_SYMBOL(dss_mgr_disconnect);
209
210void dss_mgr_set_timings(struct omap_overlay_manager *mgr,
211 const struct omap_video_timings *timings)
212{
213 dss_mgr_ops->set_timings(mgr, timings);
214}
215EXPORT_SYMBOL(dss_mgr_set_timings);
216
217void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr,
218 const struct dss_lcd_mgr_config *config)
219{
220 dss_mgr_ops->set_lcd_config(mgr, config);
221}
222EXPORT_SYMBOL(dss_mgr_set_lcd_config);
223
224int dss_mgr_enable(struct omap_overlay_manager *mgr)
225{
226 return dss_mgr_ops->enable(mgr);
227}
228EXPORT_SYMBOL(dss_mgr_enable);
229
230void dss_mgr_disable(struct omap_overlay_manager *mgr)
231{
232 dss_mgr_ops->disable(mgr);
233}
234EXPORT_SYMBOL(dss_mgr_disable);
235
236void dss_mgr_start_update(struct omap_overlay_manager *mgr)
237{
238 dss_mgr_ops->start_update(mgr);
239}
240EXPORT_SYMBOL(dss_mgr_start_update);
241
242int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr,
243 void (*handler)(void *), void *data)
244{
245 return dss_mgr_ops->register_framedone_handler(mgr, handler, data);
246}
247EXPORT_SYMBOL(dss_mgr_register_framedone_handler);
248
249void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr,
250 void (*handler)(void *), void *data)
251{
252 dss_mgr_ops->unregister_framedone_handler(mgr, handler, data);
253}
254EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler);
diff --git a/drivers/video/fbdev/omap2/dss/overlay-sysfs.c b/drivers/video/fbdev/omap2/dss/overlay-sysfs.c
new file mode 100644
index 000000000000..4cc5ddebfb34
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/overlay-sysfs.c
@@ -0,0 +1,456 @@
1/*
2 * Copyright (C) 2009 Nokia Corporation
3 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
4 *
5 * Some code and ideas taken from drivers/video/omap/ driver
6 * by Imre Deak.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#define DSS_SUBSYS_NAME "OVERLAY"
22
23#include <linux/module.h>
24#include <linux/err.h>
25#include <linux/sysfs.h>
26#include <linux/kobject.h>
27#include <linux/platform_device.h>
28
29#include <video/omapdss.h>
30
31#include "dss.h"
32#include "dss_features.h"
33
34static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
35{
36 return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
37}
38
39static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
40{
41 return snprintf(buf, PAGE_SIZE, "%s\n",
42 ovl->manager ? ovl->manager->name : "<none>");
43}
44
45static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
46 size_t size)
47{
48 int i, r;
49 struct omap_overlay_manager *mgr = NULL;
50 struct omap_overlay_manager *old_mgr;
51 int len = size;
52
53 if (buf[size-1] == '\n')
54 --len;
55
56 if (len > 0) {
57 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
58 mgr = omap_dss_get_overlay_manager(i);
59
60 if (sysfs_streq(buf, mgr->name))
61 break;
62
63 mgr = NULL;
64 }
65 }
66
67 if (len > 0 && mgr == NULL)
68 return -EINVAL;
69
70 if (mgr)
71 DSSDBG("manager %s found\n", mgr->name);
72
73 if (mgr == ovl->manager)
74 return size;
75
76 old_mgr = ovl->manager;
77
78 r = dispc_runtime_get();
79 if (r)
80 return r;
81
82 /* detach old manager */
83 if (old_mgr) {
84 r = ovl->unset_manager(ovl);
85 if (r) {
86 DSSERR("detach failed\n");
87 goto err;
88 }
89
90 r = old_mgr->apply(old_mgr);
91 if (r)
92 goto err;
93 }
94
95 if (mgr) {
96 r = ovl->set_manager(ovl, mgr);
97 if (r) {
98 DSSERR("Failed to attach overlay\n");
99 goto err;
100 }
101
102 r = mgr->apply(mgr);
103 if (r)
104 goto err;
105 }
106
107 dispc_runtime_put();
108
109 return size;
110
111err:
112 dispc_runtime_put();
113 return r;
114}
115
116static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
117{
118 struct omap_overlay_info info;
119
120 ovl->get_overlay_info(ovl, &info);
121
122 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
123 info.width, info.height);
124}
125
126static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
127{
128 struct omap_overlay_info info;
129
130 ovl->get_overlay_info(ovl, &info);
131
132 return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width);
133}
134
135static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
136{
137 struct omap_overlay_info info;
138
139 ovl->get_overlay_info(ovl, &info);
140
141 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
142 info.pos_x, info.pos_y);
143}
144
145static ssize_t overlay_position_store(struct omap_overlay *ovl,
146 const char *buf, size_t size)
147{
148 int r;
149 char *last;
150 struct omap_overlay_info info;
151
152 ovl->get_overlay_info(ovl, &info);
153
154 info.pos_x = simple_strtoul(buf, &last, 10);
155 ++last;
156 if (last - buf >= size)
157 return -EINVAL;
158
159 info.pos_y = simple_strtoul(last, &last, 10);
160
161 r = ovl->set_overlay_info(ovl, &info);
162 if (r)
163 return r;
164
165 if (ovl->manager) {
166 r = ovl->manager->apply(ovl->manager);
167 if (r)
168 return r;
169 }
170
171 return size;
172}
173
174static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
175{
176 struct omap_overlay_info info;
177
178 ovl->get_overlay_info(ovl, &info);
179
180 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
181 info.out_width, info.out_height);
182}
183
184static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
185 const char *buf, size_t size)
186{
187 int r;
188 char *last;
189 struct omap_overlay_info info;
190
191 ovl->get_overlay_info(ovl, &info);
192
193 info.out_width = simple_strtoul(buf, &last, 10);
194 ++last;
195 if (last - buf >= size)
196 return -EINVAL;
197
198 info.out_height = simple_strtoul(last, &last, 10);
199
200 r = ovl->set_overlay_info(ovl, &info);
201 if (r)
202 return r;
203
204 if (ovl->manager) {
205 r = ovl->manager->apply(ovl->manager);
206 if (r)
207 return r;
208 }
209
210 return size;
211}
212
213static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
214{
215 return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl));
216}
217
218static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
219 size_t size)
220{
221 int r;
222 bool enable;
223
224 r = strtobool(buf, &enable);
225 if (r)
226 return r;
227
228 if (enable)
229 r = ovl->enable(ovl);
230 else
231 r = ovl->disable(ovl);
232
233 if (r)
234 return r;
235
236 return size;
237}
238
239static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
240{
241 struct omap_overlay_info info;
242
243 ovl->get_overlay_info(ovl, &info);
244
245 return snprintf(buf, PAGE_SIZE, "%d\n",
246 info.global_alpha);
247}
248
249static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
250 const char *buf, size_t size)
251{
252 int r;
253 u8 alpha;
254 struct omap_overlay_info info;
255
256 if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
257 return -ENODEV;
258
259 r = kstrtou8(buf, 0, &alpha);
260 if (r)
261 return r;
262
263 ovl->get_overlay_info(ovl, &info);
264
265 info.global_alpha = alpha;
266
267 r = ovl->set_overlay_info(ovl, &info);
268 if (r)
269 return r;
270
271 if (ovl->manager) {
272 r = ovl->manager->apply(ovl->manager);
273 if (r)
274 return r;
275 }
276
277 return size;
278}
279
280static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl,
281 char *buf)
282{
283 struct omap_overlay_info info;
284
285 ovl->get_overlay_info(ovl, &info);
286
287 return snprintf(buf, PAGE_SIZE, "%d\n",
288 info.pre_mult_alpha);
289}
290
291static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
292 const char *buf, size_t size)
293{
294 int r;
295 u8 alpha;
296 struct omap_overlay_info info;
297
298 if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
299 return -ENODEV;
300
301 r = kstrtou8(buf, 0, &alpha);
302 if (r)
303 return r;
304
305 ovl->get_overlay_info(ovl, &info);
306
307 info.pre_mult_alpha = alpha;
308
309 r = ovl->set_overlay_info(ovl, &info);
310 if (r)
311 return r;
312
313 if (ovl->manager) {
314 r = ovl->manager->apply(ovl->manager);
315 if (r)
316 return r;
317 }
318
319 return size;
320}
321
322static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf)
323{
324 struct omap_overlay_info info;
325
326 ovl->get_overlay_info(ovl, &info);
327
328 return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder);
329}
330
331static ssize_t overlay_zorder_store(struct omap_overlay *ovl,
332 const char *buf, size_t size)
333{
334 int r;
335 u8 zorder;
336 struct omap_overlay_info info;
337
338 if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
339 return -ENODEV;
340
341 r = kstrtou8(buf, 0, &zorder);
342 if (r)
343 return r;
344
345 ovl->get_overlay_info(ovl, &info);
346
347 info.zorder = zorder;
348
349 r = ovl->set_overlay_info(ovl, &info);
350 if (r)
351 return r;
352
353 if (ovl->manager) {
354 r = ovl->manager->apply(ovl->manager);
355 if (r)
356 return r;
357 }
358
359 return size;
360}
361
362struct overlay_attribute {
363 struct attribute attr;
364 ssize_t (*show)(struct omap_overlay *, char *);
365 ssize_t (*store)(struct omap_overlay *, const char *, size_t);
366};
367
368#define OVERLAY_ATTR(_name, _mode, _show, _store) \
369 struct overlay_attribute overlay_attr_##_name = \
370 __ATTR(_name, _mode, _show, _store)
371
372static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
373static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
374 overlay_manager_show, overlay_manager_store);
375static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
376static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
377static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
378 overlay_position_show, overlay_position_store);
379static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
380 overlay_output_size_show, overlay_output_size_store);
381static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
382 overlay_enabled_show, overlay_enabled_store);
383static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
384 overlay_global_alpha_show, overlay_global_alpha_store);
385static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR,
386 overlay_pre_mult_alpha_show,
387 overlay_pre_mult_alpha_store);
388static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR,
389 overlay_zorder_show, overlay_zorder_store);
390
391static struct attribute *overlay_sysfs_attrs[] = {
392 &overlay_attr_name.attr,
393 &overlay_attr_manager.attr,
394 &overlay_attr_input_size.attr,
395 &overlay_attr_screen_width.attr,
396 &overlay_attr_position.attr,
397 &overlay_attr_output_size.attr,
398 &overlay_attr_enabled.attr,
399 &overlay_attr_global_alpha.attr,
400 &overlay_attr_pre_mult_alpha.attr,
401 &overlay_attr_zorder.attr,
402 NULL
403};
404
405static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
406 char *buf)
407{
408 struct omap_overlay *overlay;
409 struct overlay_attribute *overlay_attr;
410
411 overlay = container_of(kobj, struct omap_overlay, kobj);
412 overlay_attr = container_of(attr, struct overlay_attribute, attr);
413
414 if (!overlay_attr->show)
415 return -ENOENT;
416
417 return overlay_attr->show(overlay, buf);
418}
419
420static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
421 const char *buf, size_t size)
422{
423 struct omap_overlay *overlay;
424 struct overlay_attribute *overlay_attr;
425
426 overlay = container_of(kobj, struct omap_overlay, kobj);
427 overlay_attr = container_of(attr, struct overlay_attribute, attr);
428
429 if (!overlay_attr->store)
430 return -ENOENT;
431
432 return overlay_attr->store(overlay, buf, size);
433}
434
435static const struct sysfs_ops overlay_sysfs_ops = {
436 .show = overlay_attr_show,
437 .store = overlay_attr_store,
438};
439
440static struct kobj_type overlay_ktype = {
441 .sysfs_ops = &overlay_sysfs_ops,
442 .default_attrs = overlay_sysfs_attrs,
443};
444
445int dss_overlay_kobj_init(struct omap_overlay *ovl,
446 struct platform_device *pdev)
447{
448 return kobject_init_and_add(&ovl->kobj, &overlay_ktype,
449 &pdev->dev.kobj, "overlay%d", ovl->id);
450}
451
452void dss_overlay_kobj_uninit(struct omap_overlay *ovl)
453{
454 kobject_del(&ovl->kobj);
455 kobject_put(&ovl->kobj);
456}
diff --git a/drivers/video/fbdev/omap2/dss/overlay.c b/drivers/video/fbdev/omap2/dss/overlay.c
new file mode 100644
index 000000000000..2f7cee985cdd
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/overlay.c
@@ -0,0 +1,202 @@
1/*
2 * linux/drivers/video/omap2/dss/overlay.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 "OVERLAY"
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/err.h>
28#include <linux/sysfs.h>
29#include <linux/platform_device.h>
30#include <linux/delay.h>
31#include <linux/slab.h>
32
33#include <video/omapdss.h>
34
35#include "dss.h"
36#include "dss_features.h"
37
38static int num_overlays;
39static struct omap_overlay *overlays;
40
41int omap_dss_get_num_overlays(void)
42{
43 return num_overlays;
44}
45EXPORT_SYMBOL(omap_dss_get_num_overlays);
46
47struct omap_overlay *omap_dss_get_overlay(int num)
48{
49 if (num >= num_overlays)
50 return NULL;
51
52 return &overlays[num];
53}
54EXPORT_SYMBOL(omap_dss_get_overlay);
55
56void dss_init_overlays(struct platform_device *pdev)
57{
58 int i, r;
59
60 num_overlays = dss_feat_get_num_ovls();
61
62 overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays,
63 GFP_KERNEL);
64
65 BUG_ON(overlays == NULL);
66
67 for (i = 0; i < num_overlays; ++i) {
68 struct omap_overlay *ovl = &overlays[i];
69
70 switch (i) {
71 case 0:
72 ovl->name = "gfx";
73 ovl->id = OMAP_DSS_GFX;
74 break;
75 case 1:
76 ovl->name = "vid1";
77 ovl->id = OMAP_DSS_VIDEO1;
78 break;
79 case 2:
80 ovl->name = "vid2";
81 ovl->id = OMAP_DSS_VIDEO2;
82 break;
83 case 3:
84 ovl->name = "vid3";
85 ovl->id = OMAP_DSS_VIDEO3;
86 break;
87 }
88
89 ovl->caps = dss_feat_get_overlay_caps(ovl->id);
90 ovl->supported_modes =
91 dss_feat_get_supported_color_modes(ovl->id);
92
93 r = dss_overlay_kobj_init(ovl, pdev);
94 if (r)
95 DSSERR("failed to create sysfs file\n");
96 }
97}
98
99void dss_uninit_overlays(struct platform_device *pdev)
100{
101 int i;
102
103 for (i = 0; i < num_overlays; ++i) {
104 struct omap_overlay *ovl = &overlays[i];
105 dss_overlay_kobj_uninit(ovl);
106 }
107
108 kfree(overlays);
109 overlays = NULL;
110 num_overlays = 0;
111}
112
113int dss_ovl_simple_check(struct omap_overlay *ovl,
114 const struct omap_overlay_info *info)
115{
116 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
117 if (info->out_width != 0 && info->width != info->out_width) {
118 DSSERR("check_overlay: overlay %d doesn't support "
119 "scaling\n", ovl->id);
120 return -EINVAL;
121 }
122
123 if (info->out_height != 0 && info->height != info->out_height) {
124 DSSERR("check_overlay: overlay %d doesn't support "
125 "scaling\n", ovl->id);
126 return -EINVAL;
127 }
128 }
129
130 if ((ovl->supported_modes & info->color_mode) == 0) {
131 DSSERR("check_overlay: overlay %d doesn't support mode %d\n",
132 ovl->id, info->color_mode);
133 return -EINVAL;
134 }
135
136 if (info->zorder >= omap_dss_get_num_overlays()) {
137 DSSERR("check_overlay: zorder %d too high\n", info->zorder);
138 return -EINVAL;
139 }
140
141 if (dss_feat_rotation_type_supported(info->rotation_type) == 0) {
142 DSSERR("check_overlay: rotation type %d not supported\n",
143 info->rotation_type);
144 return -EINVAL;
145 }
146
147 return 0;
148}
149
150int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info,
151 const struct omap_video_timings *mgr_timings)
152{
153 u16 outw, outh;
154 u16 dw, dh;
155
156 dw = mgr_timings->x_res;
157 dh = mgr_timings->y_res;
158
159 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
160 outw = info->width;
161 outh = info->height;
162 } else {
163 if (info->out_width == 0)
164 outw = info->width;
165 else
166 outw = info->out_width;
167
168 if (info->out_height == 0)
169 outh = info->height;
170 else
171 outh = info->out_height;
172 }
173
174 if (dw < info->pos_x + outw) {
175 DSSERR("overlay %d horizontally not inside the display area "
176 "(%d + %d >= %d)\n",
177 ovl->id, info->pos_x, outw, dw);
178 return -EINVAL;
179 }
180
181 if (dh < info->pos_y + outh) {
182 DSSERR("overlay %d vertically not inside the display area "
183 "(%d + %d >= %d)\n",
184 ovl->id, info->pos_y, outh, dh);
185 return -EINVAL;
186 }
187
188 return 0;
189}
190
191/*
192 * Checks if replication logic should be used. Only use when overlay is in
193 * RGB12U or RGB16 mode, and video port width interface is 18bpp or 24bpp
194 */
195bool dss_ovl_use_replication(struct dss_lcd_mgr_config config,
196 enum omap_color_mode mode)
197{
198 if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
199 return false;
200
201 return config.video_port_width > 16;
202}
diff --git a/drivers/video/fbdev/omap2/dss/rfbi.c b/drivers/video/fbdev/omap2/dss/rfbi.c
new file mode 100644
index 000000000000..c8a81a2b879c
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/rfbi.c
@@ -0,0 +1,1058 @@
1/*
2 * linux/drivers/video/omap2/dss/rfbi.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 "RFBI"
24
25#include <linux/kernel.h>
26#include <linux/dma-mapping.h>
27#include <linux/export.h>
28#include <linux/vmalloc.h>
29#include <linux/clk.h>
30#include <linux/io.h>
31#include <linux/delay.h>
32#include <linux/kfifo.h>
33#include <linux/ktime.h>
34#include <linux/hrtimer.h>
35#include <linux/seq_file.h>
36#include <linux/semaphore.h>
37#include <linux/platform_device.h>
38#include <linux/pm_runtime.h>
39
40#include <video/omapdss.h>
41#include "dss.h"
42
43struct rfbi_reg { u16 idx; };
44
45#define RFBI_REG(idx) ((const struct rfbi_reg) { idx })
46
47#define RFBI_REVISION RFBI_REG(0x0000)
48#define RFBI_SYSCONFIG RFBI_REG(0x0010)
49#define RFBI_SYSSTATUS RFBI_REG(0x0014)
50#define RFBI_CONTROL RFBI_REG(0x0040)
51#define RFBI_PIXEL_CNT RFBI_REG(0x0044)
52#define RFBI_LINE_NUMBER RFBI_REG(0x0048)
53#define RFBI_CMD RFBI_REG(0x004c)
54#define RFBI_PARAM RFBI_REG(0x0050)
55#define RFBI_DATA RFBI_REG(0x0054)
56#define RFBI_READ RFBI_REG(0x0058)
57#define RFBI_STATUS RFBI_REG(0x005c)
58
59#define RFBI_CONFIG(n) RFBI_REG(0x0060 + (n)*0x18)
60#define RFBI_ONOFF_TIME(n) RFBI_REG(0x0064 + (n)*0x18)
61#define RFBI_CYCLE_TIME(n) RFBI_REG(0x0068 + (n)*0x18)
62#define RFBI_DATA_CYCLE1(n) RFBI_REG(0x006c + (n)*0x18)
63#define RFBI_DATA_CYCLE2(n) RFBI_REG(0x0070 + (n)*0x18)
64#define RFBI_DATA_CYCLE3(n) RFBI_REG(0x0074 + (n)*0x18)
65
66#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090)
67#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094)
68
69#define REG_FLD_MOD(idx, val, start, end) \
70 rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
71
72enum omap_rfbi_cycleformat {
73 OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0,
74 OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1,
75 OMAP_DSS_RFBI_CYCLEFORMAT_3_1 = 2,
76 OMAP_DSS_RFBI_CYCLEFORMAT_3_2 = 3,
77};
78
79enum omap_rfbi_datatype {
80 OMAP_DSS_RFBI_DATATYPE_12 = 0,
81 OMAP_DSS_RFBI_DATATYPE_16 = 1,
82 OMAP_DSS_RFBI_DATATYPE_18 = 2,
83 OMAP_DSS_RFBI_DATATYPE_24 = 3,
84};
85
86enum omap_rfbi_parallelmode {
87 OMAP_DSS_RFBI_PARALLELMODE_8 = 0,
88 OMAP_DSS_RFBI_PARALLELMODE_9 = 1,
89 OMAP_DSS_RFBI_PARALLELMODE_12 = 2,
90 OMAP_DSS_RFBI_PARALLELMODE_16 = 3,
91};
92
93static int rfbi_convert_timings(struct rfbi_timings *t);
94static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
95
96static struct {
97 struct platform_device *pdev;
98 void __iomem *base;
99
100 unsigned long l4_khz;
101
102 enum omap_rfbi_datatype datatype;
103 enum omap_rfbi_parallelmode parallelmode;
104
105 enum omap_rfbi_te_mode te_mode;
106 int te_enabled;
107
108 void (*framedone_callback)(void *data);
109 void *framedone_callback_data;
110
111 struct omap_dss_device *dssdev[2];
112
113 struct semaphore bus_lock;
114
115 struct omap_video_timings timings;
116 int pixel_size;
117 int data_lines;
118 struct rfbi_timings intf_timings;
119
120 struct omap_dss_device output;
121} rfbi;
122
123static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
124{
125 __raw_writel(val, rfbi.base + idx.idx);
126}
127
128static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
129{
130 return __raw_readl(rfbi.base + idx.idx);
131}
132
133static int rfbi_runtime_get(void)
134{
135 int r;
136
137 DSSDBG("rfbi_runtime_get\n");
138
139 r = pm_runtime_get_sync(&rfbi.pdev->dev);
140 WARN_ON(r < 0);
141 return r < 0 ? r : 0;
142}
143
144static void rfbi_runtime_put(void)
145{
146 int r;
147
148 DSSDBG("rfbi_runtime_put\n");
149
150 r = pm_runtime_put_sync(&rfbi.pdev->dev);
151 WARN_ON(r < 0 && r != -ENOSYS);
152}
153
154static void rfbi_bus_lock(void)
155{
156 down(&rfbi.bus_lock);
157}
158
159static void rfbi_bus_unlock(void)
160{
161 up(&rfbi.bus_lock);
162}
163
164static void rfbi_write_command(const void *buf, u32 len)
165{
166 switch (rfbi.parallelmode) {
167 case OMAP_DSS_RFBI_PARALLELMODE_8:
168 {
169 const u8 *b = buf;
170 for (; len; len--)
171 rfbi_write_reg(RFBI_CMD, *b++);
172 break;
173 }
174
175 case OMAP_DSS_RFBI_PARALLELMODE_16:
176 {
177 const u16 *w = buf;
178 BUG_ON(len & 1);
179 for (; len; len -= 2)
180 rfbi_write_reg(RFBI_CMD, *w++);
181 break;
182 }
183
184 case OMAP_DSS_RFBI_PARALLELMODE_9:
185 case OMAP_DSS_RFBI_PARALLELMODE_12:
186 default:
187 BUG();
188 }
189}
190
191static void rfbi_read_data(void *buf, u32 len)
192{
193 switch (rfbi.parallelmode) {
194 case OMAP_DSS_RFBI_PARALLELMODE_8:
195 {
196 u8 *b = buf;
197 for (; len; len--) {
198 rfbi_write_reg(RFBI_READ, 0);
199 *b++ = rfbi_read_reg(RFBI_READ);
200 }
201 break;
202 }
203
204 case OMAP_DSS_RFBI_PARALLELMODE_16:
205 {
206 u16 *w = buf;
207 BUG_ON(len & ~1);
208 for (; len; len -= 2) {
209 rfbi_write_reg(RFBI_READ, 0);
210 *w++ = rfbi_read_reg(RFBI_READ);
211 }
212 break;
213 }
214
215 case OMAP_DSS_RFBI_PARALLELMODE_9:
216 case OMAP_DSS_RFBI_PARALLELMODE_12:
217 default:
218 BUG();
219 }
220}
221
222static void rfbi_write_data(const void *buf, u32 len)
223{
224 switch (rfbi.parallelmode) {
225 case OMAP_DSS_RFBI_PARALLELMODE_8:
226 {
227 const u8 *b = buf;
228 for (; len; len--)
229 rfbi_write_reg(RFBI_PARAM, *b++);
230 break;
231 }
232
233 case OMAP_DSS_RFBI_PARALLELMODE_16:
234 {
235 const u16 *w = buf;
236 BUG_ON(len & 1);
237 for (; len; len -= 2)
238 rfbi_write_reg(RFBI_PARAM, *w++);
239 break;
240 }
241
242 case OMAP_DSS_RFBI_PARALLELMODE_9:
243 case OMAP_DSS_RFBI_PARALLELMODE_12:
244 default:
245 BUG();
246
247 }
248}
249
250static void rfbi_write_pixels(const void __iomem *buf, int scr_width,
251 u16 x, u16 y,
252 u16 w, u16 h)
253{
254 int start_offset = scr_width * y + x;
255 int horiz_offset = scr_width - w;
256 int i;
257
258 if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
259 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
260 const u16 __iomem *pd = buf;
261 pd += start_offset;
262
263 for (; h; --h) {
264 for (i = 0; i < w; ++i) {
265 const u8 __iomem *b = (const u8 __iomem *)pd;
266 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
267 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
268 ++pd;
269 }
270 pd += horiz_offset;
271 }
272 } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_24 &&
273 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
274 const u32 __iomem *pd = buf;
275 pd += start_offset;
276
277 for (; h; --h) {
278 for (i = 0; i < w; ++i) {
279 const u8 __iomem *b = (const u8 __iomem *)pd;
280 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+2));
281 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
282 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
283 ++pd;
284 }
285 pd += horiz_offset;
286 }
287 } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
288 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_16) {
289 const u16 __iomem *pd = buf;
290 pd += start_offset;
291
292 for (; h; --h) {
293 for (i = 0; i < w; ++i) {
294 rfbi_write_reg(RFBI_PARAM, __raw_readw(pd));
295 ++pd;
296 }
297 pd += horiz_offset;
298 }
299 } else {
300 BUG();
301 }
302}
303
304static int rfbi_transfer_area(struct omap_dss_device *dssdev,
305 void (*callback)(void *data), void *data)
306{
307 u32 l;
308 int r;
309 struct omap_overlay_manager *mgr = rfbi.output.manager;
310 u16 width = rfbi.timings.x_res;
311 u16 height = rfbi.timings.y_res;
312
313 /*BUG_ON(callback == 0);*/
314 BUG_ON(rfbi.framedone_callback != NULL);
315
316 DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
317
318 dss_mgr_set_timings(mgr, &rfbi.timings);
319
320 r = dss_mgr_enable(mgr);
321 if (r)
322 return r;
323
324 rfbi.framedone_callback = callback;
325 rfbi.framedone_callback_data = data;
326
327 rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
328
329 l = rfbi_read_reg(RFBI_CONTROL);
330 l = FLD_MOD(l, 1, 0, 0); /* enable */
331 if (!rfbi.te_enabled)
332 l = FLD_MOD(l, 1, 4, 4); /* ITE */
333
334 rfbi_write_reg(RFBI_CONTROL, l);
335
336 return 0;
337}
338
339static void framedone_callback(void *data)
340{
341 void (*callback)(void *data);
342
343 DSSDBG("FRAMEDONE\n");
344
345 REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
346
347 callback = rfbi.framedone_callback;
348 rfbi.framedone_callback = NULL;
349
350 if (callback != NULL)
351 callback(rfbi.framedone_callback_data);
352}
353
354#if 1 /* VERBOSE */
355static void rfbi_print_timings(void)
356{
357 u32 l;
358 u32 time;
359
360 l = rfbi_read_reg(RFBI_CONFIG(0));
361 time = 1000000000 / rfbi.l4_khz;
362 if (l & (1 << 4))
363 time *= 2;
364
365 DSSDBG("Tick time %u ps\n", time);
366 l = rfbi_read_reg(RFBI_ONOFF_TIME(0));
367 DSSDBG("CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
368 "REONTIME %d, REOFFTIME %d\n",
369 l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
370 (l >> 20) & 0x0f, (l >> 24) & 0x3f);
371
372 l = rfbi_read_reg(RFBI_CYCLE_TIME(0));
373 DSSDBG("WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
374 "ACCESSTIME %d\n",
375 (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
376 (l >> 22) & 0x3f);
377}
378#else
379static void rfbi_print_timings(void) {}
380#endif
381
382
383
384
385static u32 extif_clk_period;
386
387static inline unsigned long round_to_extif_ticks(unsigned long ps, int div)
388{
389 int bus_tick = extif_clk_period * div;
390 return (ps + bus_tick - 1) / bus_tick * bus_tick;
391}
392
393static int calc_reg_timing(struct rfbi_timings *t, int div)
394{
395 t->clk_div = div;
396
397 t->cs_on_time = round_to_extif_ticks(t->cs_on_time, div);
398
399 t->we_on_time = round_to_extif_ticks(t->we_on_time, div);
400 t->we_off_time = round_to_extif_ticks(t->we_off_time, div);
401 t->we_cycle_time = round_to_extif_ticks(t->we_cycle_time, div);
402
403 t->re_on_time = round_to_extif_ticks(t->re_on_time, div);
404 t->re_off_time = round_to_extif_ticks(t->re_off_time, div);
405 t->re_cycle_time = round_to_extif_ticks(t->re_cycle_time, div);
406
407 t->access_time = round_to_extif_ticks(t->access_time, div);
408 t->cs_off_time = round_to_extif_ticks(t->cs_off_time, div);
409 t->cs_pulse_width = round_to_extif_ticks(t->cs_pulse_width, div);
410
411 DSSDBG("[reg]cson %d csoff %d reon %d reoff %d\n",
412 t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
413 DSSDBG("[reg]weon %d weoff %d recyc %d wecyc %d\n",
414 t->we_on_time, t->we_off_time, t->re_cycle_time,
415 t->we_cycle_time);
416 DSSDBG("[reg]rdaccess %d cspulse %d\n",
417 t->access_time, t->cs_pulse_width);
418
419 return rfbi_convert_timings(t);
420}
421
422static int calc_extif_timings(struct rfbi_timings *t)
423{
424 u32 max_clk_div;
425 int div;
426
427 rfbi_get_clk_info(&extif_clk_period, &max_clk_div);
428 for (div = 1; div <= max_clk_div; div++) {
429 if (calc_reg_timing(t, div) == 0)
430 break;
431 }
432
433 if (div <= max_clk_div)
434 return 0;
435
436 DSSERR("can't setup timings\n");
437 return -1;
438}
439
440
441static void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
442{
443 int r;
444
445 if (!t->converted) {
446 r = calc_extif_timings(t);
447 if (r < 0)
448 DSSERR("Failed to calc timings\n");
449 }
450
451 BUG_ON(!t->converted);
452
453 rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]);
454 rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]);
455
456 /* TIMEGRANULARITY */
457 REG_FLD_MOD(RFBI_CONFIG(rfbi_module),
458 (t->tim[2] ? 1 : 0), 4, 4);
459
460 rfbi_print_timings();
461}
462
463static int ps_to_rfbi_ticks(int time, int div)
464{
465 unsigned long tick_ps;
466 int ret;
467
468 /* Calculate in picosecs to yield more exact results */
469 tick_ps = 1000000000 / (rfbi.l4_khz) * div;
470
471 ret = (time + tick_ps - 1) / tick_ps;
472
473 return ret;
474}
475
476static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
477{
478 *clk_period = 1000000000 / rfbi.l4_khz;
479 *max_clk_div = 2;
480}
481
482static int rfbi_convert_timings(struct rfbi_timings *t)
483{
484 u32 l;
485 int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
486 int actim, recyc, wecyc;
487 int div = t->clk_div;
488
489 if (div <= 0 || div > 2)
490 return -1;
491
492 /* Make sure that after conversion it still holds that:
493 * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
494 * csoff > cson, csoff >= max(weoff, reoff), actim > reon
495 */
496 weon = ps_to_rfbi_ticks(t->we_on_time, div);
497 weoff = ps_to_rfbi_ticks(t->we_off_time, div);
498 if (weoff <= weon)
499 weoff = weon + 1;
500 if (weon > 0x0f)
501 return -1;
502 if (weoff > 0x3f)
503 return -1;
504
505 reon = ps_to_rfbi_ticks(t->re_on_time, div);
506 reoff = ps_to_rfbi_ticks(t->re_off_time, div);
507 if (reoff <= reon)
508 reoff = reon + 1;
509 if (reon > 0x0f)
510 return -1;
511 if (reoff > 0x3f)
512 return -1;
513
514 cson = ps_to_rfbi_ticks(t->cs_on_time, div);
515 csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
516 if (csoff <= cson)
517 csoff = cson + 1;
518 if (csoff < max(weoff, reoff))
519 csoff = max(weoff, reoff);
520 if (cson > 0x0f)
521 return -1;
522 if (csoff > 0x3f)
523 return -1;
524
525 l = cson;
526 l |= csoff << 4;
527 l |= weon << 10;
528 l |= weoff << 14;
529 l |= reon << 20;
530 l |= reoff << 24;
531
532 t->tim[0] = l;
533
534 actim = ps_to_rfbi_ticks(t->access_time, div);
535 if (actim <= reon)
536 actim = reon + 1;
537 if (actim > 0x3f)
538 return -1;
539
540 wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
541 if (wecyc < weoff)
542 wecyc = weoff;
543 if (wecyc > 0x3f)
544 return -1;
545
546 recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
547 if (recyc < reoff)
548 recyc = reoff;
549 if (recyc > 0x3f)
550 return -1;
551
552 cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
553 if (cs_pulse > 0x3f)
554 return -1;
555
556 l = wecyc;
557 l |= recyc << 6;
558 l |= cs_pulse << 12;
559 l |= actim << 22;
560
561 t->tim[1] = l;
562
563 t->tim[2] = div - 1;
564
565 t->converted = 1;
566
567 return 0;
568}
569
570/* xxx FIX module selection missing */
571static int rfbi_setup_te(enum omap_rfbi_te_mode mode,
572 unsigned hs_pulse_time, unsigned vs_pulse_time,
573 int hs_pol_inv, int vs_pol_inv, int extif_div)
574{
575 int hs, vs;
576 int min;
577 u32 l;
578
579 hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
580 vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
581 if (hs < 2)
582 return -EDOM;
583 if (mode == OMAP_DSS_RFBI_TE_MODE_2)
584 min = 2;
585 else /* OMAP_DSS_RFBI_TE_MODE_1 */
586 min = 4;
587 if (vs < min)
588 return -EDOM;
589 if (vs == hs)
590 return -EINVAL;
591 rfbi.te_mode = mode;
592 DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n",
593 mode, hs, vs, hs_pol_inv, vs_pol_inv);
594
595 rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
596 rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
597
598 l = rfbi_read_reg(RFBI_CONFIG(0));
599 if (hs_pol_inv)
600 l &= ~(1 << 21);
601 else
602 l |= 1 << 21;
603 if (vs_pol_inv)
604 l &= ~(1 << 20);
605 else
606 l |= 1 << 20;
607
608 return 0;
609}
610
611/* xxx FIX module selection missing */
612static int rfbi_enable_te(bool enable, unsigned line)
613{
614 u32 l;
615
616 DSSDBG("te %d line %d mode %d\n", enable, line, rfbi.te_mode);
617 if (line > (1 << 11) - 1)
618 return -EINVAL;
619
620 l = rfbi_read_reg(RFBI_CONFIG(0));
621 l &= ~(0x3 << 2);
622 if (enable) {
623 rfbi.te_enabled = 1;
624 l |= rfbi.te_mode << 2;
625 } else
626 rfbi.te_enabled = 0;
627 rfbi_write_reg(RFBI_CONFIG(0), l);
628 rfbi_write_reg(RFBI_LINE_NUMBER, line);
629
630 return 0;
631}
632
633static int rfbi_configure_bus(int rfbi_module, int bpp, int lines)
634{
635 u32 l;
636 int cycle1 = 0, cycle2 = 0, cycle3 = 0;
637 enum omap_rfbi_cycleformat cycleformat;
638 enum omap_rfbi_datatype datatype;
639 enum omap_rfbi_parallelmode parallelmode;
640
641 switch (bpp) {
642 case 12:
643 datatype = OMAP_DSS_RFBI_DATATYPE_12;
644 break;
645 case 16:
646 datatype = OMAP_DSS_RFBI_DATATYPE_16;
647 break;
648 case 18:
649 datatype = OMAP_DSS_RFBI_DATATYPE_18;
650 break;
651 case 24:
652 datatype = OMAP_DSS_RFBI_DATATYPE_24;
653 break;
654 default:
655 BUG();
656 return 1;
657 }
658 rfbi.datatype = datatype;
659
660 switch (lines) {
661 case 8:
662 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_8;
663 break;
664 case 9:
665 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_9;
666 break;
667 case 12:
668 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_12;
669 break;
670 case 16:
671 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_16;
672 break;
673 default:
674 BUG();
675 return 1;
676 }
677 rfbi.parallelmode = parallelmode;
678
679 if ((bpp % lines) == 0) {
680 switch (bpp / lines) {
681 case 1:
682 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_1_1;
683 break;
684 case 2:
685 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_2_1;
686 break;
687 case 3:
688 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_1;
689 break;
690 default:
691 BUG();
692 return 1;
693 }
694 } else if ((2 * bpp % lines) == 0) {
695 if ((2 * bpp / lines) == 3)
696 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_2;
697 else {
698 BUG();
699 return 1;
700 }
701 } else {
702 BUG();
703 return 1;
704 }
705
706 switch (cycleformat) {
707 case OMAP_DSS_RFBI_CYCLEFORMAT_1_1:
708 cycle1 = lines;
709 break;
710
711 case OMAP_DSS_RFBI_CYCLEFORMAT_2_1:
712 cycle1 = lines;
713 cycle2 = lines;
714 break;
715
716 case OMAP_DSS_RFBI_CYCLEFORMAT_3_1:
717 cycle1 = lines;
718 cycle2 = lines;
719 cycle3 = lines;
720 break;
721
722 case OMAP_DSS_RFBI_CYCLEFORMAT_3_2:
723 cycle1 = lines;
724 cycle2 = (lines / 2) | ((lines / 2) << 16);
725 cycle3 = (lines << 16);
726 break;
727 }
728
729 REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */
730
731 l = 0;
732 l |= FLD_VAL(parallelmode, 1, 0);
733 l |= FLD_VAL(0, 3, 2); /* TRIGGERMODE: ITE */
734 l |= FLD_VAL(0, 4, 4); /* TIMEGRANULARITY */
735 l |= FLD_VAL(datatype, 6, 5);
736 /* l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
737 l |= FLD_VAL(0, 8, 7); /* L4FORMAT, 1pix/L4 */
738 l |= FLD_VAL(cycleformat, 10, 9);
739 l |= FLD_VAL(0, 12, 11); /* UNUSEDBITS */
740 l |= FLD_VAL(0, 16, 16); /* A0POLARITY */
741 l |= FLD_VAL(0, 17, 17); /* REPOLARITY */
742 l |= FLD_VAL(0, 18, 18); /* WEPOLARITY */
743 l |= FLD_VAL(0, 19, 19); /* CSPOLARITY */
744 l |= FLD_VAL(1, 20, 20); /* TE_VSYNC_POLARITY */
745 l |= FLD_VAL(1, 21, 21); /* HSYNCPOLARITY */
746 rfbi_write_reg(RFBI_CONFIG(rfbi_module), l);
747
748 rfbi_write_reg(RFBI_DATA_CYCLE1(rfbi_module), cycle1);
749 rfbi_write_reg(RFBI_DATA_CYCLE2(rfbi_module), cycle2);
750 rfbi_write_reg(RFBI_DATA_CYCLE3(rfbi_module), cycle3);
751
752
753 l = rfbi_read_reg(RFBI_CONTROL);
754 l = FLD_MOD(l, rfbi_module+1, 3, 2); /* Select CSx */
755 l = FLD_MOD(l, 0, 1, 1); /* clear bypass */
756 rfbi_write_reg(RFBI_CONTROL, l);
757
758
759 DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n",
760 bpp, lines, cycle1, cycle2, cycle3);
761
762 return 0;
763}
764
765static int rfbi_configure(struct omap_dss_device *dssdev)
766{
767 return rfbi_configure_bus(dssdev->phy.rfbi.channel, rfbi.pixel_size,
768 rfbi.data_lines);
769}
770
771static int rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *),
772 void *data)
773{
774 return rfbi_transfer_area(dssdev, callback, data);
775}
776
777static void rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
778{
779 rfbi.timings.x_res = w;
780 rfbi.timings.y_res = h;
781}
782
783static void rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size)
784{
785 rfbi.pixel_size = pixel_size;
786}
787
788static void rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
789{
790 rfbi.data_lines = data_lines;
791}
792
793static void rfbi_set_interface_timings(struct omap_dss_device *dssdev,
794 struct rfbi_timings *timings)
795{
796 rfbi.intf_timings = *timings;
797}
798
799static void rfbi_dump_regs(struct seq_file *s)
800{
801#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
802
803 if (rfbi_runtime_get())
804 return;
805
806 DUMPREG(RFBI_REVISION);
807 DUMPREG(RFBI_SYSCONFIG);
808 DUMPREG(RFBI_SYSSTATUS);
809 DUMPREG(RFBI_CONTROL);
810 DUMPREG(RFBI_PIXEL_CNT);
811 DUMPREG(RFBI_LINE_NUMBER);
812 DUMPREG(RFBI_CMD);
813 DUMPREG(RFBI_PARAM);
814 DUMPREG(RFBI_DATA);
815 DUMPREG(RFBI_READ);
816 DUMPREG(RFBI_STATUS);
817
818 DUMPREG(RFBI_CONFIG(0));
819 DUMPREG(RFBI_ONOFF_TIME(0));
820 DUMPREG(RFBI_CYCLE_TIME(0));
821 DUMPREG(RFBI_DATA_CYCLE1(0));
822 DUMPREG(RFBI_DATA_CYCLE2(0));
823 DUMPREG(RFBI_DATA_CYCLE3(0));
824
825 DUMPREG(RFBI_CONFIG(1));
826 DUMPREG(RFBI_ONOFF_TIME(1));
827 DUMPREG(RFBI_CYCLE_TIME(1));
828 DUMPREG(RFBI_DATA_CYCLE1(1));
829 DUMPREG(RFBI_DATA_CYCLE2(1));
830 DUMPREG(RFBI_DATA_CYCLE3(1));
831
832 DUMPREG(RFBI_VSYNC_WIDTH);
833 DUMPREG(RFBI_HSYNC_WIDTH);
834
835 rfbi_runtime_put();
836#undef DUMPREG
837}
838
839static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev)
840{
841 struct omap_overlay_manager *mgr = rfbi.output.manager;
842 struct dss_lcd_mgr_config mgr_config;
843
844 mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI;
845
846 mgr_config.stallmode = true;
847 /* Do we need fifohandcheck for RFBI? */
848 mgr_config.fifohandcheck = false;
849
850 mgr_config.video_port_width = rfbi.pixel_size;
851 mgr_config.lcden_sig_polarity = 0;
852
853 dss_mgr_set_lcd_config(mgr, &mgr_config);
854
855 /*
856 * Set rfbi.timings with default values, the x_res and y_res fields
857 * are expected to be already configured by the panel driver via
858 * omapdss_rfbi_set_size()
859 */
860 rfbi.timings.hsw = 1;
861 rfbi.timings.hfp = 1;
862 rfbi.timings.hbp = 1;
863 rfbi.timings.vsw = 1;
864 rfbi.timings.vfp = 0;
865 rfbi.timings.vbp = 0;
866
867 rfbi.timings.interlace = false;
868 rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
869 rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH;
870 rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
871 rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH;
872 rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
873
874 dss_mgr_set_timings(mgr, &rfbi.timings);
875}
876
877static int rfbi_display_enable(struct omap_dss_device *dssdev)
878{
879 struct omap_dss_device *out = &rfbi.output;
880 int r;
881
882 if (out == NULL || out->manager == NULL) {
883 DSSERR("failed to enable display: no output/manager\n");
884 return -ENODEV;
885 }
886
887 r = rfbi_runtime_get();
888 if (r)
889 return r;
890
891 r = dss_mgr_register_framedone_handler(out->manager,
892 framedone_callback, NULL);
893 if (r) {
894 DSSERR("can't get FRAMEDONE irq\n");
895 goto err1;
896 }
897
898 rfbi_config_lcd_manager(dssdev);
899
900 rfbi_configure_bus(dssdev->phy.rfbi.channel, rfbi.pixel_size,
901 rfbi.data_lines);
902
903 rfbi_set_timings(dssdev->phy.rfbi.channel, &rfbi.intf_timings);
904
905 return 0;
906err1:
907 rfbi_runtime_put();
908 return r;
909}
910
911static void rfbi_display_disable(struct omap_dss_device *dssdev)
912{
913 struct omap_dss_device *out = &rfbi.output;
914
915 dss_mgr_unregister_framedone_handler(out->manager,
916 framedone_callback, NULL);
917
918 rfbi_runtime_put();
919}
920
921static int rfbi_init_display(struct omap_dss_device *dssdev)
922{
923 rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
924 return 0;
925}
926
927static void rfbi_init_output(struct platform_device *pdev)
928{
929 struct omap_dss_device *out = &rfbi.output;
930
931 out->dev = &pdev->dev;
932 out->id = OMAP_DSS_OUTPUT_DBI;
933 out->output_type = OMAP_DISPLAY_TYPE_DBI;
934 out->name = "rfbi.0";
935 out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
936 out->owner = THIS_MODULE;
937
938 omapdss_register_output(out);
939}
940
941static void __exit rfbi_uninit_output(struct platform_device *pdev)
942{
943 struct omap_dss_device *out = &rfbi.output;
944
945 omapdss_unregister_output(out);
946}
947
948/* RFBI HW IP initialisation */
949static int omap_rfbihw_probe(struct platform_device *pdev)
950{
951 u32 rev;
952 struct resource *rfbi_mem;
953 struct clk *clk;
954 int r;
955
956 rfbi.pdev = pdev;
957
958 sema_init(&rfbi.bus_lock, 1);
959
960 rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
961 if (!rfbi_mem) {
962 DSSERR("can't get IORESOURCE_MEM RFBI\n");
963 return -EINVAL;
964 }
965
966 rfbi.base = devm_ioremap(&pdev->dev, rfbi_mem->start,
967 resource_size(rfbi_mem));
968 if (!rfbi.base) {
969 DSSERR("can't ioremap RFBI\n");
970 return -ENOMEM;
971 }
972
973 clk = clk_get(&pdev->dev, "ick");
974 if (IS_ERR(clk)) {
975 DSSERR("can't get ick\n");
976 return PTR_ERR(clk);
977 }
978
979 rfbi.l4_khz = clk_get_rate(clk) / 1000;
980
981 clk_put(clk);
982
983 pm_runtime_enable(&pdev->dev);
984
985 r = rfbi_runtime_get();
986 if (r)
987 goto err_runtime_get;
988
989 msleep(10);
990
991 rev = rfbi_read_reg(RFBI_REVISION);
992 dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n",
993 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
994
995 rfbi_runtime_put();
996
997 dss_debugfs_create_file("rfbi", rfbi_dump_regs);
998
999 rfbi_init_output(pdev);
1000
1001 return 0;
1002
1003err_runtime_get:
1004 pm_runtime_disable(&pdev->dev);
1005 return r;
1006}
1007
1008static int __exit omap_rfbihw_remove(struct platform_device *pdev)
1009{
1010 rfbi_uninit_output(pdev);
1011
1012 pm_runtime_disable(&pdev->dev);
1013
1014 return 0;
1015}
1016
1017static int rfbi_runtime_suspend(struct device *dev)
1018{
1019 dispc_runtime_put();
1020
1021 return 0;
1022}
1023
1024static int rfbi_runtime_resume(struct device *dev)
1025{
1026 int r;
1027
1028 r = dispc_runtime_get();
1029 if (r < 0)
1030 return r;
1031
1032 return 0;
1033}
1034
1035static const struct dev_pm_ops rfbi_pm_ops = {
1036 .runtime_suspend = rfbi_runtime_suspend,
1037 .runtime_resume = rfbi_runtime_resume,
1038};
1039
1040static struct platform_driver omap_rfbihw_driver = {
1041 .probe = omap_rfbihw_probe,
1042 .remove = __exit_p(omap_rfbihw_remove),
1043 .driver = {
1044 .name = "omapdss_rfbi",
1045 .owner = THIS_MODULE,
1046 .pm = &rfbi_pm_ops,
1047 },
1048};
1049
1050int __init rfbi_init_platform_driver(void)
1051{
1052 return platform_driver_register(&omap_rfbihw_driver);
1053}
1054
1055void __exit rfbi_uninit_platform_driver(void)
1056{
1057 platform_driver_unregister(&omap_rfbihw_driver);
1058}
diff --git a/drivers/video/fbdev/omap2/dss/sdi.c b/drivers/video/fbdev/omap2/dss/sdi.c
new file mode 100644
index 000000000000..911dcc9173a6
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/sdi.c
@@ -0,0 +1,433 @@
1/*
2 * linux/drivers/video/omap2/dss/sdi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#define DSS_SUBSYS_NAME "SDI"
21
22#include <linux/kernel.h>
23#include <linux/delay.h>
24#include <linux/err.h>
25#include <linux/regulator/consumer.h>
26#include <linux/export.h>
27#include <linux/platform_device.h>
28#include <linux/string.h>
29#include <linux/of.h>
30
31#include <video/omapdss.h>
32#include "dss.h"
33
34static struct {
35 struct platform_device *pdev;
36
37 bool update_enabled;
38 struct regulator *vdds_sdi_reg;
39
40 struct dss_lcd_mgr_config mgr_config;
41 struct omap_video_timings timings;
42 int datapairs;
43
44 struct omap_dss_device output;
45
46 bool port_initialized;
47} sdi;
48
49struct sdi_clk_calc_ctx {
50 unsigned long pck_min, pck_max;
51
52 unsigned long fck;
53 struct dispc_clock_info dispc_cinfo;
54};
55
56static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
57 unsigned long pck, void *data)
58{
59 struct sdi_clk_calc_ctx *ctx = data;
60
61 ctx->dispc_cinfo.lck_div = lckd;
62 ctx->dispc_cinfo.pck_div = pckd;
63 ctx->dispc_cinfo.lck = lck;
64 ctx->dispc_cinfo.pck = pck;
65
66 return true;
67}
68
69static bool dpi_calc_dss_cb(unsigned long fck, void *data)
70{
71 struct sdi_clk_calc_ctx *ctx = data;
72
73 ctx->fck = fck;
74
75 return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
76 dpi_calc_dispc_cb, ctx);
77}
78
79static int sdi_calc_clock_div(unsigned long pclk,
80 unsigned long *fck,
81 struct dispc_clock_info *dispc_cinfo)
82{
83 int i;
84 struct sdi_clk_calc_ctx ctx;
85
86 /*
87 * DSS fclk gives us very few possibilities, so finding a good pixel
88 * clock may not be possible. We try multiple times to find the clock,
89 * each time widening the pixel clock range we look for, up to
90 * +/- 1MHz.
91 */
92
93 for (i = 0; i < 10; ++i) {
94 bool ok;
95
96 memset(&ctx, 0, sizeof(ctx));
97 if (pclk > 1000 * i * i * i)
98 ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu);
99 else
100 ctx.pck_min = 0;
101 ctx.pck_max = pclk + 1000 * i * i * i;
102
103 ok = dss_div_calc(pclk, ctx.pck_min, dpi_calc_dss_cb, &ctx);
104 if (ok) {
105 *fck = ctx.fck;
106 *dispc_cinfo = ctx.dispc_cinfo;
107 return 0;
108 }
109 }
110
111 return -EINVAL;
112}
113
114static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
115{
116 struct omap_overlay_manager *mgr = sdi.output.manager;
117
118 sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
119
120 sdi.mgr_config.stallmode = false;
121 sdi.mgr_config.fifohandcheck = false;
122
123 sdi.mgr_config.video_port_width = 24;
124 sdi.mgr_config.lcden_sig_polarity = 1;
125
126 dss_mgr_set_lcd_config(mgr, &sdi.mgr_config);
127}
128
129static int sdi_display_enable(struct omap_dss_device *dssdev)
130{
131 struct omap_dss_device *out = &sdi.output;
132 struct omap_video_timings *t = &sdi.timings;
133 unsigned long fck;
134 struct dispc_clock_info dispc_cinfo;
135 unsigned long pck;
136 int r;
137
138 if (out == NULL || out->manager == NULL) {
139 DSSERR("failed to enable display: no output/manager\n");
140 return -ENODEV;
141 }
142
143 r = regulator_enable(sdi.vdds_sdi_reg);
144 if (r)
145 goto err_reg_enable;
146
147 r = dispc_runtime_get();
148 if (r)
149 goto err_get_dispc;
150
151 /* 15.5.9.1.2 */
152 t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
153 t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
154
155 r = sdi_calc_clock_div(t->pixelclock, &fck, &dispc_cinfo);
156 if (r)
157 goto err_calc_clock_div;
158
159 sdi.mgr_config.clock_info = dispc_cinfo;
160
161 pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
162
163 if (pck != t->pixelclock) {
164 DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
165 t->pixelclock, pck);
166
167 t->pixelclock = pck;
168 }
169
170
171 dss_mgr_set_timings(out->manager, t);
172
173 r = dss_set_fck_rate(fck);
174 if (r)
175 goto err_set_dss_clock_div;
176
177 sdi_config_lcd_manager(dssdev);
178
179 /*
180 * LCLK and PCLK divisors are located in shadow registers, and we
181 * normally write them to DISPC registers when enabling the output.
182 * However, SDI uses pck-free as source clock for its PLL, and pck-free
183 * is affected by the divisors. And as we need the PLL before enabling
184 * the output, we need to write the divisors early.
185 *
186 * It seems just writing to the DISPC register is enough, and we don't
187 * need to care about the shadow register mechanism for pck-free. The
188 * exact reason for this is unknown.
189 */
190 dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info);
191
192 dss_sdi_init(sdi.datapairs);
193 r = dss_sdi_enable();
194 if (r)
195 goto err_sdi_enable;
196 mdelay(2);
197
198 r = dss_mgr_enable(out->manager);
199 if (r)
200 goto err_mgr_enable;
201
202 return 0;
203
204err_mgr_enable:
205 dss_sdi_disable();
206err_sdi_enable:
207err_set_dss_clock_div:
208err_calc_clock_div:
209 dispc_runtime_put();
210err_get_dispc:
211 regulator_disable(sdi.vdds_sdi_reg);
212err_reg_enable:
213 return r;
214}
215
216static void sdi_display_disable(struct omap_dss_device *dssdev)
217{
218 struct omap_overlay_manager *mgr = sdi.output.manager;
219
220 dss_mgr_disable(mgr);
221
222 dss_sdi_disable();
223
224 dispc_runtime_put();
225
226 regulator_disable(sdi.vdds_sdi_reg);
227}
228
229static void sdi_set_timings(struct omap_dss_device *dssdev,
230 struct omap_video_timings *timings)
231{
232 sdi.timings = *timings;
233}
234
235static void sdi_get_timings(struct omap_dss_device *dssdev,
236 struct omap_video_timings *timings)
237{
238 *timings = sdi.timings;
239}
240
241static int sdi_check_timings(struct omap_dss_device *dssdev,
242 struct omap_video_timings *timings)
243{
244 struct omap_overlay_manager *mgr = sdi.output.manager;
245
246 if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
247 return -EINVAL;
248
249 if (timings->pixelclock == 0)
250 return -EINVAL;
251
252 return 0;
253}
254
255static void sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs)
256{
257 sdi.datapairs = datapairs;
258}
259
260static int sdi_init_regulator(void)
261{
262 struct regulator *vdds_sdi;
263
264 if (sdi.vdds_sdi_reg)
265 return 0;
266
267 vdds_sdi = devm_regulator_get(&sdi.pdev->dev, "vdds_sdi");
268 if (IS_ERR(vdds_sdi)) {
269 if (PTR_ERR(vdds_sdi) != -EPROBE_DEFER)
270 DSSERR("can't get VDDS_SDI regulator\n");
271 return PTR_ERR(vdds_sdi);
272 }
273
274 sdi.vdds_sdi_reg = vdds_sdi;
275
276 return 0;
277}
278
279static int sdi_connect(struct omap_dss_device *dssdev,
280 struct omap_dss_device *dst)
281{
282 struct omap_overlay_manager *mgr;
283 int r;
284
285 r = sdi_init_regulator();
286 if (r)
287 return r;
288
289 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
290 if (!mgr)
291 return -ENODEV;
292
293 r = dss_mgr_connect(mgr, dssdev);
294 if (r)
295 return r;
296
297 r = omapdss_output_set_device(dssdev, dst);
298 if (r) {
299 DSSERR("failed to connect output to new device: %s\n",
300 dst->name);
301 dss_mgr_disconnect(mgr, dssdev);
302 return r;
303 }
304
305 return 0;
306}
307
308static void sdi_disconnect(struct omap_dss_device *dssdev,
309 struct omap_dss_device *dst)
310{
311 WARN_ON(dst != dssdev->dst);
312
313 if (dst != dssdev->dst)
314 return;
315
316 omapdss_output_unset_device(dssdev);
317
318 if (dssdev->manager)
319 dss_mgr_disconnect(dssdev->manager, dssdev);
320}
321
322static const struct omapdss_sdi_ops sdi_ops = {
323 .connect = sdi_connect,
324 .disconnect = sdi_disconnect,
325
326 .enable = sdi_display_enable,
327 .disable = sdi_display_disable,
328
329 .check_timings = sdi_check_timings,
330 .set_timings = sdi_set_timings,
331 .get_timings = sdi_get_timings,
332
333 .set_datapairs = sdi_set_datapairs,
334};
335
336static void sdi_init_output(struct platform_device *pdev)
337{
338 struct omap_dss_device *out = &sdi.output;
339
340 out->dev = &pdev->dev;
341 out->id = OMAP_DSS_OUTPUT_SDI;
342 out->output_type = OMAP_DISPLAY_TYPE_SDI;
343 out->name = "sdi.0";
344 out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
345 out->ops.sdi = &sdi_ops;
346 out->owner = THIS_MODULE;
347
348 omapdss_register_output(out);
349}
350
351static void __exit sdi_uninit_output(struct platform_device *pdev)
352{
353 struct omap_dss_device *out = &sdi.output;
354
355 omapdss_unregister_output(out);
356}
357
358static int omap_sdi_probe(struct platform_device *pdev)
359{
360 sdi.pdev = pdev;
361
362 sdi_init_output(pdev);
363
364 return 0;
365}
366
367static int __exit omap_sdi_remove(struct platform_device *pdev)
368{
369 sdi_uninit_output(pdev);
370
371 return 0;
372}
373
374static struct platform_driver omap_sdi_driver = {
375 .probe = omap_sdi_probe,
376 .remove = __exit_p(omap_sdi_remove),
377 .driver = {
378 .name = "omapdss_sdi",
379 .owner = THIS_MODULE,
380 },
381};
382
383int __init sdi_init_platform_driver(void)
384{
385 return platform_driver_register(&omap_sdi_driver);
386}
387
388void __exit sdi_uninit_platform_driver(void)
389{
390 platform_driver_unregister(&omap_sdi_driver);
391}
392
393int __init sdi_init_port(struct platform_device *pdev, struct device_node *port)
394{
395 struct device_node *ep;
396 u32 datapairs;
397 int r;
398
399 ep = omapdss_of_get_next_endpoint(port, NULL);
400 if (!ep)
401 return 0;
402
403 r = of_property_read_u32(ep, "datapairs", &datapairs);
404 if (r) {
405 DSSERR("failed to parse datapairs\n");
406 goto err_datapairs;
407 }
408
409 sdi.datapairs = datapairs;
410
411 of_node_put(ep);
412
413 sdi.pdev = pdev;
414
415 sdi_init_output(pdev);
416
417 sdi.port_initialized = true;
418
419 return 0;
420
421err_datapairs:
422 of_node_put(ep);
423
424 return r;
425}
426
427void __exit sdi_uninit_port(void)
428{
429 if (!sdi.port_initialized)
430 return;
431
432 sdi_uninit_output(sdi.pdev);
433}
diff --git a/drivers/video/fbdev/omap2/dss/venc.c b/drivers/video/fbdev/omap2/dss/venc.c
new file mode 100644
index 000000000000..21d81113962b
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/venc.c
@@ -0,0 +1,980 @@
1/*
2 * linux/drivers/video/omap2/dss/venc.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * VENC settings from TI's DSS driver
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#define DSS_SUBSYS_NAME "VENC"
23
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/clk.h>
27#include <linux/err.h>
28#include <linux/io.h>
29#include <linux/mutex.h>
30#include <linux/completion.h>
31#include <linux/delay.h>
32#include <linux/string.h>
33#include <linux/seq_file.h>
34#include <linux/platform_device.h>
35#include <linux/regulator/consumer.h>
36#include <linux/pm_runtime.h>
37#include <linux/of.h>
38
39#include <video/omapdss.h>
40
41#include "dss.h"
42#include "dss_features.h"
43
44/* Venc registers */
45#define VENC_REV_ID 0x00
46#define VENC_STATUS 0x04
47#define VENC_F_CONTROL 0x08
48#define VENC_VIDOUT_CTRL 0x10
49#define VENC_SYNC_CTRL 0x14
50#define VENC_LLEN 0x1C
51#define VENC_FLENS 0x20
52#define VENC_HFLTR_CTRL 0x24
53#define VENC_CC_CARR_WSS_CARR 0x28
54#define VENC_C_PHASE 0x2C
55#define VENC_GAIN_U 0x30
56#define VENC_GAIN_V 0x34
57#define VENC_GAIN_Y 0x38
58#define VENC_BLACK_LEVEL 0x3C
59#define VENC_BLANK_LEVEL 0x40
60#define VENC_X_COLOR 0x44
61#define VENC_M_CONTROL 0x48
62#define VENC_BSTAMP_WSS_DATA 0x4C
63#define VENC_S_CARR 0x50
64#define VENC_LINE21 0x54
65#define VENC_LN_SEL 0x58
66#define VENC_L21__WC_CTL 0x5C
67#define VENC_HTRIGGER_VTRIGGER 0x60
68#define VENC_SAVID__EAVID 0x64
69#define VENC_FLEN__FAL 0x68
70#define VENC_LAL__PHASE_RESET 0x6C
71#define VENC_HS_INT_START_STOP_X 0x70
72#define VENC_HS_EXT_START_STOP_X 0x74
73#define VENC_VS_INT_START_X 0x78
74#define VENC_VS_INT_STOP_X__VS_INT_START_Y 0x7C
75#define VENC_VS_INT_STOP_Y__VS_EXT_START_X 0x80
76#define VENC_VS_EXT_STOP_X__VS_EXT_START_Y 0x84
77#define VENC_VS_EXT_STOP_Y 0x88
78#define VENC_AVID_START_STOP_X 0x90
79#define VENC_AVID_START_STOP_Y 0x94
80#define VENC_FID_INT_START_X__FID_INT_START_Y 0xA0
81#define VENC_FID_INT_OFFSET_Y__FID_EXT_START_X 0xA4
82#define VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y 0xA8
83#define VENC_TVDETGP_INT_START_STOP_X 0xB0
84#define VENC_TVDETGP_INT_START_STOP_Y 0xB4
85#define VENC_GEN_CTRL 0xB8
86#define VENC_OUTPUT_CONTROL 0xC4
87#define VENC_OUTPUT_TEST 0xC8
88#define VENC_DAC_B__DAC_C 0xC8
89
90struct venc_config {
91 u32 f_control;
92 u32 vidout_ctrl;
93 u32 sync_ctrl;
94 u32 llen;
95 u32 flens;
96 u32 hfltr_ctrl;
97 u32 cc_carr_wss_carr;
98 u32 c_phase;
99 u32 gain_u;
100 u32 gain_v;
101 u32 gain_y;
102 u32 black_level;
103 u32 blank_level;
104 u32 x_color;
105 u32 m_control;
106 u32 bstamp_wss_data;
107 u32 s_carr;
108 u32 line21;
109 u32 ln_sel;
110 u32 l21__wc_ctl;
111 u32 htrigger_vtrigger;
112 u32 savid__eavid;
113 u32 flen__fal;
114 u32 lal__phase_reset;
115 u32 hs_int_start_stop_x;
116 u32 hs_ext_start_stop_x;
117 u32 vs_int_start_x;
118 u32 vs_int_stop_x__vs_int_start_y;
119 u32 vs_int_stop_y__vs_ext_start_x;
120 u32 vs_ext_stop_x__vs_ext_start_y;
121 u32 vs_ext_stop_y;
122 u32 avid_start_stop_x;
123 u32 avid_start_stop_y;
124 u32 fid_int_start_x__fid_int_start_y;
125 u32 fid_int_offset_y__fid_ext_start_x;
126 u32 fid_ext_start_y__fid_ext_offset_y;
127 u32 tvdetgp_int_start_stop_x;
128 u32 tvdetgp_int_start_stop_y;
129 u32 gen_ctrl;
130};
131
132/* from TRM */
133static const struct venc_config venc_config_pal_trm = {
134 .f_control = 0,
135 .vidout_ctrl = 1,
136 .sync_ctrl = 0x40,
137 .llen = 0x35F, /* 863 */
138 .flens = 0x270, /* 624 */
139 .hfltr_ctrl = 0,
140 .cc_carr_wss_carr = 0x2F7225ED,
141 .c_phase = 0,
142 .gain_u = 0x111,
143 .gain_v = 0x181,
144 .gain_y = 0x140,
145 .black_level = 0x3B,
146 .blank_level = 0x3B,
147 .x_color = 0x7,
148 .m_control = 0x2,
149 .bstamp_wss_data = 0x3F,
150 .s_carr = 0x2A098ACB,
151 .line21 = 0,
152 .ln_sel = 0x01290015,
153 .l21__wc_ctl = 0x0000F603,
154 .htrigger_vtrigger = 0,
155
156 .savid__eavid = 0x06A70108,
157 .flen__fal = 0x00180270,
158 .lal__phase_reset = 0x00040135,
159 .hs_int_start_stop_x = 0x00880358,
160 .hs_ext_start_stop_x = 0x000F035F,
161 .vs_int_start_x = 0x01A70000,
162 .vs_int_stop_x__vs_int_start_y = 0x000001A7,
163 .vs_int_stop_y__vs_ext_start_x = 0x01AF0000,
164 .vs_ext_stop_x__vs_ext_start_y = 0x000101AF,
165 .vs_ext_stop_y = 0x00000025,
166 .avid_start_stop_x = 0x03530083,
167 .avid_start_stop_y = 0x026C002E,
168 .fid_int_start_x__fid_int_start_y = 0x0001008A,
169 .fid_int_offset_y__fid_ext_start_x = 0x002E0138,
170 .fid_ext_start_y__fid_ext_offset_y = 0x01380001,
171
172 .tvdetgp_int_start_stop_x = 0x00140001,
173 .tvdetgp_int_start_stop_y = 0x00010001,
174 .gen_ctrl = 0x00FF0000,
175};
176
177/* from TRM */
178static const struct venc_config venc_config_ntsc_trm = {
179 .f_control = 0,
180 .vidout_ctrl = 1,
181 .sync_ctrl = 0x8040,
182 .llen = 0x359,
183 .flens = 0x20C,
184 .hfltr_ctrl = 0,
185 .cc_carr_wss_carr = 0x043F2631,
186 .c_phase = 0,
187 .gain_u = 0x102,
188 .gain_v = 0x16C,
189 .gain_y = 0x12F,
190 .black_level = 0x43,
191 .blank_level = 0x38,
192 .x_color = 0x7,
193 .m_control = 0x1,
194 .bstamp_wss_data = 0x38,
195 .s_carr = 0x21F07C1F,
196 .line21 = 0,
197 .ln_sel = 0x01310011,
198 .l21__wc_ctl = 0x0000F003,
199 .htrigger_vtrigger = 0,
200
201 .savid__eavid = 0x069300F4,
202 .flen__fal = 0x0016020C,
203 .lal__phase_reset = 0x00060107,
204 .hs_int_start_stop_x = 0x008E0350,
205 .hs_ext_start_stop_x = 0x000F0359,
206 .vs_int_start_x = 0x01A00000,
207 .vs_int_stop_x__vs_int_start_y = 0x020701A0,
208 .vs_int_stop_y__vs_ext_start_x = 0x01AC0024,
209 .vs_ext_stop_x__vs_ext_start_y = 0x020D01AC,
210 .vs_ext_stop_y = 0x00000006,
211 .avid_start_stop_x = 0x03480078,
212 .avid_start_stop_y = 0x02060024,
213 .fid_int_start_x__fid_int_start_y = 0x0001008A,
214 .fid_int_offset_y__fid_ext_start_x = 0x01AC0106,
215 .fid_ext_start_y__fid_ext_offset_y = 0x01060006,
216
217 .tvdetgp_int_start_stop_x = 0x00140001,
218 .tvdetgp_int_start_stop_y = 0x00010001,
219 .gen_ctrl = 0x00F90000,
220};
221
222static const struct venc_config venc_config_pal_bdghi = {
223 .f_control = 0,
224 .vidout_ctrl = 0,
225 .sync_ctrl = 0,
226 .hfltr_ctrl = 0,
227 .x_color = 0,
228 .line21 = 0,
229 .ln_sel = 21,
230 .htrigger_vtrigger = 0,
231 .tvdetgp_int_start_stop_x = 0x00140001,
232 .tvdetgp_int_start_stop_y = 0x00010001,
233 .gen_ctrl = 0x00FB0000,
234
235 .llen = 864-1,
236 .flens = 625-1,
237 .cc_carr_wss_carr = 0x2F7625ED,
238 .c_phase = 0xDF,
239 .gain_u = 0x111,
240 .gain_v = 0x181,
241 .gain_y = 0x140,
242 .black_level = 0x3e,
243 .blank_level = 0x3e,
244 .m_control = 0<<2 | 1<<1,
245 .bstamp_wss_data = 0x42,
246 .s_carr = 0x2a098acb,
247 .l21__wc_ctl = 0<<13 | 0x16<<8 | 0<<0,
248 .savid__eavid = 0x06A70108,
249 .flen__fal = 23<<16 | 624<<0,
250 .lal__phase_reset = 2<<17 | 310<<0,
251 .hs_int_start_stop_x = 0x00920358,
252 .hs_ext_start_stop_x = 0x000F035F,
253 .vs_int_start_x = 0x1a7<<16,
254 .vs_int_stop_x__vs_int_start_y = 0x000601A7,
255 .vs_int_stop_y__vs_ext_start_x = 0x01AF0036,
256 .vs_ext_stop_x__vs_ext_start_y = 0x27101af,
257 .vs_ext_stop_y = 0x05,
258 .avid_start_stop_x = 0x03530082,
259 .avid_start_stop_y = 0x0270002E,
260 .fid_int_start_x__fid_int_start_y = 0x0005008A,
261 .fid_int_offset_y__fid_ext_start_x = 0x002E0138,
262 .fid_ext_start_y__fid_ext_offset_y = 0x01380005,
263};
264
265const struct omap_video_timings omap_dss_pal_timings = {
266 .x_res = 720,
267 .y_res = 574,
268 .pixelclock = 13500000,
269 .hsw = 64,
270 .hfp = 12,
271 .hbp = 68,
272 .vsw = 5,
273 .vfp = 5,
274 .vbp = 41,
275
276 .interlace = true,
277};
278EXPORT_SYMBOL(omap_dss_pal_timings);
279
280const struct omap_video_timings omap_dss_ntsc_timings = {
281 .x_res = 720,
282 .y_res = 482,
283 .pixelclock = 13500000,
284 .hsw = 64,
285 .hfp = 16,
286 .hbp = 58,
287 .vsw = 6,
288 .vfp = 6,
289 .vbp = 31,
290
291 .interlace = true,
292};
293EXPORT_SYMBOL(omap_dss_ntsc_timings);
294
295static struct {
296 struct platform_device *pdev;
297 void __iomem *base;
298 struct mutex venc_lock;
299 u32 wss_data;
300 struct regulator *vdda_dac_reg;
301
302 struct clk *tv_dac_clk;
303
304 struct omap_video_timings timings;
305 enum omap_dss_venc_type type;
306 bool invert_polarity;
307
308 struct omap_dss_device output;
309} venc;
310
311static inline void venc_write_reg(int idx, u32 val)
312{
313 __raw_writel(val, venc.base + idx);
314}
315
316static inline u32 venc_read_reg(int idx)
317{
318 u32 l = __raw_readl(venc.base + idx);
319 return l;
320}
321
322static void venc_write_config(const struct venc_config *config)
323{
324 DSSDBG("write venc conf\n");
325
326 venc_write_reg(VENC_LLEN, config->llen);
327 venc_write_reg(VENC_FLENS, config->flens);
328 venc_write_reg(VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);
329 venc_write_reg(VENC_C_PHASE, config->c_phase);
330 venc_write_reg(VENC_GAIN_U, config->gain_u);
331 venc_write_reg(VENC_GAIN_V, config->gain_v);
332 venc_write_reg(VENC_GAIN_Y, config->gain_y);
333 venc_write_reg(VENC_BLACK_LEVEL, config->black_level);
334 venc_write_reg(VENC_BLANK_LEVEL, config->blank_level);
335 venc_write_reg(VENC_M_CONTROL, config->m_control);
336 venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
337 venc.wss_data);
338 venc_write_reg(VENC_S_CARR, config->s_carr);
339 venc_write_reg(VENC_L21__WC_CTL, config->l21__wc_ctl);
340 venc_write_reg(VENC_SAVID__EAVID, config->savid__eavid);
341 venc_write_reg(VENC_FLEN__FAL, config->flen__fal);
342 venc_write_reg(VENC_LAL__PHASE_RESET, config->lal__phase_reset);
343 venc_write_reg(VENC_HS_INT_START_STOP_X, config->hs_int_start_stop_x);
344 venc_write_reg(VENC_HS_EXT_START_STOP_X, config->hs_ext_start_stop_x);
345 venc_write_reg(VENC_VS_INT_START_X, config->vs_int_start_x);
346 venc_write_reg(VENC_VS_INT_STOP_X__VS_INT_START_Y,
347 config->vs_int_stop_x__vs_int_start_y);
348 venc_write_reg(VENC_VS_INT_STOP_Y__VS_EXT_START_X,
349 config->vs_int_stop_y__vs_ext_start_x);
350 venc_write_reg(VENC_VS_EXT_STOP_X__VS_EXT_START_Y,
351 config->vs_ext_stop_x__vs_ext_start_y);
352 venc_write_reg(VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);
353 venc_write_reg(VENC_AVID_START_STOP_X, config->avid_start_stop_x);
354 venc_write_reg(VENC_AVID_START_STOP_Y, config->avid_start_stop_y);
355 venc_write_reg(VENC_FID_INT_START_X__FID_INT_START_Y,
356 config->fid_int_start_x__fid_int_start_y);
357 venc_write_reg(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,
358 config->fid_int_offset_y__fid_ext_start_x);
359 venc_write_reg(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,
360 config->fid_ext_start_y__fid_ext_offset_y);
361
362 venc_write_reg(VENC_DAC_B__DAC_C, venc_read_reg(VENC_DAC_B__DAC_C));
363 venc_write_reg(VENC_VIDOUT_CTRL, config->vidout_ctrl);
364 venc_write_reg(VENC_HFLTR_CTRL, config->hfltr_ctrl);
365 venc_write_reg(VENC_X_COLOR, config->x_color);
366 venc_write_reg(VENC_LINE21, config->line21);
367 venc_write_reg(VENC_LN_SEL, config->ln_sel);
368 venc_write_reg(VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);
369 venc_write_reg(VENC_TVDETGP_INT_START_STOP_X,
370 config->tvdetgp_int_start_stop_x);
371 venc_write_reg(VENC_TVDETGP_INT_START_STOP_Y,
372 config->tvdetgp_int_start_stop_y);
373 venc_write_reg(VENC_GEN_CTRL, config->gen_ctrl);
374 venc_write_reg(VENC_F_CONTROL, config->f_control);
375 venc_write_reg(VENC_SYNC_CTRL, config->sync_ctrl);
376}
377
378static void venc_reset(void)
379{
380 int t = 1000;
381
382 venc_write_reg(VENC_F_CONTROL, 1<<8);
383 while (venc_read_reg(VENC_F_CONTROL) & (1<<8)) {
384 if (--t == 0) {
385 DSSERR("Failed to reset venc\n");
386 return;
387 }
388 }
389
390#ifdef CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET
391 /* the magical sleep that makes things work */
392 /* XXX more info? What bug this circumvents? */
393 msleep(20);
394#endif
395}
396
397static int venc_runtime_get(void)
398{
399 int r;
400
401 DSSDBG("venc_runtime_get\n");
402
403 r = pm_runtime_get_sync(&venc.pdev->dev);
404 WARN_ON(r < 0);
405 return r < 0 ? r : 0;
406}
407
408static void venc_runtime_put(void)
409{
410 int r;
411
412 DSSDBG("venc_runtime_put\n");
413
414 r = pm_runtime_put_sync(&venc.pdev->dev);
415 WARN_ON(r < 0 && r != -ENOSYS);
416}
417
418static const struct venc_config *venc_timings_to_config(
419 struct omap_video_timings *timings)
420{
421 if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
422 return &venc_config_pal_trm;
423
424 if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
425 return &venc_config_ntsc_trm;
426
427 BUG();
428 return NULL;
429}
430
431static int venc_power_on(struct omap_dss_device *dssdev)
432{
433 struct omap_overlay_manager *mgr = venc.output.manager;
434 u32 l;
435 int r;
436
437 r = venc_runtime_get();
438 if (r)
439 goto err0;
440
441 venc_reset();
442 venc_write_config(venc_timings_to_config(&venc.timings));
443
444 dss_set_venc_output(venc.type);
445 dss_set_dac_pwrdn_bgz(1);
446
447 l = 0;
448
449 if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
450 l |= 1 << 1;
451 else /* S-Video */
452 l |= (1 << 0) | (1 << 2);
453
454 if (venc.invert_polarity == false)
455 l |= 1 << 3;
456
457 venc_write_reg(VENC_OUTPUT_CONTROL, l);
458
459 dss_mgr_set_timings(mgr, &venc.timings);
460
461 r = regulator_enable(venc.vdda_dac_reg);
462 if (r)
463 goto err1;
464
465 r = dss_mgr_enable(mgr);
466 if (r)
467 goto err2;
468
469 return 0;
470
471err2:
472 regulator_disable(venc.vdda_dac_reg);
473err1:
474 venc_write_reg(VENC_OUTPUT_CONTROL, 0);
475 dss_set_dac_pwrdn_bgz(0);
476
477 venc_runtime_put();
478err0:
479 return r;
480}
481
482static void venc_power_off(struct omap_dss_device *dssdev)
483{
484 struct omap_overlay_manager *mgr = venc.output.manager;
485
486 venc_write_reg(VENC_OUTPUT_CONTROL, 0);
487 dss_set_dac_pwrdn_bgz(0);
488
489 dss_mgr_disable(mgr);
490
491 regulator_disable(venc.vdda_dac_reg);
492
493 venc_runtime_put();
494}
495
496static int venc_display_enable(struct omap_dss_device *dssdev)
497{
498 struct omap_dss_device *out = &venc.output;
499 int r;
500
501 DSSDBG("venc_display_enable\n");
502
503 mutex_lock(&venc.venc_lock);
504
505 if (out == NULL || out->manager == NULL) {
506 DSSERR("Failed to enable display: no output/manager\n");
507 r = -ENODEV;
508 goto err0;
509 }
510
511 r = venc_power_on(dssdev);
512 if (r)
513 goto err0;
514
515 venc.wss_data = 0;
516
517 mutex_unlock(&venc.venc_lock);
518
519 return 0;
520err0:
521 mutex_unlock(&venc.venc_lock);
522 return r;
523}
524
525static void venc_display_disable(struct omap_dss_device *dssdev)
526{
527 DSSDBG("venc_display_disable\n");
528
529 mutex_lock(&venc.venc_lock);
530
531 venc_power_off(dssdev);
532
533 mutex_unlock(&venc.venc_lock);
534}
535
536static void venc_set_timings(struct omap_dss_device *dssdev,
537 struct omap_video_timings *timings)
538{
539 DSSDBG("venc_set_timings\n");
540
541 mutex_lock(&venc.venc_lock);
542
543 /* Reset WSS data when the TV standard changes. */
544 if (memcmp(&venc.timings, timings, sizeof(*timings)))
545 venc.wss_data = 0;
546
547 venc.timings = *timings;
548
549 dispc_set_tv_pclk(13500000);
550
551 mutex_unlock(&venc.venc_lock);
552}
553
554static int venc_check_timings(struct omap_dss_device *dssdev,
555 struct omap_video_timings *timings)
556{
557 DSSDBG("venc_check_timings\n");
558
559 if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
560 return 0;
561
562 if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
563 return 0;
564
565 return -EINVAL;
566}
567
568static void venc_get_timings(struct omap_dss_device *dssdev,
569 struct omap_video_timings *timings)
570{
571 mutex_lock(&venc.venc_lock);
572
573 *timings = venc.timings;
574
575 mutex_unlock(&venc.venc_lock);
576}
577
578static u32 venc_get_wss(struct omap_dss_device *dssdev)
579{
580 /* Invert due to VENC_L21_WC_CTL:INV=1 */
581 return (venc.wss_data >> 8) ^ 0xfffff;
582}
583
584static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
585{
586 const struct venc_config *config;
587 int r;
588
589 DSSDBG("venc_set_wss\n");
590
591 mutex_lock(&venc.venc_lock);
592
593 config = venc_timings_to_config(&venc.timings);
594
595 /* Invert due to VENC_L21_WC_CTL:INV=1 */
596 venc.wss_data = (wss ^ 0xfffff) << 8;
597
598 r = venc_runtime_get();
599 if (r)
600 goto err;
601
602 venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
603 venc.wss_data);
604
605 venc_runtime_put();
606
607err:
608 mutex_unlock(&venc.venc_lock);
609
610 return r;
611}
612
613static void venc_set_type(struct omap_dss_device *dssdev,
614 enum omap_dss_venc_type type)
615{
616 mutex_lock(&venc.venc_lock);
617
618 venc.type = type;
619
620 mutex_unlock(&venc.venc_lock);
621}
622
623static void venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
624 bool invert_polarity)
625{
626 mutex_lock(&venc.venc_lock);
627
628 venc.invert_polarity = invert_polarity;
629
630 mutex_unlock(&venc.venc_lock);
631}
632
633static int venc_init_regulator(void)
634{
635 struct regulator *vdda_dac;
636
637 if (venc.vdda_dac_reg != NULL)
638 return 0;
639
640 if (venc.pdev->dev.of_node)
641 vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda");
642 else
643 vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac");
644
645 if (IS_ERR(vdda_dac)) {
646 if (PTR_ERR(vdda_dac) != -EPROBE_DEFER)
647 DSSERR("can't get VDDA_DAC regulator\n");
648 return PTR_ERR(vdda_dac);
649 }
650
651 venc.vdda_dac_reg = vdda_dac;
652
653 return 0;
654}
655
656static void venc_dump_regs(struct seq_file *s)
657{
658#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
659
660 if (venc_runtime_get())
661 return;
662
663 DUMPREG(VENC_F_CONTROL);
664 DUMPREG(VENC_VIDOUT_CTRL);
665 DUMPREG(VENC_SYNC_CTRL);
666 DUMPREG(VENC_LLEN);
667 DUMPREG(VENC_FLENS);
668 DUMPREG(VENC_HFLTR_CTRL);
669 DUMPREG(VENC_CC_CARR_WSS_CARR);
670 DUMPREG(VENC_C_PHASE);
671 DUMPREG(VENC_GAIN_U);
672 DUMPREG(VENC_GAIN_V);
673 DUMPREG(VENC_GAIN_Y);
674 DUMPREG(VENC_BLACK_LEVEL);
675 DUMPREG(VENC_BLANK_LEVEL);
676 DUMPREG(VENC_X_COLOR);
677 DUMPREG(VENC_M_CONTROL);
678 DUMPREG(VENC_BSTAMP_WSS_DATA);
679 DUMPREG(VENC_S_CARR);
680 DUMPREG(VENC_LINE21);
681 DUMPREG(VENC_LN_SEL);
682 DUMPREG(VENC_L21__WC_CTL);
683 DUMPREG(VENC_HTRIGGER_VTRIGGER);
684 DUMPREG(VENC_SAVID__EAVID);
685 DUMPREG(VENC_FLEN__FAL);
686 DUMPREG(VENC_LAL__PHASE_RESET);
687 DUMPREG(VENC_HS_INT_START_STOP_X);
688 DUMPREG(VENC_HS_EXT_START_STOP_X);
689 DUMPREG(VENC_VS_INT_START_X);
690 DUMPREG(VENC_VS_INT_STOP_X__VS_INT_START_Y);
691 DUMPREG(VENC_VS_INT_STOP_Y__VS_EXT_START_X);
692 DUMPREG(VENC_VS_EXT_STOP_X__VS_EXT_START_Y);
693 DUMPREG(VENC_VS_EXT_STOP_Y);
694 DUMPREG(VENC_AVID_START_STOP_X);
695 DUMPREG(VENC_AVID_START_STOP_Y);
696 DUMPREG(VENC_FID_INT_START_X__FID_INT_START_Y);
697 DUMPREG(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);
698 DUMPREG(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);
699 DUMPREG(VENC_TVDETGP_INT_START_STOP_X);
700 DUMPREG(VENC_TVDETGP_INT_START_STOP_Y);
701 DUMPREG(VENC_GEN_CTRL);
702 DUMPREG(VENC_OUTPUT_CONTROL);
703 DUMPREG(VENC_OUTPUT_TEST);
704
705 venc_runtime_put();
706
707#undef DUMPREG
708}
709
710static int venc_get_clocks(struct platform_device *pdev)
711{
712 struct clk *clk;
713
714 if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
715 clk = devm_clk_get(&pdev->dev, "tv_dac_clk");
716 if (IS_ERR(clk)) {
717 DSSERR("can't get tv_dac_clk\n");
718 return PTR_ERR(clk);
719 }
720 } else {
721 clk = NULL;
722 }
723
724 venc.tv_dac_clk = clk;
725
726 return 0;
727}
728
729static int venc_connect(struct omap_dss_device *dssdev,
730 struct omap_dss_device *dst)
731{
732 struct omap_overlay_manager *mgr;
733 int r;
734
735 r = venc_init_regulator();
736 if (r)
737 return r;
738
739 mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
740 if (!mgr)
741 return -ENODEV;
742
743 r = dss_mgr_connect(mgr, dssdev);
744 if (r)
745 return r;
746
747 r = omapdss_output_set_device(dssdev, dst);
748 if (r) {
749 DSSERR("failed to connect output to new device: %s\n",
750 dst->name);
751 dss_mgr_disconnect(mgr, dssdev);
752 return r;
753 }
754
755 return 0;
756}
757
758static void venc_disconnect(struct omap_dss_device *dssdev,
759 struct omap_dss_device *dst)
760{
761 WARN_ON(dst != dssdev->dst);
762
763 if (dst != dssdev->dst)
764 return;
765
766 omapdss_output_unset_device(dssdev);
767
768 if (dssdev->manager)
769 dss_mgr_disconnect(dssdev->manager, dssdev);
770}
771
772static const struct omapdss_atv_ops venc_ops = {
773 .connect = venc_connect,
774 .disconnect = venc_disconnect,
775
776 .enable = venc_display_enable,
777 .disable = venc_display_disable,
778
779 .check_timings = venc_check_timings,
780 .set_timings = venc_set_timings,
781 .get_timings = venc_get_timings,
782
783 .set_type = venc_set_type,
784 .invert_vid_out_polarity = venc_invert_vid_out_polarity,
785
786 .set_wss = venc_set_wss,
787 .get_wss = venc_get_wss,
788};
789
790static void venc_init_output(struct platform_device *pdev)
791{
792 struct omap_dss_device *out = &venc.output;
793
794 out->dev = &pdev->dev;
795 out->id = OMAP_DSS_OUTPUT_VENC;
796 out->output_type = OMAP_DISPLAY_TYPE_VENC;
797 out->name = "venc.0";
798 out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
799 out->ops.atv = &venc_ops;
800 out->owner = THIS_MODULE;
801
802 omapdss_register_output(out);
803}
804
805static void __exit venc_uninit_output(struct platform_device *pdev)
806{
807 struct omap_dss_device *out = &venc.output;
808
809 omapdss_unregister_output(out);
810}
811
812static int venc_probe_of(struct platform_device *pdev)
813{
814 struct device_node *node = pdev->dev.of_node;
815 struct device_node *ep;
816 u32 channels;
817 int r;
818
819 ep = omapdss_of_get_first_endpoint(node);
820 if (!ep)
821 return 0;
822
823 venc.invert_polarity = of_property_read_bool(ep, "ti,invert-polarity");
824
825 r = of_property_read_u32(ep, "ti,channels", &channels);
826 if (r) {
827 dev_err(&pdev->dev,
828 "failed to read property 'ti,channels': %d\n", r);
829 goto err;
830 }
831
832 switch (channels) {
833 case 1:
834 venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE;
835 break;
836 case 2:
837 venc.type = OMAP_DSS_VENC_TYPE_SVIDEO;
838 break;
839 default:
840 dev_err(&pdev->dev, "bad channel propert '%d'\n", channels);
841 r = -EINVAL;
842 goto err;
843 }
844
845 of_node_put(ep);
846
847 return 0;
848err:
849 of_node_put(ep);
850
851 return 0;
852}
853
854/* VENC HW IP initialisation */
855static int omap_venchw_probe(struct platform_device *pdev)
856{
857 u8 rev_id;
858 struct resource *venc_mem;
859 int r;
860
861 venc.pdev = pdev;
862
863 mutex_init(&venc.venc_lock);
864
865 venc.wss_data = 0;
866
867 venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0);
868 if (!venc_mem) {
869 DSSERR("can't get IORESOURCE_MEM VENC\n");
870 return -EINVAL;
871 }
872
873 venc.base = devm_ioremap(&pdev->dev, venc_mem->start,
874 resource_size(venc_mem));
875 if (!venc.base) {
876 DSSERR("can't ioremap VENC\n");
877 return -ENOMEM;
878 }
879
880 r = venc_get_clocks(pdev);
881 if (r)
882 return r;
883
884 pm_runtime_enable(&pdev->dev);
885
886 r = venc_runtime_get();
887 if (r)
888 goto err_runtime_get;
889
890 rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
891 dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id);
892
893 venc_runtime_put();
894
895 if (pdev->dev.of_node) {
896 r = venc_probe_of(pdev);
897 if (r) {
898 DSSERR("Invalid DT data\n");
899 goto err_probe_of;
900 }
901 }
902
903 dss_debugfs_create_file("venc", venc_dump_regs);
904
905 venc_init_output(pdev);
906
907 return 0;
908
909err_probe_of:
910err_runtime_get:
911 pm_runtime_disable(&pdev->dev);
912 return r;
913}
914
915static int __exit omap_venchw_remove(struct platform_device *pdev)
916{
917 venc_uninit_output(pdev);
918
919 pm_runtime_disable(&pdev->dev);
920
921 return 0;
922}
923
924static int venc_runtime_suspend(struct device *dev)
925{
926 if (venc.tv_dac_clk)
927 clk_disable_unprepare(venc.tv_dac_clk);
928
929 dispc_runtime_put();
930
931 return 0;
932}
933
934static int venc_runtime_resume(struct device *dev)
935{
936 int r;
937
938 r = dispc_runtime_get();
939 if (r < 0)
940 return r;
941
942 if (venc.tv_dac_clk)
943 clk_prepare_enable(venc.tv_dac_clk);
944
945 return 0;
946}
947
948static const struct dev_pm_ops venc_pm_ops = {
949 .runtime_suspend = venc_runtime_suspend,
950 .runtime_resume = venc_runtime_resume,
951};
952
953
954static const struct of_device_id venc_of_match[] = {
955 { .compatible = "ti,omap2-venc", },
956 { .compatible = "ti,omap3-venc", },
957 { .compatible = "ti,omap4-venc", },
958 {},
959};
960
961static struct platform_driver omap_venchw_driver = {
962 .probe = omap_venchw_probe,
963 .remove = __exit_p(omap_venchw_remove),
964 .driver = {
965 .name = "omapdss_venc",
966 .owner = THIS_MODULE,
967 .pm = &venc_pm_ops,
968 .of_match_table = venc_of_match,
969 },
970};
971
972int __init venc_init_platform_driver(void)
973{
974 return platform_driver_register(&omap_venchw_driver);
975}
976
977void __exit venc_uninit_platform_driver(void)
978{
979 platform_driver_unregister(&omap_venchw_driver);
980}
diff --git a/drivers/video/fbdev/omap2/dss/venc_panel.c b/drivers/video/fbdev/omap2/dss/venc_panel.c
new file mode 100644
index 000000000000..af68cd444d7e
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/venc_panel.c
@@ -0,0 +1,232 @@
1/*
2 * Copyright (C) 2009 Nokia Corporation
3 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
4 *
5 * VENC panel driver
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/kernel.h>
21#include <linux/err.h>
22#include <linux/io.h>
23#include <linux/mutex.h>
24#include <linux/module.h>
25
26#include <video/omapdss.h>
27
28#include "dss.h"
29
30static struct {
31 struct mutex lock;
32} venc_panel;
33
34static ssize_t display_output_type_show(struct device *dev,
35 struct device_attribute *attr, char *buf)
36{
37 struct omap_dss_device *dssdev = to_dss_device(dev);
38 const char *ret;
39
40 switch (dssdev->phy.venc.type) {
41 case OMAP_DSS_VENC_TYPE_COMPOSITE:
42 ret = "composite";
43 break;
44 case OMAP_DSS_VENC_TYPE_SVIDEO:
45 ret = "svideo";
46 break;
47 default:
48 return -EINVAL;
49 }
50
51 return snprintf(buf, PAGE_SIZE, "%s\n", ret);
52}
53
54static ssize_t display_output_type_store(struct device *dev,
55 struct device_attribute *attr, const char *buf, size_t size)
56{
57 struct omap_dss_device *dssdev = to_dss_device(dev);
58 enum omap_dss_venc_type new_type;
59
60 if (sysfs_streq("composite", buf))
61 new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
62 else if (sysfs_streq("svideo", buf))
63 new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
64 else
65 return -EINVAL;
66
67 mutex_lock(&venc_panel.lock);
68
69 if (dssdev->phy.venc.type != new_type) {
70 dssdev->phy.venc.type = new_type;
71 omapdss_venc_set_type(dssdev, new_type);
72 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
73 omapdss_venc_display_disable(dssdev);
74 omapdss_venc_display_enable(dssdev);
75 }
76 }
77
78 mutex_unlock(&venc_panel.lock);
79
80 return size;
81}
82
83static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
84 display_output_type_show, display_output_type_store);
85
86static int venc_panel_probe(struct omap_dss_device *dssdev)
87{
88 /* set default timings to PAL */
89 const struct omap_video_timings default_timings = {
90 .x_res = 720,
91 .y_res = 574,
92 .pixelclock = 13500000,
93 .hsw = 64,
94 .hfp = 12,
95 .hbp = 68,
96 .vsw = 5,
97 .vfp = 5,
98 .vbp = 41,
99
100 .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
101 .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
102
103 .interlace = true,
104 };
105
106 mutex_init(&venc_panel.lock);
107
108 dssdev->panel.timings = default_timings;
109
110 return device_create_file(dssdev->dev, &dev_attr_output_type);
111}
112
113static void venc_panel_remove(struct omap_dss_device *dssdev)
114{
115 device_remove_file(dssdev->dev, &dev_attr_output_type);
116}
117
118static int venc_panel_enable(struct omap_dss_device *dssdev)
119{
120 int r;
121
122 dev_dbg(dssdev->dev, "venc_panel_enable\n");
123
124 mutex_lock(&venc_panel.lock);
125
126 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
127 r = -EINVAL;
128 goto err;
129 }
130
131 omapdss_venc_set_timings(dssdev, &dssdev->panel.timings);
132 omapdss_venc_set_type(dssdev, dssdev->phy.venc.type);
133 omapdss_venc_invert_vid_out_polarity(dssdev,
134 dssdev->phy.venc.invert_polarity);
135
136 r = omapdss_venc_display_enable(dssdev);
137 if (r)
138 goto err;
139
140 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
141
142 mutex_unlock(&venc_panel.lock);
143
144 return 0;
145err:
146 mutex_unlock(&venc_panel.lock);
147
148 return r;
149}
150
151static void venc_panel_disable(struct omap_dss_device *dssdev)
152{
153 dev_dbg(dssdev->dev, "venc_panel_disable\n");
154
155 mutex_lock(&venc_panel.lock);
156
157 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
158 goto end;
159
160 omapdss_venc_display_disable(dssdev);
161
162 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
163end:
164 mutex_unlock(&venc_panel.lock);
165}
166
167static void venc_panel_set_timings(struct omap_dss_device *dssdev,
168 struct omap_video_timings *timings)
169{
170 dev_dbg(dssdev->dev, "venc_panel_set_timings\n");
171
172 mutex_lock(&venc_panel.lock);
173
174 omapdss_venc_set_timings(dssdev, timings);
175 dssdev->panel.timings = *timings;
176
177 mutex_unlock(&venc_panel.lock);
178}
179
180static int venc_panel_check_timings(struct omap_dss_device *dssdev,
181 struct omap_video_timings *timings)
182{
183 dev_dbg(dssdev->dev, "venc_panel_check_timings\n");
184
185 return omapdss_venc_check_timings(dssdev, timings);
186}
187
188static u32 venc_panel_get_wss(struct omap_dss_device *dssdev)
189{
190 dev_dbg(dssdev->dev, "venc_panel_get_wss\n");
191
192 return omapdss_venc_get_wss(dssdev);
193}
194
195static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss)
196{
197 dev_dbg(dssdev->dev, "venc_panel_set_wss\n");
198
199 return omapdss_venc_set_wss(dssdev, wss);
200}
201
202static struct omap_dss_driver venc_driver = {
203 .probe = venc_panel_probe,
204 .remove = venc_panel_remove,
205
206 .enable = venc_panel_enable,
207 .disable = venc_panel_disable,
208
209 .get_resolution = omapdss_default_get_resolution,
210 .get_recommended_bpp = omapdss_default_get_recommended_bpp,
211
212 .set_timings = venc_panel_set_timings,
213 .check_timings = venc_panel_check_timings,
214
215 .get_wss = venc_panel_get_wss,
216 .set_wss = venc_panel_set_wss,
217
218 .driver = {
219 .name = "venc",
220 .owner = THIS_MODULE,
221 },
222};
223
224int venc_panel_init(void)
225{
226 return omap_dss_register_driver(&venc_driver);
227}
228
229void venc_panel_exit(void)
230{
231 omap_dss_unregister_driver(&venc_driver);
232}