aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@nokia.com>2009-11-03 04:23:50 -0500
committerTomi Valkeinen <tomi.valkeinen@nokia.com>2009-12-09 05:04:34 -0500
commit559d67018950ced65c73358cd69c4bdd2b0c5dd6 (patch)
tree0c77ad7a8959b05583dd7502a0da4bdf56ef8d1d /drivers/video
parent4d1a7c122aeae6ae9732be0a32f5e199fff63fb7 (diff)
OMAP: DSS2: Display Subsystem Driver core
The core files of DSS2. DSS2 commits are split a bit artificially to make the individual commits smaller, and DSS2 doesn't compile properly without the rest of the core commits. This shouldn't be a problem, as no configuration uses DSS2 yet. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/omap2/Kconfig2
-rw-r--r--drivers/video/omap2/Makefile2
-rw-r--r--drivers/video/omap2/dss/Kconfig89
-rw-r--r--drivers/video/omap2/dss/Makefile6
-rw-r--r--drivers/video/omap2/dss/core.c919
-rw-r--r--drivers/video/omap2/dss/dss.c596
-rw-r--r--drivers/video/omap2/dss/dss.h370
7 files changed, 1984 insertions, 0 deletions
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig
index ac8b65057a01..55b4c4265f57 100644
--- a/drivers/video/omap2/Kconfig
+++ b/drivers/video/omap2/Kconfig
@@ -3,3 +3,5 @@ config OMAP2_VRAM
3 3
4config OMAP2_VRFB 4config OMAP2_VRFB
5 bool 5 bool
6
7source "drivers/video/omap2/dss/Kconfig"
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile
index aa3751b3dc90..ee0644f9d3c1 100644
--- a/drivers/video/omap2/Makefile
+++ b/drivers/video/omap2/Makefile
@@ -1,2 +1,4 @@
1obj-$(CONFIG_OMAP2_VRAM) += vram.o 1obj-$(CONFIG_OMAP2_VRAM) += vram.o
2obj-$(CONFIG_OMAP2_VRFB) += vrfb.o 2obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
3
4obj-y += dss/
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
new file mode 100644
index 000000000000..71d8dec30635
--- /dev/null
+++ b/drivers/video/omap2/dss/Kconfig
@@ -0,0 +1,89 @@
1menuconfig OMAP2_DSS
2 tristate "OMAP2/3 Display Subsystem support (EXPERIMENTAL)"
3 depends on ARCH_OMAP2 || ARCH_OMAP3
4 help
5 OMAP2/3 Display Subsystem support.
6
7if OMAP2_DSS
8
9config OMAP2_VRAM_SIZE
10 int "VRAM size (MB)"
11 range 0 32
12 default 0
13 help
14 The amount of SDRAM to reserve at boot time for video RAM use.
15 This VRAM will be used by omapfb and other drivers that need
16 large continuous RAM area for video use.
17
18 You can also set this with "vram=<bytes>" kernel argument, or
19 in the board file.
20
21config OMAP2_DSS_DEBUG_SUPPORT
22 bool "Debug support"
23 default y
24 help
25 This enables debug messages. You need to enable printing
26 with 'debug' module parameter.
27
28config OMAP2_DSS_RFBI
29 bool "RFBI support"
30 default n
31 help
32 MIPI DBI, or RFBI (Remote Framebuffer Interface), support.
33
34config OMAP2_DSS_VENC
35 bool "VENC support"
36 default y
37 help
38 OMAP Video Encoder support.
39
40config OMAP2_DSS_SDI
41 bool "SDI support"
42 depends on ARCH_OMAP3
43 default n
44 help
45 SDI (Serial Display Interface) support.
46
47config OMAP2_DSS_DSI
48 bool "DSI support"
49 depends on ARCH_OMAP3
50 default n
51 help
52 MIPI DSI support.
53
54config OMAP2_DSS_USE_DSI_PLL
55 bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
56 default n
57 depends on OMAP2_DSS_DSI
58 help
59 Use DSI PLL to generate pixel clock. Currently only for DPI output.
60 DSI PLL can be used to generate higher and more precise pixel clocks.
61
62config OMAP2_DSS_FAKE_VSYNC
63 bool "Fake VSYNC irq from manual update displays"
64 default n
65 help
66 If this is selected, DSI will generate a fake DISPC VSYNC interrupt
67 when DSI has sent a frame. This is only needed with DSI or RFBI
68 displays using manual mode, and you want VSYNC to, for example,
69 time animation.
70
71config OMAP2_DSS_MIN_FCK_PER_PCK
72 int "Minimum FCK/PCK ratio (for scaling)"
73 range 0 32
74 default 0
75 help
76 This can be used to adjust the minimum FCK/PCK ratio.
77
78 With this you can make sure that DISPC FCK is at least
79 n x PCK. Video plane scaling requires higher FCK than
80 normally.
81
82 If this is set to 0, there's no extra constraint on the
83 DISPC FCK. However, the FCK will at minimum be
84 2xPCK (if active matrix) or 3xPCK (if passive matrix).
85
86 Max FCK is 173MHz, so this doesn't work if your PCK
87 is very high.
88
89endif
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
new file mode 100644
index 000000000000..980c72c2db98
--- /dev/null
+++ b/drivers/video/omap2/dss/Makefile
@@ -0,0 +1,6 @@
1obj-$(CONFIG_OMAP2_DSS) += omapdss.o
2omapdss-y := core.o dss.o dispc.o dpi.o display.o manager.o overlay.o
3omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
4omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
5omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
6omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
new file mode 100644
index 000000000000..29497a0c9a91
--- /dev/null
+++ b/drivers/video/omap2/dss/core.c
@@ -0,0 +1,919 @@
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
35#include <plat/display.h>
36#include <plat/clock.h>
37
38#include "dss.h"
39
40static struct {
41 struct platform_device *pdev;
42 int ctx_id;
43
44 struct clk *dss_ick;
45 struct clk *dss1_fck;
46 struct clk *dss2_fck;
47 struct clk *dss_54m_fck;
48 struct clk *dss_96m_fck;
49 unsigned num_clks_enabled;
50} core;
51
52static void dss_clk_enable_all_no_ctx(void);
53static void dss_clk_disable_all_no_ctx(void);
54static void dss_clk_enable_no_ctx(enum dss_clock clks);
55static void dss_clk_disable_no_ctx(enum dss_clock clks);
56
57static char *def_disp_name;
58module_param_named(def_disp, def_disp_name, charp, 0);
59MODULE_PARM_DESC(def_disp_name, "default display name");
60
61#ifdef DEBUG
62unsigned int dss_debug;
63module_param_named(debug, dss_debug, bool, 0644);
64#endif
65
66/* CONTEXT */
67static int dss_get_ctx_id(void)
68{
69 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
70 int r;
71
72 if (!pdata->get_last_off_on_transaction_id)
73 return 0;
74 r = pdata->get_last_off_on_transaction_id(&core.pdev->dev);
75 if (r < 0) {
76 dev_err(&core.pdev->dev, "getting transaction ID failed, "
77 "will force context restore\n");
78 r = -1;
79 }
80 return r;
81}
82
83int dss_need_ctx_restore(void)
84{
85 int id = dss_get_ctx_id();
86
87 if (id < 0 || id != core.ctx_id) {
88 DSSDBG("ctx id %d -> id %d\n",
89 core.ctx_id, id);
90 core.ctx_id = id;
91 return 1;
92 } else {
93 return 0;
94 }
95}
96
97static void save_all_ctx(void)
98{
99 DSSDBG("save context\n");
100
101 dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
102
103 dss_save_context();
104 dispc_save_context();
105#ifdef CONFIG_OMAP2_DSS_DSI
106 dsi_save_context();
107#endif
108
109 dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
110}
111
112static void restore_all_ctx(void)
113{
114 DSSDBG("restore context\n");
115
116 dss_clk_enable_all_no_ctx();
117
118 dss_restore_context();
119 dispc_restore_context();
120#ifdef CONFIG_OMAP2_DSS_DSI
121 dsi_restore_context();
122#endif
123
124 dss_clk_disable_all_no_ctx();
125}
126
127/* CLOCKS */
128static void core_dump_clocks(struct seq_file *s)
129{
130 int i;
131 struct clk *clocks[5] = {
132 core.dss_ick,
133 core.dss1_fck,
134 core.dss2_fck,
135 core.dss_54m_fck,
136 core.dss_96m_fck
137 };
138
139 seq_printf(s, "- CORE -\n");
140
141 seq_printf(s, "internal clk count\t\t%u\n", core.num_clks_enabled);
142
143 for (i = 0; i < 5; i++) {
144 if (!clocks[i])
145 continue;
146 seq_printf(s, "%-15s\t%lu\t%d\n",
147 clocks[i]->name,
148 clk_get_rate(clocks[i]),
149 clocks[i]->usecount);
150 }
151}
152
153static int dss_get_clock(struct clk **clock, const char *clk_name)
154{
155 struct clk *clk;
156
157 clk = clk_get(&core.pdev->dev, clk_name);
158
159 if (IS_ERR(clk)) {
160 DSSERR("can't get clock %s", clk_name);
161 return PTR_ERR(clk);
162 }
163
164 *clock = clk;
165
166 DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
167
168 return 0;
169}
170
171static int dss_get_clocks(void)
172{
173 int r;
174
175 core.dss_ick = NULL;
176 core.dss1_fck = NULL;
177 core.dss2_fck = NULL;
178 core.dss_54m_fck = NULL;
179 core.dss_96m_fck = NULL;
180
181 r = dss_get_clock(&core.dss_ick, "ick");
182 if (r)
183 goto err;
184
185 r = dss_get_clock(&core.dss1_fck, "dss1_fck");
186 if (r)
187 goto err;
188
189 r = dss_get_clock(&core.dss2_fck, "dss2_fck");
190 if (r)
191 goto err;
192
193 r = dss_get_clock(&core.dss_54m_fck, "tv_fck");
194 if (r)
195 goto err;
196
197 r = dss_get_clock(&core.dss_96m_fck, "video_fck");
198 if (r)
199 goto err;
200
201 return 0;
202
203err:
204 if (core.dss_ick)
205 clk_put(core.dss_ick);
206 if (core.dss1_fck)
207 clk_put(core.dss1_fck);
208 if (core.dss2_fck)
209 clk_put(core.dss2_fck);
210 if (core.dss_54m_fck)
211 clk_put(core.dss_54m_fck);
212 if (core.dss_96m_fck)
213 clk_put(core.dss_96m_fck);
214
215 return r;
216}
217
218static void dss_put_clocks(void)
219{
220 if (core.dss_96m_fck)
221 clk_put(core.dss_96m_fck);
222 clk_put(core.dss_54m_fck);
223 clk_put(core.dss1_fck);
224 clk_put(core.dss2_fck);
225 clk_put(core.dss_ick);
226}
227
228unsigned long dss_clk_get_rate(enum dss_clock clk)
229{
230 switch (clk) {
231 case DSS_CLK_ICK:
232 return clk_get_rate(core.dss_ick);
233 case DSS_CLK_FCK1:
234 return clk_get_rate(core.dss1_fck);
235 case DSS_CLK_FCK2:
236 return clk_get_rate(core.dss2_fck);
237 case DSS_CLK_54M:
238 return clk_get_rate(core.dss_54m_fck);
239 case DSS_CLK_96M:
240 return clk_get_rate(core.dss_96m_fck);
241 }
242
243 BUG();
244 return 0;
245}
246
247static unsigned count_clk_bits(enum dss_clock clks)
248{
249 unsigned num_clks = 0;
250
251 if (clks & DSS_CLK_ICK)
252 ++num_clks;
253 if (clks & DSS_CLK_FCK1)
254 ++num_clks;
255 if (clks & DSS_CLK_FCK2)
256 ++num_clks;
257 if (clks & DSS_CLK_54M)
258 ++num_clks;
259 if (clks & DSS_CLK_96M)
260 ++num_clks;
261
262 return num_clks;
263}
264
265static void dss_clk_enable_no_ctx(enum dss_clock clks)
266{
267 unsigned num_clks = count_clk_bits(clks);
268
269 if (clks & DSS_CLK_ICK)
270 clk_enable(core.dss_ick);
271 if (clks & DSS_CLK_FCK1)
272 clk_enable(core.dss1_fck);
273 if (clks & DSS_CLK_FCK2)
274 clk_enable(core.dss2_fck);
275 if (clks & DSS_CLK_54M)
276 clk_enable(core.dss_54m_fck);
277 if (clks & DSS_CLK_96M)
278 clk_enable(core.dss_96m_fck);
279
280 core.num_clks_enabled += num_clks;
281}
282
283void dss_clk_enable(enum dss_clock clks)
284{
285 dss_clk_enable_no_ctx(clks);
286
287 if (cpu_is_omap34xx() && dss_need_ctx_restore())
288 restore_all_ctx();
289}
290
291static void dss_clk_disable_no_ctx(enum dss_clock clks)
292{
293 unsigned num_clks = count_clk_bits(clks);
294
295 if (clks & DSS_CLK_ICK)
296 clk_disable(core.dss_ick);
297 if (clks & DSS_CLK_FCK1)
298 clk_disable(core.dss1_fck);
299 if (clks & DSS_CLK_FCK2)
300 clk_disable(core.dss2_fck);
301 if (clks & DSS_CLK_54M)
302 clk_disable(core.dss_54m_fck);
303 if (clks & DSS_CLK_96M)
304 clk_disable(core.dss_96m_fck);
305
306 core.num_clks_enabled -= num_clks;
307}
308
309void dss_clk_disable(enum dss_clock clks)
310{
311 if (cpu_is_omap34xx()) {
312 unsigned num_clks = count_clk_bits(clks);
313
314 BUG_ON(core.num_clks_enabled < num_clks);
315
316 if (core.num_clks_enabled == num_clks)
317 save_all_ctx();
318 }
319
320 dss_clk_disable_no_ctx(clks);
321}
322
323static void dss_clk_enable_all_no_ctx(void)
324{
325 enum dss_clock clks;
326
327 clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
328 if (cpu_is_omap34xx())
329 clks |= DSS_CLK_96M;
330 dss_clk_enable_no_ctx(clks);
331}
332
333static void dss_clk_disable_all_no_ctx(void)
334{
335 enum dss_clock clks;
336
337 clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
338 if (cpu_is_omap34xx())
339 clks |= DSS_CLK_96M;
340 dss_clk_disable_no_ctx(clks);
341}
342
343static void dss_clk_disable_all(void)
344{
345 enum dss_clock clks;
346
347 clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
348 if (cpu_is_omap34xx())
349 clks |= DSS_CLK_96M;
350 dss_clk_disable(clks);
351}
352
353/* DEBUGFS */
354#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
355static void dss_debug_dump_clocks(struct seq_file *s)
356{
357 core_dump_clocks(s);
358 dss_dump_clocks(s);
359 dispc_dump_clocks(s);
360#ifdef CONFIG_OMAP2_DSS_DSI
361 dsi_dump_clocks(s);
362#endif
363}
364
365static int dss_debug_show(struct seq_file *s, void *unused)
366{
367 void (*func)(struct seq_file *) = s->private;
368 func(s);
369 return 0;
370}
371
372static int dss_debug_open(struct inode *inode, struct file *file)
373{
374 return single_open(file, dss_debug_show, inode->i_private);
375}
376
377static const struct file_operations dss_debug_fops = {
378 .open = dss_debug_open,
379 .read = seq_read,
380 .llseek = seq_lseek,
381 .release = single_release,
382};
383
384static struct dentry *dss_debugfs_dir;
385
386static int dss_initialize_debugfs(void)
387{
388 dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
389 if (IS_ERR(dss_debugfs_dir)) {
390 int err = PTR_ERR(dss_debugfs_dir);
391 dss_debugfs_dir = NULL;
392 return err;
393 }
394
395 debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
396 &dss_debug_dump_clocks, &dss_debug_fops);
397
398 debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir,
399 &dss_dump_regs, &dss_debug_fops);
400 debugfs_create_file("dispc", S_IRUGO, dss_debugfs_dir,
401 &dispc_dump_regs, &dss_debug_fops);
402#ifdef CONFIG_OMAP2_DSS_RFBI
403 debugfs_create_file("rfbi", S_IRUGO, dss_debugfs_dir,
404 &rfbi_dump_regs, &dss_debug_fops);
405#endif
406#ifdef CONFIG_OMAP2_DSS_DSI
407 debugfs_create_file("dsi", S_IRUGO, dss_debugfs_dir,
408 &dsi_dump_regs, &dss_debug_fops);
409#endif
410#ifdef CONFIG_OMAP2_DSS_VENC
411 debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
412 &venc_dump_regs, &dss_debug_fops);
413#endif
414 return 0;
415}
416
417static void dss_uninitialize_debugfs(void)
418{
419 if (dss_debugfs_dir)
420 debugfs_remove_recursive(dss_debugfs_dir);
421}
422#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
423
424/* PLATFORM DEVICE */
425static int omap_dss_probe(struct platform_device *pdev)
426{
427 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
428 int skip_init = 0;
429 int r;
430 int i;
431
432 core.pdev = pdev;
433
434 dss_init_overlay_managers(pdev);
435 dss_init_overlays(pdev);
436
437 r = dss_get_clocks();
438 if (r)
439 goto fail0;
440
441 dss_clk_enable_all_no_ctx();
442
443 core.ctx_id = dss_get_ctx_id();
444 DSSDBG("initial ctx id %u\n", core.ctx_id);
445
446#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
447 /* DISPC_CONTROL */
448 if (omap_readl(0x48050440) & 1) /* LCD enabled? */
449 skip_init = 1;
450#endif
451
452 r = dss_init(skip_init);
453 if (r) {
454 DSSERR("Failed to initialize DSS\n");
455 goto fail0;
456 }
457
458#ifdef CONFIG_OMAP2_DSS_RFBI
459 r = rfbi_init();
460 if (r) {
461 DSSERR("Failed to initialize rfbi\n");
462 goto fail0;
463 }
464#endif
465
466 r = dpi_init();
467 if (r) {
468 DSSERR("Failed to initialize dpi\n");
469 goto fail0;
470 }
471
472 r = dispc_init();
473 if (r) {
474 DSSERR("Failed to initialize dispc\n");
475 goto fail0;
476 }
477#ifdef CONFIG_OMAP2_DSS_VENC
478 r = venc_init(pdev);
479 if (r) {
480 DSSERR("Failed to initialize venc\n");
481 goto fail0;
482 }
483#endif
484 if (cpu_is_omap34xx()) {
485#ifdef CONFIG_OMAP2_DSS_SDI
486 r = sdi_init(skip_init);
487 if (r) {
488 DSSERR("Failed to initialize SDI\n");
489 goto fail0;
490 }
491#endif
492#ifdef CONFIG_OMAP2_DSS_DSI
493 r = dsi_init(pdev);
494 if (r) {
495 DSSERR("Failed to initialize DSI\n");
496 goto fail0;
497 }
498#endif
499 }
500
501#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
502 r = dss_initialize_debugfs();
503 if (r)
504 goto fail0;
505#endif
506
507 for (i = 0; i < pdata->num_devices; ++i) {
508 struct omap_dss_device *dssdev = pdata->devices[i];
509
510 r = omap_dss_register_device(dssdev);
511 if (r)
512 DSSERR("device reg failed %d\n", i);
513
514 if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0)
515 pdata->default_device = dssdev;
516 }
517
518 dss_clk_disable_all();
519
520 return 0;
521
522 /* XXX fail correctly */
523fail0:
524 return r;
525}
526
527static int omap_dss_remove(struct platform_device *pdev)
528{
529 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
530 int i;
531 int c;
532
533#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
534 dss_uninitialize_debugfs();
535#endif
536
537#ifdef CONFIG_OMAP2_DSS_VENC
538 venc_exit();
539#endif
540 dispc_exit();
541 dpi_exit();
542#ifdef CONFIG_OMAP2_DSS_RFBI
543 rfbi_exit();
544#endif
545 if (cpu_is_omap34xx()) {
546#ifdef CONFIG_OMAP2_DSS_DSI
547 dsi_exit();
548#endif
549#ifdef CONFIG_OMAP2_DSS_SDI
550 sdi_exit();
551#endif
552 }
553
554 dss_exit();
555
556 /* these should be removed at some point */
557 c = core.dss_ick->usecount;
558 if (c > 0) {
559 DSSERR("warning: dss_ick usecount %d, disabling\n", c);
560 while (c-- > 0)
561 clk_disable(core.dss_ick);
562 }
563
564 c = core.dss1_fck->usecount;
565 if (c > 0) {
566 DSSERR("warning: dss1_fck usecount %d, disabling\n", c);
567 while (c-- > 0)
568 clk_disable(core.dss1_fck);
569 }
570
571 c = core.dss2_fck->usecount;
572 if (c > 0) {
573 DSSERR("warning: dss2_fck usecount %d, disabling\n", c);
574 while (c-- > 0)
575 clk_disable(core.dss2_fck);
576 }
577
578 c = core.dss_54m_fck->usecount;
579 if (c > 0) {
580 DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c);
581 while (c-- > 0)
582 clk_disable(core.dss_54m_fck);
583 }
584
585 if (core.dss_96m_fck) {
586 c = core.dss_96m_fck->usecount;
587 if (c > 0) {
588 DSSERR("warning: dss_96m_fck usecount %d, disabling\n",
589 c);
590 while (c-- > 0)
591 clk_disable(core.dss_96m_fck);
592 }
593 }
594
595 dss_put_clocks();
596
597 dss_uninit_overlays(pdev);
598 dss_uninit_overlay_managers(pdev);
599
600 for (i = 0; i < pdata->num_devices; ++i)
601 omap_dss_unregister_device(pdata->devices[i]);
602
603 return 0;
604}
605
606static void omap_dss_shutdown(struct platform_device *pdev)
607{
608 DSSDBG("shutdown\n");
609 dss_disable_all_devices();
610}
611
612static int omap_dss_suspend(struct platform_device *pdev, pm_message_t state)
613{
614 DSSDBG("suspend %d\n", state.event);
615
616 return dss_suspend_all_devices();
617}
618
619static int omap_dss_resume(struct platform_device *pdev)
620{
621 DSSDBG("resume\n");
622
623 return dss_resume_all_devices();
624}
625
626static struct platform_driver omap_dss_driver = {
627 .probe = omap_dss_probe,
628 .remove = omap_dss_remove,
629 .shutdown = omap_dss_shutdown,
630 .suspend = omap_dss_suspend,
631 .resume = omap_dss_resume,
632 .driver = {
633 .name = "omapdss",
634 .owner = THIS_MODULE,
635 },
636};
637
638/* BUS */
639static int dss_bus_match(struct device *dev, struct device_driver *driver)
640{
641 struct omap_dss_device *dssdev = to_dss_device(dev);
642
643 DSSDBG("bus_match. dev %s/%s, drv %s\n",
644 dev_name(dev), dssdev->driver_name, driver->name);
645
646 return strcmp(dssdev->driver_name, driver->name) == 0;
647}
648
649static ssize_t device_name_show(struct device *dev,
650 struct device_attribute *attr, char *buf)
651{
652 struct omap_dss_device *dssdev = to_dss_device(dev);
653 return snprintf(buf, PAGE_SIZE, "%s\n",
654 dssdev->name ?
655 dssdev->name : "");
656}
657
658static struct device_attribute default_dev_attrs[] = {
659 __ATTR(name, S_IRUGO, device_name_show, NULL),
660 __ATTR_NULL,
661};
662
663static ssize_t driver_name_show(struct device_driver *drv, char *buf)
664{
665 struct omap_dss_driver *dssdrv = to_dss_driver(drv);
666 return snprintf(buf, PAGE_SIZE, "%s\n",
667 dssdrv->driver.name ?
668 dssdrv->driver.name : "");
669}
670static struct driver_attribute default_drv_attrs[] = {
671 __ATTR(name, S_IRUGO, driver_name_show, NULL),
672 __ATTR_NULL,
673};
674
675static struct bus_type dss_bus_type = {
676 .name = "omapdss",
677 .match = dss_bus_match,
678 .dev_attrs = default_dev_attrs,
679 .drv_attrs = default_drv_attrs,
680};
681
682static void dss_bus_release(struct device *dev)
683{
684 DSSDBG("bus_release\n");
685}
686
687static struct device dss_bus = {
688 .release = dss_bus_release,
689};
690
691struct bus_type *dss_get_bus(void)
692{
693 return &dss_bus_type;
694}
695
696/* DRIVER */
697static int dss_driver_probe(struct device *dev)
698{
699 int r;
700 struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
701 struct omap_dss_device *dssdev = to_dss_device(dev);
702 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
703 bool force;
704
705 DSSDBG("driver_probe: dev %s/%s, drv %s\n",
706 dev_name(dev), dssdev->driver_name,
707 dssdrv->driver.name);
708
709 dss_init_device(core.pdev, dssdev);
710
711 /* skip this if the device is behind a ctrl */
712 if (!dssdev->panel.ctrl) {
713 force = pdata->default_device == dssdev;
714 dss_recheck_connections(dssdev, force);
715 }
716
717 r = dssdrv->probe(dssdev);
718
719 if (r) {
720 DSSERR("driver probe failed: %d\n", r);
721 return r;
722 }
723
724 DSSDBG("probe done for device %s\n", dev_name(dev));
725
726 dssdev->driver = dssdrv;
727
728 return 0;
729}
730
731static int dss_driver_remove(struct device *dev)
732{
733 struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
734 struct omap_dss_device *dssdev = to_dss_device(dev);
735
736 DSSDBG("driver_remove: dev %s/%s\n", dev_name(dev),
737 dssdev->driver_name);
738
739 dssdrv->remove(dssdev);
740
741 dss_uninit_device(core.pdev, dssdev);
742
743 dssdev->driver = NULL;
744
745 return 0;
746}
747
748int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
749{
750 dssdriver->driver.bus = &dss_bus_type;
751 dssdriver->driver.probe = dss_driver_probe;
752 dssdriver->driver.remove = dss_driver_remove;
753 return driver_register(&dssdriver->driver);
754}
755EXPORT_SYMBOL(omap_dss_register_driver);
756
757void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver)
758{
759 driver_unregister(&dssdriver->driver);
760}
761EXPORT_SYMBOL(omap_dss_unregister_driver);
762
763/* DEVICE */
764static void reset_device(struct device *dev, int check)
765{
766 u8 *dev_p = (u8 *)dev;
767 u8 *dev_end = dev_p + sizeof(*dev);
768 void *saved_pdata;
769
770 saved_pdata = dev->platform_data;
771 if (check) {
772 /*
773 * Check if there is any other setting than platform_data
774 * in struct device; warn that these will be reset by our
775 * init.
776 */
777 dev->platform_data = NULL;
778 while (dev_p < dev_end) {
779 if (*dev_p) {
780 WARN("%s: struct device fields will be "
781 "discarded\n",
782 __func__);
783 break;
784 }
785 dev_p++;
786 }
787 }
788 memset(dev, 0, sizeof(*dev));
789 dev->platform_data = saved_pdata;
790}
791
792
793static void omap_dss_dev_release(struct device *dev)
794{
795 reset_device(dev, 0);
796}
797
798int omap_dss_register_device(struct omap_dss_device *dssdev)
799{
800 static int dev_num;
801 static int panel_num;
802 int r;
803
804 WARN_ON(!dssdev->driver_name);
805
806 reset_device(&dssdev->dev, 1);
807 dssdev->dev.bus = &dss_bus_type;
808 dssdev->dev.parent = &dss_bus;
809 dssdev->dev.release = omap_dss_dev_release;
810 dev_set_name(&dssdev->dev, "display%d", dev_num++);
811 r = device_register(&dssdev->dev);
812 if (r)
813 return r;
814
815 if (dssdev->ctrl.panel) {
816 struct omap_dss_device *panel = dssdev->ctrl.panel;
817
818 panel->panel.ctrl = dssdev;
819
820 reset_device(&panel->dev, 1);
821 panel->dev.bus = &dss_bus_type;
822 panel->dev.parent = &dssdev->dev;
823 panel->dev.release = omap_dss_dev_release;
824 dev_set_name(&panel->dev, "panel%d", panel_num++);
825 r = device_register(&panel->dev);
826 if (r)
827 return r;
828 }
829
830 return 0;
831}
832
833void omap_dss_unregister_device(struct omap_dss_device *dssdev)
834{
835 device_unregister(&dssdev->dev);
836
837 if (dssdev->ctrl.panel) {
838 struct omap_dss_device *panel = dssdev->ctrl.panel;
839 device_unregister(&panel->dev);
840 }
841}
842
843/* BUS */
844static int omap_dss_bus_register(void)
845{
846 int r;
847
848 r = bus_register(&dss_bus_type);
849 if (r) {
850 DSSERR("bus register failed\n");
851 return r;
852 }
853
854 dev_set_name(&dss_bus, "omapdss");
855 r = device_register(&dss_bus);
856 if (r) {
857 DSSERR("bus driver register failed\n");
858 bus_unregister(&dss_bus_type);
859 return r;
860 }
861
862 return 0;
863}
864
865/* INIT */
866
867#ifdef CONFIG_OMAP2_DSS_MODULE
868static void omap_dss_bus_unregister(void)
869{
870 device_unregister(&dss_bus);
871
872 bus_unregister(&dss_bus_type);
873}
874
875static int __init omap_dss_init(void)
876{
877 int r;
878
879 r = omap_dss_bus_register();
880 if (r)
881 return r;
882
883 r = platform_driver_register(&omap_dss_driver);
884 if (r) {
885 omap_dss_bus_unregister();
886 return r;
887 }
888
889 return 0;
890}
891
892static void __exit omap_dss_exit(void)
893{
894 platform_driver_unregister(&omap_dss_driver);
895
896 omap_dss_bus_unregister();
897}
898
899module_init(omap_dss_init);
900module_exit(omap_dss_exit);
901#else
902static int __init omap_dss_init(void)
903{
904 return omap_dss_bus_register();
905}
906
907static int __init omap_dss_init2(void)
908{
909 return platform_driver_register(&omap_dss_driver);
910}
911
912core_initcall(omap_dss_init);
913device_initcall(omap_dss_init2);
914#endif
915
916MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
917MODULE_DESCRIPTION("OMAP2/3 Display Subsystem");
918MODULE_LICENSE("GPL v2");
919
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
new file mode 100644
index 000000000000..9b05ee65a15d
--- /dev/null
+++ b/drivers/video/omap2/dss/dss.c
@@ -0,0 +1,596 @@
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/io.h>
27#include <linux/err.h>
28#include <linux/delay.h>
29#include <linux/interrupt.h>
30#include <linux/seq_file.h>
31#include <linux/clk.h>
32
33#include <plat/display.h>
34#include "dss.h"
35
36#define DSS_BASE 0x48050000
37
38#define DSS_SZ_REGS SZ_512
39
40struct dss_reg {
41 u16 idx;
42};
43
44#define DSS_REG(idx) ((const struct dss_reg) { idx })
45
46#define DSS_REVISION DSS_REG(0x0000)
47#define DSS_SYSCONFIG DSS_REG(0x0010)
48#define DSS_SYSSTATUS DSS_REG(0x0014)
49#define DSS_IRQSTATUS DSS_REG(0x0018)
50#define DSS_CONTROL DSS_REG(0x0040)
51#define DSS_SDI_CONTROL DSS_REG(0x0044)
52#define DSS_PLL_CONTROL DSS_REG(0x0048)
53#define DSS_SDI_STATUS DSS_REG(0x005C)
54
55#define REG_GET(idx, start, end) \
56 FLD_GET(dss_read_reg(idx), start, end)
57
58#define REG_FLD_MOD(idx, val, start, end) \
59 dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
60
61static struct {
62 void __iomem *base;
63
64 struct clk *dpll4_m4_ck;
65
66 unsigned long cache_req_pck;
67 unsigned long cache_prate;
68 struct dss_clock_info cache_dss_cinfo;
69 struct dispc_clock_info cache_dispc_cinfo;
70
71 u32 ctx[DSS_SZ_REGS / sizeof(u32)];
72} dss;
73
74static int _omap_dss_wait_reset(void);
75
76static inline void dss_write_reg(const struct dss_reg idx, u32 val)
77{
78 __raw_writel(val, dss.base + idx.idx);
79}
80
81static inline u32 dss_read_reg(const struct dss_reg idx)
82{
83 return __raw_readl(dss.base + idx.idx);
84}
85
86#define SR(reg) \
87 dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
88#define RR(reg) \
89 dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
90
91void dss_save_context(void)
92{
93 if (cpu_is_omap24xx())
94 return;
95
96 SR(SYSCONFIG);
97 SR(CONTROL);
98
99#ifdef CONFIG_OMAP2_DSS_SDI
100 SR(SDI_CONTROL);
101 SR(PLL_CONTROL);
102#endif
103}
104
105void dss_restore_context(void)
106{
107 if (_omap_dss_wait_reset())
108 DSSERR("DSS not coming out of reset after sleep\n");
109
110 RR(SYSCONFIG);
111 RR(CONTROL);
112
113#ifdef CONFIG_OMAP2_DSS_SDI
114 RR(SDI_CONTROL);
115 RR(PLL_CONTROL);
116#endif
117}
118
119#undef SR
120#undef RR
121
122void dss_sdi_init(u8 datapairs)
123{
124 u32 l;
125
126 BUG_ON(datapairs > 3 || datapairs < 1);
127
128 l = dss_read_reg(DSS_SDI_CONTROL);
129 l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */
130 l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */
131 l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */
132 dss_write_reg(DSS_SDI_CONTROL, l);
133
134 l = dss_read_reg(DSS_PLL_CONTROL);
135 l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */
136 l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */
137 l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */
138 dss_write_reg(DSS_PLL_CONTROL, l);
139}
140
141int dss_sdi_enable(void)
142{
143 unsigned long timeout;
144
145 dispc_pck_free_enable(1);
146
147 /* Reset SDI PLL */
148 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
149 udelay(1); /* wait 2x PCLK */
150
151 /* Lock SDI PLL */
152 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
153
154 /* Waiting for PLL lock request to complete */
155 timeout = jiffies + msecs_to_jiffies(500);
156 while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
157 if (time_after_eq(jiffies, timeout)) {
158 DSSERR("PLL lock request timed out\n");
159 goto err1;
160 }
161 }
162
163 /* Clearing PLL_GO bit */
164 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
165
166 /* Waiting for PLL to lock */
167 timeout = jiffies + msecs_to_jiffies(500);
168 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
169 if (time_after_eq(jiffies, timeout)) {
170 DSSERR("PLL lock timed out\n");
171 goto err1;
172 }
173 }
174
175 dispc_lcd_enable_signal(1);
176
177 /* Waiting for SDI reset to complete */
178 timeout = jiffies + msecs_to_jiffies(500);
179 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
180 if (time_after_eq(jiffies, timeout)) {
181 DSSERR("SDI reset timed out\n");
182 goto err2;
183 }
184 }
185
186 return 0;
187
188 err2:
189 dispc_lcd_enable_signal(0);
190 err1:
191 /* Reset SDI PLL */
192 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
193
194 dispc_pck_free_enable(0);
195
196 return -ETIMEDOUT;
197}
198
199void dss_sdi_disable(void)
200{
201 dispc_lcd_enable_signal(0);
202
203 dispc_pck_free_enable(0);
204
205 /* Reset SDI PLL */
206 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
207}
208
209void dss_dump_clocks(struct seq_file *s)
210{
211 unsigned long dpll4_ck_rate;
212 unsigned long dpll4_m4_ck_rate;
213
214 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
215
216 dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
217 dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
218
219 seq_printf(s, "- DSS -\n");
220
221 seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
222
223 seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n",
224 dpll4_ck_rate,
225 dpll4_ck_rate / dpll4_m4_ck_rate,
226 dss_clk_get_rate(DSS_CLK_FCK1));
227
228 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
229}
230
231void dss_dump_regs(struct seq_file *s)
232{
233#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
234
235 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
236
237 DUMPREG(DSS_REVISION);
238 DUMPREG(DSS_SYSCONFIG);
239 DUMPREG(DSS_SYSSTATUS);
240 DUMPREG(DSS_IRQSTATUS);
241 DUMPREG(DSS_CONTROL);
242 DUMPREG(DSS_SDI_CONTROL);
243 DUMPREG(DSS_PLL_CONTROL);
244 DUMPREG(DSS_SDI_STATUS);
245
246 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
247#undef DUMPREG
248}
249
250void dss_select_clk_source(bool dsi, bool dispc)
251{
252 u32 r;
253 r = dss_read_reg(DSS_CONTROL);
254 r = FLD_MOD(r, dsi, 1, 1); /* DSI_CLK_SWITCH */
255 r = FLD_MOD(r, dispc, 0, 0); /* DISPC_CLK_SWITCH */
256 dss_write_reg(DSS_CONTROL, r);
257}
258
259int dss_get_dsi_clk_source(void)
260{
261 return FLD_GET(dss_read_reg(DSS_CONTROL), 1, 1);
262}
263
264int dss_get_dispc_clk_source(void)
265{
266 return FLD_GET(dss_read_reg(DSS_CONTROL), 0, 0);
267}
268
269/* calculate clock rates using dividers in cinfo */
270int dss_calc_clock_rates(struct dss_clock_info *cinfo)
271{
272 unsigned long prate;
273
274 if (cinfo->fck_div > 16 || cinfo->fck_div == 0)
275 return -EINVAL;
276
277 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
278
279 cinfo->fck = prate / cinfo->fck_div;
280
281 return 0;
282}
283
284int dss_set_clock_div(struct dss_clock_info *cinfo)
285{
286 unsigned long prate;
287 int r;
288
289 if (cpu_is_omap34xx()) {
290 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
291 DSSDBG("dpll4_m4 = %ld\n", prate);
292
293 r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
294 if (r)
295 return r;
296 }
297
298 DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
299
300 return 0;
301}
302
303int dss_get_clock_div(struct dss_clock_info *cinfo)
304{
305 cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK1);
306
307 if (cpu_is_omap34xx()) {
308 unsigned long prate;
309 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
310 cinfo->fck_div = prate / (cinfo->fck / 2);
311 } else {
312 cinfo->fck_div = 0;
313 }
314
315 return 0;
316}
317
318unsigned long dss_get_dpll4_rate(void)
319{
320 if (cpu_is_omap34xx())
321 return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
322 else
323 return 0;
324}
325
326int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
327 struct dss_clock_info *dss_cinfo,
328 struct dispc_clock_info *dispc_cinfo)
329{
330 unsigned long prate;
331 struct dss_clock_info best_dss;
332 struct dispc_clock_info best_dispc;
333
334 unsigned long fck;
335
336 u16 fck_div;
337
338 int match = 0;
339 int min_fck_per_pck;
340
341 prate = dss_get_dpll4_rate();
342
343 fck = dss_clk_get_rate(DSS_CLK_FCK1);
344 if (req_pck == dss.cache_req_pck &&
345 ((cpu_is_omap34xx() && prate == dss.cache_prate) ||
346 dss.cache_dss_cinfo.fck == fck)) {
347 DSSDBG("dispc clock info found from cache.\n");
348 *dss_cinfo = dss.cache_dss_cinfo;
349 *dispc_cinfo = dss.cache_dispc_cinfo;
350 return 0;
351 }
352
353 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
354
355 if (min_fck_per_pck &&
356 req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
357 DSSERR("Requested pixel clock not possible with the current "
358 "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
359 "the constraint off.\n");
360 min_fck_per_pck = 0;
361 }
362
363retry:
364 memset(&best_dss, 0, sizeof(best_dss));
365 memset(&best_dispc, 0, sizeof(best_dispc));
366
367 if (cpu_is_omap24xx()) {
368 struct dispc_clock_info cur_dispc;
369 /* XXX can we change the clock on omap2? */
370 fck = dss_clk_get_rate(DSS_CLK_FCK1);
371 fck_div = 1;
372
373 dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
374 match = 1;
375
376 best_dss.fck = fck;
377 best_dss.fck_div = fck_div;
378
379 best_dispc = cur_dispc;
380
381 goto found;
382 } else if (cpu_is_omap34xx()) {
383 for (fck_div = 16; fck_div > 0; --fck_div) {
384 struct dispc_clock_info cur_dispc;
385
386 fck = prate / fck_div * 2;
387
388 if (fck > DISPC_MAX_FCK)
389 continue;
390
391 if (min_fck_per_pck &&
392 fck < req_pck * min_fck_per_pck)
393 continue;
394
395 match = 1;
396
397 dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
398
399 if (abs(cur_dispc.pck - req_pck) <
400 abs(best_dispc.pck - req_pck)) {
401
402 best_dss.fck = fck;
403 best_dss.fck_div = fck_div;
404
405 best_dispc = cur_dispc;
406
407 if (cur_dispc.pck == req_pck)
408 goto found;
409 }
410 }
411 } else {
412 BUG();
413 }
414
415found:
416 if (!match) {
417 if (min_fck_per_pck) {
418 DSSERR("Could not find suitable clock settings.\n"
419 "Turning FCK/PCK constraint off and"
420 "trying again.\n");
421 min_fck_per_pck = 0;
422 goto retry;
423 }
424
425 DSSERR("Could not find suitable clock settings.\n");
426
427 return -EINVAL;
428 }
429
430 if (dss_cinfo)
431 *dss_cinfo = best_dss;
432 if (dispc_cinfo)
433 *dispc_cinfo = best_dispc;
434
435 dss.cache_req_pck = req_pck;
436 dss.cache_prate = prate;
437 dss.cache_dss_cinfo = best_dss;
438 dss.cache_dispc_cinfo = best_dispc;
439
440 return 0;
441}
442
443
444
445static irqreturn_t dss_irq_handler_omap2(int irq, void *arg)
446{
447 dispc_irq_handler();
448
449 return IRQ_HANDLED;
450}
451
452static irqreturn_t dss_irq_handler_omap3(int irq, void *arg)
453{
454 u32 irqstatus;
455
456 irqstatus = dss_read_reg(DSS_IRQSTATUS);
457
458 if (irqstatus & (1<<0)) /* DISPC_IRQ */
459 dispc_irq_handler();
460#ifdef CONFIG_OMAP2_DSS_DSI
461 if (irqstatus & (1<<1)) /* DSI_IRQ */
462 dsi_irq_handler();
463#endif
464
465 return IRQ_HANDLED;
466}
467
468static int _omap_dss_wait_reset(void)
469{
470 unsigned timeout = 1000;
471
472 while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) {
473 udelay(1);
474 if (!--timeout) {
475 DSSERR("soft reset failed\n");
476 return -ENODEV;
477 }
478 }
479
480 return 0;
481}
482
483static int _omap_dss_reset(void)
484{
485 /* Soft reset */
486 REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1);
487 return _omap_dss_wait_reset();
488}
489
490void dss_set_venc_output(enum omap_dss_venc_type type)
491{
492 int l = 0;
493
494 if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
495 l = 0;
496 else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
497 l = 1;
498 else
499 BUG();
500
501 /* venc out selection. 0 = comp, 1 = svideo */
502 REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
503}
504
505void dss_set_dac_pwrdn_bgz(bool enable)
506{
507 REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
508}
509
510int dss_init(bool skip_init)
511{
512 int r;
513 u32 rev;
514
515 dss.base = ioremap(DSS_BASE, DSS_SZ_REGS);
516 if (!dss.base) {
517 DSSERR("can't ioremap DSS\n");
518 r = -ENOMEM;
519 goto fail0;
520 }
521
522 if (!skip_init) {
523 /* disable LCD and DIGIT output. This seems to fix the synclost
524 * problem that we get, if the bootloader starts the DSS and
525 * the kernel resets it */
526 omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
527
528 /* We need to wait here a bit, otherwise we sometimes start to
529 * get synclost errors, and after that only power cycle will
530 * restore DSS functionality. I have no idea why this happens.
531 * And we have to wait _before_ resetting the DSS, but after
532 * enabling clocks.
533 */
534 msleep(50);
535
536 _omap_dss_reset();
537 }
538
539 /* autoidle */
540 REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
541
542 /* Select DPLL */
543 REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
544
545#ifdef CONFIG_OMAP2_DSS_VENC
546 REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
547 REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
548 REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
549#endif
550
551 r = request_irq(INT_24XX_DSS_IRQ,
552 cpu_is_omap24xx()
553 ? dss_irq_handler_omap2
554 : dss_irq_handler_omap3,
555 0, "OMAP DSS", NULL);
556
557 if (r < 0) {
558 DSSERR("omap2 dss: request_irq failed\n");
559 goto fail1;
560 }
561
562 if (cpu_is_omap34xx()) {
563 dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
564 if (IS_ERR(dss.dpll4_m4_ck)) {
565 DSSERR("Failed to get dpll4_m4_ck\n");
566 r = PTR_ERR(dss.dpll4_m4_ck);
567 goto fail2;
568 }
569 }
570
571 dss_save_context();
572
573 rev = dss_read_reg(DSS_REVISION);
574 printk(KERN_INFO "OMAP DSS rev %d.%d\n",
575 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
576
577 return 0;
578
579fail2:
580 free_irq(INT_24XX_DSS_IRQ, NULL);
581fail1:
582 iounmap(dss.base);
583fail0:
584 return r;
585}
586
587void dss_exit(void)
588{
589 if (cpu_is_omap34xx())
590 clk_put(dss.dpll4_m4_ck);
591
592 free_irq(INT_24XX_DSS_IRQ, NULL);
593
594 iounmap(dss.base);
595}
596
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
new file mode 100644
index 000000000000..8da5ac42151b
--- /dev/null
+++ b/drivers/video/omap2/dss/dss.h
@@ -0,0 +1,370 @@
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#ifdef CONFIG_OMAP2_DSS_DEBUG_SUPPORT
27#define DEBUG
28#endif
29
30#ifdef DEBUG
31extern unsigned int dss_debug;
32#ifdef DSS_SUBSYS_NAME
33#define DSSDBG(format, ...) \
34 if (dss_debug) \
35 printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME ": " format, \
36 ## __VA_ARGS__)
37#else
38#define DSSDBG(format, ...) \
39 if (dss_debug) \
40 printk(KERN_DEBUG "omapdss: " format, ## __VA_ARGS__)
41#endif
42
43#ifdef DSS_SUBSYS_NAME
44#define DSSDBGF(format, ...) \
45 if (dss_debug) \
46 printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME \
47 ": %s(" format ")\n", \
48 __func__, \
49 ## __VA_ARGS__)
50#else
51#define DSSDBGF(format, ...) \
52 if (dss_debug) \
53 printk(KERN_DEBUG "omapdss: " \
54 ": %s(" format ")\n", \
55 __func__, \
56 ## __VA_ARGS__)
57#endif
58
59#else /* DEBUG */
60#define DSSDBG(format, ...)
61#define DSSDBGF(format, ...)
62#endif
63
64
65#ifdef DSS_SUBSYS_NAME
66#define DSSERR(format, ...) \
67 printk(KERN_ERR "omapdss " DSS_SUBSYS_NAME " error: " format, \
68 ## __VA_ARGS__)
69#else
70#define DSSERR(format, ...) \
71 printk(KERN_ERR "omapdss error: " format, ## __VA_ARGS__)
72#endif
73
74#ifdef DSS_SUBSYS_NAME
75#define DSSINFO(format, ...) \
76 printk(KERN_INFO "omapdss " DSS_SUBSYS_NAME ": " format, \
77 ## __VA_ARGS__)
78#else
79#define DSSINFO(format, ...) \
80 printk(KERN_INFO "omapdss: " format, ## __VA_ARGS__)
81#endif
82
83#ifdef DSS_SUBSYS_NAME
84#define DSSWARN(format, ...) \
85 printk(KERN_WARNING "omapdss " DSS_SUBSYS_NAME ": " format, \
86 ## __VA_ARGS__)
87#else
88#define DSSWARN(format, ...) \
89 printk(KERN_WARNING "omapdss: " format, ## __VA_ARGS__)
90#endif
91
92/* OMAP TRM gives bitfields as start:end, where start is the higher bit
93 number. For example 7:0 */
94#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
95#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
96#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
97#define FLD_MOD(orig, val, start, end) \
98 (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
99
100#define DISPC_MAX_FCK 173000000
101
102enum omap_burst_size {
103 OMAP_DSS_BURST_4x32 = 0,
104 OMAP_DSS_BURST_8x32 = 1,
105 OMAP_DSS_BURST_16x32 = 2,
106};
107
108enum omap_parallel_interface_mode {
109 OMAP_DSS_PARALLELMODE_BYPASS, /* MIPI DPI */
110 OMAP_DSS_PARALLELMODE_RFBI, /* MIPI DBI */
111 OMAP_DSS_PARALLELMODE_DSI,
112};
113
114enum dss_clock {
115 DSS_CLK_ICK = 1 << 0,
116 DSS_CLK_FCK1 = 1 << 1,
117 DSS_CLK_FCK2 = 1 << 2,
118 DSS_CLK_54M = 1 << 3,
119 DSS_CLK_96M = 1 << 4,
120};
121
122struct dss_clock_info {
123 /* rates that we get with dividers below */
124 unsigned long fck;
125
126 /* dividers */
127 u16 fck_div;
128};
129
130struct dispc_clock_info {
131 /* rates that we get with dividers below */
132 unsigned long lck;
133 unsigned long pck;
134
135 /* dividers */
136 u16 lck_div;
137 u16 pck_div;
138};
139
140struct dsi_clock_info {
141 /* rates that we get with dividers below */
142 unsigned long fint;
143 unsigned long clkin4ddr;
144 unsigned long clkin;
145 unsigned long dsi1_pll_fclk;
146 unsigned long dsi2_pll_fclk;
147
148 unsigned long lp_clk;
149
150 /* dividers */
151 u16 regn;
152 u16 regm;
153 u16 regm3;
154 u16 regm4;
155
156 u16 lp_clk_div;
157
158 u8 highfreq;
159 bool use_dss2_fck;
160};
161
162struct seq_file;
163struct platform_device;
164
165/* core */
166void dss_clk_enable(enum dss_clock clks);
167void dss_clk_disable(enum dss_clock clks);
168unsigned long dss_clk_get_rate(enum dss_clock clk);
169int dss_need_ctx_restore(void);
170void dss_dump_clocks(struct seq_file *s);
171struct bus_type *dss_get_bus(void);
172
173/* display */
174int dss_suspend_all_devices(void);
175int dss_resume_all_devices(void);
176void dss_disable_all_devices(void);
177
178void dss_init_device(struct platform_device *pdev,
179 struct omap_dss_device *dssdev);
180void dss_uninit_device(struct platform_device *pdev,
181 struct omap_dss_device *dssdev);
182bool dss_use_replication(struct omap_dss_device *dssdev,
183 enum omap_color_mode mode);
184void default_get_overlay_fifo_thresholds(enum omap_plane plane,
185 u32 fifo_size, enum omap_burst_size *burst_size,
186 u32 *fifo_low, u32 *fifo_high);
187
188/* manager */
189int dss_init_overlay_managers(struct platform_device *pdev);
190void dss_uninit_overlay_managers(struct platform_device *pdev);
191int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
192void dss_setup_partial_planes(struct omap_dss_device *dssdev,
193 u16 *x, u16 *y, u16 *w, u16 *h);
194void dss_start_update(struct omap_dss_device *dssdev);
195
196/* overlay */
197void dss_init_overlays(struct platform_device *pdev);
198void dss_uninit_overlays(struct platform_device *pdev);
199int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev);
200void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
201#ifdef L4_EXAMPLE
202void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr);
203#endif
204void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
205
206/* DSS */
207int dss_init(bool skip_init);
208void dss_exit(void);
209
210void dss_save_context(void);
211void dss_restore_context(void);
212
213void dss_dump_regs(struct seq_file *s);
214
215void dss_sdi_init(u8 datapairs);
216int dss_sdi_enable(void);
217void dss_sdi_disable(void);
218
219void dss_select_clk_source(bool dsi, bool dispc);
220int dss_get_dsi_clk_source(void);
221int dss_get_dispc_clk_source(void);
222void dss_set_venc_output(enum omap_dss_venc_type type);
223void dss_set_dac_pwrdn_bgz(bool enable);
224
225unsigned long dss_get_dpll4_rate(void);
226int dss_calc_clock_rates(struct dss_clock_info *cinfo);
227int dss_set_clock_div(struct dss_clock_info *cinfo);
228int dss_get_clock_div(struct dss_clock_info *cinfo);
229int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
230 struct dss_clock_info *dss_cinfo,
231 struct dispc_clock_info *dispc_cinfo);
232
233/* SDI */
234int sdi_init(bool skip_init);
235void sdi_exit(void);
236int sdi_init_display(struct omap_dss_device *display);
237
238/* DSI */
239int dsi_init(struct platform_device *pdev);
240void dsi_exit(void);
241
242void dsi_dump_clocks(struct seq_file *s);
243void dsi_dump_regs(struct seq_file *s);
244
245void dsi_save_context(void);
246void dsi_restore_context(void);
247
248int dsi_init_display(struct omap_dss_device *display);
249void dsi_irq_handler(void);
250unsigned long dsi_get_dsi1_pll_rate(void);
251int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo);
252int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
253 struct dsi_clock_info *cinfo,
254 struct dispc_clock_info *dispc_cinfo);
255int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
256 bool enable_hsdiv);
257void dsi_pll_uninit(void);
258void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
259 u32 fifo_size, enum omap_burst_size *burst_size,
260 u32 *fifo_low, u32 *fifo_high);
261
262/* DPI */
263int dpi_init(void);
264void dpi_exit(void);
265int dpi_init_display(struct omap_dss_device *dssdev);
266
267/* DISPC */
268int dispc_init(void);
269void dispc_exit(void);
270void dispc_dump_clocks(struct seq_file *s);
271void dispc_dump_regs(struct seq_file *s);
272void dispc_irq_handler(void);
273void dispc_fake_vsync_irq(void);
274
275void dispc_save_context(void);
276void dispc_restore_context(void);
277
278void dispc_enable_sidle(void);
279void dispc_disable_sidle(void);
280
281void dispc_lcd_enable_signal_polarity(bool act_high);
282void dispc_lcd_enable_signal(bool enable);
283void dispc_pck_free_enable(bool enable);
284void dispc_enable_fifohandcheck(bool enable);
285
286void dispc_set_lcd_size(u16 width, u16 height);
287void dispc_set_digit_size(u16 width, u16 height);
288u32 dispc_get_plane_fifo_size(enum omap_plane plane);
289void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
290void dispc_enable_fifomerge(bool enable);
291void dispc_set_burst_size(enum omap_plane plane,
292 enum omap_burst_size burst_size);
293
294void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr);
295void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
296void dispc_set_plane_pos(enum omap_plane plane, u16 x, u16 y);
297void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height);
298void dispc_set_channel_out(enum omap_plane plane,
299 enum omap_channel channel_out);
300
301int dispc_setup_plane(enum omap_plane plane,
302 u32 paddr, u16 screen_width,
303 u16 pos_x, u16 pos_y,
304 u16 width, u16 height,
305 u16 out_width, u16 out_height,
306 enum omap_color_mode color_mode,
307 bool ilace,
308 enum omap_dss_rotation_type rotation_type,
309 u8 rotation, bool mirror,
310 u8 global_alpha);
311
312bool dispc_go_busy(enum omap_channel channel);
313void dispc_go(enum omap_channel channel);
314void dispc_enable_lcd_out(bool enable);
315void dispc_enable_digit_out(bool enable);
316int dispc_enable_plane(enum omap_plane plane, bool enable);
317void dispc_enable_replication(enum omap_plane plane, bool enable);
318
319void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode);
320void dispc_set_tft_data_lines(u8 data_lines);
321void dispc_set_lcd_display_type(enum omap_lcd_display_type type);
322void dispc_set_loadmode(enum omap_dss_load_mode mode);
323
324void dispc_set_default_color(enum omap_channel channel, u32 color);
325u32 dispc_get_default_color(enum omap_channel channel);
326void dispc_set_trans_key(enum omap_channel ch,
327 enum omap_dss_trans_key_type type,
328 u32 trans_key);
329void dispc_get_trans_key(enum omap_channel ch,
330 enum omap_dss_trans_key_type *type,
331 u32 *trans_key);
332void dispc_enable_trans_key(enum omap_channel ch, bool enable);
333void dispc_enable_alpha_blending(enum omap_channel ch, bool enable);
334bool dispc_trans_key_enabled(enum omap_channel ch);
335bool dispc_alpha_blending_enabled(enum omap_channel ch);
336
337bool dispc_lcd_timings_ok(struct omap_video_timings *timings);
338void dispc_set_lcd_timings(struct omap_video_timings *timings);
339unsigned long dispc_fclk_rate(void);
340unsigned long dispc_lclk_rate(void);
341unsigned long dispc_pclk_rate(void);
342void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb);
343void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
344 struct dispc_clock_info *cinfo);
345int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
346 struct dispc_clock_info *cinfo);
347int dispc_set_clock_div(struct dispc_clock_info *cinfo);
348int dispc_get_clock_div(struct dispc_clock_info *cinfo);
349
350
351/* VENC */
352int venc_init(struct platform_device *pdev);
353void venc_exit(void);
354void venc_dump_regs(struct seq_file *s);
355int venc_init_display(struct omap_dss_device *display);
356
357/* RFBI */
358int rfbi_init(void);
359void rfbi_exit(void);
360void rfbi_dump_regs(struct seq_file *s);
361
362int rfbi_configure(int rfbi_module, int bpp, int lines);
363void rfbi_enable_rfbi(bool enable);
364void rfbi_transfer_area(u16 width, u16 height,
365 void (callback)(void *data), void *data);
366void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
367unsigned long rfbi_get_max_tx_rate(void);
368int rfbi_init_display(struct omap_dss_device *display);
369
370#endif