aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/omap2
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/omap2')
-rw-r--r--drivers/video/omap2/Kconfig9
-rw-r--r--drivers/video/omap2/Makefile6
-rw-r--r--drivers/video/omap2/displays/Kconfig40
-rw-r--r--drivers/video/omap2/displays/Makefile7
-rw-r--r--drivers/video/omap2/displays/panel-generic.c168
-rw-r--r--drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c159
-rw-r--r--drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c148
-rw-r--r--drivers/video/omap2/displays/panel-taal.c1166
-rw-r--r--drivers/video/omap2/displays/panel-toppoly-tdo35s.c154
-rw-r--r--drivers/video/omap2/displays/panel-tpo-td043mtea1.c529
-rw-r--r--drivers/video/omap2/dss/Kconfig114
-rw-r--r--drivers/video/omap2/dss/Makefile6
-rw-r--r--drivers/video/omap2/dss/core.c976
-rw-r--r--drivers/video/omap2/dss/dispc.c3181
-rw-r--r--drivers/video/omap2/dss/display.c626
-rw-r--r--drivers/video/omap2/dss/dpi.c321
-rw-r--r--drivers/video/omap2/dss/dsi.c3340
-rw-r--r--drivers/video/omap2/dss/dss.c621
-rw-r--r--drivers/video/omap2/dss/dss.h395
-rw-r--r--drivers/video/omap2/dss/manager.c1520
-rw-r--r--drivers/video/omap2/dss/overlay.c681
-rw-r--r--drivers/video/omap2/dss/rfbi.c1056
-rw-r--r--drivers/video/omap2/dss/sdi.c176
-rw-r--r--drivers/video/omap2/dss/venc.c755
-rw-r--r--drivers/video/omap2/omapfb/Kconfig28
-rw-r--r--drivers/video/omap2/omapfb/Makefile2
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c785
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c2287
-rw-r--r--drivers/video/omap2/omapfb/omapfb-sysfs.c507
-rw-r--r--drivers/video/omap2/omapfb/omapfb.h155
-rw-r--r--drivers/video/omap2/vram.c657
-rw-r--r--drivers/video/omap2/vrfb.c315
32 files changed, 20890 insertions, 0 deletions
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig
new file mode 100644
index 000000000000..d877c361abda
--- /dev/null
+++ b/drivers/video/omap2/Kconfig
@@ -0,0 +1,9 @@
1config OMAP2_VRAM
2 bool
3
4config OMAP2_VRFB
5 bool
6
7source "drivers/video/omap2/dss/Kconfig"
8source "drivers/video/omap2/omapfb/Kconfig"
9source "drivers/video/omap2/displays/Kconfig"
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile
new file mode 100644
index 000000000000..d853d05dad31
--- /dev/null
+++ b/drivers/video/omap2/Makefile
@@ -0,0 +1,6 @@
1obj-$(CONFIG_OMAP2_VRAM) += vram.o
2obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
3
4obj-y += dss/
5obj-y += omapfb/
6obj-y += displays/
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
new file mode 100644
index 000000000000..dfb57ee50861
--- /dev/null
+++ b/drivers/video/omap2/displays/Kconfig
@@ -0,0 +1,40 @@
1menu "OMAP2/3 Display Device Drivers"
2 depends on OMAP2_DSS
3
4config PANEL_GENERIC
5 tristate "Generic Panel"
6 help
7 Generic panel driver.
8 Used for DVI output for Beagle and OMAP3 SDP.
9
10config PANEL_SHARP_LS037V7DW01
11 tristate "Sharp LS037V7DW01 LCD Panel"
12 depends on OMAP2_DSS
13 help
14 LCD Panel used in TI's SDP3430 and EVM boards
15
16config PANEL_SHARP_LQ043T1DG01
17 tristate "Sharp LQ043T1DG01 LCD Panel"
18 depends on OMAP2_DSS
19 help
20 LCD Panel used in TI's OMAP3517 EVM boards
21
22config PANEL_TAAL
23 tristate "Taal DSI Panel"
24 depends on OMAP2_DSS_DSI
25 help
26 Taal DSI command mode panel from TPO.
27
28config PANEL_TOPPOLY_TDO35S
29 tristate "Toppoly TDO35S LCD Panel support"
30 depends on OMAP2_DSS
31 help
32 LCD Panel used in CM-T35
33
34config PANEL_TPO_TD043MTEA1
35 tristate "TPO TD043MTEA1 LCD Panel"
36 depends on OMAP2_DSS && I2C
37 help
38 LCD Panel used in OMAP3 Pandora
39
40endmenu
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
new file mode 100644
index 000000000000..e2bb32168dee
--- /dev/null
+++ b/drivers/video/omap2/displays/Makefile
@@ -0,0 +1,7 @@
1obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
2obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
3obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o
4
5obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
6obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o
7obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
diff --git a/drivers/video/omap2/displays/panel-generic.c b/drivers/video/omap2/displays/panel-generic.c
new file mode 100644
index 000000000000..300eff5de1b4
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-generic.c
@@ -0,0 +1,168 @@
1/*
2 * Generic panel support
3 *
4 * Copyright (C) 2008 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#include <linux/module.h>
21#include <linux/delay.h>
22
23#include <plat/display.h>
24
25static struct omap_video_timings generic_panel_timings = {
26 /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
27 .x_res = 640,
28 .y_res = 480,
29 .pixel_clock = 23500,
30 .hfp = 48,
31 .hsw = 32,
32 .hbp = 80,
33 .vfp = 3,
34 .vsw = 4,
35 .vbp = 7,
36};
37
38static int generic_panel_power_on(struct omap_dss_device *dssdev)
39{
40 int r;
41
42 r = omapdss_dpi_display_enable(dssdev);
43 if (r)
44 goto err0;
45
46 if (dssdev->platform_enable) {
47 r = dssdev->platform_enable(dssdev);
48 if (r)
49 goto err1;
50 }
51
52 return 0;
53err1:
54 omapdss_dpi_display_disable(dssdev);
55err0:
56 return r;
57}
58
59static void generic_panel_power_off(struct omap_dss_device *dssdev)
60{
61 if (dssdev->platform_disable)
62 dssdev->platform_disable(dssdev);
63
64 omapdss_dpi_display_disable(dssdev);
65}
66
67static int generic_panel_probe(struct omap_dss_device *dssdev)
68{
69 dssdev->panel.config = OMAP_DSS_LCD_TFT;
70 dssdev->panel.timings = generic_panel_timings;
71
72 return 0;
73}
74
75static void generic_panel_remove(struct omap_dss_device *dssdev)
76{
77}
78
79static int generic_panel_enable(struct omap_dss_device *dssdev)
80{
81 int r = 0;
82
83 r = generic_panel_power_on(dssdev);
84 if (r)
85 return r;
86
87 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
88
89 return 0;
90}
91
92static void generic_panel_disable(struct omap_dss_device *dssdev)
93{
94 generic_panel_power_off(dssdev);
95
96 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
97}
98
99static int generic_panel_suspend(struct omap_dss_device *dssdev)
100{
101 generic_panel_power_off(dssdev);
102 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
103 return 0;
104}
105
106static int generic_panel_resume(struct omap_dss_device *dssdev)
107{
108 int r = 0;
109
110 r = generic_panel_power_on(dssdev);
111 if (r)
112 return r;
113
114 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
115
116 return 0;
117}
118
119static void generic_panel_set_timings(struct omap_dss_device *dssdev,
120 struct omap_video_timings *timings)
121{
122 dpi_set_timings(dssdev, timings);
123}
124
125static void generic_panel_get_timings(struct omap_dss_device *dssdev,
126 struct omap_video_timings *timings)
127{
128 *timings = dssdev->panel.timings;
129}
130
131static int generic_panel_check_timings(struct omap_dss_device *dssdev,
132 struct omap_video_timings *timings)
133{
134 return dpi_check_timings(dssdev, timings);
135}
136
137static struct omap_dss_driver generic_driver = {
138 .probe = generic_panel_probe,
139 .remove = generic_panel_remove,
140
141 .enable = generic_panel_enable,
142 .disable = generic_panel_disable,
143 .suspend = generic_panel_suspend,
144 .resume = generic_panel_resume,
145
146 .set_timings = generic_panel_set_timings,
147 .get_timings = generic_panel_get_timings,
148 .check_timings = generic_panel_check_timings,
149
150 .driver = {
151 .name = "generic_panel",
152 .owner = THIS_MODULE,
153 },
154};
155
156static int __init generic_panel_drv_init(void)
157{
158 return omap_dss_register_driver(&generic_driver);
159}
160
161static void __exit generic_panel_drv_exit(void)
162{
163 omap_dss_unregister_driver(&generic_driver);
164}
165
166module_init(generic_panel_drv_init);
167module_exit(generic_panel_drv_exit);
168MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c b/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c
new file mode 100644
index 000000000000..10267461991c
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c
@@ -0,0 +1,159 @@
1/*
2 * LCD panel driver for Sharp LQ043T1DG01
3 *
4 * Copyright (C) 2009 Texas Instruments Inc
5 * Author: Vaibhav Hiremath <hvaibhav@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/module.h>
21#include <linux/delay.h>
22#include <linux/device.h>
23#include <linux/err.h>
24
25#include <plat/display.h>
26
27static struct omap_video_timings sharp_lq_timings = {
28 .x_res = 480,
29 .y_res = 272,
30
31 .pixel_clock = 9000,
32
33 .hsw = 42,
34 .hfp = 3,
35 .hbp = 2,
36
37 .vsw = 11,
38 .vfp = 3,
39 .vbp = 2,
40};
41
42static int sharp_lq_panel_power_on(struct omap_dss_device *dssdev)
43{
44 int r;
45
46 r = omapdss_dpi_display_enable(dssdev);
47 if (r)
48 goto err0;
49
50 /* wait couple of vsyncs until enabling the LCD */
51 msleep(50);
52
53 if (dssdev->platform_enable) {
54 r = dssdev->platform_enable(dssdev);
55 if (r)
56 goto err1;
57 }
58
59 return 0;
60err1:
61 omapdss_dpi_display_disable(dssdev);
62err0:
63 return r;
64}
65
66static void sharp_lq_panel_power_off(struct omap_dss_device *dssdev)
67{
68 if (dssdev->platform_disable)
69 dssdev->platform_disable(dssdev);
70
71 /* wait at least 5 vsyncs after disabling the LCD */
72 msleep(100);
73
74 omapdss_dpi_display_disable(dssdev);
75}
76
77static int sharp_lq_panel_probe(struct omap_dss_device *dssdev)
78{
79
80 dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
81 OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO;
82 dssdev->panel.acb = 0x0;
83 dssdev->panel.timings = sharp_lq_timings;
84
85 return 0;
86}
87
88static void sharp_lq_panel_remove(struct omap_dss_device *dssdev)
89{
90}
91
92static int sharp_lq_panel_enable(struct omap_dss_device *dssdev)
93{
94 int r = 0;
95
96 r = sharp_lq_panel_power_on(dssdev);
97 if (r)
98 return r;
99
100 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
101
102 return 0;
103}
104
105static void sharp_lq_panel_disable(struct omap_dss_device *dssdev)
106{
107 sharp_lq_panel_power_off(dssdev);
108
109 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
110}
111
112static int sharp_lq_panel_suspend(struct omap_dss_device *dssdev)
113{
114 sharp_lq_panel_power_off(dssdev);
115 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
116 return 0;
117}
118
119static int sharp_lq_panel_resume(struct omap_dss_device *dssdev)
120{
121 int r = 0;
122
123 r = sharp_lq_panel_power_on(dssdev);
124 if (r)
125 return r;
126
127 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
128
129 return 0;
130}
131
132static struct omap_dss_driver sharp_lq_driver = {
133 .probe = sharp_lq_panel_probe,
134 .remove = sharp_lq_panel_remove,
135
136 .enable = sharp_lq_panel_enable,
137 .disable = sharp_lq_panel_disable,
138 .suspend = sharp_lq_panel_suspend,
139 .resume = sharp_lq_panel_resume,
140
141 .driver = {
142 .name = "sharp_lq_panel",
143 .owner = THIS_MODULE,
144 },
145};
146
147static int __init sharp_lq_panel_drv_init(void)
148{
149 return omap_dss_register_driver(&sharp_lq_driver);
150}
151
152static void __exit sharp_lq_panel_drv_exit(void)
153{
154 omap_dss_unregister_driver(&sharp_lq_driver);
155}
156
157module_init(sharp_lq_panel_drv_init);
158module_exit(sharp_lq_panel_drv_exit);
159MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
new file mode 100644
index 000000000000..8d51a5e6341c
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
@@ -0,0 +1,148 @@
1/*
2 * LCD panel driver for Sharp LS037V7DW01
3 *
4 * Copyright (C) 2008 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#include <linux/module.h>
21#include <linux/delay.h>
22#include <linux/device.h>
23#include <linux/err.h>
24
25#include <plat/display.h>
26
27static struct omap_video_timings sharp_ls_timings = {
28 .x_res = 480,
29 .y_res = 640,
30
31 .pixel_clock = 19200,
32
33 .hsw = 2,
34 .hfp = 1,
35 .hbp = 28,
36
37 .vsw = 1,
38 .vfp = 1,
39 .vbp = 1,
40};
41
42static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
43{
44 dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
45 OMAP_DSS_LCD_IHS;
46 dssdev->panel.acb = 0x28;
47 dssdev->panel.timings = sharp_ls_timings;
48
49 return 0;
50}
51
52static void sharp_ls_panel_remove(struct omap_dss_device *dssdev)
53{
54}
55
56static int sharp_ls_power_on(struct omap_dss_device *dssdev)
57{
58 int r = 0;
59
60 r = omapdss_dpi_display_enable(dssdev);
61 if (r)
62 goto err0;
63
64 /* wait couple of vsyncs until enabling the LCD */
65 msleep(50);
66
67 if (dssdev->platform_enable) {
68 r = dssdev->platform_enable(dssdev);
69 if (r)
70 goto err1;
71 }
72
73 return 0;
74err1:
75 omapdss_dpi_display_disable(dssdev);
76err0:
77 return r;
78}
79
80static void sharp_ls_power_off(struct omap_dss_device *dssdev)
81{
82 if (dssdev->platform_disable)
83 dssdev->platform_disable(dssdev);
84
85 /* wait at least 5 vsyncs after disabling the LCD */
86
87 msleep(100);
88
89 omapdss_dpi_display_disable(dssdev);
90}
91
92static int sharp_ls_panel_enable(struct omap_dss_device *dssdev)
93{
94 int r;
95 r = sharp_ls_power_on(dssdev);
96 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
97 return r;
98}
99
100static void sharp_ls_panel_disable(struct omap_dss_device *dssdev)
101{
102 sharp_ls_power_off(dssdev);
103 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
104}
105
106static int sharp_ls_panel_suspend(struct omap_dss_device *dssdev)
107{
108 sharp_ls_power_off(dssdev);
109 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
110 return 0;
111}
112
113static int sharp_ls_panel_resume(struct omap_dss_device *dssdev)
114{
115 int r;
116 r = sharp_ls_power_on(dssdev);
117 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
118 return r;
119}
120
121static struct omap_dss_driver sharp_ls_driver = {
122 .probe = sharp_ls_panel_probe,
123 .remove = sharp_ls_panel_remove,
124
125 .enable = sharp_ls_panel_enable,
126 .disable = sharp_ls_panel_disable,
127 .suspend = sharp_ls_panel_suspend,
128 .resume = sharp_ls_panel_resume,
129
130 .driver = {
131 .name = "sharp_ls_panel",
132 .owner = THIS_MODULE,
133 },
134};
135
136static int __init sharp_ls_panel_drv_init(void)
137{
138 return omap_dss_register_driver(&sharp_ls_driver);
139}
140
141static void __exit sharp_ls_panel_drv_exit(void)
142{
143 omap_dss_unregister_driver(&sharp_ls_driver);
144}
145
146module_init(sharp_ls_panel_drv_init);
147module_exit(sharp_ls_panel_drv_exit);
148MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
new file mode 100644
index 000000000000..4f3988a41082
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -0,0 +1,1166 @@
1/*
2 * Taal DSI command mode panel
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 DEBUG*/
21
22#include <linux/module.h>
23#include <linux/delay.h>
24#include <linux/err.h>
25#include <linux/jiffies.h>
26#include <linux/sched.h>
27#include <linux/backlight.h>
28#include <linux/fb.h>
29#include <linux/interrupt.h>
30#include <linux/gpio.h>
31#include <linux/completion.h>
32#include <linux/workqueue.h>
33#include <linux/slab.h>
34
35#include <plat/display.h>
36
37/* DSI Virtual channel. Hardcoded for now. */
38#define TCH 0
39
40#define DCS_READ_NUM_ERRORS 0x05
41#define DCS_READ_POWER_MODE 0x0a
42#define DCS_READ_MADCTL 0x0b
43#define DCS_READ_PIXEL_FORMAT 0x0c
44#define DCS_RDDSDR 0x0f
45#define DCS_SLEEP_IN 0x10
46#define DCS_SLEEP_OUT 0x11
47#define DCS_DISPLAY_OFF 0x28
48#define DCS_DISPLAY_ON 0x29
49#define DCS_COLUMN_ADDR 0x2a
50#define DCS_PAGE_ADDR 0x2b
51#define DCS_MEMORY_WRITE 0x2c
52#define DCS_TEAR_OFF 0x34
53#define DCS_TEAR_ON 0x35
54#define DCS_MEM_ACC_CTRL 0x36
55#define DCS_PIXEL_FORMAT 0x3a
56#define DCS_BRIGHTNESS 0x51
57#define DCS_CTRL_DISPLAY 0x53
58#define DCS_WRITE_CABC 0x55
59#define DCS_READ_CABC 0x56
60#define DCS_GET_ID1 0xda
61#define DCS_GET_ID2 0xdb
62#define DCS_GET_ID3 0xdc
63
64/* #define TAAL_USE_ESD_CHECK */
65#define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000)
66
67static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
68
69struct taal_data {
70 struct backlight_device *bldev;
71
72 unsigned long hw_guard_end; /* next value of jiffies when we can
73 * issue the next sleep in/out command
74 */
75 unsigned long hw_guard_wait; /* max guard time in jiffies */
76
77 struct omap_dss_device *dssdev;
78
79 bool enabled;
80 u8 rotate;
81 bool mirror;
82
83 bool te_enabled;
84 bool use_ext_te;
85 struct completion te_completion;
86
87 bool use_dsi_bl;
88
89 bool cabc_broken;
90 unsigned cabc_mode;
91
92 bool intro_printed;
93
94 struct workqueue_struct *esd_wq;
95 struct delayed_work esd_work;
96};
97
98static void taal_esd_work(struct work_struct *work);
99
100static void hw_guard_start(struct taal_data *td, int guard_msec)
101{
102 td->hw_guard_wait = msecs_to_jiffies(guard_msec);
103 td->hw_guard_end = jiffies + td->hw_guard_wait;
104}
105
106static void hw_guard_wait(struct taal_data *td)
107{
108 unsigned long wait = td->hw_guard_end - jiffies;
109
110 if ((long)wait > 0 && wait <= td->hw_guard_wait) {
111 set_current_state(TASK_UNINTERRUPTIBLE);
112 schedule_timeout(wait);
113 }
114}
115
116static int taal_dcs_read_1(u8 dcs_cmd, u8 *data)
117{
118 int r;
119 u8 buf[1];
120
121 r = dsi_vc_dcs_read(TCH, dcs_cmd, buf, 1);
122
123 if (r < 0)
124 return r;
125
126 *data = buf[0];
127
128 return 0;
129}
130
131static int taal_dcs_write_0(u8 dcs_cmd)
132{
133 return dsi_vc_dcs_write(TCH, &dcs_cmd, 1);
134}
135
136static int taal_dcs_write_1(u8 dcs_cmd, u8 param)
137{
138 u8 buf[2];
139 buf[0] = dcs_cmd;
140 buf[1] = param;
141 return dsi_vc_dcs_write(TCH, buf, 2);
142}
143
144static int taal_sleep_in(struct taal_data *td)
145
146{
147 u8 cmd;
148 int r;
149
150 hw_guard_wait(td);
151
152 cmd = DCS_SLEEP_IN;
153 r = dsi_vc_dcs_write_nosync(TCH, &cmd, 1);
154 if (r)
155 return r;
156
157 hw_guard_start(td, 120);
158
159 msleep(5);
160
161 return 0;
162}
163
164static int taal_sleep_out(struct taal_data *td)
165{
166 int r;
167
168 hw_guard_wait(td);
169
170 r = taal_dcs_write_0(DCS_SLEEP_OUT);
171 if (r)
172 return r;
173
174 hw_guard_start(td, 120);
175
176 msleep(5);
177
178 return 0;
179}
180
181static int taal_get_id(u8 *id1, u8 *id2, u8 *id3)
182{
183 int r;
184
185 r = taal_dcs_read_1(DCS_GET_ID1, id1);
186 if (r)
187 return r;
188 r = taal_dcs_read_1(DCS_GET_ID2, id2);
189 if (r)
190 return r;
191 r = taal_dcs_read_1(DCS_GET_ID3, id3);
192 if (r)
193 return r;
194
195 return 0;
196}
197
198static int taal_set_addr_mode(u8 rotate, bool mirror)
199{
200 int r;
201 u8 mode;
202 int b5, b6, b7;
203
204 r = taal_dcs_read_1(DCS_READ_MADCTL, &mode);
205 if (r)
206 return r;
207
208 switch (rotate) {
209 default:
210 case 0:
211 b7 = 0;
212 b6 = 0;
213 b5 = 0;
214 break;
215 case 1:
216 b7 = 0;
217 b6 = 1;
218 b5 = 1;
219 break;
220 case 2:
221 b7 = 1;
222 b6 = 1;
223 b5 = 0;
224 break;
225 case 3:
226 b7 = 1;
227 b6 = 0;
228 b5 = 1;
229 break;
230 }
231
232 if (mirror)
233 b6 = !b6;
234
235 mode &= ~((1<<7) | (1<<6) | (1<<5));
236 mode |= (b7 << 7) | (b6 << 6) | (b5 << 5);
237
238 return taal_dcs_write_1(DCS_MEM_ACC_CTRL, mode);
239}
240
241static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h)
242{
243 int r;
244 u16 x1 = x;
245 u16 x2 = x + w - 1;
246 u16 y1 = y;
247 u16 y2 = y + h - 1;
248
249 u8 buf[5];
250 buf[0] = DCS_COLUMN_ADDR;
251 buf[1] = (x1 >> 8) & 0xff;
252 buf[2] = (x1 >> 0) & 0xff;
253 buf[3] = (x2 >> 8) & 0xff;
254 buf[4] = (x2 >> 0) & 0xff;
255
256 r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
257 if (r)
258 return r;
259
260 buf[0] = DCS_PAGE_ADDR;
261 buf[1] = (y1 >> 8) & 0xff;
262 buf[2] = (y1 >> 0) & 0xff;
263 buf[3] = (y2 >> 8) & 0xff;
264 buf[4] = (y2 >> 0) & 0xff;
265
266 r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
267 if (r)
268 return r;
269
270 dsi_vc_send_bta_sync(TCH);
271
272 return r;
273}
274
275static int taal_bl_update_status(struct backlight_device *dev)
276{
277 struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
278 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
279 int r;
280 int level;
281
282 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
283 dev->props.power == FB_BLANK_UNBLANK)
284 level = dev->props.brightness;
285 else
286 level = 0;
287
288 dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
289
290 if (td->use_dsi_bl) {
291 if (td->enabled) {
292 dsi_bus_lock();
293 r = taal_dcs_write_1(DCS_BRIGHTNESS, level);
294 dsi_bus_unlock();
295 if (r)
296 return r;
297 }
298 } else {
299 if (!dssdev->set_backlight)
300 return -EINVAL;
301
302 r = dssdev->set_backlight(dssdev, level);
303 if (r)
304 return r;
305 }
306
307 return 0;
308}
309
310static int taal_bl_get_intensity(struct backlight_device *dev)
311{
312 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
313 dev->props.power == FB_BLANK_UNBLANK)
314 return dev->props.brightness;
315
316 return 0;
317}
318
319static struct backlight_ops taal_bl_ops = {
320 .get_brightness = taal_bl_get_intensity,
321 .update_status = taal_bl_update_status,
322};
323
324static void taal_get_timings(struct omap_dss_device *dssdev,
325 struct omap_video_timings *timings)
326{
327 *timings = dssdev->panel.timings;
328}
329
330static void taal_get_resolution(struct omap_dss_device *dssdev,
331 u16 *xres, u16 *yres)
332{
333 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
334
335 if (td->rotate == 0 || td->rotate == 2) {
336 *xres = dssdev->panel.timings.x_res;
337 *yres = dssdev->panel.timings.y_res;
338 } else {
339 *yres = dssdev->panel.timings.x_res;
340 *xres = dssdev->panel.timings.y_res;
341 }
342}
343
344static irqreturn_t taal_te_isr(int irq, void *data)
345{
346 struct omap_dss_device *dssdev = data;
347 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
348
349 complete_all(&td->te_completion);
350
351 return IRQ_HANDLED;
352}
353
354static ssize_t taal_num_errors_show(struct device *dev,
355 struct device_attribute *attr, char *buf)
356{
357 struct omap_dss_device *dssdev = to_dss_device(dev);
358 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
359 u8 errors;
360 int r;
361
362 if (td->enabled) {
363 dsi_bus_lock();
364 r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors);
365 dsi_bus_unlock();
366 } else {
367 r = -ENODEV;
368 }
369
370 if (r)
371 return r;
372
373 return snprintf(buf, PAGE_SIZE, "%d\n", errors);
374}
375
376static ssize_t taal_hw_revision_show(struct device *dev,
377 struct device_attribute *attr, char *buf)
378{
379 struct omap_dss_device *dssdev = to_dss_device(dev);
380 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
381 u8 id1, id2, id3;
382 int r;
383
384 if (td->enabled) {
385 dsi_bus_lock();
386 r = taal_get_id(&id1, &id2, &id3);
387 dsi_bus_unlock();
388 } else {
389 r = -ENODEV;
390 }
391
392 if (r)
393 return r;
394
395 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3);
396}
397
398static const char *cabc_modes[] = {
399 "off", /* used also always when CABC is not supported */
400 "ui",
401 "still-image",
402 "moving-image",
403};
404
405static ssize_t show_cabc_mode(struct device *dev,
406 struct device_attribute *attr,
407 char *buf)
408{
409 struct omap_dss_device *dssdev = to_dss_device(dev);
410 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
411 const char *mode_str;
412 int mode;
413 int len;
414
415 mode = td->cabc_mode;
416
417 mode_str = "unknown";
418 if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
419 mode_str = cabc_modes[mode];
420 len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
421
422 return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
423}
424
425static ssize_t store_cabc_mode(struct device *dev,
426 struct device_attribute *attr,
427 const char *buf, size_t count)
428{
429 struct omap_dss_device *dssdev = to_dss_device(dev);
430 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
431 int i;
432
433 for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
434 if (sysfs_streq(cabc_modes[i], buf))
435 break;
436 }
437
438 if (i == ARRAY_SIZE(cabc_modes))
439 return -EINVAL;
440
441 if (td->enabled) {
442 dsi_bus_lock();
443 if (!td->cabc_broken)
444 taal_dcs_write_1(DCS_WRITE_CABC, i);
445 dsi_bus_unlock();
446 }
447
448 td->cabc_mode = i;
449
450 return count;
451}
452
453static ssize_t show_cabc_available_modes(struct device *dev,
454 struct device_attribute *attr,
455 char *buf)
456{
457 int len;
458 int i;
459
460 for (i = 0, len = 0;
461 len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
462 len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
463 i ? " " : "", cabc_modes[i],
464 i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
465
466 return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
467}
468
469static DEVICE_ATTR(num_dsi_errors, S_IRUGO, taal_num_errors_show, NULL);
470static DEVICE_ATTR(hw_revision, S_IRUGO, taal_hw_revision_show, NULL);
471static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
472 show_cabc_mode, store_cabc_mode);
473static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
474 show_cabc_available_modes, NULL);
475
476static struct attribute *taal_attrs[] = {
477 &dev_attr_num_dsi_errors.attr,
478 &dev_attr_hw_revision.attr,
479 &dev_attr_cabc_mode.attr,
480 &dev_attr_cabc_available_modes.attr,
481 NULL,
482};
483
484static struct attribute_group taal_attr_group = {
485 .attrs = taal_attrs,
486};
487
488static int taal_probe(struct omap_dss_device *dssdev)
489{
490 struct backlight_properties props;
491 struct taal_data *td;
492 struct backlight_device *bldev;
493 int r;
494
495 const struct omap_video_timings taal_panel_timings = {
496 .x_res = 864,
497 .y_res = 480,
498 };
499
500 dev_dbg(&dssdev->dev, "probe\n");
501
502 dssdev->panel.config = OMAP_DSS_LCD_TFT;
503 dssdev->panel.timings = taal_panel_timings;
504 dssdev->ctrl.pixel_size = 24;
505
506 td = kzalloc(sizeof(*td), GFP_KERNEL);
507 if (!td) {
508 r = -ENOMEM;
509 goto err0;
510 }
511 td->dssdev = dssdev;
512
513 td->esd_wq = create_singlethread_workqueue("taal_esd");
514 if (td->esd_wq == NULL) {
515 dev_err(&dssdev->dev, "can't create ESD workqueue\n");
516 r = -ENOMEM;
517 goto err1;
518 }
519 INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
520
521 dev_set_drvdata(&dssdev->dev, td);
522
523 /* if no platform set_backlight() defined, presume DSI backlight
524 * control */
525 memset(&props, 0, sizeof(struct backlight_properties));
526 if (!dssdev->set_backlight)
527 td->use_dsi_bl = true;
528
529 if (td->use_dsi_bl)
530 props.max_brightness = 255;
531 else
532 props.max_brightness = 127;
533 bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
534 &taal_bl_ops, &props);
535 if (IS_ERR(bldev)) {
536 r = PTR_ERR(bldev);
537 goto err2;
538 }
539
540 td->bldev = bldev;
541
542 bldev->props.fb_blank = FB_BLANK_UNBLANK;
543 bldev->props.power = FB_BLANK_UNBLANK;
544 if (td->use_dsi_bl)
545 bldev->props.brightness = 255;
546 else
547 bldev->props.brightness = 127;
548
549 taal_bl_update_status(bldev);
550
551 if (dssdev->phy.dsi.ext_te) {
552 int gpio = dssdev->phy.dsi.ext_te_gpio;
553
554 r = gpio_request(gpio, "taal irq");
555 if (r) {
556 dev_err(&dssdev->dev, "GPIO request failed\n");
557 goto err3;
558 }
559
560 gpio_direction_input(gpio);
561
562 r = request_irq(gpio_to_irq(gpio), taal_te_isr,
563 IRQF_DISABLED | IRQF_TRIGGER_RISING,
564 "taal vsync", dssdev);
565
566 if (r) {
567 dev_err(&dssdev->dev, "IRQ request failed\n");
568 gpio_free(gpio);
569 goto err3;
570 }
571
572 init_completion(&td->te_completion);
573
574 td->use_ext_te = true;
575 }
576
577 r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group);
578 if (r) {
579 dev_err(&dssdev->dev, "failed to create sysfs files\n");
580 goto err4;
581 }
582
583 return 0;
584err4:
585 if (td->use_ext_te) {
586 int gpio = dssdev->phy.dsi.ext_te_gpio;
587 free_irq(gpio_to_irq(gpio), dssdev);
588 gpio_free(gpio);
589 }
590err3:
591 backlight_device_unregister(bldev);
592err2:
593 cancel_delayed_work_sync(&td->esd_work);
594 destroy_workqueue(td->esd_wq);
595err1:
596 kfree(td);
597err0:
598 return r;
599}
600
601static void taal_remove(struct omap_dss_device *dssdev)
602{
603 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
604 struct backlight_device *bldev;
605
606 dev_dbg(&dssdev->dev, "remove\n");
607
608 sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group);
609
610 if (td->use_ext_te) {
611 int gpio = dssdev->phy.dsi.ext_te_gpio;
612 free_irq(gpio_to_irq(gpio), dssdev);
613 gpio_free(gpio);
614 }
615
616 bldev = td->bldev;
617 bldev->props.power = FB_BLANK_POWERDOWN;
618 taal_bl_update_status(bldev);
619 backlight_device_unregister(bldev);
620
621 cancel_delayed_work_sync(&td->esd_work);
622 destroy_workqueue(td->esd_wq);
623
624 kfree(td);
625}
626
627static int taal_power_on(struct omap_dss_device *dssdev)
628{
629 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
630 u8 id1, id2, id3;
631 int r;
632
633 if (dssdev->platform_enable) {
634 r = dssdev->platform_enable(dssdev);
635 if (r)
636 return r;
637 }
638
639 /* it seems we have to wait a bit until taal is ready */
640 msleep(5);
641
642 dsi_bus_lock();
643
644 r = omapdss_dsi_display_enable(dssdev);
645 if (r) {
646 dev_err(&dssdev->dev, "failed to enable DSI\n");
647 goto err0;
648 }
649
650 omapdss_dsi_vc_enable_hs(TCH, false);
651
652 r = taal_sleep_out(td);
653 if (r)
654 goto err;
655
656 r = taal_get_id(&id1, &id2, &id3);
657 if (r)
658 goto err;
659
660 /* on early revisions CABC is broken */
661 if (id2 == 0x00 || id2 == 0xff || id2 == 0x81)
662 td->cabc_broken = true;
663
664 taal_dcs_write_1(DCS_BRIGHTNESS, 0xff);
665 taal_dcs_write_1(DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */
666
667 taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
668
669 taal_set_addr_mode(td->rotate, td->mirror);
670 if (!td->cabc_broken)
671 taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode);
672
673 taal_dcs_write_0(DCS_DISPLAY_ON);
674
675 r = _taal_enable_te(dssdev, td->te_enabled);
676 if (r)
677 goto err;
678
679#ifdef TAAL_USE_ESD_CHECK
680 queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
681#endif
682
683 td->enabled = 1;
684
685 if (!td->intro_printed) {
686 dev_info(&dssdev->dev, "revision %02x.%02x.%02x\n",
687 id1, id2, id3);
688 if (td->cabc_broken)
689 dev_info(&dssdev->dev,
690 "old Taal version, CABC disabled\n");
691 td->intro_printed = true;
692 }
693
694 omapdss_dsi_vc_enable_hs(TCH, true);
695
696 dsi_bus_unlock();
697
698 return 0;
699err:
700 dsi_bus_unlock();
701
702 omapdss_dsi_display_disable(dssdev);
703err0:
704 if (dssdev->platform_disable)
705 dssdev->platform_disable(dssdev);
706
707 return r;
708}
709
710static void taal_power_off(struct omap_dss_device *dssdev)
711{
712 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
713
714 dsi_bus_lock();
715
716 cancel_delayed_work(&td->esd_work);
717
718 taal_dcs_write_0(DCS_DISPLAY_OFF);
719 taal_sleep_in(td);
720
721 /* wait a bit so that the message goes through */
722 msleep(10);
723
724 omapdss_dsi_display_disable(dssdev);
725
726 if (dssdev->platform_disable)
727 dssdev->platform_disable(dssdev);
728
729 td->enabled = 0;
730
731 dsi_bus_unlock();
732}
733
734static int taal_enable(struct omap_dss_device *dssdev)
735{
736 int r;
737 dev_dbg(&dssdev->dev, "enable\n");
738
739 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
740 return -EINVAL;
741
742 r = taal_power_on(dssdev);
743 if (r)
744 return r;
745
746 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
747
748 return r;
749}
750
751static void taal_disable(struct omap_dss_device *dssdev)
752{
753 dev_dbg(&dssdev->dev, "disable\n");
754
755 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
756 taal_power_off(dssdev);
757
758 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
759}
760
761static int taal_suspend(struct omap_dss_device *dssdev)
762{
763 dev_dbg(&dssdev->dev, "suspend\n");
764
765 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
766 return -EINVAL;
767
768 taal_power_off(dssdev);
769 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
770
771 return 0;
772}
773
774static int taal_resume(struct omap_dss_device *dssdev)
775{
776 int r;
777 dev_dbg(&dssdev->dev, "resume\n");
778
779 if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
780 return -EINVAL;
781
782 r = taal_power_on(dssdev);
783 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
784 return r;
785}
786
787static void taal_framedone_cb(int err, void *data)
788{
789 struct omap_dss_device *dssdev = data;
790 dev_dbg(&dssdev->dev, "framedone, err %d\n", err);
791 dsi_bus_unlock();
792}
793
794static int taal_update(struct omap_dss_device *dssdev,
795 u16 x, u16 y, u16 w, u16 h)
796{
797 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
798 int r;
799
800 dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
801
802 dsi_bus_lock();
803
804 if (!td->enabled) {
805 r = 0;
806 goto err;
807 }
808
809 r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h);
810 if (r)
811 goto err;
812
813 r = taal_set_update_window(x, y, w, h);
814 if (r)
815 goto err;
816
817 r = omap_dsi_update(dssdev, TCH, x, y, w, h,
818 taal_framedone_cb, dssdev);
819 if (r)
820 goto err;
821
822 /* note: no bus_unlock here. unlock is in framedone_cb */
823 return 0;
824err:
825 dsi_bus_unlock();
826 return r;
827}
828
829static int taal_sync(struct omap_dss_device *dssdev)
830{
831 dev_dbg(&dssdev->dev, "sync\n");
832
833 dsi_bus_lock();
834 dsi_bus_unlock();
835
836 dev_dbg(&dssdev->dev, "sync done\n");
837
838 return 0;
839}
840
841static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
842{
843 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
844 int r;
845
846 td->te_enabled = enable;
847
848 if (enable)
849 r = taal_dcs_write_1(DCS_TEAR_ON, 0);
850 else
851 r = taal_dcs_write_0(DCS_TEAR_OFF);
852
853 omapdss_dsi_enable_te(dssdev, enable);
854
855 /* XXX for some reason, DSI TE breaks if we don't wait here.
856 * Panel bug? Needs more studying */
857 msleep(100);
858
859 return r;
860}
861
862static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
863{
864 int r;
865
866 dsi_bus_lock();
867
868 r = _taal_enable_te(dssdev, enable);
869
870 dsi_bus_unlock();
871
872 return r;
873}
874
875static int taal_get_te(struct omap_dss_device *dssdev)
876{
877 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
878 return td->te_enabled;
879}
880
881static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
882{
883 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
884 int r;
885
886 dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
887
888 dsi_bus_lock();
889
890 if (td->enabled) {
891 r = taal_set_addr_mode(rotate, td->mirror);
892 if (r)
893 goto err;
894 }
895
896 td->rotate = rotate;
897
898 dsi_bus_unlock();
899 return 0;
900err:
901 dsi_bus_unlock();
902 return r;
903}
904
905static u8 taal_get_rotate(struct omap_dss_device *dssdev)
906{
907 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
908 return td->rotate;
909}
910
911static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
912{
913 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
914 int r;
915
916 dev_dbg(&dssdev->dev, "mirror %d\n", enable);
917
918 dsi_bus_lock();
919 if (td->enabled) {
920 r = taal_set_addr_mode(td->rotate, enable);
921 if (r)
922 goto err;
923 }
924
925 td->mirror = enable;
926
927 dsi_bus_unlock();
928 return 0;
929err:
930 dsi_bus_unlock();
931 return r;
932}
933
934static bool taal_get_mirror(struct omap_dss_device *dssdev)
935{
936 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
937 return td->mirror;
938}
939
940static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
941{
942 u8 id1, id2, id3;
943 int r;
944
945 dsi_bus_lock();
946
947 r = taal_dcs_read_1(DCS_GET_ID1, &id1);
948 if (r)
949 goto err;
950 r = taal_dcs_read_1(DCS_GET_ID2, &id2);
951 if (r)
952 goto err;
953 r = taal_dcs_read_1(DCS_GET_ID3, &id3);
954 if (r)
955 goto err;
956
957 dsi_bus_unlock();
958 return 0;
959err:
960 dsi_bus_unlock();
961 return r;
962}
963
964static int taal_memory_read(struct omap_dss_device *dssdev,
965 void *buf, size_t size,
966 u16 x, u16 y, u16 w, u16 h)
967{
968 int r;
969 int first = 1;
970 int plen;
971 unsigned buf_used = 0;
972 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
973
974 if (!td->enabled)
975 return -ENODEV;
976
977 if (size < w * h * 3)
978 return -ENOMEM;
979
980 size = min(w * h * 3,
981 dssdev->panel.timings.x_res *
982 dssdev->panel.timings.y_res * 3);
983
984 dsi_bus_lock();
985
986 /* plen 1 or 2 goes into short packet. until checksum error is fixed,
987 * use short packets. plen 32 works, but bigger packets seem to cause
988 * an error. */
989 if (size % 2)
990 plen = 1;
991 else
992 plen = 2;
993
994 taal_set_update_window(x, y, w, h);
995
996 r = dsi_vc_set_max_rx_packet_size(TCH, plen);
997 if (r)
998 goto err0;
999
1000 while (buf_used < size) {
1001 u8 dcs_cmd = first ? 0x2e : 0x3e;
1002 first = 0;
1003
1004 r = dsi_vc_dcs_read(TCH, dcs_cmd,
1005 buf + buf_used, size - buf_used);
1006
1007 if (r < 0) {
1008 dev_err(&dssdev->dev, "read error\n");
1009 goto err;
1010 }
1011
1012 buf_used += r;
1013
1014 if (r < plen) {
1015 dev_err(&dssdev->dev, "short read\n");
1016 break;
1017 }
1018
1019 if (signal_pending(current)) {
1020 dev_err(&dssdev->dev, "signal pending, "
1021 "aborting memory read\n");
1022 r = -ERESTARTSYS;
1023 goto err;
1024 }
1025 }
1026
1027 r = buf_used;
1028
1029err:
1030 dsi_vc_set_max_rx_packet_size(TCH, 1);
1031err0:
1032 dsi_bus_unlock();
1033 return r;
1034}
1035
1036static void taal_esd_work(struct work_struct *work)
1037{
1038 struct taal_data *td = container_of(work, struct taal_data,
1039 esd_work.work);
1040 struct omap_dss_device *dssdev = td->dssdev;
1041 u8 state1, state2;
1042 int r;
1043
1044 if (!td->enabled)
1045 return;
1046
1047 dsi_bus_lock();
1048
1049 r = taal_dcs_read_1(DCS_RDDSDR, &state1);
1050 if (r) {
1051 dev_err(&dssdev->dev, "failed to read Taal status\n");
1052 goto err;
1053 }
1054
1055 /* Run self diagnostics */
1056 r = taal_sleep_out(td);
1057 if (r) {
1058 dev_err(&dssdev->dev, "failed to run Taal self-diagnostics\n");
1059 goto err;
1060 }
1061
1062 r = taal_dcs_read_1(DCS_RDDSDR, &state2);
1063 if (r) {
1064 dev_err(&dssdev->dev, "failed to read Taal status\n");
1065 goto err;
1066 }
1067
1068 /* Each sleep out command will trigger a self diagnostic and flip
1069 * Bit6 if the test passes.
1070 */
1071 if (!((state1 ^ state2) & (1 << 6))) {
1072 dev_err(&dssdev->dev, "LCD self diagnostics failed\n");
1073 goto err;
1074 }
1075 /* Self-diagnostics result is also shown on TE GPIO line. We need
1076 * to re-enable TE after self diagnostics */
1077 if (td->use_ext_te && td->te_enabled) {
1078 r = taal_dcs_write_1(DCS_TEAR_ON, 0);
1079 if (r)
1080 goto err;
1081 }
1082
1083 dsi_bus_unlock();
1084
1085 queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
1086
1087 return;
1088err:
1089 dev_err(&dssdev->dev, "performing LCD reset\n");
1090
1091 taal_disable(dssdev);
1092 taal_enable(dssdev);
1093
1094 dsi_bus_unlock();
1095
1096 queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
1097}
1098
1099static int taal_set_update_mode(struct omap_dss_device *dssdev,
1100 enum omap_dss_update_mode mode)
1101{
1102 if (mode != OMAP_DSS_UPDATE_MANUAL)
1103 return -EINVAL;
1104 return 0;
1105}
1106
1107static enum omap_dss_update_mode taal_get_update_mode(
1108 struct omap_dss_device *dssdev)
1109{
1110 return OMAP_DSS_UPDATE_MANUAL;
1111}
1112
1113static struct omap_dss_driver taal_driver = {
1114 .probe = taal_probe,
1115 .remove = taal_remove,
1116
1117 .enable = taal_enable,
1118 .disable = taal_disable,
1119 .suspend = taal_suspend,
1120 .resume = taal_resume,
1121
1122 .set_update_mode = taal_set_update_mode,
1123 .get_update_mode = taal_get_update_mode,
1124
1125 .update = taal_update,
1126 .sync = taal_sync,
1127
1128 .get_resolution = taal_get_resolution,
1129 .get_recommended_bpp = omapdss_default_get_recommended_bpp,
1130
1131 .enable_te = taal_enable_te,
1132 .get_te = taal_get_te,
1133
1134 .set_rotate = taal_rotate,
1135 .get_rotate = taal_get_rotate,
1136 .set_mirror = taal_mirror,
1137 .get_mirror = taal_get_mirror,
1138 .run_test = taal_run_test,
1139 .memory_read = taal_memory_read,
1140
1141 .get_timings = taal_get_timings,
1142
1143 .driver = {
1144 .name = "taal",
1145 .owner = THIS_MODULE,
1146 },
1147};
1148
1149static int __init taal_init(void)
1150{
1151 omap_dss_register_driver(&taal_driver);
1152
1153 return 0;
1154}
1155
1156static void __exit taal_exit(void)
1157{
1158 omap_dss_unregister_driver(&taal_driver);
1159}
1160
1161module_init(taal_init);
1162module_exit(taal_exit);
1163
1164MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
1165MODULE_DESCRIPTION("Taal Driver");
1166MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c
new file mode 100644
index 000000000000..fa434ca6e4b7
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c
@@ -0,0 +1,154 @@
1/*
2 * LCD panel driver for Toppoly TDO35S
3 *
4 * Copyright (C) 2009 CompuLab, Ltd.
5 * Author: Mike Rapoport <mike@compulab.co.il>
6 *
7 * Based on generic panel support
8 * Copyright (C) 2008 Nokia Corporation
9 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 as published by
13 * the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 *
20 * You should have received a copy of the GNU General Public License along with
21 * this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24#include <linux/module.h>
25#include <linux/delay.h>
26
27#include <plat/display.h>
28
29static struct omap_video_timings toppoly_tdo_panel_timings = {
30 /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
31 .x_res = 480,
32 .y_res = 640,
33
34 .pixel_clock = 26000,
35
36 .hfp = 104,
37 .hsw = 8,
38 .hbp = 8,
39
40 .vfp = 4,
41 .vsw = 2,
42 .vbp = 2,
43};
44
45static int toppoly_tdo_panel_power_on(struct omap_dss_device *dssdev)
46{
47 int r;
48
49 r = omapdss_dpi_display_enable(dssdev);
50 if (r)
51 goto err0;
52
53 if (dssdev->platform_enable) {
54 r = dssdev->platform_enable(dssdev);
55 if (r)
56 goto err1;
57 }
58
59 return 0;
60err1:
61 omapdss_dpi_display_disable(dssdev);
62err0:
63 return r;
64}
65
66static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev)
67{
68 if (dssdev->platform_disable)
69 dssdev->platform_disable(dssdev);
70
71 omapdss_dpi_display_disable(dssdev);
72}
73
74static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev)
75{
76 dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
77 OMAP_DSS_LCD_IHS;
78 dssdev->panel.timings = toppoly_tdo_panel_timings;
79
80 return 0;
81}
82
83static void toppoly_tdo_panel_remove(struct omap_dss_device *dssdev)
84{
85}
86
87static int toppoly_tdo_panel_enable(struct omap_dss_device *dssdev)
88{
89 int r = 0;
90
91 r = toppoly_tdo_panel_power_on(dssdev);
92 if (r)
93 return r;
94
95 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
96
97 return 0;
98}
99
100static void toppoly_tdo_panel_disable(struct omap_dss_device *dssdev)
101{
102 toppoly_tdo_panel_power_off(dssdev);
103
104 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
105}
106
107static int toppoly_tdo_panel_suspend(struct omap_dss_device *dssdev)
108{
109 toppoly_tdo_panel_power_off(dssdev);
110 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
111 return 0;
112}
113
114static int toppoly_tdo_panel_resume(struct omap_dss_device *dssdev)
115{
116 int r = 0;
117
118 r = toppoly_tdo_panel_power_on(dssdev);
119 if (r)
120 return r;
121
122 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
123
124 return 0;
125}
126
127static struct omap_dss_driver generic_driver = {
128 .probe = toppoly_tdo_panel_probe,
129 .remove = toppoly_tdo_panel_remove,
130
131 .enable = toppoly_tdo_panel_enable,
132 .disable = toppoly_tdo_panel_disable,
133 .suspend = toppoly_tdo_panel_suspend,
134 .resume = toppoly_tdo_panel_resume,
135
136 .driver = {
137 .name = "toppoly_tdo35s_panel",
138 .owner = THIS_MODULE,
139 },
140};
141
142static int __init toppoly_tdo_panel_drv_init(void)
143{
144 return omap_dss_register_driver(&generic_driver);
145}
146
147static void __exit toppoly_tdo_panel_drv_exit(void)
148{
149 omap_dss_unregister_driver(&generic_driver);
150}
151
152module_init(toppoly_tdo_panel_drv_init);
153module_exit(toppoly_tdo_panel_drv_exit);
154MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
new file mode 100644
index 000000000000..e866e76b13d0
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -0,0 +1,529 @@
1/*
2 * LCD panel driver for TPO TD043MTEA1
3 *
4 * Author: Gražvydas Ignotas <notasas@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/module.h>
13#include <linux/delay.h>
14#include <linux/spi/spi.h>
15#include <linux/regulator/consumer.h>
16#include <linux/gpio.h>
17#include <linux/err.h>
18#include <linux/slab.h>
19
20#include <plat/display.h>
21
22#define TPO_R02_MODE(x) ((x) & 7)
23#define TPO_R02_MODE_800x480 7
24#define TPO_R02_NCLK_RISING BIT(3)
25#define TPO_R02_HSYNC_HIGH BIT(4)
26#define TPO_R02_VSYNC_HIGH BIT(5)
27
28#define TPO_R03_NSTANDBY BIT(0)
29#define TPO_R03_EN_CP_CLK BIT(1)
30#define TPO_R03_EN_VGL_PUMP BIT(2)
31#define TPO_R03_EN_PWM BIT(3)
32#define TPO_R03_DRIVING_CAP_100 BIT(4)
33#define TPO_R03_EN_PRE_CHARGE BIT(6)
34#define TPO_R03_SOFTWARE_CTL BIT(7)
35
36#define TPO_R04_NFLIP_H BIT(0)
37#define TPO_R04_NFLIP_V BIT(1)
38#define TPO_R04_CP_CLK_FREQ_1H BIT(2)
39#define TPO_R04_VGL_FREQ_1H BIT(4)
40
41#define TPO_R03_VAL_NORMAL (TPO_R03_NSTANDBY | TPO_R03_EN_CP_CLK | \
42 TPO_R03_EN_VGL_PUMP | TPO_R03_EN_PWM | \
43 TPO_R03_DRIVING_CAP_100 | TPO_R03_EN_PRE_CHARGE | \
44 TPO_R03_SOFTWARE_CTL)
45
46#define TPO_R03_VAL_STANDBY (TPO_R03_DRIVING_CAP_100 | \
47 TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL)
48
49static const u16 tpo_td043_def_gamma[12] = {
50 106, 200, 289, 375, 460, 543, 625, 705, 785, 864, 942, 1020
51};
52
53struct tpo_td043_device {
54 struct spi_device *spi;
55 struct regulator *vcc_reg;
56 u16 gamma[12];
57 u32 mode;
58 u32 hmirror:1;
59 u32 vmirror:1;
60};
61
62static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
63{
64 struct spi_message m;
65 struct spi_transfer xfer;
66 u16 w;
67 int r;
68
69 spi_message_init(&m);
70
71 memset(&xfer, 0, sizeof(xfer));
72
73 w = ((u16)addr << 10) | (1 << 8) | data;
74 xfer.tx_buf = &w;
75 xfer.bits_per_word = 16;
76 xfer.len = 2;
77 spi_message_add_tail(&xfer, &m);
78
79 r = spi_sync(spi, &m);
80 if (r < 0)
81 dev_warn(&spi->dev, "failed to write to LCD reg (%d)\n", r);
82 return r;
83}
84
85static void tpo_td043_write_gamma(struct spi_device *spi, u16 gamma[12])
86{
87 u8 i, val;
88
89 /* gamma bits [9:8] */
90 for (val = i = 0; i < 4; i++)
91 val |= (gamma[i] & 0x300) >> ((i + 1) * 2);
92 tpo_td043_write(spi, 0x11, val);
93
94 for (val = i = 0; i < 4; i++)
95 val |= (gamma[i+4] & 0x300) >> ((i + 1) * 2);
96 tpo_td043_write(spi, 0x12, val);
97
98 for (val = i = 0; i < 4; i++)
99 val |= (gamma[i+8] & 0x300) >> ((i + 1) * 2);
100 tpo_td043_write(spi, 0x13, val);
101
102 /* gamma bits [7:0] */
103 for (val = i = 0; i < 12; i++)
104 tpo_td043_write(spi, 0x14 + i, gamma[i] & 0xff);
105}
106
107static int tpo_td043_write_mirror(struct spi_device *spi, bool h, bool v)
108{
109 u8 reg4 = TPO_R04_NFLIP_H | TPO_R04_NFLIP_V | \
110 TPO_R04_CP_CLK_FREQ_1H | TPO_R04_VGL_FREQ_1H;
111 if (h)
112 reg4 &= ~TPO_R04_NFLIP_H;
113 if (v)
114 reg4 &= ~TPO_R04_NFLIP_V;
115
116 return tpo_td043_write(spi, 4, reg4);
117}
118
119static int tpo_td043_set_hmirror(struct omap_dss_device *dssdev, bool enable)
120{
121 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
122
123 tpo_td043->hmirror = enable;
124 return tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror,
125 tpo_td043->vmirror);
126}
127
128static bool tpo_td043_get_hmirror(struct omap_dss_device *dssdev)
129{
130 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
131
132 return tpo_td043->hmirror;
133}
134
135static ssize_t tpo_td043_vmirror_show(struct device *dev,
136 struct device_attribute *attr, char *buf)
137{
138 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
139
140 return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->vmirror);
141}
142
143static ssize_t tpo_td043_vmirror_store(struct device *dev,
144 struct device_attribute *attr, const char *buf, size_t count)
145{
146 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
147 long val;
148 int ret;
149
150 ret = strict_strtol(buf, 0, &val);
151 if (ret < 0)
152 return ret;
153
154 ret = tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, val);
155 if (ret < 0)
156 return ret;
157
158 tpo_td043->vmirror = val;
159
160 return count;
161}
162
163static ssize_t tpo_td043_mode_show(struct device *dev,
164 struct device_attribute *attr, char *buf)
165{
166 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
167
168 return snprintf(buf, PAGE_SIZE, "%d\n", tpo_td043->mode);
169}
170
171static ssize_t tpo_td043_mode_store(struct device *dev,
172 struct device_attribute *attr, const char *buf, size_t count)
173{
174 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
175 long val;
176 int ret;
177
178 ret = strict_strtol(buf, 0, &val);
179 if (ret != 0 || val & ~7)
180 return -EINVAL;
181
182 tpo_td043->mode = val;
183
184 val |= TPO_R02_NCLK_RISING;
185 tpo_td043_write(tpo_td043->spi, 2, val);
186
187 return count;
188}
189
190static ssize_t tpo_td043_gamma_show(struct device *dev,
191 struct device_attribute *attr, char *buf)
192{
193 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
194 ssize_t len = 0;
195 int ret;
196 int i;
197
198 for (i = 0; i < ARRAY_SIZE(tpo_td043->gamma); i++) {
199 ret = snprintf(buf + len, PAGE_SIZE - len, "%u ",
200 tpo_td043->gamma[i]);
201 if (ret < 0)
202 return ret;
203 len += ret;
204 }
205 buf[len - 1] = '\n';
206
207 return len;
208}
209
210static ssize_t tpo_td043_gamma_store(struct device *dev,
211 struct device_attribute *attr, const char *buf, size_t count)
212{
213 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
214 unsigned int g[12];
215 int ret;
216 int i;
217
218 ret = sscanf(buf, "%u %u %u %u %u %u %u %u %u %u %u %u",
219 &g[0], &g[1], &g[2], &g[3], &g[4], &g[5],
220 &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
221
222 if (ret != 12)
223 return -EINVAL;
224
225 for (i = 0; i < 12; i++)
226 tpo_td043->gamma[i] = g[i];
227
228 tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma);
229
230 return count;
231}
232
233static DEVICE_ATTR(vmirror, S_IRUGO | S_IWUSR,
234 tpo_td043_vmirror_show, tpo_td043_vmirror_store);
235static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
236 tpo_td043_mode_show, tpo_td043_mode_store);
237static DEVICE_ATTR(gamma, S_IRUGO | S_IWUSR,
238 tpo_td043_gamma_show, tpo_td043_gamma_store);
239
240static struct attribute *tpo_td043_attrs[] = {
241 &dev_attr_vmirror.attr,
242 &dev_attr_mode.attr,
243 &dev_attr_gamma.attr,
244 NULL,
245};
246
247static struct attribute_group tpo_td043_attr_group = {
248 .attrs = tpo_td043_attrs,
249};
250
251static const struct omap_video_timings tpo_td043_timings = {
252 .x_res = 800,
253 .y_res = 480,
254
255 .pixel_clock = 36000,
256
257 .hsw = 1,
258 .hfp = 68,
259 .hbp = 214,
260
261 .vsw = 1,
262 .vfp = 39,
263 .vbp = 34,
264};
265
266static int tpo_td043_power_on(struct omap_dss_device *dssdev)
267{
268 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
269 int nreset_gpio = dssdev->reset_gpio;
270 int r;
271
272 r = omapdss_dpi_display_enable(dssdev);
273 if (r)
274 goto err0;
275
276 if (dssdev->platform_enable) {
277 r = dssdev->platform_enable(dssdev);
278 if (r)
279 goto err1;
280 }
281
282 regulator_enable(tpo_td043->vcc_reg);
283
284 /* wait for power up */
285 msleep(160);
286
287 if (gpio_is_valid(nreset_gpio))
288 gpio_set_value(nreset_gpio, 1);
289
290 tpo_td043_write(tpo_td043->spi, 2,
291 TPO_R02_MODE(tpo_td043->mode) | TPO_R02_NCLK_RISING);
292 tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_NORMAL);
293 tpo_td043_write(tpo_td043->spi, 0x20, 0xf0);
294 tpo_td043_write(tpo_td043->spi, 0x21, 0xf0);
295 tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror,
296 tpo_td043->vmirror);
297 tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma);
298
299 return 0;
300err1:
301 omapdss_dpi_display_disable(dssdev);
302err0:
303 return r;
304}
305
306static void tpo_td043_power_off(struct omap_dss_device *dssdev)
307{
308 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
309 int nreset_gpio = dssdev->reset_gpio;
310
311 tpo_td043_write(tpo_td043->spi, 3,
312 TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM);
313
314 if (gpio_is_valid(nreset_gpio))
315 gpio_set_value(nreset_gpio, 0);
316
317 /* wait for at least 2 vsyncs before cutting off power */
318 msleep(50);
319
320 tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_STANDBY);
321
322 regulator_disable(tpo_td043->vcc_reg);
323
324 if (dssdev->platform_disable)
325 dssdev->platform_disable(dssdev);
326
327 omapdss_dpi_display_disable(dssdev);
328}
329
330static int tpo_td043_enable(struct omap_dss_device *dssdev)
331{
332 int ret;
333
334 dev_dbg(&dssdev->dev, "enable\n");
335
336 ret = tpo_td043_power_on(dssdev);
337 if (ret)
338 return ret;
339
340 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
341
342 return 0;
343}
344
345static void tpo_td043_disable(struct omap_dss_device *dssdev)
346{
347 dev_dbg(&dssdev->dev, "disable\n");
348
349 tpo_td043_power_off(dssdev);
350
351 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
352}
353
354static int tpo_td043_suspend(struct omap_dss_device *dssdev)
355{
356 tpo_td043_power_off(dssdev);
357 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
358 return 0;
359}
360
361static int tpo_td043_resume(struct omap_dss_device *dssdev)
362{
363 int r = 0;
364
365 r = tpo_td043_power_on(dssdev);
366 if (r)
367 return r;
368
369 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
370
371 return 0;
372}
373
374static int tpo_td043_probe(struct omap_dss_device *dssdev)
375{
376 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
377 int nreset_gpio = dssdev->reset_gpio;
378 int ret = 0;
379
380 dev_dbg(&dssdev->dev, "probe\n");
381
382 if (tpo_td043 == NULL) {
383 dev_err(&dssdev->dev, "missing tpo_td043_device\n");
384 return -ENODEV;
385 }
386
387 dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IHS |
388 OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IPC;
389 dssdev->panel.timings = tpo_td043_timings;
390 dssdev->ctrl.pixel_size = 24;
391
392 tpo_td043->mode = TPO_R02_MODE_800x480;
393 memcpy(tpo_td043->gamma, tpo_td043_def_gamma, sizeof(tpo_td043->gamma));
394
395 tpo_td043->vcc_reg = regulator_get(&dssdev->dev, "vcc");
396 if (IS_ERR(tpo_td043->vcc_reg)) {
397 dev_err(&dssdev->dev, "failed to get LCD VCC regulator\n");
398 ret = PTR_ERR(tpo_td043->vcc_reg);
399 goto fail_regulator;
400 }
401
402 if (gpio_is_valid(nreset_gpio)) {
403 ret = gpio_request(nreset_gpio, "lcd reset");
404 if (ret < 0) {
405 dev_err(&dssdev->dev, "couldn't request reset GPIO\n");
406 goto fail_gpio_req;
407 }
408
409 ret = gpio_direction_output(nreset_gpio, 0);
410 if (ret < 0) {
411 dev_err(&dssdev->dev, "couldn't set GPIO direction\n");
412 goto fail_gpio_direction;
413 }
414 }
415
416 ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
417 if (ret)
418 dev_warn(&dssdev->dev, "failed to create sysfs files\n");
419
420 return 0;
421
422fail_gpio_direction:
423 gpio_free(nreset_gpio);
424fail_gpio_req:
425 regulator_put(tpo_td043->vcc_reg);
426fail_regulator:
427 kfree(tpo_td043);
428 return ret;
429}
430
431static void tpo_td043_remove(struct omap_dss_device *dssdev)
432{
433 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
434 int nreset_gpio = dssdev->reset_gpio;
435
436 dev_dbg(&dssdev->dev, "remove\n");
437
438 sysfs_remove_group(&dssdev->dev.kobj, &tpo_td043_attr_group);
439 regulator_put(tpo_td043->vcc_reg);
440 if (gpio_is_valid(nreset_gpio))
441 gpio_free(nreset_gpio);
442}
443
444static struct omap_dss_driver tpo_td043_driver = {
445 .probe = tpo_td043_probe,
446 .remove = tpo_td043_remove,
447
448 .enable = tpo_td043_enable,
449 .disable = tpo_td043_disable,
450 .suspend = tpo_td043_suspend,
451 .resume = tpo_td043_resume,
452 .set_mirror = tpo_td043_set_hmirror,
453 .get_mirror = tpo_td043_get_hmirror,
454
455 .driver = {
456 .name = "tpo_td043mtea1_panel",
457 .owner = THIS_MODULE,
458 },
459};
460
461static int tpo_td043_spi_probe(struct spi_device *spi)
462{
463 struct omap_dss_device *dssdev = spi->dev.platform_data;
464 struct tpo_td043_device *tpo_td043;
465 int ret;
466
467 if (dssdev == NULL) {
468 dev_err(&spi->dev, "missing dssdev\n");
469 return -ENODEV;
470 }
471
472 spi->bits_per_word = 16;
473 spi->mode = SPI_MODE_0;
474
475 ret = spi_setup(spi);
476 if (ret < 0) {
477 dev_err(&spi->dev, "spi_setup failed: %d\n", ret);
478 return ret;
479 }
480
481 tpo_td043 = kzalloc(sizeof(*tpo_td043), GFP_KERNEL);
482 if (tpo_td043 == NULL)
483 return -ENOMEM;
484
485 tpo_td043->spi = spi;
486 dev_set_drvdata(&spi->dev, tpo_td043);
487 dev_set_drvdata(&dssdev->dev, tpo_td043);
488
489 omap_dss_register_driver(&tpo_td043_driver);
490
491 return 0;
492}
493
494static int __devexit tpo_td043_spi_remove(struct spi_device *spi)
495{
496 struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&spi->dev);
497
498 omap_dss_unregister_driver(&tpo_td043_driver);
499 kfree(tpo_td043);
500
501 return 0;
502}
503
504static struct spi_driver tpo_td043_spi_driver = {
505 .driver = {
506 .name = "tpo_td043mtea1_panel_spi",
507 .bus = &spi_bus_type,
508 .owner = THIS_MODULE,
509 },
510 .probe = tpo_td043_spi_probe,
511 .remove = __devexit_p(tpo_td043_spi_remove),
512};
513
514static int __init tpo_td043_init(void)
515{
516 return spi_register_driver(&tpo_td043_spi_driver);
517}
518
519static void __exit tpo_td043_exit(void)
520{
521 spi_unregister_driver(&tpo_td043_spi_driver);
522}
523
524module_init(tpo_td043_init);
525module_exit(tpo_td043_exit);
526
527MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");
528MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver");
529MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
new file mode 100644
index 000000000000..87afb81b2c44
--- /dev/null
+++ b/drivers/video/omap2/dss/Kconfig
@@ -0,0 +1,114 @@
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_COLLECT_IRQ_STATS
29 bool "Collect DSS IRQ statistics"
30 depends on OMAP2_DSS_DEBUG_SUPPORT
31 default n
32 help
33 Collect DSS IRQ statistics, printable via debugfs.
34
35 The statistics can be found from
36 <debugfs>/omapdss/dispc_irq for DISPC interrupts, and
37 <debugfs>/omapdss/dsi_irq for DSI interrupts.
38
39config OMAP2_DSS_RFBI
40 bool "RFBI support"
41 default n
42 help
43 MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas
44 Instrument's terminology).
45
46 DBI is a bus between the host processor and a peripheral,
47 such as a display or a framebuffer chip.
48
49 See http://www.mipi.org/ for DBI spesifications.
50
51config OMAP2_DSS_VENC
52 bool "VENC support"
53 default y
54 help
55 OMAP Video Encoder support for S-Video and composite TV-out.
56
57config OMAP2_DSS_SDI
58 bool "SDI support"
59 depends on ARCH_OMAP3
60 default n
61 help
62 SDI (Serial Display Interface) support.
63
64 SDI is a high speed one-way display serial bus between the host
65 processor and a display.
66
67config OMAP2_DSS_DSI
68 bool "DSI support"
69 depends on ARCH_OMAP3
70 default n
71 help
72 MIPI DSI (Display Serial Interface) support.
73
74 DSI is a high speed half-duplex serial interface between the host
75 processor and a peripheral, such as a display or a framebuffer chip.
76
77 See http://www.mipi.org/ for DSI spesifications.
78
79config OMAP2_DSS_USE_DSI_PLL
80 bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
81 default n
82 depends on OMAP2_DSS_DSI
83 help
84 Use DSI PLL to generate pixel clock. Currently only for DPI output.
85 DSI PLL can be used to generate higher and more precise pixel clocks.
86
87config OMAP2_DSS_FAKE_VSYNC
88 bool "Fake VSYNC irq from manual update displays"
89 default n
90 help
91 If this is selected, DSI will generate a fake DISPC VSYNC interrupt
92 when DSI has sent a frame. This is only needed with DSI or RFBI
93 displays using manual mode, and you want VSYNC to, for example,
94 time animation.
95
96config OMAP2_DSS_MIN_FCK_PER_PCK
97 int "Minimum FCK/PCK ratio (for scaling)"
98 range 0 32
99 default 0
100 help
101 This can be used to adjust the minimum FCK/PCK ratio.
102
103 With this you can make sure that DISPC FCK is at least
104 n x PCK. Video plane scaling requires higher FCK than
105 normally.
106
107 If this is set to 0, there's no extra constraint on the
108 DISPC FCK. However, the FCK will at minimum be
109 2xPCK (if active matrix) or 3xPCK (if passive matrix).
110
111 Max FCK is 173MHz, so this doesn't work if your PCK
112 is very high.
113
114endif
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..7ebe50b335ed
--- /dev/null
+++ b/drivers/video/omap2/dss/core.c
@@ -0,0 +1,976 @@
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
36#include <plat/display.h>
37#include <plat/clock.h>
38
39#include "dss.h"
40
41static struct {
42 struct platform_device *pdev;
43 int ctx_id;
44
45 struct clk *dss_ick;
46 struct clk *dss1_fck;
47 struct clk *dss2_fck;
48 struct clk *dss_54m_fck;
49 struct clk *dss_96m_fck;
50 unsigned num_clks_enabled;
51
52 struct regulator *vdds_dsi_reg;
53 struct regulator *vdds_sdi_reg;
54 struct regulator *vdda_dac_reg;
55} core;
56
57static void dss_clk_enable_all_no_ctx(void);
58static void dss_clk_disable_all_no_ctx(void);
59static void dss_clk_enable_no_ctx(enum dss_clock clks);
60static void dss_clk_disable_no_ctx(enum dss_clock clks);
61
62static char *def_disp_name;
63module_param_named(def_disp, def_disp_name, charp, 0);
64MODULE_PARM_DESC(def_disp_name, "default display name");
65
66#ifdef DEBUG
67unsigned int dss_debug;
68module_param_named(debug, dss_debug, bool, 0644);
69#endif
70
71/* CONTEXT */
72static int dss_get_ctx_id(void)
73{
74 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
75 int r;
76
77 if (!pdata->get_last_off_on_transaction_id)
78 return 0;
79 r = pdata->get_last_off_on_transaction_id(&core.pdev->dev);
80 if (r < 0) {
81 dev_err(&core.pdev->dev, "getting transaction ID failed, "
82 "will force context restore\n");
83 r = -1;
84 }
85 return r;
86}
87
88int dss_need_ctx_restore(void)
89{
90 int id = dss_get_ctx_id();
91
92 if (id < 0 || id != core.ctx_id) {
93 DSSDBG("ctx id %d -> id %d\n",
94 core.ctx_id, id);
95 core.ctx_id = id;
96 return 1;
97 } else {
98 return 0;
99 }
100}
101
102static void save_all_ctx(void)
103{
104 DSSDBG("save context\n");
105
106 dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
107
108 dss_save_context();
109 dispc_save_context();
110#ifdef CONFIG_OMAP2_DSS_DSI
111 dsi_save_context();
112#endif
113
114 dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
115}
116
117static void restore_all_ctx(void)
118{
119 DSSDBG("restore context\n");
120
121 dss_clk_enable_all_no_ctx();
122
123 dss_restore_context();
124 dispc_restore_context();
125#ifdef CONFIG_OMAP2_DSS_DSI
126 dsi_restore_context();
127#endif
128
129 dss_clk_disable_all_no_ctx();
130}
131
132#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
133/* CLOCKS */
134static void core_dump_clocks(struct seq_file *s)
135{
136 int i;
137 struct clk *clocks[5] = {
138 core.dss_ick,
139 core.dss1_fck,
140 core.dss2_fck,
141 core.dss_54m_fck,
142 core.dss_96m_fck
143 };
144
145 seq_printf(s, "- CORE -\n");
146
147 seq_printf(s, "internal clk count\t\t%u\n", core.num_clks_enabled);
148
149 for (i = 0; i < 5; i++) {
150 if (!clocks[i])
151 continue;
152 seq_printf(s, "%-15s\t%lu\t%d\n",
153 clocks[i]->name,
154 clk_get_rate(clocks[i]),
155 clocks[i]->usecount);
156 }
157}
158#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */
159
160static int dss_get_clock(struct clk **clock, const char *clk_name)
161{
162 struct clk *clk;
163
164 clk = clk_get(&core.pdev->dev, clk_name);
165
166 if (IS_ERR(clk)) {
167 DSSERR("can't get clock %s", clk_name);
168 return PTR_ERR(clk);
169 }
170
171 *clock = clk;
172
173 DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
174
175 return 0;
176}
177
178static int dss_get_clocks(void)
179{
180 int r;
181
182 core.dss_ick = NULL;
183 core.dss1_fck = NULL;
184 core.dss2_fck = NULL;
185 core.dss_54m_fck = NULL;
186 core.dss_96m_fck = NULL;
187
188 r = dss_get_clock(&core.dss_ick, "ick");
189 if (r)
190 goto err;
191
192 r = dss_get_clock(&core.dss1_fck, "dss1_fck");
193 if (r)
194 goto err;
195
196 r = dss_get_clock(&core.dss2_fck, "dss2_fck");
197 if (r)
198 goto err;
199
200 r = dss_get_clock(&core.dss_54m_fck, "tv_fck");
201 if (r)
202 goto err;
203
204 r = dss_get_clock(&core.dss_96m_fck, "video_fck");
205 if (r)
206 goto err;
207
208 return 0;
209
210err:
211 if (core.dss_ick)
212 clk_put(core.dss_ick);
213 if (core.dss1_fck)
214 clk_put(core.dss1_fck);
215 if (core.dss2_fck)
216 clk_put(core.dss2_fck);
217 if (core.dss_54m_fck)
218 clk_put(core.dss_54m_fck);
219 if (core.dss_96m_fck)
220 clk_put(core.dss_96m_fck);
221
222 return r;
223}
224
225static void dss_put_clocks(void)
226{
227 if (core.dss_96m_fck)
228 clk_put(core.dss_96m_fck);
229 clk_put(core.dss_54m_fck);
230 clk_put(core.dss1_fck);
231 clk_put(core.dss2_fck);
232 clk_put(core.dss_ick);
233}
234
235unsigned long dss_clk_get_rate(enum dss_clock clk)
236{
237 switch (clk) {
238 case DSS_CLK_ICK:
239 return clk_get_rate(core.dss_ick);
240 case DSS_CLK_FCK1:
241 return clk_get_rate(core.dss1_fck);
242 case DSS_CLK_FCK2:
243 return clk_get_rate(core.dss2_fck);
244 case DSS_CLK_54M:
245 return clk_get_rate(core.dss_54m_fck);
246 case DSS_CLK_96M:
247 return clk_get_rate(core.dss_96m_fck);
248 }
249
250 BUG();
251 return 0;
252}
253
254static unsigned count_clk_bits(enum dss_clock clks)
255{
256 unsigned num_clks = 0;
257
258 if (clks & DSS_CLK_ICK)
259 ++num_clks;
260 if (clks & DSS_CLK_FCK1)
261 ++num_clks;
262 if (clks & DSS_CLK_FCK2)
263 ++num_clks;
264 if (clks & DSS_CLK_54M)
265 ++num_clks;
266 if (clks & DSS_CLK_96M)
267 ++num_clks;
268
269 return num_clks;
270}
271
272static void dss_clk_enable_no_ctx(enum dss_clock clks)
273{
274 unsigned num_clks = count_clk_bits(clks);
275
276 if (clks & DSS_CLK_ICK)
277 clk_enable(core.dss_ick);
278 if (clks & DSS_CLK_FCK1)
279 clk_enable(core.dss1_fck);
280 if (clks & DSS_CLK_FCK2)
281 clk_enable(core.dss2_fck);
282 if (clks & DSS_CLK_54M)
283 clk_enable(core.dss_54m_fck);
284 if (clks & DSS_CLK_96M)
285 clk_enable(core.dss_96m_fck);
286
287 core.num_clks_enabled += num_clks;
288}
289
290void dss_clk_enable(enum dss_clock clks)
291{
292 bool check_ctx = core.num_clks_enabled == 0;
293
294 dss_clk_enable_no_ctx(clks);
295
296 if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore())
297 restore_all_ctx();
298}
299
300static void dss_clk_disable_no_ctx(enum dss_clock clks)
301{
302 unsigned num_clks = count_clk_bits(clks);
303
304 if (clks & DSS_CLK_ICK)
305 clk_disable(core.dss_ick);
306 if (clks & DSS_CLK_FCK1)
307 clk_disable(core.dss1_fck);
308 if (clks & DSS_CLK_FCK2)
309 clk_disable(core.dss2_fck);
310 if (clks & DSS_CLK_54M)
311 clk_disable(core.dss_54m_fck);
312 if (clks & DSS_CLK_96M)
313 clk_disable(core.dss_96m_fck);
314
315 core.num_clks_enabled -= num_clks;
316}
317
318void dss_clk_disable(enum dss_clock clks)
319{
320 if (cpu_is_omap34xx()) {
321 unsigned num_clks = count_clk_bits(clks);
322
323 BUG_ON(core.num_clks_enabled < num_clks);
324
325 if (core.num_clks_enabled == num_clks)
326 save_all_ctx();
327 }
328
329 dss_clk_disable_no_ctx(clks);
330}
331
332static void dss_clk_enable_all_no_ctx(void)
333{
334 enum dss_clock clks;
335
336 clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
337 if (cpu_is_omap34xx())
338 clks |= DSS_CLK_96M;
339 dss_clk_enable_no_ctx(clks);
340}
341
342static void dss_clk_disable_all_no_ctx(void)
343{
344 enum dss_clock clks;
345
346 clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
347 if (cpu_is_omap34xx())
348 clks |= DSS_CLK_96M;
349 dss_clk_disable_no_ctx(clks);
350}
351
352static void dss_clk_disable_all(void)
353{
354 enum dss_clock clks;
355
356 clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
357 if (cpu_is_omap34xx())
358 clks |= DSS_CLK_96M;
359 dss_clk_disable(clks);
360}
361
362/* REGULATORS */
363
364struct regulator *dss_get_vdds_dsi(void)
365{
366 struct regulator *reg;
367
368 if (core.vdds_dsi_reg != NULL)
369 return core.vdds_dsi_reg;
370
371 reg = regulator_get(&core.pdev->dev, "vdds_dsi");
372 if (!IS_ERR(reg))
373 core.vdds_dsi_reg = reg;
374
375 return reg;
376}
377
378struct regulator *dss_get_vdds_sdi(void)
379{
380 struct regulator *reg;
381
382 if (core.vdds_sdi_reg != NULL)
383 return core.vdds_sdi_reg;
384
385 reg = regulator_get(&core.pdev->dev, "vdds_sdi");
386 if (!IS_ERR(reg))
387 core.vdds_sdi_reg = reg;
388
389 return reg;
390}
391
392struct regulator *dss_get_vdda_dac(void)
393{
394 struct regulator *reg;
395
396 if (core.vdda_dac_reg != NULL)
397 return core.vdda_dac_reg;
398
399 reg = regulator_get(&core.pdev->dev, "vdda_dac");
400 if (!IS_ERR(reg))
401 core.vdda_dac_reg = reg;
402
403 return reg;
404}
405
406/* DEBUGFS */
407#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
408static void dss_debug_dump_clocks(struct seq_file *s)
409{
410 core_dump_clocks(s);
411 dss_dump_clocks(s);
412 dispc_dump_clocks(s);
413#ifdef CONFIG_OMAP2_DSS_DSI
414 dsi_dump_clocks(s);
415#endif
416}
417
418static int dss_debug_show(struct seq_file *s, void *unused)
419{
420 void (*func)(struct seq_file *) = s->private;
421 func(s);
422 return 0;
423}
424
425static int dss_debug_open(struct inode *inode, struct file *file)
426{
427 return single_open(file, dss_debug_show, inode->i_private);
428}
429
430static const struct file_operations dss_debug_fops = {
431 .open = dss_debug_open,
432 .read = seq_read,
433 .llseek = seq_lseek,
434 .release = single_release,
435};
436
437static struct dentry *dss_debugfs_dir;
438
439static int dss_initialize_debugfs(void)
440{
441 dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
442 if (IS_ERR(dss_debugfs_dir)) {
443 int err = PTR_ERR(dss_debugfs_dir);
444 dss_debugfs_dir = NULL;
445 return err;
446 }
447
448 debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
449 &dss_debug_dump_clocks, &dss_debug_fops);
450
451#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
452 debugfs_create_file("dispc_irq", S_IRUGO, dss_debugfs_dir,
453 &dispc_dump_irqs, &dss_debug_fops);
454#endif
455
456#if defined(CONFIG_OMAP2_DSS_DSI) && defined(CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS)
457 debugfs_create_file("dsi_irq", S_IRUGO, dss_debugfs_dir,
458 &dsi_dump_irqs, &dss_debug_fops);
459#endif
460
461 debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir,
462 &dss_dump_regs, &dss_debug_fops);
463 debugfs_create_file("dispc", S_IRUGO, dss_debugfs_dir,
464 &dispc_dump_regs, &dss_debug_fops);
465#ifdef CONFIG_OMAP2_DSS_RFBI
466 debugfs_create_file("rfbi", S_IRUGO, dss_debugfs_dir,
467 &rfbi_dump_regs, &dss_debug_fops);
468#endif
469#ifdef CONFIG_OMAP2_DSS_DSI
470 debugfs_create_file("dsi", S_IRUGO, dss_debugfs_dir,
471 &dsi_dump_regs, &dss_debug_fops);
472#endif
473#ifdef CONFIG_OMAP2_DSS_VENC
474 debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
475 &venc_dump_regs, &dss_debug_fops);
476#endif
477 return 0;
478}
479
480static void dss_uninitialize_debugfs(void)
481{
482 if (dss_debugfs_dir)
483 debugfs_remove_recursive(dss_debugfs_dir);
484}
485#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
486
487/* PLATFORM DEVICE */
488static int omap_dss_probe(struct platform_device *pdev)
489{
490 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
491 int skip_init = 0;
492 int r;
493 int i;
494
495 core.pdev = pdev;
496
497 dss_init_overlay_managers(pdev);
498 dss_init_overlays(pdev);
499
500 r = dss_get_clocks();
501 if (r)
502 goto fail0;
503
504 dss_clk_enable_all_no_ctx();
505
506 core.ctx_id = dss_get_ctx_id();
507 DSSDBG("initial ctx id %u\n", core.ctx_id);
508
509#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
510 /* DISPC_CONTROL */
511 if (omap_readl(0x48050440) & 1) /* LCD enabled? */
512 skip_init = 1;
513#endif
514
515 r = dss_init(skip_init);
516 if (r) {
517 DSSERR("Failed to initialize DSS\n");
518 goto fail0;
519 }
520
521#ifdef CONFIG_OMAP2_DSS_RFBI
522 r = rfbi_init();
523 if (r) {
524 DSSERR("Failed to initialize rfbi\n");
525 goto fail0;
526 }
527#endif
528
529 r = dpi_init(pdev);
530 if (r) {
531 DSSERR("Failed to initialize dpi\n");
532 goto fail0;
533 }
534
535 r = dispc_init();
536 if (r) {
537 DSSERR("Failed to initialize dispc\n");
538 goto fail0;
539 }
540#ifdef CONFIG_OMAP2_DSS_VENC
541 r = venc_init(pdev);
542 if (r) {
543 DSSERR("Failed to initialize venc\n");
544 goto fail0;
545 }
546#endif
547 if (cpu_is_omap34xx()) {
548#ifdef CONFIG_OMAP2_DSS_SDI
549 r = sdi_init(skip_init);
550 if (r) {
551 DSSERR("Failed to initialize SDI\n");
552 goto fail0;
553 }
554#endif
555#ifdef CONFIG_OMAP2_DSS_DSI
556 r = dsi_init(pdev);
557 if (r) {
558 DSSERR("Failed to initialize DSI\n");
559 goto fail0;
560 }
561#endif
562 }
563
564#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
565 r = dss_initialize_debugfs();
566 if (r)
567 goto fail0;
568#endif
569
570 for (i = 0; i < pdata->num_devices; ++i) {
571 struct omap_dss_device *dssdev = pdata->devices[i];
572
573 r = omap_dss_register_device(dssdev);
574 if (r)
575 DSSERR("device reg failed %d\n", i);
576
577 if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0)
578 pdata->default_device = dssdev;
579 }
580
581 dss_clk_disable_all();
582
583 return 0;
584
585 /* XXX fail correctly */
586fail0:
587 return r;
588}
589
590static int omap_dss_remove(struct platform_device *pdev)
591{
592 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
593 int i;
594 int c;
595
596#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
597 dss_uninitialize_debugfs();
598#endif
599
600#ifdef CONFIG_OMAP2_DSS_VENC
601 venc_exit();
602#endif
603 dispc_exit();
604 dpi_exit();
605#ifdef CONFIG_OMAP2_DSS_RFBI
606 rfbi_exit();
607#endif
608 if (cpu_is_omap34xx()) {
609#ifdef CONFIG_OMAP2_DSS_DSI
610 dsi_exit();
611#endif
612#ifdef CONFIG_OMAP2_DSS_SDI
613 sdi_exit();
614#endif
615 }
616
617 dss_exit();
618
619 /* these should be removed at some point */
620 c = core.dss_ick->usecount;
621 if (c > 0) {
622 DSSERR("warning: dss_ick usecount %d, disabling\n", c);
623 while (c-- > 0)
624 clk_disable(core.dss_ick);
625 }
626
627 c = core.dss1_fck->usecount;
628 if (c > 0) {
629 DSSERR("warning: dss1_fck usecount %d, disabling\n", c);
630 while (c-- > 0)
631 clk_disable(core.dss1_fck);
632 }
633
634 c = core.dss2_fck->usecount;
635 if (c > 0) {
636 DSSERR("warning: dss2_fck usecount %d, disabling\n", c);
637 while (c-- > 0)
638 clk_disable(core.dss2_fck);
639 }
640
641 c = core.dss_54m_fck->usecount;
642 if (c > 0) {
643 DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c);
644 while (c-- > 0)
645 clk_disable(core.dss_54m_fck);
646 }
647
648 if (core.dss_96m_fck) {
649 c = core.dss_96m_fck->usecount;
650 if (c > 0) {
651 DSSERR("warning: dss_96m_fck usecount %d, disabling\n",
652 c);
653 while (c-- > 0)
654 clk_disable(core.dss_96m_fck);
655 }
656 }
657
658 dss_put_clocks();
659
660 dss_uninit_overlays(pdev);
661 dss_uninit_overlay_managers(pdev);
662
663 for (i = 0; i < pdata->num_devices; ++i)
664 omap_dss_unregister_device(pdata->devices[i]);
665
666 return 0;
667}
668
669static void omap_dss_shutdown(struct platform_device *pdev)
670{
671 DSSDBG("shutdown\n");
672 dss_disable_all_devices();
673}
674
675static int omap_dss_suspend(struct platform_device *pdev, pm_message_t state)
676{
677 DSSDBG("suspend %d\n", state.event);
678
679 return dss_suspend_all_devices();
680}
681
682static int omap_dss_resume(struct platform_device *pdev)
683{
684 DSSDBG("resume\n");
685
686 return dss_resume_all_devices();
687}
688
689static struct platform_driver omap_dss_driver = {
690 .probe = omap_dss_probe,
691 .remove = omap_dss_remove,
692 .shutdown = omap_dss_shutdown,
693 .suspend = omap_dss_suspend,
694 .resume = omap_dss_resume,
695 .driver = {
696 .name = "omapdss",
697 .owner = THIS_MODULE,
698 },
699};
700
701/* BUS */
702static int dss_bus_match(struct device *dev, struct device_driver *driver)
703{
704 struct omap_dss_device *dssdev = to_dss_device(dev);
705
706 DSSDBG("bus_match. dev %s/%s, drv %s\n",
707 dev_name(dev), dssdev->driver_name, driver->name);
708
709 return strcmp(dssdev->driver_name, driver->name) == 0;
710}
711
712static ssize_t device_name_show(struct device *dev,
713 struct device_attribute *attr, char *buf)
714{
715 struct omap_dss_device *dssdev = to_dss_device(dev);
716 return snprintf(buf, PAGE_SIZE, "%s\n",
717 dssdev->name ?
718 dssdev->name : "");
719}
720
721static struct device_attribute default_dev_attrs[] = {
722 __ATTR(name, S_IRUGO, device_name_show, NULL),
723 __ATTR_NULL,
724};
725
726static ssize_t driver_name_show(struct device_driver *drv, char *buf)
727{
728 struct omap_dss_driver *dssdrv = to_dss_driver(drv);
729 return snprintf(buf, PAGE_SIZE, "%s\n",
730 dssdrv->driver.name ?
731 dssdrv->driver.name : "");
732}
733static struct driver_attribute default_drv_attrs[] = {
734 __ATTR(name, S_IRUGO, driver_name_show, NULL),
735 __ATTR_NULL,
736};
737
738static struct bus_type dss_bus_type = {
739 .name = "omapdss",
740 .match = dss_bus_match,
741 .dev_attrs = default_dev_attrs,
742 .drv_attrs = default_drv_attrs,
743};
744
745static void dss_bus_release(struct device *dev)
746{
747 DSSDBG("bus_release\n");
748}
749
750static struct device dss_bus = {
751 .release = dss_bus_release,
752};
753
754struct bus_type *dss_get_bus(void)
755{
756 return &dss_bus_type;
757}
758
759/* DRIVER */
760static int dss_driver_probe(struct device *dev)
761{
762 int r;
763 struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
764 struct omap_dss_device *dssdev = to_dss_device(dev);
765 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
766 bool force;
767
768 DSSDBG("driver_probe: dev %s/%s, drv %s\n",
769 dev_name(dev), dssdev->driver_name,
770 dssdrv->driver.name);
771
772 dss_init_device(core.pdev, dssdev);
773
774 force = pdata->default_device == dssdev;
775 dss_recheck_connections(dssdev, force);
776
777 r = dssdrv->probe(dssdev);
778
779 if (r) {
780 DSSERR("driver probe failed: %d\n", r);
781 dss_uninit_device(core.pdev, dssdev);
782 return r;
783 }
784
785 DSSDBG("probe done for device %s\n", dev_name(dev));
786
787 dssdev->driver = dssdrv;
788
789 return 0;
790}
791
792static int dss_driver_remove(struct device *dev)
793{
794 struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
795 struct omap_dss_device *dssdev = to_dss_device(dev);
796
797 DSSDBG("driver_remove: dev %s/%s\n", dev_name(dev),
798 dssdev->driver_name);
799
800 dssdrv->remove(dssdev);
801
802 dss_uninit_device(core.pdev, dssdev);
803
804 dssdev->driver = NULL;
805
806 return 0;
807}
808
809int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
810{
811 dssdriver->driver.bus = &dss_bus_type;
812 dssdriver->driver.probe = dss_driver_probe;
813 dssdriver->driver.remove = dss_driver_remove;
814
815 if (dssdriver->get_resolution == NULL)
816 dssdriver->get_resolution = omapdss_default_get_resolution;
817 if (dssdriver->get_recommended_bpp == NULL)
818 dssdriver->get_recommended_bpp =
819 omapdss_default_get_recommended_bpp;
820
821 return driver_register(&dssdriver->driver);
822}
823EXPORT_SYMBOL(omap_dss_register_driver);
824
825void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver)
826{
827 driver_unregister(&dssdriver->driver);
828}
829EXPORT_SYMBOL(omap_dss_unregister_driver);
830
831/* DEVICE */
832static void reset_device(struct device *dev, int check)
833{
834 u8 *dev_p = (u8 *)dev;
835 u8 *dev_end = dev_p + sizeof(*dev);
836 void *saved_pdata;
837
838 saved_pdata = dev->platform_data;
839 if (check) {
840 /*
841 * Check if there is any other setting than platform_data
842 * in struct device; warn that these will be reset by our
843 * init.
844 */
845 dev->platform_data = NULL;
846 while (dev_p < dev_end) {
847 if (*dev_p) {
848 WARN("%s: struct device fields will be "
849 "discarded\n",
850 __func__);
851 break;
852 }
853 dev_p++;
854 }
855 }
856 memset(dev, 0, sizeof(*dev));
857 dev->platform_data = saved_pdata;
858}
859
860
861static void omap_dss_dev_release(struct device *dev)
862{
863 reset_device(dev, 0);
864}
865
866int omap_dss_register_device(struct omap_dss_device *dssdev)
867{
868 static int dev_num;
869
870 WARN_ON(!dssdev->driver_name);
871
872 reset_device(&dssdev->dev, 1);
873 dssdev->dev.bus = &dss_bus_type;
874 dssdev->dev.parent = &dss_bus;
875 dssdev->dev.release = omap_dss_dev_release;
876 dev_set_name(&dssdev->dev, "display%d", dev_num++);
877 return device_register(&dssdev->dev);
878}
879
880void omap_dss_unregister_device(struct omap_dss_device *dssdev)
881{
882 device_unregister(&dssdev->dev);
883}
884
885/* BUS */
886static int omap_dss_bus_register(void)
887{
888 int r;
889
890 r = bus_register(&dss_bus_type);
891 if (r) {
892 DSSERR("bus register failed\n");
893 return r;
894 }
895
896 dev_set_name(&dss_bus, "omapdss");
897 r = device_register(&dss_bus);
898 if (r) {
899 DSSERR("bus driver register failed\n");
900 bus_unregister(&dss_bus_type);
901 return r;
902 }
903
904 return 0;
905}
906
907/* INIT */
908
909#ifdef CONFIG_OMAP2_DSS_MODULE
910static void omap_dss_bus_unregister(void)
911{
912 device_unregister(&dss_bus);
913
914 bus_unregister(&dss_bus_type);
915}
916
917static int __init omap_dss_init(void)
918{
919 int r;
920
921 r = omap_dss_bus_register();
922 if (r)
923 return r;
924
925 r = platform_driver_register(&omap_dss_driver);
926 if (r) {
927 omap_dss_bus_unregister();
928 return r;
929 }
930
931 return 0;
932}
933
934static void __exit omap_dss_exit(void)
935{
936 if (core.vdds_dsi_reg != NULL) {
937 regulator_put(core.vdds_dsi_reg);
938 core.vdds_dsi_reg = NULL;
939 }
940
941 if (core.vdds_sdi_reg != NULL) {
942 regulator_put(core.vdds_sdi_reg);
943 core.vdds_sdi_reg = NULL;
944 }
945
946 if (core.vdda_dac_reg != NULL) {
947 regulator_put(core.vdda_dac_reg);
948 core.vdda_dac_reg = NULL;
949 }
950
951 platform_driver_unregister(&omap_dss_driver);
952
953 omap_dss_bus_unregister();
954}
955
956module_init(omap_dss_init);
957module_exit(omap_dss_exit);
958#else
959static int __init omap_dss_init(void)
960{
961 return omap_dss_bus_register();
962}
963
964static int __init omap_dss_init2(void)
965{
966 return platform_driver_register(&omap_dss_driver);
967}
968
969core_initcall(omap_dss_init);
970device_initcall(omap_dss_init2);
971#endif
972
973MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
974MODULE_DESCRIPTION("OMAP2/3 Display Subsystem");
975MODULE_LICENSE("GPL v2");
976
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
new file mode 100644
index 000000000000..e777e352dbcd
--- /dev/null
+++ b/drivers/video/omap2/dss/dispc.c
@@ -0,0 +1,3181 @@
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/clk.h>
29#include <linux/io.h>
30#include <linux/jiffies.h>
31#include <linux/seq_file.h>
32#include <linux/delay.h>
33#include <linux/workqueue.h>
34
35#include <plat/sram.h>
36#include <plat/clock.h>
37
38#include <plat/display.h>
39
40#include "dss.h"
41
42/* DISPC */
43#define DISPC_BASE 0x48050400
44
45#define DISPC_SZ_REGS SZ_1K
46
47struct dispc_reg { u16 idx; };
48
49#define DISPC_REG(idx) ((const struct dispc_reg) { idx })
50
51/* DISPC common */
52#define DISPC_REVISION DISPC_REG(0x0000)
53#define DISPC_SYSCONFIG DISPC_REG(0x0010)
54#define DISPC_SYSSTATUS DISPC_REG(0x0014)
55#define DISPC_IRQSTATUS DISPC_REG(0x0018)
56#define DISPC_IRQENABLE DISPC_REG(0x001C)
57#define DISPC_CONTROL DISPC_REG(0x0040)
58#define DISPC_CONFIG DISPC_REG(0x0044)
59#define DISPC_CAPABLE DISPC_REG(0x0048)
60#define DISPC_DEFAULT_COLOR0 DISPC_REG(0x004C)
61#define DISPC_DEFAULT_COLOR1 DISPC_REG(0x0050)
62#define DISPC_TRANS_COLOR0 DISPC_REG(0x0054)
63#define DISPC_TRANS_COLOR1 DISPC_REG(0x0058)
64#define DISPC_LINE_STATUS DISPC_REG(0x005C)
65#define DISPC_LINE_NUMBER DISPC_REG(0x0060)
66#define DISPC_TIMING_H DISPC_REG(0x0064)
67#define DISPC_TIMING_V DISPC_REG(0x0068)
68#define DISPC_POL_FREQ DISPC_REG(0x006C)
69#define DISPC_DIVISOR DISPC_REG(0x0070)
70#define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074)
71#define DISPC_SIZE_DIG DISPC_REG(0x0078)
72#define DISPC_SIZE_LCD DISPC_REG(0x007C)
73
74/* DISPC GFX plane */
75#define DISPC_GFX_BA0 DISPC_REG(0x0080)
76#define DISPC_GFX_BA1 DISPC_REG(0x0084)
77#define DISPC_GFX_POSITION DISPC_REG(0x0088)
78#define DISPC_GFX_SIZE DISPC_REG(0x008C)
79#define DISPC_GFX_ATTRIBUTES DISPC_REG(0x00A0)
80#define DISPC_GFX_FIFO_THRESHOLD DISPC_REG(0x00A4)
81#define DISPC_GFX_FIFO_SIZE_STATUS DISPC_REG(0x00A8)
82#define DISPC_GFX_ROW_INC DISPC_REG(0x00AC)
83#define DISPC_GFX_PIXEL_INC DISPC_REG(0x00B0)
84#define DISPC_GFX_WINDOW_SKIP DISPC_REG(0x00B4)
85#define DISPC_GFX_TABLE_BA DISPC_REG(0x00B8)
86
87#define DISPC_DATA_CYCLE1 DISPC_REG(0x01D4)
88#define DISPC_DATA_CYCLE2 DISPC_REG(0x01D8)
89#define DISPC_DATA_CYCLE3 DISPC_REG(0x01DC)
90
91#define DISPC_CPR_COEF_R DISPC_REG(0x0220)
92#define DISPC_CPR_COEF_G DISPC_REG(0x0224)
93#define DISPC_CPR_COEF_B DISPC_REG(0x0228)
94
95#define DISPC_GFX_PRELOAD DISPC_REG(0x022C)
96
97/* DISPC Video plane, n = 0 for VID1 and n = 1 for VID2 */
98#define DISPC_VID_REG(n, idx) DISPC_REG(0x00BC + (n)*0x90 + idx)
99
100#define DISPC_VID_BA0(n) DISPC_VID_REG(n, 0x0000)
101#define DISPC_VID_BA1(n) DISPC_VID_REG(n, 0x0004)
102#define DISPC_VID_POSITION(n) DISPC_VID_REG(n, 0x0008)
103#define DISPC_VID_SIZE(n) DISPC_VID_REG(n, 0x000C)
104#define DISPC_VID_ATTRIBUTES(n) DISPC_VID_REG(n, 0x0010)
105#define DISPC_VID_FIFO_THRESHOLD(n) DISPC_VID_REG(n, 0x0014)
106#define DISPC_VID_FIFO_SIZE_STATUS(n) DISPC_VID_REG(n, 0x0018)
107#define DISPC_VID_ROW_INC(n) DISPC_VID_REG(n, 0x001C)
108#define DISPC_VID_PIXEL_INC(n) DISPC_VID_REG(n, 0x0020)
109#define DISPC_VID_FIR(n) DISPC_VID_REG(n, 0x0024)
110#define DISPC_VID_PICTURE_SIZE(n) DISPC_VID_REG(n, 0x0028)
111#define DISPC_VID_ACCU0(n) DISPC_VID_REG(n, 0x002C)
112#define DISPC_VID_ACCU1(n) DISPC_VID_REG(n, 0x0030)
113
114/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
115#define DISPC_VID_FIR_COEF_H(n, i) DISPC_REG(0x00F0 + (n)*0x90 + (i)*0x8)
116/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
117#define DISPC_VID_FIR_COEF_HV(n, i) DISPC_REG(0x00F4 + (n)*0x90 + (i)*0x8)
118/* coef index i = {0, 1, 2, 3, 4} */
119#define DISPC_VID_CONV_COEF(n, i) DISPC_REG(0x0130 + (n)*0x90 + (i)*0x4)
120/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
121#define DISPC_VID_FIR_COEF_V(n, i) DISPC_REG(0x01E0 + (n)*0x20 + (i)*0x4)
122
123#define DISPC_VID_PRELOAD(n) DISPC_REG(0x230 + (n)*0x04)
124
125
126#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
127 DISPC_IRQ_OCP_ERR | \
128 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
129 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
130 DISPC_IRQ_SYNC_LOST | \
131 DISPC_IRQ_SYNC_LOST_DIGIT)
132
133#define DISPC_MAX_NR_ISRS 8
134
135struct omap_dispc_isr_data {
136 omap_dispc_isr_t isr;
137 void *arg;
138 u32 mask;
139};
140
141#define REG_GET(idx, start, end) \
142 FLD_GET(dispc_read_reg(idx), start, end)
143
144#define REG_FLD_MOD(idx, val, start, end) \
145 dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
146
147static const struct dispc_reg dispc_reg_att[] = { DISPC_GFX_ATTRIBUTES,
148 DISPC_VID_ATTRIBUTES(0),
149 DISPC_VID_ATTRIBUTES(1) };
150
151struct dispc_irq_stats {
152 unsigned long last_reset;
153 unsigned irq_count;
154 unsigned irqs[32];
155};
156
157static struct {
158 void __iomem *base;
159
160 u32 fifo_size[3];
161
162 spinlock_t irq_lock;
163 u32 irq_error_mask;
164 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
165 u32 error_irqs;
166 struct work_struct error_work;
167
168 u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
169
170#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
171 spinlock_t irq_stats_lock;
172 struct dispc_irq_stats irq_stats;
173#endif
174} dispc;
175
176static void _omap_dispc_set_irqs(void);
177
178static inline void dispc_write_reg(const struct dispc_reg idx, u32 val)
179{
180 __raw_writel(val, dispc.base + idx.idx);
181}
182
183static inline u32 dispc_read_reg(const struct dispc_reg idx)
184{
185 return __raw_readl(dispc.base + idx.idx);
186}
187
188#define SR(reg) \
189 dispc.ctx[(DISPC_##reg).idx / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
190#define RR(reg) \
191 dispc_write_reg(DISPC_##reg, dispc.ctx[(DISPC_##reg).idx / sizeof(u32)])
192
193void dispc_save_context(void)
194{
195 if (cpu_is_omap24xx())
196 return;
197
198 SR(SYSCONFIG);
199 SR(IRQENABLE);
200 SR(CONTROL);
201 SR(CONFIG);
202 SR(DEFAULT_COLOR0);
203 SR(DEFAULT_COLOR1);
204 SR(TRANS_COLOR0);
205 SR(TRANS_COLOR1);
206 SR(LINE_NUMBER);
207 SR(TIMING_H);
208 SR(TIMING_V);
209 SR(POL_FREQ);
210 SR(DIVISOR);
211 SR(GLOBAL_ALPHA);
212 SR(SIZE_DIG);
213 SR(SIZE_LCD);
214
215 SR(GFX_BA0);
216 SR(GFX_BA1);
217 SR(GFX_POSITION);
218 SR(GFX_SIZE);
219 SR(GFX_ATTRIBUTES);
220 SR(GFX_FIFO_THRESHOLD);
221 SR(GFX_ROW_INC);
222 SR(GFX_PIXEL_INC);
223 SR(GFX_WINDOW_SKIP);
224 SR(GFX_TABLE_BA);
225
226 SR(DATA_CYCLE1);
227 SR(DATA_CYCLE2);
228 SR(DATA_CYCLE3);
229
230 SR(CPR_COEF_R);
231 SR(CPR_COEF_G);
232 SR(CPR_COEF_B);
233
234 SR(GFX_PRELOAD);
235
236 /* VID1 */
237 SR(VID_BA0(0));
238 SR(VID_BA1(0));
239 SR(VID_POSITION(0));
240 SR(VID_SIZE(0));
241 SR(VID_ATTRIBUTES(0));
242 SR(VID_FIFO_THRESHOLD(0));
243 SR(VID_ROW_INC(0));
244 SR(VID_PIXEL_INC(0));
245 SR(VID_FIR(0));
246 SR(VID_PICTURE_SIZE(0));
247 SR(VID_ACCU0(0));
248 SR(VID_ACCU1(0));
249
250 SR(VID_FIR_COEF_H(0, 0));
251 SR(VID_FIR_COEF_H(0, 1));
252 SR(VID_FIR_COEF_H(0, 2));
253 SR(VID_FIR_COEF_H(0, 3));
254 SR(VID_FIR_COEF_H(0, 4));
255 SR(VID_FIR_COEF_H(0, 5));
256 SR(VID_FIR_COEF_H(0, 6));
257 SR(VID_FIR_COEF_H(0, 7));
258
259 SR(VID_FIR_COEF_HV(0, 0));
260 SR(VID_FIR_COEF_HV(0, 1));
261 SR(VID_FIR_COEF_HV(0, 2));
262 SR(VID_FIR_COEF_HV(0, 3));
263 SR(VID_FIR_COEF_HV(0, 4));
264 SR(VID_FIR_COEF_HV(0, 5));
265 SR(VID_FIR_COEF_HV(0, 6));
266 SR(VID_FIR_COEF_HV(0, 7));
267
268 SR(VID_CONV_COEF(0, 0));
269 SR(VID_CONV_COEF(0, 1));
270 SR(VID_CONV_COEF(0, 2));
271 SR(VID_CONV_COEF(0, 3));
272 SR(VID_CONV_COEF(0, 4));
273
274 SR(VID_FIR_COEF_V(0, 0));
275 SR(VID_FIR_COEF_V(0, 1));
276 SR(VID_FIR_COEF_V(0, 2));
277 SR(VID_FIR_COEF_V(0, 3));
278 SR(VID_FIR_COEF_V(0, 4));
279 SR(VID_FIR_COEF_V(0, 5));
280 SR(VID_FIR_COEF_V(0, 6));
281 SR(VID_FIR_COEF_V(0, 7));
282
283 SR(VID_PRELOAD(0));
284
285 /* VID2 */
286 SR(VID_BA0(1));
287 SR(VID_BA1(1));
288 SR(VID_POSITION(1));
289 SR(VID_SIZE(1));
290 SR(VID_ATTRIBUTES(1));
291 SR(VID_FIFO_THRESHOLD(1));
292 SR(VID_ROW_INC(1));
293 SR(VID_PIXEL_INC(1));
294 SR(VID_FIR(1));
295 SR(VID_PICTURE_SIZE(1));
296 SR(VID_ACCU0(1));
297 SR(VID_ACCU1(1));
298
299 SR(VID_FIR_COEF_H(1, 0));
300 SR(VID_FIR_COEF_H(1, 1));
301 SR(VID_FIR_COEF_H(1, 2));
302 SR(VID_FIR_COEF_H(1, 3));
303 SR(VID_FIR_COEF_H(1, 4));
304 SR(VID_FIR_COEF_H(1, 5));
305 SR(VID_FIR_COEF_H(1, 6));
306 SR(VID_FIR_COEF_H(1, 7));
307
308 SR(VID_FIR_COEF_HV(1, 0));
309 SR(VID_FIR_COEF_HV(1, 1));
310 SR(VID_FIR_COEF_HV(1, 2));
311 SR(VID_FIR_COEF_HV(1, 3));
312 SR(VID_FIR_COEF_HV(1, 4));
313 SR(VID_FIR_COEF_HV(1, 5));
314 SR(VID_FIR_COEF_HV(1, 6));
315 SR(VID_FIR_COEF_HV(1, 7));
316
317 SR(VID_CONV_COEF(1, 0));
318 SR(VID_CONV_COEF(1, 1));
319 SR(VID_CONV_COEF(1, 2));
320 SR(VID_CONV_COEF(1, 3));
321 SR(VID_CONV_COEF(1, 4));
322
323 SR(VID_FIR_COEF_V(1, 0));
324 SR(VID_FIR_COEF_V(1, 1));
325 SR(VID_FIR_COEF_V(1, 2));
326 SR(VID_FIR_COEF_V(1, 3));
327 SR(VID_FIR_COEF_V(1, 4));
328 SR(VID_FIR_COEF_V(1, 5));
329 SR(VID_FIR_COEF_V(1, 6));
330 SR(VID_FIR_COEF_V(1, 7));
331
332 SR(VID_PRELOAD(1));
333}
334
335void dispc_restore_context(void)
336{
337 RR(SYSCONFIG);
338 RR(IRQENABLE);
339 /*RR(CONTROL);*/
340 RR(CONFIG);
341 RR(DEFAULT_COLOR0);
342 RR(DEFAULT_COLOR1);
343 RR(TRANS_COLOR0);
344 RR(TRANS_COLOR1);
345 RR(LINE_NUMBER);
346 RR(TIMING_H);
347 RR(TIMING_V);
348 RR(POL_FREQ);
349 RR(DIVISOR);
350 RR(GLOBAL_ALPHA);
351 RR(SIZE_DIG);
352 RR(SIZE_LCD);
353
354 RR(GFX_BA0);
355 RR(GFX_BA1);
356 RR(GFX_POSITION);
357 RR(GFX_SIZE);
358 RR(GFX_ATTRIBUTES);
359 RR(GFX_FIFO_THRESHOLD);
360 RR(GFX_ROW_INC);
361 RR(GFX_PIXEL_INC);
362 RR(GFX_WINDOW_SKIP);
363 RR(GFX_TABLE_BA);
364
365 RR(DATA_CYCLE1);
366 RR(DATA_CYCLE2);
367 RR(DATA_CYCLE3);
368
369 RR(CPR_COEF_R);
370 RR(CPR_COEF_G);
371 RR(CPR_COEF_B);
372
373 RR(GFX_PRELOAD);
374
375 /* VID1 */
376 RR(VID_BA0(0));
377 RR(VID_BA1(0));
378 RR(VID_POSITION(0));
379 RR(VID_SIZE(0));
380 RR(VID_ATTRIBUTES(0));
381 RR(VID_FIFO_THRESHOLD(0));
382 RR(VID_ROW_INC(0));
383 RR(VID_PIXEL_INC(0));
384 RR(VID_FIR(0));
385 RR(VID_PICTURE_SIZE(0));
386 RR(VID_ACCU0(0));
387 RR(VID_ACCU1(0));
388
389 RR(VID_FIR_COEF_H(0, 0));
390 RR(VID_FIR_COEF_H(0, 1));
391 RR(VID_FIR_COEF_H(0, 2));
392 RR(VID_FIR_COEF_H(0, 3));
393 RR(VID_FIR_COEF_H(0, 4));
394 RR(VID_FIR_COEF_H(0, 5));
395 RR(VID_FIR_COEF_H(0, 6));
396 RR(VID_FIR_COEF_H(0, 7));
397
398 RR(VID_FIR_COEF_HV(0, 0));
399 RR(VID_FIR_COEF_HV(0, 1));
400 RR(VID_FIR_COEF_HV(0, 2));
401 RR(VID_FIR_COEF_HV(0, 3));
402 RR(VID_FIR_COEF_HV(0, 4));
403 RR(VID_FIR_COEF_HV(0, 5));
404 RR(VID_FIR_COEF_HV(0, 6));
405 RR(VID_FIR_COEF_HV(0, 7));
406
407 RR(VID_CONV_COEF(0, 0));
408 RR(VID_CONV_COEF(0, 1));
409 RR(VID_CONV_COEF(0, 2));
410 RR(VID_CONV_COEF(0, 3));
411 RR(VID_CONV_COEF(0, 4));
412
413 RR(VID_FIR_COEF_V(0, 0));
414 RR(VID_FIR_COEF_V(0, 1));
415 RR(VID_FIR_COEF_V(0, 2));
416 RR(VID_FIR_COEF_V(0, 3));
417 RR(VID_FIR_COEF_V(0, 4));
418 RR(VID_FIR_COEF_V(0, 5));
419 RR(VID_FIR_COEF_V(0, 6));
420 RR(VID_FIR_COEF_V(0, 7));
421
422 RR(VID_PRELOAD(0));
423
424 /* VID2 */
425 RR(VID_BA0(1));
426 RR(VID_BA1(1));
427 RR(VID_POSITION(1));
428 RR(VID_SIZE(1));
429 RR(VID_ATTRIBUTES(1));
430 RR(VID_FIFO_THRESHOLD(1));
431 RR(VID_ROW_INC(1));
432 RR(VID_PIXEL_INC(1));
433 RR(VID_FIR(1));
434 RR(VID_PICTURE_SIZE(1));
435 RR(VID_ACCU0(1));
436 RR(VID_ACCU1(1));
437
438 RR(VID_FIR_COEF_H(1, 0));
439 RR(VID_FIR_COEF_H(1, 1));
440 RR(VID_FIR_COEF_H(1, 2));
441 RR(VID_FIR_COEF_H(1, 3));
442 RR(VID_FIR_COEF_H(1, 4));
443 RR(VID_FIR_COEF_H(1, 5));
444 RR(VID_FIR_COEF_H(1, 6));
445 RR(VID_FIR_COEF_H(1, 7));
446
447 RR(VID_FIR_COEF_HV(1, 0));
448 RR(VID_FIR_COEF_HV(1, 1));
449 RR(VID_FIR_COEF_HV(1, 2));
450 RR(VID_FIR_COEF_HV(1, 3));
451 RR(VID_FIR_COEF_HV(1, 4));
452 RR(VID_FIR_COEF_HV(1, 5));
453 RR(VID_FIR_COEF_HV(1, 6));
454 RR(VID_FIR_COEF_HV(1, 7));
455
456 RR(VID_CONV_COEF(1, 0));
457 RR(VID_CONV_COEF(1, 1));
458 RR(VID_CONV_COEF(1, 2));
459 RR(VID_CONV_COEF(1, 3));
460 RR(VID_CONV_COEF(1, 4));
461
462 RR(VID_FIR_COEF_V(1, 0));
463 RR(VID_FIR_COEF_V(1, 1));
464 RR(VID_FIR_COEF_V(1, 2));
465 RR(VID_FIR_COEF_V(1, 3));
466 RR(VID_FIR_COEF_V(1, 4));
467 RR(VID_FIR_COEF_V(1, 5));
468 RR(VID_FIR_COEF_V(1, 6));
469 RR(VID_FIR_COEF_V(1, 7));
470
471 RR(VID_PRELOAD(1));
472
473 /* enable last, because LCD & DIGIT enable are here */
474 RR(CONTROL);
475}
476
477#undef SR
478#undef RR
479
480static inline void enable_clocks(bool enable)
481{
482 if (enable)
483 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
484 else
485 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
486}
487
488bool dispc_go_busy(enum omap_channel channel)
489{
490 int bit;
491
492 if (channel == OMAP_DSS_CHANNEL_LCD)
493 bit = 5; /* GOLCD */
494 else
495 bit = 6; /* GODIGIT */
496
497 return REG_GET(DISPC_CONTROL, bit, bit) == 1;
498}
499
500void dispc_go(enum omap_channel channel)
501{
502 int bit;
503
504 enable_clocks(1);
505
506 if (channel == OMAP_DSS_CHANNEL_LCD)
507 bit = 0; /* LCDENABLE */
508 else
509 bit = 1; /* DIGITALENABLE */
510
511 /* if the channel is not enabled, we don't need GO */
512 if (REG_GET(DISPC_CONTROL, bit, bit) == 0)
513 goto end;
514
515 if (channel == OMAP_DSS_CHANNEL_LCD)
516 bit = 5; /* GOLCD */
517 else
518 bit = 6; /* GODIGIT */
519
520 if (REG_GET(DISPC_CONTROL, bit, bit) == 1) {
521 DSSERR("GO bit not down for channel %d\n", channel);
522 goto end;
523 }
524
525 DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT");
526
527 REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
528end:
529 enable_clocks(0);
530}
531
532static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
533{
534 BUG_ON(plane == OMAP_DSS_GFX);
535
536 dispc_write_reg(DISPC_VID_FIR_COEF_H(plane-1, reg), value);
537}
538
539static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
540{
541 BUG_ON(plane == OMAP_DSS_GFX);
542
543 dispc_write_reg(DISPC_VID_FIR_COEF_HV(plane-1, reg), value);
544}
545
546static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
547{
548 BUG_ON(plane == OMAP_DSS_GFX);
549
550 dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
551}
552
553static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
554 int vscaleup, int five_taps)
555{
556 /* Coefficients for horizontal up-sampling */
557 static const u32 coef_hup[8] = {
558 0x00800000,
559 0x0D7CF800,
560 0x1E70F5FF,
561 0x335FF5FE,
562 0xF74949F7,
563 0xF55F33FB,
564 0xF5701EFE,
565 0xF87C0DFF,
566 };
567
568 /* Coefficients for horizontal down-sampling */
569 static const u32 coef_hdown[8] = {
570 0x24382400,
571 0x28371FFE,
572 0x2C361BFB,
573 0x303516F9,
574 0x11343311,
575 0x1635300C,
576 0x1B362C08,
577 0x1F372804,
578 };
579
580 /* Coefficients for horizontal and vertical up-sampling */
581 static const u32 coef_hvup[2][8] = {
582 {
583 0x00800000,
584 0x037B02FF,
585 0x0C6F05FE,
586 0x205907FB,
587 0x00404000,
588 0x075920FE,
589 0x056F0CFF,
590 0x027B0300,
591 },
592 {
593 0x00800000,
594 0x0D7CF8FF,
595 0x1E70F5FE,
596 0x335FF5FB,
597 0xF7404000,
598 0xF55F33FE,
599 0xF5701EFF,
600 0xF87C0D00,
601 },
602 };
603
604 /* Coefficients for horizontal and vertical down-sampling */
605 static const u32 coef_hvdown[2][8] = {
606 {
607 0x24382400,
608 0x28391F04,
609 0x2D381B08,
610 0x3237170C,
611 0x123737F7,
612 0x173732F9,
613 0x1B382DFB,
614 0x1F3928FE,
615 },
616 {
617 0x24382400,
618 0x28371F04,
619 0x2C361B08,
620 0x3035160C,
621 0x113433F7,
622 0x163530F9,
623 0x1B362CFB,
624 0x1F3728FE,
625 },
626 };
627
628 /* Coefficients for vertical up-sampling */
629 static const u32 coef_vup[8] = {
630 0x00000000,
631 0x0000FF00,
632 0x0000FEFF,
633 0x0000FBFE,
634 0x000000F7,
635 0x0000FEFB,
636 0x0000FFFE,
637 0x000000FF,
638 };
639
640
641 /* Coefficients for vertical down-sampling */
642 static const u32 coef_vdown[8] = {
643 0x00000000,
644 0x000004FE,
645 0x000008FB,
646 0x00000CF9,
647 0x0000F711,
648 0x0000F90C,
649 0x0000FB08,
650 0x0000FE04,
651 };
652
653 const u32 *h_coef;
654 const u32 *hv_coef;
655 const u32 *hv_coef_mod;
656 const u32 *v_coef;
657 int i;
658
659 if (hscaleup)
660 h_coef = coef_hup;
661 else
662 h_coef = coef_hdown;
663
664 if (vscaleup) {
665 hv_coef = coef_hvup[five_taps];
666 v_coef = coef_vup;
667
668 if (hscaleup)
669 hv_coef_mod = NULL;
670 else
671 hv_coef_mod = coef_hvdown[five_taps];
672 } else {
673 hv_coef = coef_hvdown[five_taps];
674 v_coef = coef_vdown;
675
676 if (hscaleup)
677 hv_coef_mod = coef_hvup[five_taps];
678 else
679 hv_coef_mod = NULL;
680 }
681
682 for (i = 0; i < 8; i++) {
683 u32 h, hv;
684
685 h = h_coef[i];
686
687 hv = hv_coef[i];
688
689 if (hv_coef_mod) {
690 hv &= 0xffffff00;
691 hv |= (hv_coef_mod[i] & 0xff);
692 }
693
694 _dispc_write_firh_reg(plane, i, h);
695 _dispc_write_firhv_reg(plane, i, hv);
696 }
697
698 if (!five_taps)
699 return;
700
701 for (i = 0; i < 8; i++) {
702 u32 v;
703 v = v_coef[i];
704 _dispc_write_firv_reg(plane, i, v);
705 }
706}
707
708static void _dispc_setup_color_conv_coef(void)
709{
710 const struct color_conv_coef {
711 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
712 int full_range;
713 } ctbl_bt601_5 = {
714 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
715 };
716
717 const struct color_conv_coef *ct;
718
719#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
720
721 ct = &ctbl_bt601_5;
722
723 dispc_write_reg(DISPC_VID_CONV_COEF(0, 0), CVAL(ct->rcr, ct->ry));
724 dispc_write_reg(DISPC_VID_CONV_COEF(0, 1), CVAL(ct->gy, ct->rcb));
725 dispc_write_reg(DISPC_VID_CONV_COEF(0, 2), CVAL(ct->gcb, ct->gcr));
726 dispc_write_reg(DISPC_VID_CONV_COEF(0, 3), CVAL(ct->bcr, ct->by));
727 dispc_write_reg(DISPC_VID_CONV_COEF(0, 4), CVAL(0, ct->bcb));
728
729 dispc_write_reg(DISPC_VID_CONV_COEF(1, 0), CVAL(ct->rcr, ct->ry));
730 dispc_write_reg(DISPC_VID_CONV_COEF(1, 1), CVAL(ct->gy, ct->rcb));
731 dispc_write_reg(DISPC_VID_CONV_COEF(1, 2), CVAL(ct->gcb, ct->gcr));
732 dispc_write_reg(DISPC_VID_CONV_COEF(1, 3), CVAL(ct->bcr, ct->by));
733 dispc_write_reg(DISPC_VID_CONV_COEF(1, 4), CVAL(0, ct->bcb));
734
735#undef CVAL
736
737 REG_FLD_MOD(DISPC_VID_ATTRIBUTES(0), ct->full_range, 11, 11);
738 REG_FLD_MOD(DISPC_VID_ATTRIBUTES(1), ct->full_range, 11, 11);
739}
740
741
742static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
743{
744 const struct dispc_reg ba0_reg[] = { DISPC_GFX_BA0,
745 DISPC_VID_BA0(0),
746 DISPC_VID_BA0(1) };
747
748 dispc_write_reg(ba0_reg[plane], paddr);
749}
750
751static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr)
752{
753 const struct dispc_reg ba1_reg[] = { DISPC_GFX_BA1,
754 DISPC_VID_BA1(0),
755 DISPC_VID_BA1(1) };
756
757 dispc_write_reg(ba1_reg[plane], paddr);
758}
759
760static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
761{
762 const struct dispc_reg pos_reg[] = { DISPC_GFX_POSITION,
763 DISPC_VID_POSITION(0),
764 DISPC_VID_POSITION(1) };
765
766 u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
767 dispc_write_reg(pos_reg[plane], val);
768}
769
770static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
771{
772 const struct dispc_reg siz_reg[] = { DISPC_GFX_SIZE,
773 DISPC_VID_PICTURE_SIZE(0),
774 DISPC_VID_PICTURE_SIZE(1) };
775 u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
776 dispc_write_reg(siz_reg[plane], val);
777}
778
779static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
780{
781 u32 val;
782 const struct dispc_reg vsi_reg[] = { DISPC_VID_SIZE(0),
783 DISPC_VID_SIZE(1) };
784
785 BUG_ON(plane == OMAP_DSS_GFX);
786
787 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
788 dispc_write_reg(vsi_reg[plane-1], val);
789}
790
791static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
792{
793
794 BUG_ON(plane == OMAP_DSS_VIDEO1);
795
796 if (cpu_is_omap24xx())
797 return;
798
799 if (plane == OMAP_DSS_GFX)
800 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
801 else if (plane == OMAP_DSS_VIDEO2)
802 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16);
803}
804
805static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
806{
807 const struct dispc_reg ri_reg[] = { DISPC_GFX_PIXEL_INC,
808 DISPC_VID_PIXEL_INC(0),
809 DISPC_VID_PIXEL_INC(1) };
810
811 dispc_write_reg(ri_reg[plane], inc);
812}
813
814static void _dispc_set_row_inc(enum omap_plane plane, s32 inc)
815{
816 const struct dispc_reg ri_reg[] = { DISPC_GFX_ROW_INC,
817 DISPC_VID_ROW_INC(0),
818 DISPC_VID_ROW_INC(1) };
819
820 dispc_write_reg(ri_reg[plane], inc);
821}
822
823static void _dispc_set_color_mode(enum omap_plane plane,
824 enum omap_color_mode color_mode)
825{
826 u32 m = 0;
827
828 switch (color_mode) {
829 case OMAP_DSS_COLOR_CLUT1:
830 m = 0x0; break;
831 case OMAP_DSS_COLOR_CLUT2:
832 m = 0x1; break;
833 case OMAP_DSS_COLOR_CLUT4:
834 m = 0x2; break;
835 case OMAP_DSS_COLOR_CLUT8:
836 m = 0x3; break;
837 case OMAP_DSS_COLOR_RGB12U:
838 m = 0x4; break;
839 case OMAP_DSS_COLOR_ARGB16:
840 m = 0x5; break;
841 case OMAP_DSS_COLOR_RGB16:
842 m = 0x6; break;
843 case OMAP_DSS_COLOR_RGB24U:
844 m = 0x8; break;
845 case OMAP_DSS_COLOR_RGB24P:
846 m = 0x9; break;
847 case OMAP_DSS_COLOR_YUV2:
848 m = 0xa; break;
849 case OMAP_DSS_COLOR_UYVY:
850 m = 0xb; break;
851 case OMAP_DSS_COLOR_ARGB32:
852 m = 0xc; break;
853 case OMAP_DSS_COLOR_RGBA32:
854 m = 0xd; break;
855 case OMAP_DSS_COLOR_RGBX32:
856 m = 0xe; break;
857 default:
858 BUG(); break;
859 }
860
861 REG_FLD_MOD(dispc_reg_att[plane], m, 4, 1);
862}
863
864static void _dispc_set_channel_out(enum omap_plane plane,
865 enum omap_channel channel)
866{
867 int shift;
868 u32 val;
869
870 switch (plane) {
871 case OMAP_DSS_GFX:
872 shift = 8;
873 break;
874 case OMAP_DSS_VIDEO1:
875 case OMAP_DSS_VIDEO2:
876 shift = 16;
877 break;
878 default:
879 BUG();
880 return;
881 }
882
883 val = dispc_read_reg(dispc_reg_att[plane]);
884 val = FLD_MOD(val, channel, shift, shift);
885 dispc_write_reg(dispc_reg_att[plane], val);
886}
887
888void dispc_set_burst_size(enum omap_plane plane,
889 enum omap_burst_size burst_size)
890{
891 int shift;
892 u32 val;
893
894 enable_clocks(1);
895
896 switch (plane) {
897 case OMAP_DSS_GFX:
898 shift = 6;
899 break;
900 case OMAP_DSS_VIDEO1:
901 case OMAP_DSS_VIDEO2:
902 shift = 14;
903 break;
904 default:
905 BUG();
906 return;
907 }
908
909 val = dispc_read_reg(dispc_reg_att[plane]);
910 val = FLD_MOD(val, burst_size, shift+1, shift);
911 dispc_write_reg(dispc_reg_att[plane], val);
912
913 enable_clocks(0);
914}
915
916static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
917{
918 u32 val;
919
920 BUG_ON(plane == OMAP_DSS_GFX);
921
922 val = dispc_read_reg(dispc_reg_att[plane]);
923 val = FLD_MOD(val, enable, 9, 9);
924 dispc_write_reg(dispc_reg_att[plane], val);
925}
926
927void dispc_enable_replication(enum omap_plane plane, bool enable)
928{
929 int bit;
930
931 if (plane == OMAP_DSS_GFX)
932 bit = 5;
933 else
934 bit = 10;
935
936 enable_clocks(1);
937 REG_FLD_MOD(dispc_reg_att[plane], enable, bit, bit);
938 enable_clocks(0);
939}
940
941void dispc_set_lcd_size(u16 width, u16 height)
942{
943 u32 val;
944 BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
945 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
946 enable_clocks(1);
947 dispc_write_reg(DISPC_SIZE_LCD, val);
948 enable_clocks(0);
949}
950
951void dispc_set_digit_size(u16 width, u16 height)
952{
953 u32 val;
954 BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
955 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
956 enable_clocks(1);
957 dispc_write_reg(DISPC_SIZE_DIG, val);
958 enable_clocks(0);
959}
960
961static void dispc_read_plane_fifo_sizes(void)
962{
963 const struct dispc_reg fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
964 DISPC_VID_FIFO_SIZE_STATUS(0),
965 DISPC_VID_FIFO_SIZE_STATUS(1) };
966 u32 size;
967 int plane;
968
969 enable_clocks(1);
970
971 for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
972 if (cpu_is_omap24xx())
973 size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 8, 0);
974 else if (cpu_is_omap34xx())
975 size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 10, 0);
976 else
977 BUG();
978
979 dispc.fifo_size[plane] = size;
980 }
981
982 enable_clocks(0);
983}
984
985u32 dispc_get_plane_fifo_size(enum omap_plane plane)
986{
987 return dispc.fifo_size[plane];
988}
989
990void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
991{
992 const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
993 DISPC_VID_FIFO_THRESHOLD(0),
994 DISPC_VID_FIFO_THRESHOLD(1) };
995 enable_clocks(1);
996
997 DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
998 plane,
999 REG_GET(ftrs_reg[plane], 11, 0),
1000 REG_GET(ftrs_reg[plane], 27, 16),
1001 low, high);
1002
1003 if (cpu_is_omap24xx())
1004 dispc_write_reg(ftrs_reg[plane],
1005 FLD_VAL(high, 24, 16) | FLD_VAL(low, 8, 0));
1006 else
1007 dispc_write_reg(ftrs_reg[plane],
1008 FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0));
1009
1010 enable_clocks(0);
1011}
1012
1013void dispc_enable_fifomerge(bool enable)
1014{
1015 enable_clocks(1);
1016
1017 DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1018 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
1019
1020 enable_clocks(0);
1021}
1022
1023static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
1024{
1025 u32 val;
1026 const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0),
1027 DISPC_VID_FIR(1) };
1028
1029 BUG_ON(plane == OMAP_DSS_GFX);
1030
1031 if (cpu_is_omap24xx())
1032 val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0);
1033 else
1034 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1035 dispc_write_reg(fir_reg[plane-1], val);
1036}
1037
1038static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
1039{
1040 u32 val;
1041 const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
1042 DISPC_VID_ACCU0(1) };
1043
1044 BUG_ON(plane == OMAP_DSS_GFX);
1045
1046 val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
1047 dispc_write_reg(ac0_reg[plane-1], val);
1048}
1049
1050static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
1051{
1052 u32 val;
1053 const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
1054 DISPC_VID_ACCU1(1) };
1055
1056 BUG_ON(plane == OMAP_DSS_GFX);
1057
1058 val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
1059 dispc_write_reg(ac1_reg[plane-1], val);
1060}
1061
1062
1063static void _dispc_set_scaling(enum omap_plane plane,
1064 u16 orig_width, u16 orig_height,
1065 u16 out_width, u16 out_height,
1066 bool ilace, bool five_taps,
1067 bool fieldmode)
1068{
1069 int fir_hinc;
1070 int fir_vinc;
1071 int hscaleup, vscaleup;
1072 int accu0 = 0;
1073 int accu1 = 0;
1074 u32 l;
1075
1076 BUG_ON(plane == OMAP_DSS_GFX);
1077
1078 hscaleup = orig_width <= out_width;
1079 vscaleup = orig_height <= out_height;
1080
1081 _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps);
1082
1083 if (!orig_width || orig_width == out_width)
1084 fir_hinc = 0;
1085 else
1086 fir_hinc = 1024 * orig_width / out_width;
1087
1088 if (!orig_height || orig_height == out_height)
1089 fir_vinc = 0;
1090 else
1091 fir_vinc = 1024 * orig_height / out_height;
1092
1093 _dispc_set_fir(plane, fir_hinc, fir_vinc);
1094
1095 l = dispc_read_reg(dispc_reg_att[plane]);
1096 l &= ~((0x0f << 5) | (0x3 << 21));
1097
1098 l |= fir_hinc ? (1 << 5) : 0;
1099 l |= fir_vinc ? (1 << 6) : 0;
1100
1101 l |= hscaleup ? 0 : (1 << 7);
1102 l |= vscaleup ? 0 : (1 << 8);
1103
1104 l |= five_taps ? (1 << 21) : 0;
1105 l |= five_taps ? (1 << 22) : 0;
1106
1107 dispc_write_reg(dispc_reg_att[plane], l);
1108
1109 /*
1110 * field 0 = even field = bottom field
1111 * field 1 = odd field = top field
1112 */
1113 if (ilace && !fieldmode) {
1114 accu1 = 0;
1115 accu0 = (fir_vinc / 2) & 0x3ff;
1116 if (accu0 >= 1024/2) {
1117 accu1 = 1024/2;
1118 accu0 -= accu1;
1119 }
1120 }
1121
1122 _dispc_set_vid_accu0(plane, 0, accu0);
1123 _dispc_set_vid_accu1(plane, 0, accu1);
1124}
1125
1126static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
1127 bool mirroring, enum omap_color_mode color_mode)
1128{
1129 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1130 color_mode == OMAP_DSS_COLOR_UYVY) {
1131 int vidrot = 0;
1132
1133 if (mirroring) {
1134 switch (rotation) {
1135 case OMAP_DSS_ROT_0:
1136 vidrot = 2;
1137 break;
1138 case OMAP_DSS_ROT_90:
1139 vidrot = 1;
1140 break;
1141 case OMAP_DSS_ROT_180:
1142 vidrot = 0;
1143 break;
1144 case OMAP_DSS_ROT_270:
1145 vidrot = 3;
1146 break;
1147 }
1148 } else {
1149 switch (rotation) {
1150 case OMAP_DSS_ROT_0:
1151 vidrot = 0;
1152 break;
1153 case OMAP_DSS_ROT_90:
1154 vidrot = 1;
1155 break;
1156 case OMAP_DSS_ROT_180:
1157 vidrot = 2;
1158 break;
1159 case OMAP_DSS_ROT_270:
1160 vidrot = 3;
1161 break;
1162 }
1163 }
1164
1165 REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
1166
1167 if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
1168 REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
1169 else
1170 REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
1171 } else {
1172 REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
1173 REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
1174 }
1175}
1176
1177static int color_mode_to_bpp(enum omap_color_mode color_mode)
1178{
1179 switch (color_mode) {
1180 case OMAP_DSS_COLOR_CLUT1:
1181 return 1;
1182 case OMAP_DSS_COLOR_CLUT2:
1183 return 2;
1184 case OMAP_DSS_COLOR_CLUT4:
1185 return 4;
1186 case OMAP_DSS_COLOR_CLUT8:
1187 return 8;
1188 case OMAP_DSS_COLOR_RGB12U:
1189 case OMAP_DSS_COLOR_RGB16:
1190 case OMAP_DSS_COLOR_ARGB16:
1191 case OMAP_DSS_COLOR_YUV2:
1192 case OMAP_DSS_COLOR_UYVY:
1193 return 16;
1194 case OMAP_DSS_COLOR_RGB24P:
1195 return 24;
1196 case OMAP_DSS_COLOR_RGB24U:
1197 case OMAP_DSS_COLOR_ARGB32:
1198 case OMAP_DSS_COLOR_RGBA32:
1199 case OMAP_DSS_COLOR_RGBX32:
1200 return 32;
1201 default:
1202 BUG();
1203 }
1204}
1205
1206static s32 pixinc(int pixels, u8 ps)
1207{
1208 if (pixels == 1)
1209 return 1;
1210 else if (pixels > 1)
1211 return 1 + (pixels - 1) * ps;
1212 else if (pixels < 0)
1213 return 1 - (-pixels + 1) * ps;
1214 else
1215 BUG();
1216}
1217
1218static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
1219 u16 screen_width,
1220 u16 width, u16 height,
1221 enum omap_color_mode color_mode, bool fieldmode,
1222 unsigned int field_offset,
1223 unsigned *offset0, unsigned *offset1,
1224 s32 *row_inc, s32 *pix_inc)
1225{
1226 u8 ps;
1227
1228 /* FIXME CLUT formats */
1229 switch (color_mode) {
1230 case OMAP_DSS_COLOR_CLUT1:
1231 case OMAP_DSS_COLOR_CLUT2:
1232 case OMAP_DSS_COLOR_CLUT4:
1233 case OMAP_DSS_COLOR_CLUT8:
1234 BUG();
1235 return;
1236 case OMAP_DSS_COLOR_YUV2:
1237 case OMAP_DSS_COLOR_UYVY:
1238 ps = 4;
1239 break;
1240 default:
1241 ps = color_mode_to_bpp(color_mode) / 8;
1242 break;
1243 }
1244
1245 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1246 width, height);
1247
1248 /*
1249 * field 0 = even field = bottom field
1250 * field 1 = odd field = top field
1251 */
1252 switch (rotation + mirror * 4) {
1253 case OMAP_DSS_ROT_0:
1254 case OMAP_DSS_ROT_180:
1255 /*
1256 * If the pixel format is YUV or UYVY divide the width
1257 * of the image by 2 for 0 and 180 degree rotation.
1258 */
1259 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1260 color_mode == OMAP_DSS_COLOR_UYVY)
1261 width = width >> 1;
1262 case OMAP_DSS_ROT_90:
1263 case OMAP_DSS_ROT_270:
1264 *offset1 = 0;
1265 if (field_offset)
1266 *offset0 = field_offset * screen_width * ps;
1267 else
1268 *offset0 = 0;
1269
1270 *row_inc = pixinc(1 + (screen_width - width) +
1271 (fieldmode ? screen_width : 0),
1272 ps);
1273 *pix_inc = pixinc(1, ps);
1274 break;
1275
1276 case OMAP_DSS_ROT_0 + 4:
1277 case OMAP_DSS_ROT_180 + 4:
1278 /* If the pixel format is YUV or UYVY divide the width
1279 * of the image by 2 for 0 degree and 180 degree
1280 */
1281 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1282 color_mode == OMAP_DSS_COLOR_UYVY)
1283 width = width >> 1;
1284 case OMAP_DSS_ROT_90 + 4:
1285 case OMAP_DSS_ROT_270 + 4:
1286 *offset1 = 0;
1287 if (field_offset)
1288 *offset0 = field_offset * screen_width * ps;
1289 else
1290 *offset0 = 0;
1291 *row_inc = pixinc(1 - (screen_width + width) -
1292 (fieldmode ? screen_width : 0),
1293 ps);
1294 *pix_inc = pixinc(1, ps);
1295 break;
1296
1297 default:
1298 BUG();
1299 }
1300}
1301
1302static void calc_dma_rotation_offset(u8 rotation, bool mirror,
1303 u16 screen_width,
1304 u16 width, u16 height,
1305 enum omap_color_mode color_mode, bool fieldmode,
1306 unsigned int field_offset,
1307 unsigned *offset0, unsigned *offset1,
1308 s32 *row_inc, s32 *pix_inc)
1309{
1310 u8 ps;
1311 u16 fbw, fbh;
1312
1313 /* FIXME CLUT formats */
1314 switch (color_mode) {
1315 case OMAP_DSS_COLOR_CLUT1:
1316 case OMAP_DSS_COLOR_CLUT2:
1317 case OMAP_DSS_COLOR_CLUT4:
1318 case OMAP_DSS_COLOR_CLUT8:
1319 BUG();
1320 return;
1321 default:
1322 ps = color_mode_to_bpp(color_mode) / 8;
1323 break;
1324 }
1325
1326 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1327 width, height);
1328
1329 /* width & height are overlay sizes, convert to fb sizes */
1330
1331 if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) {
1332 fbw = width;
1333 fbh = height;
1334 } else {
1335 fbw = height;
1336 fbh = width;
1337 }
1338
1339 /*
1340 * field 0 = even field = bottom field
1341 * field 1 = odd field = top field
1342 */
1343 switch (rotation + mirror * 4) {
1344 case OMAP_DSS_ROT_0:
1345 *offset1 = 0;
1346 if (field_offset)
1347 *offset0 = *offset1 + field_offset * screen_width * ps;
1348 else
1349 *offset0 = *offset1;
1350 *row_inc = pixinc(1 + (screen_width - fbw) +
1351 (fieldmode ? screen_width : 0),
1352 ps);
1353 *pix_inc = pixinc(1, ps);
1354 break;
1355 case OMAP_DSS_ROT_90:
1356 *offset1 = screen_width * (fbh - 1) * ps;
1357 if (field_offset)
1358 *offset0 = *offset1 + field_offset * ps;
1359 else
1360 *offset0 = *offset1;
1361 *row_inc = pixinc(screen_width * (fbh - 1) + 1 +
1362 (fieldmode ? 1 : 0), ps);
1363 *pix_inc = pixinc(-screen_width, ps);
1364 break;
1365 case OMAP_DSS_ROT_180:
1366 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1367 if (field_offset)
1368 *offset0 = *offset1 - field_offset * screen_width * ps;
1369 else
1370 *offset0 = *offset1;
1371 *row_inc = pixinc(-1 -
1372 (screen_width - fbw) -
1373 (fieldmode ? screen_width : 0),
1374 ps);
1375 *pix_inc = pixinc(-1, ps);
1376 break;
1377 case OMAP_DSS_ROT_270:
1378 *offset1 = (fbw - 1) * ps;
1379 if (field_offset)
1380 *offset0 = *offset1 - field_offset * ps;
1381 else
1382 *offset0 = *offset1;
1383 *row_inc = pixinc(-screen_width * (fbh - 1) - 1 -
1384 (fieldmode ? 1 : 0), ps);
1385 *pix_inc = pixinc(screen_width, ps);
1386 break;
1387
1388 /* mirroring */
1389 case OMAP_DSS_ROT_0 + 4:
1390 *offset1 = (fbw - 1) * ps;
1391 if (field_offset)
1392 *offset0 = *offset1 + field_offset * screen_width * ps;
1393 else
1394 *offset0 = *offset1;
1395 *row_inc = pixinc(screen_width * 2 - 1 +
1396 (fieldmode ? screen_width : 0),
1397 ps);
1398 *pix_inc = pixinc(-1, ps);
1399 break;
1400
1401 case OMAP_DSS_ROT_90 + 4:
1402 *offset1 = 0;
1403 if (field_offset)
1404 *offset0 = *offset1 + field_offset * ps;
1405 else
1406 *offset0 = *offset1;
1407 *row_inc = pixinc(-screen_width * (fbh - 1) + 1 +
1408 (fieldmode ? 1 : 0),
1409 ps);
1410 *pix_inc = pixinc(screen_width, ps);
1411 break;
1412
1413 case OMAP_DSS_ROT_180 + 4:
1414 *offset1 = screen_width * (fbh - 1) * ps;
1415 if (field_offset)
1416 *offset0 = *offset1 - field_offset * screen_width * ps;
1417 else
1418 *offset0 = *offset1;
1419 *row_inc = pixinc(1 - screen_width * 2 -
1420 (fieldmode ? screen_width : 0),
1421 ps);
1422 *pix_inc = pixinc(1, ps);
1423 break;
1424
1425 case OMAP_DSS_ROT_270 + 4:
1426 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1427 if (field_offset)
1428 *offset0 = *offset1 - field_offset * ps;
1429 else
1430 *offset0 = *offset1;
1431 *row_inc = pixinc(screen_width * (fbh - 1) - 1 -
1432 (fieldmode ? 1 : 0),
1433 ps);
1434 *pix_inc = pixinc(-screen_width, ps);
1435 break;
1436
1437 default:
1438 BUG();
1439 }
1440}
1441
1442static unsigned long calc_fclk_five_taps(u16 width, u16 height,
1443 u16 out_width, u16 out_height, enum omap_color_mode color_mode)
1444{
1445 u32 fclk = 0;
1446 /* FIXME venc pclk? */
1447 u64 tmp, pclk = dispc_pclk_rate();
1448
1449 if (height > out_height) {
1450 /* FIXME get real display PPL */
1451 unsigned int ppl = 800;
1452
1453 tmp = pclk * height * out_width;
1454 do_div(tmp, 2 * out_height * ppl);
1455 fclk = tmp;
1456
1457 if (height > 2 * out_height) {
1458 if (ppl == out_width)
1459 return 0;
1460
1461 tmp = pclk * (height - 2 * out_height) * out_width;
1462 do_div(tmp, 2 * out_height * (ppl - out_width));
1463 fclk = max(fclk, (u32) tmp);
1464 }
1465 }
1466
1467 if (width > out_width) {
1468 tmp = pclk * width;
1469 do_div(tmp, out_width);
1470 fclk = max(fclk, (u32) tmp);
1471
1472 if (color_mode == OMAP_DSS_COLOR_RGB24U)
1473 fclk <<= 1;
1474 }
1475
1476 return fclk;
1477}
1478
1479static unsigned long calc_fclk(u16 width, u16 height,
1480 u16 out_width, u16 out_height)
1481{
1482 unsigned int hf, vf;
1483
1484 /*
1485 * FIXME how to determine the 'A' factor
1486 * for the no downscaling case ?
1487 */
1488
1489 if (width > 3 * out_width)
1490 hf = 4;
1491 else if (width > 2 * out_width)
1492 hf = 3;
1493 else if (width > out_width)
1494 hf = 2;
1495 else
1496 hf = 1;
1497
1498 if (height > out_height)
1499 vf = 2;
1500 else
1501 vf = 1;
1502
1503 /* FIXME venc pclk? */
1504 return dispc_pclk_rate() * vf * hf;
1505}
1506
1507void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
1508{
1509 enable_clocks(1);
1510 _dispc_set_channel_out(plane, channel_out);
1511 enable_clocks(0);
1512}
1513
1514static int _dispc_setup_plane(enum omap_plane plane,
1515 u32 paddr, u16 screen_width,
1516 u16 pos_x, u16 pos_y,
1517 u16 width, u16 height,
1518 u16 out_width, u16 out_height,
1519 enum omap_color_mode color_mode,
1520 bool ilace,
1521 enum omap_dss_rotation_type rotation_type,
1522 u8 rotation, int mirror,
1523 u8 global_alpha)
1524{
1525 const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
1526 bool five_taps = 0;
1527 bool fieldmode = 0;
1528 int cconv = 0;
1529 unsigned offset0, offset1;
1530 s32 row_inc;
1531 s32 pix_inc;
1532 u16 frame_height = height;
1533 unsigned int field_offset = 0;
1534
1535 if (paddr == 0)
1536 return -EINVAL;
1537
1538 if (ilace && height == out_height)
1539 fieldmode = 1;
1540
1541 if (ilace) {
1542 if (fieldmode)
1543 height /= 2;
1544 pos_y /= 2;
1545 out_height /= 2;
1546
1547 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
1548 "out_height %d\n",
1549 height, pos_y, out_height);
1550 }
1551
1552 if (plane == OMAP_DSS_GFX) {
1553 if (width != out_width || height != out_height)
1554 return -EINVAL;
1555
1556 switch (color_mode) {
1557 case OMAP_DSS_COLOR_ARGB16:
1558 case OMAP_DSS_COLOR_ARGB32:
1559 case OMAP_DSS_COLOR_RGBA32:
1560 case OMAP_DSS_COLOR_RGBX32:
1561 if (cpu_is_omap24xx())
1562 return -EINVAL;
1563 /* fall through */
1564 case OMAP_DSS_COLOR_RGB12U:
1565 case OMAP_DSS_COLOR_RGB16:
1566 case OMAP_DSS_COLOR_RGB24P:
1567 case OMAP_DSS_COLOR_RGB24U:
1568 break;
1569
1570 default:
1571 return -EINVAL;
1572 }
1573 } else {
1574 /* video plane */
1575
1576 unsigned long fclk = 0;
1577
1578 if (out_width < width / maxdownscale ||
1579 out_width > width * 8)
1580 return -EINVAL;
1581
1582 if (out_height < height / maxdownscale ||
1583 out_height > height * 8)
1584 return -EINVAL;
1585
1586 switch (color_mode) {
1587 case OMAP_DSS_COLOR_RGBX32:
1588 case OMAP_DSS_COLOR_RGB12U:
1589 if (cpu_is_omap24xx())
1590 return -EINVAL;
1591 /* fall through */
1592 case OMAP_DSS_COLOR_RGB16:
1593 case OMAP_DSS_COLOR_RGB24P:
1594 case OMAP_DSS_COLOR_RGB24U:
1595 break;
1596
1597 case OMAP_DSS_COLOR_ARGB16:
1598 case OMAP_DSS_COLOR_ARGB32:
1599 case OMAP_DSS_COLOR_RGBA32:
1600 if (cpu_is_omap24xx())
1601 return -EINVAL;
1602 if (plane == OMAP_DSS_VIDEO1)
1603 return -EINVAL;
1604 break;
1605
1606 case OMAP_DSS_COLOR_YUV2:
1607 case OMAP_DSS_COLOR_UYVY:
1608 cconv = 1;
1609 break;
1610
1611 default:
1612 return -EINVAL;
1613 }
1614
1615 /* Must use 5-tap filter? */
1616 five_taps = height > out_height * 2;
1617
1618 if (!five_taps) {
1619 fclk = calc_fclk(width, height,
1620 out_width, out_height);
1621
1622 /* Try 5-tap filter if 3-tap fclk is too high */
1623 if (cpu_is_omap34xx() && height > out_height &&
1624 fclk > dispc_fclk_rate())
1625 five_taps = true;
1626 }
1627
1628 if (width > (2048 >> five_taps)) {
1629 DSSERR("failed to set up scaling, fclk too low\n");
1630 return -EINVAL;
1631 }
1632
1633 if (five_taps)
1634 fclk = calc_fclk_five_taps(width, height,
1635 out_width, out_height, color_mode);
1636
1637 DSSDBG("required fclk rate = %lu Hz\n", fclk);
1638 DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
1639
1640 if (!fclk || fclk > dispc_fclk_rate()) {
1641 DSSERR("failed to set up scaling, "
1642 "required fclk rate = %lu Hz, "
1643 "current fclk rate = %lu Hz\n",
1644 fclk, dispc_fclk_rate());
1645 return -EINVAL;
1646 }
1647 }
1648
1649 if (ilace && !fieldmode) {
1650 /*
1651 * when downscaling the bottom field may have to start several
1652 * source lines below the top field. Unfortunately ACCUI
1653 * registers will only hold the fractional part of the offset
1654 * so the integer part must be added to the base address of the
1655 * bottom field.
1656 */
1657 if (!height || height == out_height)
1658 field_offset = 0;
1659 else
1660 field_offset = height / out_height / 2;
1661 }
1662
1663 /* Fields are independent but interleaved in memory. */
1664 if (fieldmode)
1665 field_offset = 1;
1666
1667 if (rotation_type == OMAP_DSS_ROT_DMA)
1668 calc_dma_rotation_offset(rotation, mirror,
1669 screen_width, width, frame_height, color_mode,
1670 fieldmode, field_offset,
1671 &offset0, &offset1, &row_inc, &pix_inc);
1672 else
1673 calc_vrfb_rotation_offset(rotation, mirror,
1674 screen_width, width, frame_height, color_mode,
1675 fieldmode, field_offset,
1676 &offset0, &offset1, &row_inc, &pix_inc);
1677
1678 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
1679 offset0, offset1, row_inc, pix_inc);
1680
1681 _dispc_set_color_mode(plane, color_mode);
1682
1683 _dispc_set_plane_ba0(plane, paddr + offset0);
1684 _dispc_set_plane_ba1(plane, paddr + offset1);
1685
1686 _dispc_set_row_inc(plane, row_inc);
1687 _dispc_set_pix_inc(plane, pix_inc);
1688
1689 DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height,
1690 out_width, out_height);
1691
1692 _dispc_set_plane_pos(plane, pos_x, pos_y);
1693
1694 _dispc_set_pic_size(plane, width, height);
1695
1696 if (plane != OMAP_DSS_GFX) {
1697 _dispc_set_scaling(plane, width, height,
1698 out_width, out_height,
1699 ilace, five_taps, fieldmode);
1700 _dispc_set_vid_size(plane, out_width, out_height);
1701 _dispc_set_vid_color_conv(plane, cconv);
1702 }
1703
1704 _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
1705
1706 if (plane != OMAP_DSS_VIDEO1)
1707 _dispc_setup_global_alpha(plane, global_alpha);
1708
1709 return 0;
1710}
1711
1712static void _dispc_enable_plane(enum omap_plane plane, bool enable)
1713{
1714 REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 0, 0);
1715}
1716
1717static void dispc_disable_isr(void *data, u32 mask)
1718{
1719 struct completion *compl = data;
1720 complete(compl);
1721}
1722
1723static void _enable_lcd_out(bool enable)
1724{
1725 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
1726}
1727
1728static void dispc_enable_lcd_out(bool enable)
1729{
1730 struct completion frame_done_completion;
1731 bool is_on;
1732 int r;
1733
1734 enable_clocks(1);
1735
1736 /* When we disable LCD output, we need to wait until frame is done.
1737 * Otherwise the DSS is still working, and turning off the clocks
1738 * prevents DSS from going to OFF mode */
1739 is_on = REG_GET(DISPC_CONTROL, 0, 0);
1740
1741 if (!enable && is_on) {
1742 init_completion(&frame_done_completion);
1743
1744 r = omap_dispc_register_isr(dispc_disable_isr,
1745 &frame_done_completion,
1746 DISPC_IRQ_FRAMEDONE);
1747
1748 if (r)
1749 DSSERR("failed to register FRAMEDONE isr\n");
1750 }
1751
1752 _enable_lcd_out(enable);
1753
1754 if (!enable && is_on) {
1755 if (!wait_for_completion_timeout(&frame_done_completion,
1756 msecs_to_jiffies(100)))
1757 DSSERR("timeout waiting for FRAME DONE\n");
1758
1759 r = omap_dispc_unregister_isr(dispc_disable_isr,
1760 &frame_done_completion,
1761 DISPC_IRQ_FRAMEDONE);
1762
1763 if (r)
1764 DSSERR("failed to unregister FRAMEDONE isr\n");
1765 }
1766
1767 enable_clocks(0);
1768}
1769
1770static void _enable_digit_out(bool enable)
1771{
1772 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
1773}
1774
1775static void dispc_enable_digit_out(bool enable)
1776{
1777 struct completion frame_done_completion;
1778 int r;
1779
1780 enable_clocks(1);
1781
1782 if (REG_GET(DISPC_CONTROL, 1, 1) == enable) {
1783 enable_clocks(0);
1784 return;
1785 }
1786
1787 if (enable) {
1788 unsigned long flags;
1789 /* When we enable digit output, we'll get an extra digit
1790 * sync lost interrupt, that we need to ignore */
1791 spin_lock_irqsave(&dispc.irq_lock, flags);
1792 dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
1793 _omap_dispc_set_irqs();
1794 spin_unlock_irqrestore(&dispc.irq_lock, flags);
1795 }
1796
1797 /* When we disable digit output, we need to wait until fields are done.
1798 * Otherwise the DSS is still working, and turning off the clocks
1799 * prevents DSS from going to OFF mode. And when enabling, we need to
1800 * wait for the extra sync losts */
1801 init_completion(&frame_done_completion);
1802
1803 r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion,
1804 DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
1805 if (r)
1806 DSSERR("failed to register EVSYNC isr\n");
1807
1808 _enable_digit_out(enable);
1809
1810 /* XXX I understand from TRM that we should only wait for the
1811 * current field to complete. But it seems we have to wait
1812 * for both fields */
1813 if (!wait_for_completion_timeout(&frame_done_completion,
1814 msecs_to_jiffies(100)))
1815 DSSERR("timeout waiting for EVSYNC\n");
1816
1817 if (!wait_for_completion_timeout(&frame_done_completion,
1818 msecs_to_jiffies(100)))
1819 DSSERR("timeout waiting for EVSYNC\n");
1820
1821 r = omap_dispc_unregister_isr(dispc_disable_isr,
1822 &frame_done_completion,
1823 DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
1824 if (r)
1825 DSSERR("failed to unregister EVSYNC isr\n");
1826
1827 if (enable) {
1828 unsigned long flags;
1829 spin_lock_irqsave(&dispc.irq_lock, flags);
1830 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
1831 dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
1832 _omap_dispc_set_irqs();
1833 spin_unlock_irqrestore(&dispc.irq_lock, flags);
1834 }
1835
1836 enable_clocks(0);
1837}
1838
1839bool dispc_is_channel_enabled(enum omap_channel channel)
1840{
1841 if (channel == OMAP_DSS_CHANNEL_LCD)
1842 return !!REG_GET(DISPC_CONTROL, 0, 0);
1843 else if (channel == OMAP_DSS_CHANNEL_DIGIT)
1844 return !!REG_GET(DISPC_CONTROL, 1, 1);
1845 else
1846 BUG();
1847}
1848
1849void dispc_enable_channel(enum omap_channel channel, bool enable)
1850{
1851 if (channel == OMAP_DSS_CHANNEL_LCD)
1852 dispc_enable_lcd_out(enable);
1853 else if (channel == OMAP_DSS_CHANNEL_DIGIT)
1854 dispc_enable_digit_out(enable);
1855 else
1856 BUG();
1857}
1858
1859void dispc_lcd_enable_signal_polarity(bool act_high)
1860{
1861 enable_clocks(1);
1862 REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
1863 enable_clocks(0);
1864}
1865
1866void dispc_lcd_enable_signal(bool enable)
1867{
1868 enable_clocks(1);
1869 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
1870 enable_clocks(0);
1871}
1872
1873void dispc_pck_free_enable(bool enable)
1874{
1875 enable_clocks(1);
1876 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
1877 enable_clocks(0);
1878}
1879
1880void dispc_enable_fifohandcheck(bool enable)
1881{
1882 enable_clocks(1);
1883 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
1884 enable_clocks(0);
1885}
1886
1887
1888void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
1889{
1890 int mode;
1891
1892 switch (type) {
1893 case OMAP_DSS_LCD_DISPLAY_STN:
1894 mode = 0;
1895 break;
1896
1897 case OMAP_DSS_LCD_DISPLAY_TFT:
1898 mode = 1;
1899 break;
1900
1901 default:
1902 BUG();
1903 return;
1904 }
1905
1906 enable_clocks(1);
1907 REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
1908 enable_clocks(0);
1909}
1910
1911void dispc_set_loadmode(enum omap_dss_load_mode mode)
1912{
1913 enable_clocks(1);
1914 REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
1915 enable_clocks(0);
1916}
1917
1918
1919void dispc_set_default_color(enum omap_channel channel, u32 color)
1920{
1921 const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1922 DISPC_DEFAULT_COLOR1 };
1923
1924 enable_clocks(1);
1925 dispc_write_reg(def_reg[channel], color);
1926 enable_clocks(0);
1927}
1928
1929u32 dispc_get_default_color(enum omap_channel channel)
1930{
1931 const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1932 DISPC_DEFAULT_COLOR1 };
1933 u32 l;
1934
1935 BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
1936 channel != OMAP_DSS_CHANNEL_LCD);
1937
1938 enable_clocks(1);
1939 l = dispc_read_reg(def_reg[channel]);
1940 enable_clocks(0);
1941
1942 return l;
1943}
1944
1945void dispc_set_trans_key(enum omap_channel ch,
1946 enum omap_dss_trans_key_type type,
1947 u32 trans_key)
1948{
1949 const struct dispc_reg tr_reg[] = {
1950 DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1951
1952 enable_clocks(1);
1953 if (ch == OMAP_DSS_CHANNEL_LCD)
1954 REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
1955 else /* OMAP_DSS_CHANNEL_DIGIT */
1956 REG_FLD_MOD(DISPC_CONFIG, type, 13, 13);
1957
1958 dispc_write_reg(tr_reg[ch], trans_key);
1959 enable_clocks(0);
1960}
1961
1962void dispc_get_trans_key(enum omap_channel ch,
1963 enum omap_dss_trans_key_type *type,
1964 u32 *trans_key)
1965{
1966 const struct dispc_reg tr_reg[] = {
1967 DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1968
1969 enable_clocks(1);
1970 if (type) {
1971 if (ch == OMAP_DSS_CHANNEL_LCD)
1972 *type = REG_GET(DISPC_CONFIG, 11, 11);
1973 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
1974 *type = REG_GET(DISPC_CONFIG, 13, 13);
1975 else
1976 BUG();
1977 }
1978
1979 if (trans_key)
1980 *trans_key = dispc_read_reg(tr_reg[ch]);
1981 enable_clocks(0);
1982}
1983
1984void dispc_enable_trans_key(enum omap_channel ch, bool enable)
1985{
1986 enable_clocks(1);
1987 if (ch == OMAP_DSS_CHANNEL_LCD)
1988 REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
1989 else /* OMAP_DSS_CHANNEL_DIGIT */
1990 REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
1991 enable_clocks(0);
1992}
1993void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
1994{
1995 if (cpu_is_omap24xx())
1996 return;
1997
1998 enable_clocks(1);
1999 if (ch == OMAP_DSS_CHANNEL_LCD)
2000 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
2001 else /* OMAP_DSS_CHANNEL_DIGIT */
2002 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
2003 enable_clocks(0);
2004}
2005bool dispc_alpha_blending_enabled(enum omap_channel ch)
2006{
2007 bool enabled;
2008
2009 if (cpu_is_omap24xx())
2010 return false;
2011
2012 enable_clocks(1);
2013 if (ch == OMAP_DSS_CHANNEL_LCD)
2014 enabled = REG_GET(DISPC_CONFIG, 18, 18);
2015 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2016 enabled = REG_GET(DISPC_CONFIG, 18, 18);
2017 else
2018 BUG();
2019 enable_clocks(0);
2020
2021 return enabled;
2022
2023}
2024
2025
2026bool dispc_trans_key_enabled(enum omap_channel ch)
2027{
2028 bool enabled;
2029
2030 enable_clocks(1);
2031 if (ch == OMAP_DSS_CHANNEL_LCD)
2032 enabled = REG_GET(DISPC_CONFIG, 10, 10);
2033 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2034 enabled = REG_GET(DISPC_CONFIG, 12, 12);
2035 else
2036 BUG();
2037 enable_clocks(0);
2038
2039 return enabled;
2040}
2041
2042
2043void dispc_set_tft_data_lines(u8 data_lines)
2044{
2045 int code;
2046
2047 switch (data_lines) {
2048 case 12:
2049 code = 0;
2050 break;
2051 case 16:
2052 code = 1;
2053 break;
2054 case 18:
2055 code = 2;
2056 break;
2057 case 24:
2058 code = 3;
2059 break;
2060 default:
2061 BUG();
2062 return;
2063 }
2064
2065 enable_clocks(1);
2066 REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
2067 enable_clocks(0);
2068}
2069
2070void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
2071{
2072 u32 l;
2073 int stallmode;
2074 int gpout0 = 1;
2075 int gpout1;
2076
2077 switch (mode) {
2078 case OMAP_DSS_PARALLELMODE_BYPASS:
2079 stallmode = 0;
2080 gpout1 = 1;
2081 break;
2082
2083 case OMAP_DSS_PARALLELMODE_RFBI:
2084 stallmode = 1;
2085 gpout1 = 0;
2086 break;
2087
2088 case OMAP_DSS_PARALLELMODE_DSI:
2089 stallmode = 1;
2090 gpout1 = 1;
2091 break;
2092
2093 default:
2094 BUG();
2095 return;
2096 }
2097
2098 enable_clocks(1);
2099
2100 l = dispc_read_reg(DISPC_CONTROL);
2101
2102 l = FLD_MOD(l, stallmode, 11, 11);
2103 l = FLD_MOD(l, gpout0, 15, 15);
2104 l = FLD_MOD(l, gpout1, 16, 16);
2105
2106 dispc_write_reg(DISPC_CONTROL, l);
2107
2108 enable_clocks(0);
2109}
2110
2111static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
2112 int vsw, int vfp, int vbp)
2113{
2114 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2115 if (hsw < 1 || hsw > 64 ||
2116 hfp < 1 || hfp > 256 ||
2117 hbp < 1 || hbp > 256 ||
2118 vsw < 1 || vsw > 64 ||
2119 vfp < 0 || vfp > 255 ||
2120 vbp < 0 || vbp > 255)
2121 return false;
2122 } else {
2123 if (hsw < 1 || hsw > 256 ||
2124 hfp < 1 || hfp > 4096 ||
2125 hbp < 1 || hbp > 4096 ||
2126 vsw < 1 || vsw > 256 ||
2127 vfp < 0 || vfp > 4095 ||
2128 vbp < 0 || vbp > 4095)
2129 return false;
2130 }
2131
2132 return true;
2133}
2134
2135bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
2136{
2137 return _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2138 timings->hbp, timings->vsw,
2139 timings->vfp, timings->vbp);
2140}
2141
2142static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
2143 int vsw, int vfp, int vbp)
2144{
2145 u32 timing_h, timing_v;
2146
2147 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2148 timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
2149 FLD_VAL(hbp-1, 27, 20);
2150
2151 timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
2152 FLD_VAL(vbp, 27, 20);
2153 } else {
2154 timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
2155 FLD_VAL(hbp-1, 31, 20);
2156
2157 timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
2158 FLD_VAL(vbp, 31, 20);
2159 }
2160
2161 enable_clocks(1);
2162 dispc_write_reg(DISPC_TIMING_H, timing_h);
2163 dispc_write_reg(DISPC_TIMING_V, timing_v);
2164 enable_clocks(0);
2165}
2166
2167/* change name to mode? */
2168void dispc_set_lcd_timings(struct omap_video_timings *timings)
2169{
2170 unsigned xtot, ytot;
2171 unsigned long ht, vt;
2172
2173 if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2174 timings->hbp, timings->vsw,
2175 timings->vfp, timings->vbp))
2176 BUG();
2177
2178 _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp,
2179 timings->vsw, timings->vfp, timings->vbp);
2180
2181 dispc_set_lcd_size(timings->x_res, timings->y_res);
2182
2183 xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
2184 ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
2185
2186 ht = (timings->pixel_clock * 1000) / xtot;
2187 vt = (timings->pixel_clock * 1000) / xtot / ytot;
2188
2189 DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res);
2190 DSSDBG("pck %u\n", timings->pixel_clock);
2191 DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
2192 timings->hsw, timings->hfp, timings->hbp,
2193 timings->vsw, timings->vfp, timings->vbp);
2194
2195 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
2196}
2197
2198static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div)
2199{
2200 BUG_ON(lck_div < 1);
2201 BUG_ON(pck_div < 2);
2202
2203 enable_clocks(1);
2204 dispc_write_reg(DISPC_DIVISOR,
2205 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
2206 enable_clocks(0);
2207}
2208
2209static void dispc_get_lcd_divisor(int *lck_div, int *pck_div)
2210{
2211 u32 l;
2212 l = dispc_read_reg(DISPC_DIVISOR);
2213 *lck_div = FLD_GET(l, 23, 16);
2214 *pck_div = FLD_GET(l, 7, 0);
2215}
2216
2217unsigned long dispc_fclk_rate(void)
2218{
2219 unsigned long r = 0;
2220
2221 if (dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK)
2222 r = dss_clk_get_rate(DSS_CLK_FCK1);
2223 else
2224#ifdef CONFIG_OMAP2_DSS_DSI
2225 r = dsi_get_dsi1_pll_rate();
2226#else
2227 BUG();
2228#endif
2229 return r;
2230}
2231
2232unsigned long dispc_lclk_rate(void)
2233{
2234 int lcd;
2235 unsigned long r;
2236 u32 l;
2237
2238 l = dispc_read_reg(DISPC_DIVISOR);
2239
2240 lcd = FLD_GET(l, 23, 16);
2241
2242 r = dispc_fclk_rate();
2243
2244 return r / lcd;
2245}
2246
2247unsigned long dispc_pclk_rate(void)
2248{
2249 int lcd, pcd;
2250 unsigned long r;
2251 u32 l;
2252
2253 l = dispc_read_reg(DISPC_DIVISOR);
2254
2255 lcd = FLD_GET(l, 23, 16);
2256 pcd = FLD_GET(l, 7, 0);
2257
2258 r = dispc_fclk_rate();
2259
2260 return r / lcd / pcd;
2261}
2262
2263void dispc_dump_clocks(struct seq_file *s)
2264{
2265 int lcd, pcd;
2266
2267 enable_clocks(1);
2268
2269 dispc_get_lcd_divisor(&lcd, &pcd);
2270
2271 seq_printf(s, "- DISPC -\n");
2272
2273 seq_printf(s, "dispc fclk source = %s\n",
2274 dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
2275 "dss1_alwon_fclk" : "dsi1_pll_fclk");
2276
2277 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
2278 seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd);
2279 seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd);
2280
2281 enable_clocks(0);
2282}
2283
2284#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2285void dispc_dump_irqs(struct seq_file *s)
2286{
2287 unsigned long flags;
2288 struct dispc_irq_stats stats;
2289
2290 spin_lock_irqsave(&dispc.irq_stats_lock, flags);
2291
2292 stats = dispc.irq_stats;
2293 memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats));
2294 dispc.irq_stats.last_reset = jiffies;
2295
2296 spin_unlock_irqrestore(&dispc.irq_stats_lock, flags);
2297
2298 seq_printf(s, "period %u ms\n",
2299 jiffies_to_msecs(jiffies - stats.last_reset));
2300
2301 seq_printf(s, "irqs %d\n", stats.irq_count);
2302#define PIS(x) \
2303 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
2304
2305 PIS(FRAMEDONE);
2306 PIS(VSYNC);
2307 PIS(EVSYNC_EVEN);
2308 PIS(EVSYNC_ODD);
2309 PIS(ACBIAS_COUNT_STAT);
2310 PIS(PROG_LINE_NUM);
2311 PIS(GFX_FIFO_UNDERFLOW);
2312 PIS(GFX_END_WIN);
2313 PIS(PAL_GAMMA_MASK);
2314 PIS(OCP_ERR);
2315 PIS(VID1_FIFO_UNDERFLOW);
2316 PIS(VID1_END_WIN);
2317 PIS(VID2_FIFO_UNDERFLOW);
2318 PIS(VID2_END_WIN);
2319 PIS(SYNC_LOST);
2320 PIS(SYNC_LOST_DIGIT);
2321 PIS(WAKEUP);
2322#undef PIS
2323}
2324#endif
2325
2326void dispc_dump_regs(struct seq_file *s)
2327{
2328#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
2329
2330 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
2331
2332 DUMPREG(DISPC_REVISION);
2333 DUMPREG(DISPC_SYSCONFIG);
2334 DUMPREG(DISPC_SYSSTATUS);
2335 DUMPREG(DISPC_IRQSTATUS);
2336 DUMPREG(DISPC_IRQENABLE);
2337 DUMPREG(DISPC_CONTROL);
2338 DUMPREG(DISPC_CONFIG);
2339 DUMPREG(DISPC_CAPABLE);
2340 DUMPREG(DISPC_DEFAULT_COLOR0);
2341 DUMPREG(DISPC_DEFAULT_COLOR1);
2342 DUMPREG(DISPC_TRANS_COLOR0);
2343 DUMPREG(DISPC_TRANS_COLOR1);
2344 DUMPREG(DISPC_LINE_STATUS);
2345 DUMPREG(DISPC_LINE_NUMBER);
2346 DUMPREG(DISPC_TIMING_H);
2347 DUMPREG(DISPC_TIMING_V);
2348 DUMPREG(DISPC_POL_FREQ);
2349 DUMPREG(DISPC_DIVISOR);
2350 DUMPREG(DISPC_GLOBAL_ALPHA);
2351 DUMPREG(DISPC_SIZE_DIG);
2352 DUMPREG(DISPC_SIZE_LCD);
2353
2354 DUMPREG(DISPC_GFX_BA0);
2355 DUMPREG(DISPC_GFX_BA1);
2356 DUMPREG(DISPC_GFX_POSITION);
2357 DUMPREG(DISPC_GFX_SIZE);
2358 DUMPREG(DISPC_GFX_ATTRIBUTES);
2359 DUMPREG(DISPC_GFX_FIFO_THRESHOLD);
2360 DUMPREG(DISPC_GFX_FIFO_SIZE_STATUS);
2361 DUMPREG(DISPC_GFX_ROW_INC);
2362 DUMPREG(DISPC_GFX_PIXEL_INC);
2363 DUMPREG(DISPC_GFX_WINDOW_SKIP);
2364 DUMPREG(DISPC_GFX_TABLE_BA);
2365
2366 DUMPREG(DISPC_DATA_CYCLE1);
2367 DUMPREG(DISPC_DATA_CYCLE2);
2368 DUMPREG(DISPC_DATA_CYCLE3);
2369
2370 DUMPREG(DISPC_CPR_COEF_R);
2371 DUMPREG(DISPC_CPR_COEF_G);
2372 DUMPREG(DISPC_CPR_COEF_B);
2373
2374 DUMPREG(DISPC_GFX_PRELOAD);
2375
2376 DUMPREG(DISPC_VID_BA0(0));
2377 DUMPREG(DISPC_VID_BA1(0));
2378 DUMPREG(DISPC_VID_POSITION(0));
2379 DUMPREG(DISPC_VID_SIZE(0));
2380 DUMPREG(DISPC_VID_ATTRIBUTES(0));
2381 DUMPREG(DISPC_VID_FIFO_THRESHOLD(0));
2382 DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(0));
2383 DUMPREG(DISPC_VID_ROW_INC(0));
2384 DUMPREG(DISPC_VID_PIXEL_INC(0));
2385 DUMPREG(DISPC_VID_FIR(0));
2386 DUMPREG(DISPC_VID_PICTURE_SIZE(0));
2387 DUMPREG(DISPC_VID_ACCU0(0));
2388 DUMPREG(DISPC_VID_ACCU1(0));
2389
2390 DUMPREG(DISPC_VID_BA0(1));
2391 DUMPREG(DISPC_VID_BA1(1));
2392 DUMPREG(DISPC_VID_POSITION(1));
2393 DUMPREG(DISPC_VID_SIZE(1));
2394 DUMPREG(DISPC_VID_ATTRIBUTES(1));
2395 DUMPREG(DISPC_VID_FIFO_THRESHOLD(1));
2396 DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(1));
2397 DUMPREG(DISPC_VID_ROW_INC(1));
2398 DUMPREG(DISPC_VID_PIXEL_INC(1));
2399 DUMPREG(DISPC_VID_FIR(1));
2400 DUMPREG(DISPC_VID_PICTURE_SIZE(1));
2401 DUMPREG(DISPC_VID_ACCU0(1));
2402 DUMPREG(DISPC_VID_ACCU1(1));
2403
2404 DUMPREG(DISPC_VID_FIR_COEF_H(0, 0));
2405 DUMPREG(DISPC_VID_FIR_COEF_H(0, 1));
2406 DUMPREG(DISPC_VID_FIR_COEF_H(0, 2));
2407 DUMPREG(DISPC_VID_FIR_COEF_H(0, 3));
2408 DUMPREG(DISPC_VID_FIR_COEF_H(0, 4));
2409 DUMPREG(DISPC_VID_FIR_COEF_H(0, 5));
2410 DUMPREG(DISPC_VID_FIR_COEF_H(0, 6));
2411 DUMPREG(DISPC_VID_FIR_COEF_H(0, 7));
2412 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 0));
2413 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 1));
2414 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 2));
2415 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 3));
2416 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 4));
2417 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 5));
2418 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 6));
2419 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 7));
2420 DUMPREG(DISPC_VID_CONV_COEF(0, 0));
2421 DUMPREG(DISPC_VID_CONV_COEF(0, 1));
2422 DUMPREG(DISPC_VID_CONV_COEF(0, 2));
2423 DUMPREG(DISPC_VID_CONV_COEF(0, 3));
2424 DUMPREG(DISPC_VID_CONV_COEF(0, 4));
2425 DUMPREG(DISPC_VID_FIR_COEF_V(0, 0));
2426 DUMPREG(DISPC_VID_FIR_COEF_V(0, 1));
2427 DUMPREG(DISPC_VID_FIR_COEF_V(0, 2));
2428 DUMPREG(DISPC_VID_FIR_COEF_V(0, 3));
2429 DUMPREG(DISPC_VID_FIR_COEF_V(0, 4));
2430 DUMPREG(DISPC_VID_FIR_COEF_V(0, 5));
2431 DUMPREG(DISPC_VID_FIR_COEF_V(0, 6));
2432 DUMPREG(DISPC_VID_FIR_COEF_V(0, 7));
2433
2434 DUMPREG(DISPC_VID_FIR_COEF_H(1, 0));
2435 DUMPREG(DISPC_VID_FIR_COEF_H(1, 1));
2436 DUMPREG(DISPC_VID_FIR_COEF_H(1, 2));
2437 DUMPREG(DISPC_VID_FIR_COEF_H(1, 3));
2438 DUMPREG(DISPC_VID_FIR_COEF_H(1, 4));
2439 DUMPREG(DISPC_VID_FIR_COEF_H(1, 5));
2440 DUMPREG(DISPC_VID_FIR_COEF_H(1, 6));
2441 DUMPREG(DISPC_VID_FIR_COEF_H(1, 7));
2442 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 0));
2443 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 1));
2444 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 2));
2445 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 3));
2446 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 4));
2447 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 5));
2448 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 6));
2449 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 7));
2450 DUMPREG(DISPC_VID_CONV_COEF(1, 0));
2451 DUMPREG(DISPC_VID_CONV_COEF(1, 1));
2452 DUMPREG(DISPC_VID_CONV_COEF(1, 2));
2453 DUMPREG(DISPC_VID_CONV_COEF(1, 3));
2454 DUMPREG(DISPC_VID_CONV_COEF(1, 4));
2455 DUMPREG(DISPC_VID_FIR_COEF_V(1, 0));
2456 DUMPREG(DISPC_VID_FIR_COEF_V(1, 1));
2457 DUMPREG(DISPC_VID_FIR_COEF_V(1, 2));
2458 DUMPREG(DISPC_VID_FIR_COEF_V(1, 3));
2459 DUMPREG(DISPC_VID_FIR_COEF_V(1, 4));
2460 DUMPREG(DISPC_VID_FIR_COEF_V(1, 5));
2461 DUMPREG(DISPC_VID_FIR_COEF_V(1, 6));
2462 DUMPREG(DISPC_VID_FIR_COEF_V(1, 7));
2463
2464 DUMPREG(DISPC_VID_PRELOAD(0));
2465 DUMPREG(DISPC_VID_PRELOAD(1));
2466
2467 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
2468#undef DUMPREG
2469}
2470
2471static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
2472 bool ihs, bool ivs, u8 acbi, u8 acb)
2473{
2474 u32 l = 0;
2475
2476 DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n",
2477 onoff, rf, ieo, ipc, ihs, ivs, acbi, acb);
2478
2479 l |= FLD_VAL(onoff, 17, 17);
2480 l |= FLD_VAL(rf, 16, 16);
2481 l |= FLD_VAL(ieo, 15, 15);
2482 l |= FLD_VAL(ipc, 14, 14);
2483 l |= FLD_VAL(ihs, 13, 13);
2484 l |= FLD_VAL(ivs, 12, 12);
2485 l |= FLD_VAL(acbi, 11, 8);
2486 l |= FLD_VAL(acb, 7, 0);
2487
2488 enable_clocks(1);
2489 dispc_write_reg(DISPC_POL_FREQ, l);
2490 enable_clocks(0);
2491}
2492
2493void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb)
2494{
2495 _dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0,
2496 (config & OMAP_DSS_LCD_RF) != 0,
2497 (config & OMAP_DSS_LCD_IEO) != 0,
2498 (config & OMAP_DSS_LCD_IPC) != 0,
2499 (config & OMAP_DSS_LCD_IHS) != 0,
2500 (config & OMAP_DSS_LCD_IVS) != 0,
2501 acbi, acb);
2502}
2503
2504/* with fck as input clock rate, find dispc dividers that produce req_pck */
2505void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
2506 struct dispc_clock_info *cinfo)
2507{
2508 u16 pcd_min = is_tft ? 2 : 3;
2509 unsigned long best_pck;
2510 u16 best_ld, cur_ld;
2511 u16 best_pd, cur_pd;
2512
2513 best_pck = 0;
2514 best_ld = 0;
2515 best_pd = 0;
2516
2517 for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
2518 unsigned long lck = fck / cur_ld;
2519
2520 for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) {
2521 unsigned long pck = lck / cur_pd;
2522 long old_delta = abs(best_pck - req_pck);
2523 long new_delta = abs(pck - req_pck);
2524
2525 if (best_pck == 0 || new_delta < old_delta) {
2526 best_pck = pck;
2527 best_ld = cur_ld;
2528 best_pd = cur_pd;
2529
2530 if (pck == req_pck)
2531 goto found;
2532 }
2533
2534 if (pck < req_pck)
2535 break;
2536 }
2537
2538 if (lck / pcd_min < req_pck)
2539 break;
2540 }
2541
2542found:
2543 cinfo->lck_div = best_ld;
2544 cinfo->pck_div = best_pd;
2545 cinfo->lck = fck / cinfo->lck_div;
2546 cinfo->pck = cinfo->lck / cinfo->pck_div;
2547}
2548
2549/* calculate clock rates using dividers in cinfo */
2550int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
2551 struct dispc_clock_info *cinfo)
2552{
2553 if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
2554 return -EINVAL;
2555 if (cinfo->pck_div < 2 || cinfo->pck_div > 255)
2556 return -EINVAL;
2557
2558 cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
2559 cinfo->pck = cinfo->lck / cinfo->pck_div;
2560
2561 return 0;
2562}
2563
2564int dispc_set_clock_div(struct dispc_clock_info *cinfo)
2565{
2566 DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
2567 DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
2568
2569 dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div);
2570
2571 return 0;
2572}
2573
2574int dispc_get_clock_div(struct dispc_clock_info *cinfo)
2575{
2576 unsigned long fck;
2577
2578 fck = dispc_fclk_rate();
2579
2580 cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
2581 cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
2582
2583 cinfo->lck = fck / cinfo->lck_div;
2584 cinfo->pck = cinfo->lck / cinfo->pck_div;
2585
2586 return 0;
2587}
2588
2589/* dispc.irq_lock has to be locked by the caller */
2590static void _omap_dispc_set_irqs(void)
2591{
2592 u32 mask;
2593 u32 old_mask;
2594 int i;
2595 struct omap_dispc_isr_data *isr_data;
2596
2597 mask = dispc.irq_error_mask;
2598
2599 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2600 isr_data = &dispc.registered_isr[i];
2601
2602 if (isr_data->isr == NULL)
2603 continue;
2604
2605 mask |= isr_data->mask;
2606 }
2607
2608 enable_clocks(1);
2609
2610 old_mask = dispc_read_reg(DISPC_IRQENABLE);
2611 /* clear the irqstatus for newly enabled irqs */
2612 dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
2613
2614 dispc_write_reg(DISPC_IRQENABLE, mask);
2615
2616 enable_clocks(0);
2617}
2618
2619int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2620{
2621 int i;
2622 int ret;
2623 unsigned long flags;
2624 struct omap_dispc_isr_data *isr_data;
2625
2626 if (isr == NULL)
2627 return -EINVAL;
2628
2629 spin_lock_irqsave(&dispc.irq_lock, flags);
2630
2631 /* check for duplicate entry */
2632 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2633 isr_data = &dispc.registered_isr[i];
2634 if (isr_data->isr == isr && isr_data->arg == arg &&
2635 isr_data->mask == mask) {
2636 ret = -EINVAL;
2637 goto err;
2638 }
2639 }
2640
2641 isr_data = NULL;
2642 ret = -EBUSY;
2643
2644 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2645 isr_data = &dispc.registered_isr[i];
2646
2647 if (isr_data->isr != NULL)
2648 continue;
2649
2650 isr_data->isr = isr;
2651 isr_data->arg = arg;
2652 isr_data->mask = mask;
2653 ret = 0;
2654
2655 break;
2656 }
2657
2658 _omap_dispc_set_irqs();
2659
2660 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2661
2662 return 0;
2663err:
2664 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2665
2666 return ret;
2667}
2668EXPORT_SYMBOL(omap_dispc_register_isr);
2669
2670int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2671{
2672 int i;
2673 unsigned long flags;
2674 int ret = -EINVAL;
2675 struct omap_dispc_isr_data *isr_data;
2676
2677 spin_lock_irqsave(&dispc.irq_lock, flags);
2678
2679 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2680 isr_data = &dispc.registered_isr[i];
2681 if (isr_data->isr != isr || isr_data->arg != arg ||
2682 isr_data->mask != mask)
2683 continue;
2684
2685 /* found the correct isr */
2686
2687 isr_data->isr = NULL;
2688 isr_data->arg = NULL;
2689 isr_data->mask = 0;
2690
2691 ret = 0;
2692 break;
2693 }
2694
2695 if (ret == 0)
2696 _omap_dispc_set_irqs();
2697
2698 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2699
2700 return ret;
2701}
2702EXPORT_SYMBOL(omap_dispc_unregister_isr);
2703
2704#ifdef DEBUG
2705static void print_irq_status(u32 status)
2706{
2707 if ((status & dispc.irq_error_mask) == 0)
2708 return;
2709
2710 printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status);
2711
2712#define PIS(x) \
2713 if (status & DISPC_IRQ_##x) \
2714 printk(#x " ");
2715 PIS(GFX_FIFO_UNDERFLOW);
2716 PIS(OCP_ERR);
2717 PIS(VID1_FIFO_UNDERFLOW);
2718 PIS(VID2_FIFO_UNDERFLOW);
2719 PIS(SYNC_LOST);
2720 PIS(SYNC_LOST_DIGIT);
2721#undef PIS
2722
2723 printk("\n");
2724}
2725#endif
2726
2727/* Called from dss.c. Note that we don't touch clocks here,
2728 * but we presume they are on because we got an IRQ. However,
2729 * an irq handler may turn the clocks off, so we may not have
2730 * clock later in the function. */
2731void dispc_irq_handler(void)
2732{
2733 int i;
2734 u32 irqstatus;
2735 u32 handledirqs = 0;
2736 u32 unhandled_errors;
2737 struct omap_dispc_isr_data *isr_data;
2738 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
2739
2740 spin_lock(&dispc.irq_lock);
2741
2742 irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
2743
2744#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2745 spin_lock(&dispc.irq_stats_lock);
2746 dispc.irq_stats.irq_count++;
2747 dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs);
2748 spin_unlock(&dispc.irq_stats_lock);
2749#endif
2750
2751#ifdef DEBUG
2752 if (dss_debug)
2753 print_irq_status(irqstatus);
2754#endif
2755 /* Ack the interrupt. Do it here before clocks are possibly turned
2756 * off */
2757 dispc_write_reg(DISPC_IRQSTATUS, irqstatus);
2758 /* flush posted write */
2759 dispc_read_reg(DISPC_IRQSTATUS);
2760
2761 /* make a copy and unlock, so that isrs can unregister
2762 * themselves */
2763 memcpy(registered_isr, dispc.registered_isr,
2764 sizeof(registered_isr));
2765
2766 spin_unlock(&dispc.irq_lock);
2767
2768 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2769 isr_data = &registered_isr[i];
2770
2771 if (!isr_data->isr)
2772 continue;
2773
2774 if (isr_data->mask & irqstatus) {
2775 isr_data->isr(isr_data->arg, irqstatus);
2776 handledirqs |= isr_data->mask;
2777 }
2778 }
2779
2780 spin_lock(&dispc.irq_lock);
2781
2782 unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
2783
2784 if (unhandled_errors) {
2785 dispc.error_irqs |= unhandled_errors;
2786
2787 dispc.irq_error_mask &= ~unhandled_errors;
2788 _omap_dispc_set_irqs();
2789
2790 schedule_work(&dispc.error_work);
2791 }
2792
2793 spin_unlock(&dispc.irq_lock);
2794}
2795
2796static void dispc_error_worker(struct work_struct *work)
2797{
2798 int i;
2799 u32 errors;
2800 unsigned long flags;
2801
2802 spin_lock_irqsave(&dispc.irq_lock, flags);
2803 errors = dispc.error_irqs;
2804 dispc.error_irqs = 0;
2805 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2806
2807 if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) {
2808 DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n");
2809 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2810 struct omap_overlay *ovl;
2811 ovl = omap_dss_get_overlay(i);
2812
2813 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2814 continue;
2815
2816 if (ovl->id == 0) {
2817 dispc_enable_plane(ovl->id, 0);
2818 dispc_go(ovl->manager->id);
2819 mdelay(50);
2820 break;
2821 }
2822 }
2823 }
2824
2825 if (errors & DISPC_IRQ_VID1_FIFO_UNDERFLOW) {
2826 DSSERR("VID1_FIFO_UNDERFLOW, disabling VID1\n");
2827 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2828 struct omap_overlay *ovl;
2829 ovl = omap_dss_get_overlay(i);
2830
2831 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2832 continue;
2833
2834 if (ovl->id == 1) {
2835 dispc_enable_plane(ovl->id, 0);
2836 dispc_go(ovl->manager->id);
2837 mdelay(50);
2838 break;
2839 }
2840 }
2841 }
2842
2843 if (errors & DISPC_IRQ_VID2_FIFO_UNDERFLOW) {
2844 DSSERR("VID2_FIFO_UNDERFLOW, disabling VID2\n");
2845 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2846 struct omap_overlay *ovl;
2847 ovl = omap_dss_get_overlay(i);
2848
2849 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2850 continue;
2851
2852 if (ovl->id == 2) {
2853 dispc_enable_plane(ovl->id, 0);
2854 dispc_go(ovl->manager->id);
2855 mdelay(50);
2856 break;
2857 }
2858 }
2859 }
2860
2861 if (errors & DISPC_IRQ_SYNC_LOST) {
2862 struct omap_overlay_manager *manager = NULL;
2863 bool enable = false;
2864
2865 DSSERR("SYNC_LOST, disabling LCD\n");
2866
2867 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2868 struct omap_overlay_manager *mgr;
2869 mgr = omap_dss_get_overlay_manager(i);
2870
2871 if (mgr->id == OMAP_DSS_CHANNEL_LCD) {
2872 manager = mgr;
2873 enable = mgr->device->state ==
2874 OMAP_DSS_DISPLAY_ACTIVE;
2875 mgr->device->driver->disable(mgr->device);
2876 break;
2877 }
2878 }
2879
2880 if (manager) {
2881 struct omap_dss_device *dssdev = manager->device;
2882 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2883 struct omap_overlay *ovl;
2884 ovl = omap_dss_get_overlay(i);
2885
2886 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2887 continue;
2888
2889 if (ovl->id != 0 && ovl->manager == manager)
2890 dispc_enable_plane(ovl->id, 0);
2891 }
2892
2893 dispc_go(manager->id);
2894 mdelay(50);
2895 if (enable)
2896 dssdev->driver->enable(dssdev);
2897 }
2898 }
2899
2900 if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) {
2901 struct omap_overlay_manager *manager = NULL;
2902 bool enable = false;
2903
2904 DSSERR("SYNC_LOST_DIGIT, disabling TV\n");
2905
2906 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2907 struct omap_overlay_manager *mgr;
2908 mgr = omap_dss_get_overlay_manager(i);
2909
2910 if (mgr->id == OMAP_DSS_CHANNEL_DIGIT) {
2911 manager = mgr;
2912 enable = mgr->device->state ==
2913 OMAP_DSS_DISPLAY_ACTIVE;
2914 mgr->device->driver->disable(mgr->device);
2915 break;
2916 }
2917 }
2918
2919 if (manager) {
2920 struct omap_dss_device *dssdev = manager->device;
2921 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2922 struct omap_overlay *ovl;
2923 ovl = omap_dss_get_overlay(i);
2924
2925 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2926 continue;
2927
2928 if (ovl->id != 0 && ovl->manager == manager)
2929 dispc_enable_plane(ovl->id, 0);
2930 }
2931
2932 dispc_go(manager->id);
2933 mdelay(50);
2934 if (enable)
2935 dssdev->driver->enable(dssdev);
2936 }
2937 }
2938
2939 if (errors & DISPC_IRQ_OCP_ERR) {
2940 DSSERR("OCP_ERR\n");
2941 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2942 struct omap_overlay_manager *mgr;
2943 mgr = omap_dss_get_overlay_manager(i);
2944
2945 if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC)
2946 mgr->device->driver->disable(mgr->device);
2947 }
2948 }
2949
2950 spin_lock_irqsave(&dispc.irq_lock, flags);
2951 dispc.irq_error_mask |= errors;
2952 _omap_dispc_set_irqs();
2953 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2954}
2955
2956int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
2957{
2958 void dispc_irq_wait_handler(void *data, u32 mask)
2959 {
2960 complete((struct completion *)data);
2961 }
2962
2963 int r;
2964 DECLARE_COMPLETION_ONSTACK(completion);
2965
2966 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2967 irqmask);
2968
2969 if (r)
2970 return r;
2971
2972 timeout = wait_for_completion_timeout(&completion, timeout);
2973
2974 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
2975
2976 if (timeout == 0)
2977 return -ETIMEDOUT;
2978
2979 if (timeout == -ERESTARTSYS)
2980 return -ERESTARTSYS;
2981
2982 return 0;
2983}
2984
2985int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
2986 unsigned long timeout)
2987{
2988 void dispc_irq_wait_handler(void *data, u32 mask)
2989 {
2990 complete((struct completion *)data);
2991 }
2992
2993 int r;
2994 DECLARE_COMPLETION_ONSTACK(completion);
2995
2996 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2997 irqmask);
2998
2999 if (r)
3000 return r;
3001
3002 timeout = wait_for_completion_interruptible_timeout(&completion,
3003 timeout);
3004
3005 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
3006
3007 if (timeout == 0)
3008 return -ETIMEDOUT;
3009
3010 if (timeout == -ERESTARTSYS)
3011 return -ERESTARTSYS;
3012
3013 return 0;
3014}
3015
3016#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
3017void dispc_fake_vsync_irq(void)
3018{
3019 u32 irqstatus = DISPC_IRQ_VSYNC;
3020 int i;
3021
3022 local_irq_disable();
3023
3024 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3025 struct omap_dispc_isr_data *isr_data;
3026 isr_data = &dispc.registered_isr[i];
3027
3028 if (!isr_data->isr)
3029 continue;
3030
3031 if (isr_data->mask & irqstatus)
3032 isr_data->isr(isr_data->arg, irqstatus);
3033 }
3034
3035 local_irq_enable();
3036}
3037#endif
3038
3039static void _omap_dispc_initialize_irq(void)
3040{
3041 unsigned long flags;
3042
3043 spin_lock_irqsave(&dispc.irq_lock, flags);
3044
3045 memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
3046
3047 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
3048
3049 /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
3050 * so clear it */
3051 dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS));
3052
3053 _omap_dispc_set_irqs();
3054
3055 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3056}
3057
3058void dispc_enable_sidle(void)
3059{
3060 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
3061}
3062
3063void dispc_disable_sidle(void)
3064{
3065 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
3066}
3067
3068static void _omap_dispc_initial_config(void)
3069{
3070 u32 l;
3071
3072 l = dispc_read_reg(DISPC_SYSCONFIG);
3073 l = FLD_MOD(l, 2, 13, 12); /* MIDLEMODE: smart standby */
3074 l = FLD_MOD(l, 2, 4, 3); /* SIDLEMODE: smart idle */
3075 l = FLD_MOD(l, 1, 2, 2); /* ENWAKEUP */
3076 l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */
3077 dispc_write_reg(DISPC_SYSCONFIG, l);
3078
3079 /* FUNCGATED */
3080 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
3081
3082 /* L3 firewall setting: enable access to OCM RAM */
3083 /* XXX this should be somewhere in plat-omap */
3084 if (cpu_is_omap24xx())
3085 __raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0));
3086
3087 _dispc_setup_color_conv_coef();
3088
3089 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3090
3091 dispc_read_plane_fifo_sizes();
3092}
3093
3094int dispc_init(void)
3095{
3096 u32 rev;
3097
3098 spin_lock_init(&dispc.irq_lock);
3099
3100#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3101 spin_lock_init(&dispc.irq_stats_lock);
3102 dispc.irq_stats.last_reset = jiffies;
3103#endif
3104
3105 INIT_WORK(&dispc.error_work, dispc_error_worker);
3106
3107 dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
3108 if (!dispc.base) {
3109 DSSERR("can't ioremap DISPC\n");
3110 return -ENOMEM;
3111 }
3112
3113 enable_clocks(1);
3114
3115 _omap_dispc_initial_config();
3116
3117 _omap_dispc_initialize_irq();
3118
3119 dispc_save_context();
3120
3121 rev = dispc_read_reg(DISPC_REVISION);
3122 printk(KERN_INFO "OMAP DISPC rev %d.%d\n",
3123 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
3124
3125 enable_clocks(0);
3126
3127 return 0;
3128}
3129
3130void dispc_exit(void)
3131{
3132 iounmap(dispc.base);
3133}
3134
3135int dispc_enable_plane(enum omap_plane plane, bool enable)
3136{
3137 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
3138
3139 enable_clocks(1);
3140 _dispc_enable_plane(plane, enable);
3141 enable_clocks(0);
3142
3143 return 0;
3144}
3145
3146int dispc_setup_plane(enum omap_plane plane,
3147 u32 paddr, u16 screen_width,
3148 u16 pos_x, u16 pos_y,
3149 u16 width, u16 height,
3150 u16 out_width, u16 out_height,
3151 enum omap_color_mode color_mode,
3152 bool ilace,
3153 enum omap_dss_rotation_type rotation_type,
3154 u8 rotation, bool mirror, u8 global_alpha)
3155{
3156 int r = 0;
3157
3158 DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
3159 "%dx%d, ilace %d, cmode %x, rot %d, mir %d\n",
3160 plane, paddr, screen_width, pos_x, pos_y,
3161 width, height,
3162 out_width, out_height,
3163 ilace, color_mode,
3164 rotation, mirror);
3165
3166 enable_clocks(1);
3167
3168 r = _dispc_setup_plane(plane,
3169 paddr, screen_width,
3170 pos_x, pos_y,
3171 width, height,
3172 out_width, out_height,
3173 color_mode, ilace,
3174 rotation_type,
3175 rotation, mirror,
3176 global_alpha);
3177
3178 enable_clocks(0);
3179
3180 return r;
3181}
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
new file mode 100644
index 000000000000..6a74ea116d29
--- /dev/null
+++ b/drivers/video/omap2/dss/display.c
@@ -0,0 +1,626 @@
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/list.h>
29#include <linux/platform_device.h>
30
31#include <plat/display.h>
32#include "dss.h"
33
34static LIST_HEAD(display_list);
35
36static ssize_t display_enabled_show(struct device *dev,
37 struct device_attribute *attr, char *buf)
38{
39 struct omap_dss_device *dssdev = to_dss_device(dev);
40 bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED;
41
42 return snprintf(buf, PAGE_SIZE, "%d\n", enabled);
43}
44
45static ssize_t display_enabled_store(struct device *dev,
46 struct device_attribute *attr,
47 const char *buf, size_t size)
48{
49 struct omap_dss_device *dssdev = to_dss_device(dev);
50 bool enabled, r;
51
52 enabled = simple_strtoul(buf, NULL, 10);
53
54 if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
55 if (enabled) {
56 r = dssdev->driver->enable(dssdev);
57 if (r)
58 return r;
59 } else {
60 dssdev->driver->disable(dssdev);
61 }
62 }
63
64 return size;
65}
66
67static ssize_t display_upd_mode_show(struct device *dev,
68 struct device_attribute *attr, char *buf)
69{
70 struct omap_dss_device *dssdev = to_dss_device(dev);
71 enum omap_dss_update_mode mode = OMAP_DSS_UPDATE_AUTO;
72 if (dssdev->driver->get_update_mode)
73 mode = dssdev->driver->get_update_mode(dssdev);
74 return snprintf(buf, PAGE_SIZE, "%d\n", mode);
75}
76
77static ssize_t display_upd_mode_store(struct device *dev,
78 struct device_attribute *attr,
79 const char *buf, size_t size)
80{
81 struct omap_dss_device *dssdev = to_dss_device(dev);
82 int val, r;
83 enum omap_dss_update_mode mode;
84
85 val = simple_strtoul(buf, NULL, 10);
86
87 switch (val) {
88 case OMAP_DSS_UPDATE_DISABLED:
89 case OMAP_DSS_UPDATE_AUTO:
90 case OMAP_DSS_UPDATE_MANUAL:
91 mode = (enum omap_dss_update_mode)val;
92 break;
93 default:
94 return -EINVAL;
95 }
96
97 r = dssdev->driver->set_update_mode(dssdev, mode);
98 if (r)
99 return r;
100
101 return size;
102}
103
104static ssize_t display_tear_show(struct device *dev,
105 struct device_attribute *attr, char *buf)
106{
107 struct omap_dss_device *dssdev = to_dss_device(dev);
108 return snprintf(buf, PAGE_SIZE, "%d\n",
109 dssdev->driver->get_te ?
110 dssdev->driver->get_te(dssdev) : 0);
111}
112
113static ssize_t display_tear_store(struct device *dev,
114 struct device_attribute *attr, const char *buf, size_t size)
115{
116 struct omap_dss_device *dssdev = to_dss_device(dev);
117 unsigned long te;
118 int r;
119
120 if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
121 return -ENOENT;
122
123 te = simple_strtoul(buf, NULL, 0);
124
125 r = dssdev->driver->enable_te(dssdev, te);
126 if (r)
127 return r;
128
129 return size;
130}
131
132static ssize_t display_timings_show(struct device *dev,
133 struct device_attribute *attr, char *buf)
134{
135 struct omap_dss_device *dssdev = to_dss_device(dev);
136 struct omap_video_timings t;
137
138 if (!dssdev->driver->get_timings)
139 return -ENOENT;
140
141 dssdev->driver->get_timings(dssdev, &t);
142
143 return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
144 t.pixel_clock,
145 t.x_res, t.hfp, t.hbp, t.hsw,
146 t.y_res, t.vfp, t.vbp, t.vsw);
147}
148
149static ssize_t display_timings_store(struct device *dev,
150 struct device_attribute *attr, const char *buf, size_t size)
151{
152 struct omap_dss_device *dssdev = to_dss_device(dev);
153 struct omap_video_timings t;
154 int r, found;
155
156 if (!dssdev->driver->set_timings || !dssdev->driver->check_timings)
157 return -ENOENT;
158
159 found = 0;
160#ifdef CONFIG_OMAP2_DSS_VENC
161 if (strncmp("pal", buf, 3) == 0) {
162 t = omap_dss_pal_timings;
163 found = 1;
164 } else if (strncmp("ntsc", buf, 4) == 0) {
165 t = omap_dss_ntsc_timings;
166 found = 1;
167 }
168#endif
169 if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
170 &t.pixel_clock,
171 &t.x_res, &t.hfp, &t.hbp, &t.hsw,
172 &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
173 return -EINVAL;
174
175 r = dssdev->driver->check_timings(dssdev, &t);
176 if (r)
177 return r;
178
179 dssdev->driver->set_timings(dssdev, &t);
180
181 return size;
182}
183
184static ssize_t display_rotate_show(struct device *dev,
185 struct device_attribute *attr, char *buf)
186{
187 struct omap_dss_device *dssdev = to_dss_device(dev);
188 int rotate;
189 if (!dssdev->driver->get_rotate)
190 return -ENOENT;
191 rotate = dssdev->driver->get_rotate(dssdev);
192 return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
193}
194
195static ssize_t display_rotate_store(struct device *dev,
196 struct device_attribute *attr, const char *buf, size_t size)
197{
198 struct omap_dss_device *dssdev = to_dss_device(dev);
199 unsigned long rot;
200 int r;
201
202 if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
203 return -ENOENT;
204
205 rot = simple_strtoul(buf, NULL, 0);
206
207 r = dssdev->driver->set_rotate(dssdev, rot);
208 if (r)
209 return r;
210
211 return size;
212}
213
214static ssize_t display_mirror_show(struct device *dev,
215 struct device_attribute *attr, char *buf)
216{
217 struct omap_dss_device *dssdev = to_dss_device(dev);
218 int mirror;
219 if (!dssdev->driver->get_mirror)
220 return -ENOENT;
221 mirror = dssdev->driver->get_mirror(dssdev);
222 return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
223}
224
225static ssize_t display_mirror_store(struct device *dev,
226 struct device_attribute *attr, const char *buf, size_t size)
227{
228 struct omap_dss_device *dssdev = to_dss_device(dev);
229 unsigned long mirror;
230 int r;
231
232 if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
233 return -ENOENT;
234
235 mirror = simple_strtoul(buf, NULL, 0);
236
237 r = dssdev->driver->set_mirror(dssdev, mirror);
238 if (r)
239 return r;
240
241 return size;
242}
243
244static ssize_t display_wss_show(struct device *dev,
245 struct device_attribute *attr, char *buf)
246{
247 struct omap_dss_device *dssdev = to_dss_device(dev);
248 unsigned int wss;
249
250 if (!dssdev->driver->get_wss)
251 return -ENOENT;
252
253 wss = dssdev->driver->get_wss(dssdev);
254
255 return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
256}
257
258static ssize_t display_wss_store(struct device *dev,
259 struct device_attribute *attr, const char *buf, size_t size)
260{
261 struct omap_dss_device *dssdev = to_dss_device(dev);
262 unsigned long wss;
263 int r;
264
265 if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
266 return -ENOENT;
267
268 if (strict_strtoul(buf, 0, &wss))
269 return -EINVAL;
270
271 if (wss > 0xfffff)
272 return -EINVAL;
273
274 r = dssdev->driver->set_wss(dssdev, wss);
275 if (r)
276 return r;
277
278 return size;
279}
280
281static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
282 display_enabled_show, display_enabled_store);
283static DEVICE_ATTR(update_mode, S_IRUGO|S_IWUSR,
284 display_upd_mode_show, display_upd_mode_store);
285static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
286 display_tear_show, display_tear_store);
287static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
288 display_timings_show, display_timings_store);
289static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
290 display_rotate_show, display_rotate_store);
291static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
292 display_mirror_show, display_mirror_store);
293static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
294 display_wss_show, display_wss_store);
295
296static struct device_attribute *display_sysfs_attrs[] = {
297 &dev_attr_enabled,
298 &dev_attr_update_mode,
299 &dev_attr_tear_elim,
300 &dev_attr_timings,
301 &dev_attr_rotate,
302 &dev_attr_mirror,
303 &dev_attr_wss,
304 NULL
305};
306
307void omapdss_default_get_resolution(struct omap_dss_device *dssdev,
308 u16 *xres, u16 *yres)
309{
310 *xres = dssdev->panel.timings.x_res;
311 *yres = dssdev->panel.timings.y_res;
312}
313EXPORT_SYMBOL(omapdss_default_get_resolution);
314
315void default_get_overlay_fifo_thresholds(enum omap_plane plane,
316 u32 fifo_size, enum omap_burst_size *burst_size,
317 u32 *fifo_low, u32 *fifo_high)
318{
319 unsigned burst_size_bytes;
320
321 *burst_size = OMAP_DSS_BURST_16x32;
322 burst_size_bytes = 16 * 32 / 8;
323
324 *fifo_high = fifo_size - 1;
325 *fifo_low = fifo_size - burst_size_bytes;
326}
327
328int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
329{
330 switch (dssdev->type) {
331 case OMAP_DISPLAY_TYPE_DPI:
332 if (dssdev->phy.dpi.data_lines == 24)
333 return 24;
334 else
335 return 16;
336
337 case OMAP_DISPLAY_TYPE_DBI:
338 case OMAP_DISPLAY_TYPE_DSI:
339 if (dssdev->ctrl.pixel_size == 24)
340 return 24;
341 else
342 return 16;
343 case OMAP_DISPLAY_TYPE_VENC:
344 case OMAP_DISPLAY_TYPE_SDI:
345 return 24;
346 return 24;
347 default:
348 BUG();
349 }
350}
351EXPORT_SYMBOL(omapdss_default_get_recommended_bpp);
352
353/* Checks if replication logic should be used. Only use for active matrix,
354 * when overlay is in RGB12U or RGB16 mode, and LCD interface is
355 * 18bpp or 24bpp */
356bool dss_use_replication(struct omap_dss_device *dssdev,
357 enum omap_color_mode mode)
358{
359 int bpp;
360
361 if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
362 return false;
363
364 if (dssdev->type == OMAP_DISPLAY_TYPE_DPI &&
365 (dssdev->panel.config & OMAP_DSS_LCD_TFT) == 0)
366 return false;
367
368 switch (dssdev->type) {
369 case OMAP_DISPLAY_TYPE_DPI:
370 bpp = dssdev->phy.dpi.data_lines;
371 break;
372 case OMAP_DISPLAY_TYPE_VENC:
373 case OMAP_DISPLAY_TYPE_SDI:
374 bpp = 24;
375 break;
376 case OMAP_DISPLAY_TYPE_DBI:
377 case OMAP_DISPLAY_TYPE_DSI:
378 bpp = dssdev->ctrl.pixel_size;
379 break;
380 default:
381 BUG();
382 }
383
384 return bpp > 16;
385}
386
387void dss_init_device(struct platform_device *pdev,
388 struct omap_dss_device *dssdev)
389{
390 struct device_attribute *attr;
391 int i;
392 int r;
393
394 switch (dssdev->type) {
395 case OMAP_DISPLAY_TYPE_DPI:
396#ifdef CONFIG_OMAP2_DSS_RFBI
397 case OMAP_DISPLAY_TYPE_DBI:
398#endif
399#ifdef CONFIG_OMAP2_DSS_SDI
400 case OMAP_DISPLAY_TYPE_SDI:
401#endif
402#ifdef CONFIG_OMAP2_DSS_DSI
403 case OMAP_DISPLAY_TYPE_DSI:
404#endif
405#ifdef CONFIG_OMAP2_DSS_VENC
406 case OMAP_DISPLAY_TYPE_VENC:
407#endif
408 break;
409 default:
410 DSSERR("Support for display '%s' not compiled in.\n",
411 dssdev->name);
412 return;
413 }
414
415 switch (dssdev->type) {
416 case OMAP_DISPLAY_TYPE_DPI:
417 r = dpi_init_display(dssdev);
418 break;
419#ifdef CONFIG_OMAP2_DSS_RFBI
420 case OMAP_DISPLAY_TYPE_DBI:
421 r = rfbi_init_display(dssdev);
422 break;
423#endif
424#ifdef CONFIG_OMAP2_DSS_VENC
425 case OMAP_DISPLAY_TYPE_VENC:
426 r = venc_init_display(dssdev);
427 break;
428#endif
429#ifdef CONFIG_OMAP2_DSS_SDI
430 case OMAP_DISPLAY_TYPE_SDI:
431 r = sdi_init_display(dssdev);
432 break;
433#endif
434#ifdef CONFIG_OMAP2_DSS_DSI
435 case OMAP_DISPLAY_TYPE_DSI:
436 r = dsi_init_display(dssdev);
437 break;
438#endif
439 default:
440 BUG();
441 }
442
443 if (r) {
444 DSSERR("failed to init display %s\n", dssdev->name);
445 return;
446 }
447
448 /* create device sysfs files */
449 i = 0;
450 while ((attr = display_sysfs_attrs[i++]) != NULL) {
451 r = device_create_file(&dssdev->dev, attr);
452 if (r)
453 DSSERR("failed to create sysfs file\n");
454 }
455
456 /* create display? sysfs links */
457 r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
458 dev_name(&dssdev->dev));
459 if (r)
460 DSSERR("failed to create sysfs display link\n");
461}
462
463void dss_uninit_device(struct platform_device *pdev,
464 struct omap_dss_device *dssdev)
465{
466 struct device_attribute *attr;
467 int i = 0;
468
469 sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev));
470
471 while ((attr = display_sysfs_attrs[i++]) != NULL)
472 device_remove_file(&dssdev->dev, attr);
473
474 if (dssdev->manager)
475 dssdev->manager->unset_device(dssdev->manager);
476}
477
478static int dss_suspend_device(struct device *dev, void *data)
479{
480 int r;
481 struct omap_dss_device *dssdev = to_dss_device(dev);
482
483 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
484 dssdev->activate_after_resume = false;
485 return 0;
486 }
487
488 if (!dssdev->driver->suspend) {
489 DSSERR("display '%s' doesn't implement suspend\n",
490 dssdev->name);
491 return -ENOSYS;
492 }
493
494 r = dssdev->driver->suspend(dssdev);
495 if (r)
496 return r;
497
498 dssdev->activate_after_resume = true;
499
500 return 0;
501}
502
503int dss_suspend_all_devices(void)
504{
505 int r;
506 struct bus_type *bus = dss_get_bus();
507
508 r = bus_for_each_dev(bus, NULL, NULL, dss_suspend_device);
509 if (r) {
510 /* resume all displays that were suspended */
511 dss_resume_all_devices();
512 return r;
513 }
514
515 return 0;
516}
517
518static int dss_resume_device(struct device *dev, void *data)
519{
520 int r;
521 struct omap_dss_device *dssdev = to_dss_device(dev);
522
523 if (dssdev->activate_after_resume && dssdev->driver->resume) {
524 r = dssdev->driver->resume(dssdev);
525 if (r)
526 return r;
527 }
528
529 dssdev->activate_after_resume = false;
530
531 return 0;
532}
533
534int dss_resume_all_devices(void)
535{
536 struct bus_type *bus = dss_get_bus();
537
538 return bus_for_each_dev(bus, NULL, NULL, dss_resume_device);
539}
540
541static int dss_disable_device(struct device *dev, void *data)
542{
543 struct omap_dss_device *dssdev = to_dss_device(dev);
544 dssdev->driver->disable(dssdev);
545 return 0;
546}
547
548void dss_disable_all_devices(void)
549{
550 struct bus_type *bus = dss_get_bus();
551 bus_for_each_dev(bus, NULL, NULL, dss_disable_device);
552}
553
554
555void omap_dss_get_device(struct omap_dss_device *dssdev)
556{
557 get_device(&dssdev->dev);
558}
559EXPORT_SYMBOL(omap_dss_get_device);
560
561void omap_dss_put_device(struct omap_dss_device *dssdev)
562{
563 put_device(&dssdev->dev);
564}
565EXPORT_SYMBOL(omap_dss_put_device);
566
567/* ref count of the found device is incremented. ref count
568 * of from-device is decremented. */
569struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
570{
571 struct device *dev;
572 struct device *dev_start = NULL;
573 struct omap_dss_device *dssdev = NULL;
574
575 int match(struct device *dev, void *data)
576 {
577 return 1;
578 }
579
580 if (from)
581 dev_start = &from->dev;
582 dev = bus_find_device(dss_get_bus(), dev_start, NULL, match);
583 if (dev)
584 dssdev = to_dss_device(dev);
585 if (from)
586 put_device(&from->dev);
587
588 return dssdev;
589}
590EXPORT_SYMBOL(omap_dss_get_next_device);
591
592struct omap_dss_device *omap_dss_find_device(void *data,
593 int (*match)(struct omap_dss_device *dssdev, void *data))
594{
595 struct omap_dss_device *dssdev = NULL;
596
597 while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
598 if (match(dssdev, data))
599 return dssdev;
600 }
601
602 return NULL;
603}
604EXPORT_SYMBOL(omap_dss_find_device);
605
606int omap_dss_start_device(struct omap_dss_device *dssdev)
607{
608 if (!dssdev->driver) {
609 DSSDBG("no driver\n");
610 return -ENODEV;
611 }
612
613 if (!try_module_get(dssdev->dev.driver->owner)) {
614 return -ENODEV;
615 }
616
617 return 0;
618}
619EXPORT_SYMBOL(omap_dss_start_device);
620
621void omap_dss_stop_device(struct omap_dss_device *dssdev)
622{
623 module_put(dssdev->dev.driver->owner);
624}
625EXPORT_SYMBOL(omap_dss_stop_device);
626
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
new file mode 100644
index 000000000000..960e977a8bf0
--- /dev/null
+++ b/drivers/video/omap2/dss/dpi.c
@@ -0,0 +1,321 @@
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/clk.h>
27#include <linux/delay.h>
28#include <linux/err.h>
29#include <linux/errno.h>
30#include <linux/platform_device.h>
31#include <linux/regulator/consumer.h>
32
33#include <plat/display.h>
34#include <plat/cpu.h>
35
36#include "dss.h"
37
38static struct {
39 struct regulator *vdds_dsi_reg;
40} dpi;
41
42#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
43static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
44 unsigned long *fck, int *lck_div, int *pck_div)
45{
46 struct dsi_clock_info dsi_cinfo;
47 struct dispc_clock_info dispc_cinfo;
48 int r;
49
50 r = dsi_pll_calc_clock_div_pck(is_tft, pck_req, &dsi_cinfo,
51 &dispc_cinfo);
52 if (r)
53 return r;
54
55 r = dsi_pll_set_clock_div(&dsi_cinfo);
56 if (r)
57 return r;
58
59 dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
60
61 r = dispc_set_clock_div(&dispc_cinfo);
62 if (r)
63 return r;
64
65 *fck = dsi_cinfo.dsi1_pll_fclk;
66 *lck_div = dispc_cinfo.lck_div;
67 *pck_div = dispc_cinfo.pck_div;
68
69 return 0;
70}
71#else
72static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
73 unsigned long *fck, int *lck_div, int *pck_div)
74{
75 struct dss_clock_info dss_cinfo;
76 struct dispc_clock_info dispc_cinfo;
77 int r;
78
79 r = dss_calc_clock_div(is_tft, pck_req, &dss_cinfo, &dispc_cinfo);
80 if (r)
81 return r;
82
83 r = dss_set_clock_div(&dss_cinfo);
84 if (r)
85 return r;
86
87 r = dispc_set_clock_div(&dispc_cinfo);
88 if (r)
89 return r;
90
91 *fck = dss_cinfo.fck;
92 *lck_div = dispc_cinfo.lck_div;
93 *pck_div = dispc_cinfo.pck_div;
94
95 return 0;
96}
97#endif
98
99static int dpi_set_mode(struct omap_dss_device *dssdev)
100{
101 struct omap_video_timings *t = &dssdev->panel.timings;
102 int lck_div, pck_div;
103 unsigned long fck;
104 unsigned long pck;
105 bool is_tft;
106 int r = 0;
107
108 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
109
110 dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
111 dssdev->panel.acb);
112
113 is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
114
115#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
116 r = dpi_set_dsi_clk(is_tft, t->pixel_clock * 1000,
117 &fck, &lck_div, &pck_div);
118#else
119 r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000,
120 &fck, &lck_div, &pck_div);
121#endif
122 if (r)
123 goto err0;
124
125 pck = fck / lck_div / pck_div / 1000;
126
127 if (pck != t->pixel_clock) {
128 DSSWARN("Could not find exact pixel clock. "
129 "Requested %d kHz, got %lu kHz\n",
130 t->pixel_clock, pck);
131
132 t->pixel_clock = pck;
133 }
134
135 dispc_set_lcd_timings(t);
136
137err0:
138 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
139 return r;
140}
141
142static int dpi_basic_init(struct omap_dss_device *dssdev)
143{
144 bool is_tft;
145
146 is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
147
148 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
149 dispc_set_lcd_display_type(is_tft ? OMAP_DSS_LCD_DISPLAY_TFT :
150 OMAP_DSS_LCD_DISPLAY_STN);
151 dispc_set_tft_data_lines(dssdev->phy.dpi.data_lines);
152
153 return 0;
154}
155
156int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
157{
158 int r;
159
160 r = omap_dss_start_device(dssdev);
161 if (r) {
162 DSSERR("failed to start device\n");
163 goto err0;
164 }
165
166 if (cpu_is_omap34xx()) {
167 r = regulator_enable(dpi.vdds_dsi_reg);
168 if (r)
169 goto err1;
170 }
171
172 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
173
174 r = dpi_basic_init(dssdev);
175 if (r)
176 goto err2;
177
178#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
179 dss_clk_enable(DSS_CLK_FCK2);
180 r = dsi_pll_init(dssdev, 0, 1);
181 if (r)
182 goto err3;
183#endif
184 r = dpi_set_mode(dssdev);
185 if (r)
186 goto err4;
187
188 mdelay(2);
189
190 dssdev->manager->enable(dssdev->manager);
191
192 return 0;
193
194err4:
195#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
196 dsi_pll_uninit();
197err3:
198 dss_clk_disable(DSS_CLK_FCK2);
199#endif
200err2:
201 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
202 if (cpu_is_omap34xx())
203 regulator_disable(dpi.vdds_dsi_reg);
204err1:
205 omap_dss_stop_device(dssdev);
206err0:
207 return r;
208}
209EXPORT_SYMBOL(omapdss_dpi_display_enable);
210
211void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
212{
213 dssdev->manager->disable(dssdev->manager);
214
215#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
216 dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
217 dsi_pll_uninit();
218 dss_clk_disable(DSS_CLK_FCK2);
219#endif
220
221 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
222
223 if (cpu_is_omap34xx())
224 regulator_disable(dpi.vdds_dsi_reg);
225
226 omap_dss_stop_device(dssdev);
227}
228EXPORT_SYMBOL(omapdss_dpi_display_disable);
229
230void dpi_set_timings(struct omap_dss_device *dssdev,
231 struct omap_video_timings *timings)
232{
233 DSSDBG("dpi_set_timings\n");
234 dssdev->panel.timings = *timings;
235 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
236 dpi_set_mode(dssdev);
237 dispc_go(OMAP_DSS_CHANNEL_LCD);
238 }
239}
240EXPORT_SYMBOL(dpi_set_timings);
241
242int dpi_check_timings(struct omap_dss_device *dssdev,
243 struct omap_video_timings *timings)
244{
245 bool is_tft;
246 int r;
247 int lck_div, pck_div;
248 unsigned long fck;
249 unsigned long pck;
250
251 if (!dispc_lcd_timings_ok(timings))
252 return -EINVAL;
253
254 if (timings->pixel_clock == 0)
255 return -EINVAL;
256
257 is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
258
259#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
260 {
261 struct dsi_clock_info dsi_cinfo;
262 struct dispc_clock_info dispc_cinfo;
263 r = dsi_pll_calc_clock_div_pck(is_tft,
264 timings->pixel_clock * 1000,
265 &dsi_cinfo, &dispc_cinfo);
266
267 if (r)
268 return r;
269
270 fck = dsi_cinfo.dsi1_pll_fclk;
271 lck_div = dispc_cinfo.lck_div;
272 pck_div = dispc_cinfo.pck_div;
273 }
274#else
275 {
276 struct dss_clock_info dss_cinfo;
277 struct dispc_clock_info dispc_cinfo;
278 r = dss_calc_clock_div(is_tft, timings->pixel_clock * 1000,
279 &dss_cinfo, &dispc_cinfo);
280
281 if (r)
282 return r;
283
284 fck = dss_cinfo.fck;
285 lck_div = dispc_cinfo.lck_div;
286 pck_div = dispc_cinfo.pck_div;
287 }
288#endif
289
290 pck = fck / lck_div / pck_div / 1000;
291
292 timings->pixel_clock = pck;
293
294 return 0;
295}
296EXPORT_SYMBOL(dpi_check_timings);
297
298int dpi_init_display(struct omap_dss_device *dssdev)
299{
300 DSSDBG("init_display\n");
301
302 return 0;
303}
304
305int dpi_init(struct platform_device *pdev)
306{
307 if (cpu_is_omap34xx()) {
308 dpi.vdds_dsi_reg = dss_get_vdds_dsi();
309 if (IS_ERR(dpi.vdds_dsi_reg)) {
310 DSSERR("can't get VDDS_DSI regulator\n");
311 return PTR_ERR(dpi.vdds_dsi_reg);
312 }
313 }
314
315 return 0;
316}
317
318void dpi_exit(void)
319{
320}
321
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
new file mode 100644
index 000000000000..3af207b2bde3
--- /dev/null
+++ b/drivers/video/omap2/dss/dsi.c
@@ -0,0 +1,3340 @@
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/semaphore.h>
31#include <linux/seq_file.h>
32#include <linux/platform_device.h>
33#include <linux/regulator/consumer.h>
34#include <linux/wait.h>
35#include <linux/workqueue.h>
36
37#include <plat/display.h>
38#include <plat/clock.h>
39
40#include "dss.h"
41
42/*#define VERBOSE_IRQ*/
43#define DSI_CATCH_MISSING_TE
44
45#define DSI_BASE 0x4804FC00
46
47struct dsi_reg { u16 idx; };
48
49#define DSI_REG(idx) ((const struct dsi_reg) { idx })
50
51#define DSI_SZ_REGS SZ_1K
52/* DSI Protocol Engine */
53
54#define DSI_REVISION DSI_REG(0x0000)
55#define DSI_SYSCONFIG DSI_REG(0x0010)
56#define DSI_SYSSTATUS DSI_REG(0x0014)
57#define DSI_IRQSTATUS DSI_REG(0x0018)
58#define DSI_IRQENABLE DSI_REG(0x001C)
59#define DSI_CTRL DSI_REG(0x0040)
60#define DSI_COMPLEXIO_CFG1 DSI_REG(0x0048)
61#define DSI_COMPLEXIO_IRQ_STATUS DSI_REG(0x004C)
62#define DSI_COMPLEXIO_IRQ_ENABLE DSI_REG(0x0050)
63#define DSI_CLK_CTRL DSI_REG(0x0054)
64#define DSI_TIMING1 DSI_REG(0x0058)
65#define DSI_TIMING2 DSI_REG(0x005C)
66#define DSI_VM_TIMING1 DSI_REG(0x0060)
67#define DSI_VM_TIMING2 DSI_REG(0x0064)
68#define DSI_VM_TIMING3 DSI_REG(0x0068)
69#define DSI_CLK_TIMING DSI_REG(0x006C)
70#define DSI_TX_FIFO_VC_SIZE DSI_REG(0x0070)
71#define DSI_RX_FIFO_VC_SIZE DSI_REG(0x0074)
72#define DSI_COMPLEXIO_CFG2 DSI_REG(0x0078)
73#define DSI_RX_FIFO_VC_FULLNESS DSI_REG(0x007C)
74#define DSI_VM_TIMING4 DSI_REG(0x0080)
75#define DSI_TX_FIFO_VC_EMPTINESS DSI_REG(0x0084)
76#define DSI_VM_TIMING5 DSI_REG(0x0088)
77#define DSI_VM_TIMING6 DSI_REG(0x008C)
78#define DSI_VM_TIMING7 DSI_REG(0x0090)
79#define DSI_STOPCLK_TIMING DSI_REG(0x0094)
80#define DSI_VC_CTRL(n) DSI_REG(0x0100 + (n * 0x20))
81#define DSI_VC_TE(n) DSI_REG(0x0104 + (n * 0x20))
82#define DSI_VC_LONG_PACKET_HEADER(n) DSI_REG(0x0108 + (n * 0x20))
83#define DSI_VC_LONG_PACKET_PAYLOAD(n) DSI_REG(0x010C + (n * 0x20))
84#define DSI_VC_SHORT_PACKET_HEADER(n) DSI_REG(0x0110 + (n * 0x20))
85#define DSI_VC_IRQSTATUS(n) DSI_REG(0x0118 + (n * 0x20))
86#define DSI_VC_IRQENABLE(n) DSI_REG(0x011C + (n * 0x20))
87
88/* DSIPHY_SCP */
89
90#define DSI_DSIPHY_CFG0 DSI_REG(0x200 + 0x0000)
91#define DSI_DSIPHY_CFG1 DSI_REG(0x200 + 0x0004)
92#define DSI_DSIPHY_CFG2 DSI_REG(0x200 + 0x0008)
93#define DSI_DSIPHY_CFG5 DSI_REG(0x200 + 0x0014)
94
95/* DSI_PLL_CTRL_SCP */
96
97#define DSI_PLL_CONTROL DSI_REG(0x300 + 0x0000)
98#define DSI_PLL_STATUS DSI_REG(0x300 + 0x0004)
99#define DSI_PLL_GO DSI_REG(0x300 + 0x0008)
100#define DSI_PLL_CONFIGURATION1 DSI_REG(0x300 + 0x000C)
101#define DSI_PLL_CONFIGURATION2 DSI_REG(0x300 + 0x0010)
102
103#define REG_GET(idx, start, end) \
104 FLD_GET(dsi_read_reg(idx), start, end)
105
106#define REG_FLD_MOD(idx, val, start, end) \
107 dsi_write_reg(idx, FLD_MOD(dsi_read_reg(idx), val, start, end))
108
109/* Global interrupts */
110#define DSI_IRQ_VC0 (1 << 0)
111#define DSI_IRQ_VC1 (1 << 1)
112#define DSI_IRQ_VC2 (1 << 2)
113#define DSI_IRQ_VC3 (1 << 3)
114#define DSI_IRQ_WAKEUP (1 << 4)
115#define DSI_IRQ_RESYNC (1 << 5)
116#define DSI_IRQ_PLL_LOCK (1 << 7)
117#define DSI_IRQ_PLL_UNLOCK (1 << 8)
118#define DSI_IRQ_PLL_RECALL (1 << 9)
119#define DSI_IRQ_COMPLEXIO_ERR (1 << 10)
120#define DSI_IRQ_HS_TX_TIMEOUT (1 << 14)
121#define DSI_IRQ_LP_RX_TIMEOUT (1 << 15)
122#define DSI_IRQ_TE_TRIGGER (1 << 16)
123#define DSI_IRQ_ACK_TRIGGER (1 << 17)
124#define DSI_IRQ_SYNC_LOST (1 << 18)
125#define DSI_IRQ_LDO_POWER_GOOD (1 << 19)
126#define DSI_IRQ_TA_TIMEOUT (1 << 20)
127#define DSI_IRQ_ERROR_MASK \
128 (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \
129 DSI_IRQ_TA_TIMEOUT)
130#define DSI_IRQ_CHANNEL_MASK 0xf
131
132/* Virtual channel interrupts */
133#define DSI_VC_IRQ_CS (1 << 0)
134#define DSI_VC_IRQ_ECC_CORR (1 << 1)
135#define DSI_VC_IRQ_PACKET_SENT (1 << 2)
136#define DSI_VC_IRQ_FIFO_TX_OVF (1 << 3)
137#define DSI_VC_IRQ_FIFO_RX_OVF (1 << 4)
138#define DSI_VC_IRQ_BTA (1 << 5)
139#define DSI_VC_IRQ_ECC_NO_CORR (1 << 6)
140#define DSI_VC_IRQ_FIFO_TX_UDF (1 << 7)
141#define DSI_VC_IRQ_PP_BUSY_CHANGE (1 << 8)
142#define DSI_VC_IRQ_ERROR_MASK \
143 (DSI_VC_IRQ_CS | DSI_VC_IRQ_ECC_CORR | DSI_VC_IRQ_FIFO_TX_OVF | \
144 DSI_VC_IRQ_FIFO_RX_OVF | DSI_VC_IRQ_ECC_NO_CORR | \
145 DSI_VC_IRQ_FIFO_TX_UDF)
146
147/* ComplexIO interrupts */
148#define DSI_CIO_IRQ_ERRSYNCESC1 (1 << 0)
149#define DSI_CIO_IRQ_ERRSYNCESC2 (1 << 1)
150#define DSI_CIO_IRQ_ERRSYNCESC3 (1 << 2)
151#define DSI_CIO_IRQ_ERRESC1 (1 << 5)
152#define DSI_CIO_IRQ_ERRESC2 (1 << 6)
153#define DSI_CIO_IRQ_ERRESC3 (1 << 7)
154#define DSI_CIO_IRQ_ERRCONTROL1 (1 << 10)
155#define DSI_CIO_IRQ_ERRCONTROL2 (1 << 11)
156#define DSI_CIO_IRQ_ERRCONTROL3 (1 << 12)
157#define DSI_CIO_IRQ_STATEULPS1 (1 << 15)
158#define DSI_CIO_IRQ_STATEULPS2 (1 << 16)
159#define DSI_CIO_IRQ_STATEULPS3 (1 << 17)
160#define DSI_CIO_IRQ_ERRCONTENTIONLP0_1 (1 << 20)
161#define DSI_CIO_IRQ_ERRCONTENTIONLP1_1 (1 << 21)
162#define DSI_CIO_IRQ_ERRCONTENTIONLP0_2 (1 << 22)
163#define DSI_CIO_IRQ_ERRCONTENTIONLP1_2 (1 << 23)
164#define DSI_CIO_IRQ_ERRCONTENTIONLP0_3 (1 << 24)
165#define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25)
166#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30)
167#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31)
168
169#define DSI_DT_DCS_SHORT_WRITE_0 0x05
170#define DSI_DT_DCS_SHORT_WRITE_1 0x15
171#define DSI_DT_DCS_READ 0x06
172#define DSI_DT_SET_MAX_RET_PKG_SIZE 0x37
173#define DSI_DT_NULL_PACKET 0x09
174#define DSI_DT_DCS_LONG_WRITE 0x39
175
176#define DSI_DT_RX_ACK_WITH_ERR 0x02
177#define DSI_DT_RX_DCS_LONG_READ 0x1c
178#define DSI_DT_RX_SHORT_READ_1 0x21
179#define DSI_DT_RX_SHORT_READ_2 0x22
180
181#define FINT_MAX 2100000
182#define FINT_MIN 750000
183#define REGN_MAX (1 << 7)
184#define REGM_MAX ((1 << 11) - 1)
185#define REGM3_MAX (1 << 4)
186#define REGM4_MAX (1 << 4)
187#define LP_DIV_MAX ((1 << 13) - 1)
188
189enum fifo_size {
190 DSI_FIFO_SIZE_0 = 0,
191 DSI_FIFO_SIZE_32 = 1,
192 DSI_FIFO_SIZE_64 = 2,
193 DSI_FIFO_SIZE_96 = 3,
194 DSI_FIFO_SIZE_128 = 4,
195};
196
197enum dsi_vc_mode {
198 DSI_VC_MODE_L4 = 0,
199 DSI_VC_MODE_VP,
200};
201
202struct dsi_update_region {
203 u16 x, y, w, h;
204 struct omap_dss_device *device;
205};
206
207struct dsi_irq_stats {
208 unsigned long last_reset;
209 unsigned irq_count;
210 unsigned dsi_irqs[32];
211 unsigned vc_irqs[4][32];
212 unsigned cio_irqs[32];
213};
214
215static struct
216{
217 void __iomem *base;
218
219 struct dsi_clock_info current_cinfo;
220
221 struct regulator *vdds_dsi_reg;
222
223 struct {
224 enum dsi_vc_mode mode;
225 struct omap_dss_device *dssdev;
226 enum fifo_size fifo_size;
227 } vc[4];
228
229 struct mutex lock;
230 struct semaphore bus_lock;
231
232 unsigned pll_locked;
233
234 struct completion bta_completion;
235
236 int update_channel;
237 struct dsi_update_region update_region;
238
239 bool te_enabled;
240
241 struct work_struct framedone_work;
242 void (*framedone_callback)(int, void *);
243 void *framedone_data;
244
245 struct delayed_work framedone_timeout_work;
246
247#ifdef DSI_CATCH_MISSING_TE
248 struct timer_list te_timer;
249#endif
250
251 unsigned long cache_req_pck;
252 unsigned long cache_clk_freq;
253 struct dsi_clock_info cache_cinfo;
254
255 u32 errors;
256 spinlock_t errors_lock;
257#ifdef DEBUG
258 ktime_t perf_setup_time;
259 ktime_t perf_start_time;
260#endif
261 int debug_read;
262 int debug_write;
263
264#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
265 spinlock_t irq_stats_lock;
266 struct dsi_irq_stats irq_stats;
267#endif
268} dsi;
269
270#ifdef DEBUG
271static unsigned int dsi_perf;
272module_param_named(dsi_perf, dsi_perf, bool, 0644);
273#endif
274
275static inline void dsi_write_reg(const struct dsi_reg idx, u32 val)
276{
277 __raw_writel(val, dsi.base + idx.idx);
278}
279
280static inline u32 dsi_read_reg(const struct dsi_reg idx)
281{
282 return __raw_readl(dsi.base + idx.idx);
283}
284
285
286void dsi_save_context(void)
287{
288}
289
290void dsi_restore_context(void)
291{
292}
293
294void dsi_bus_lock(void)
295{
296 down(&dsi.bus_lock);
297}
298EXPORT_SYMBOL(dsi_bus_lock);
299
300void dsi_bus_unlock(void)
301{
302 up(&dsi.bus_lock);
303}
304EXPORT_SYMBOL(dsi_bus_unlock);
305
306static bool dsi_bus_is_locked(void)
307{
308 return dsi.bus_lock.count == 0;
309}
310
311static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
312 int value)
313{
314 int t = 100000;
315
316 while (REG_GET(idx, bitnum, bitnum) != value) {
317 if (--t == 0)
318 return !value;
319 }
320
321 return value;
322}
323
324#ifdef DEBUG
325static void dsi_perf_mark_setup(void)
326{
327 dsi.perf_setup_time = ktime_get();
328}
329
330static void dsi_perf_mark_start(void)
331{
332 dsi.perf_start_time = ktime_get();
333}
334
335static void dsi_perf_show(const char *name)
336{
337 ktime_t t, setup_time, trans_time;
338 u32 total_bytes;
339 u32 setup_us, trans_us, total_us;
340
341 if (!dsi_perf)
342 return;
343
344 t = ktime_get();
345
346 setup_time = ktime_sub(dsi.perf_start_time, dsi.perf_setup_time);
347 setup_us = (u32)ktime_to_us(setup_time);
348 if (setup_us == 0)
349 setup_us = 1;
350
351 trans_time = ktime_sub(t, dsi.perf_start_time);
352 trans_us = (u32)ktime_to_us(trans_time);
353 if (trans_us == 0)
354 trans_us = 1;
355
356 total_us = setup_us + trans_us;
357
358 total_bytes = dsi.update_region.w *
359 dsi.update_region.h *
360 dsi.update_region.device->ctrl.pixel_size / 8;
361
362 printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
363 "%u bytes, %u kbytes/sec\n",
364 name,
365 setup_us,
366 trans_us,
367 total_us,
368 1000*1000 / total_us,
369 total_bytes,
370 total_bytes * 1000 / total_us);
371}
372#else
373#define dsi_perf_mark_setup()
374#define dsi_perf_mark_start()
375#define dsi_perf_show(x)
376#endif
377
378static void print_irq_status(u32 status)
379{
380#ifndef VERBOSE_IRQ
381 if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0)
382 return;
383#endif
384 printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status);
385
386#define PIS(x) \
387 if (status & DSI_IRQ_##x) \
388 printk(#x " ");
389#ifdef VERBOSE_IRQ
390 PIS(VC0);
391 PIS(VC1);
392 PIS(VC2);
393 PIS(VC3);
394#endif
395 PIS(WAKEUP);
396 PIS(RESYNC);
397 PIS(PLL_LOCK);
398 PIS(PLL_UNLOCK);
399 PIS(PLL_RECALL);
400 PIS(COMPLEXIO_ERR);
401 PIS(HS_TX_TIMEOUT);
402 PIS(LP_RX_TIMEOUT);
403 PIS(TE_TRIGGER);
404 PIS(ACK_TRIGGER);
405 PIS(SYNC_LOST);
406 PIS(LDO_POWER_GOOD);
407 PIS(TA_TIMEOUT);
408#undef PIS
409
410 printk("\n");
411}
412
413static void print_irq_status_vc(int channel, u32 status)
414{
415#ifndef VERBOSE_IRQ
416 if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
417 return;
418#endif
419 printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status);
420
421#define PIS(x) \
422 if (status & DSI_VC_IRQ_##x) \
423 printk(#x " ");
424 PIS(CS);
425 PIS(ECC_CORR);
426#ifdef VERBOSE_IRQ
427 PIS(PACKET_SENT);
428#endif
429 PIS(FIFO_TX_OVF);
430 PIS(FIFO_RX_OVF);
431 PIS(BTA);
432 PIS(ECC_NO_CORR);
433 PIS(FIFO_TX_UDF);
434 PIS(PP_BUSY_CHANGE);
435#undef PIS
436 printk("\n");
437}
438
439static void print_irq_status_cio(u32 status)
440{
441 printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status);
442
443#define PIS(x) \
444 if (status & DSI_CIO_IRQ_##x) \
445 printk(#x " ");
446 PIS(ERRSYNCESC1);
447 PIS(ERRSYNCESC2);
448 PIS(ERRSYNCESC3);
449 PIS(ERRESC1);
450 PIS(ERRESC2);
451 PIS(ERRESC3);
452 PIS(ERRCONTROL1);
453 PIS(ERRCONTROL2);
454 PIS(ERRCONTROL3);
455 PIS(STATEULPS1);
456 PIS(STATEULPS2);
457 PIS(STATEULPS3);
458 PIS(ERRCONTENTIONLP0_1);
459 PIS(ERRCONTENTIONLP1_1);
460 PIS(ERRCONTENTIONLP0_2);
461 PIS(ERRCONTENTIONLP1_2);
462 PIS(ERRCONTENTIONLP0_3);
463 PIS(ERRCONTENTIONLP1_3);
464 PIS(ULPSACTIVENOT_ALL0);
465 PIS(ULPSACTIVENOT_ALL1);
466#undef PIS
467
468 printk("\n");
469}
470
471static int debug_irq;
472
473/* called from dss */
474void dsi_irq_handler(void)
475{
476 u32 irqstatus, vcstatus, ciostatus;
477 int i;
478
479 irqstatus = dsi_read_reg(DSI_IRQSTATUS);
480
481#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
482 spin_lock(&dsi.irq_stats_lock);
483 dsi.irq_stats.irq_count++;
484 dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs);
485#endif
486
487 if (irqstatus & DSI_IRQ_ERROR_MASK) {
488 DSSERR("DSI error, irqstatus %x\n", irqstatus);
489 print_irq_status(irqstatus);
490 spin_lock(&dsi.errors_lock);
491 dsi.errors |= irqstatus & DSI_IRQ_ERROR_MASK;
492 spin_unlock(&dsi.errors_lock);
493 } else if (debug_irq) {
494 print_irq_status(irqstatus);
495 }
496
497#ifdef DSI_CATCH_MISSING_TE
498 if (irqstatus & DSI_IRQ_TE_TRIGGER)
499 del_timer(&dsi.te_timer);
500#endif
501
502 for (i = 0; i < 4; ++i) {
503 if ((irqstatus & (1<<i)) == 0)
504 continue;
505
506 vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i));
507
508#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
509 dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]);
510#endif
511
512 if (vcstatus & DSI_VC_IRQ_BTA)
513 complete(&dsi.bta_completion);
514
515 if (vcstatus & DSI_VC_IRQ_ERROR_MASK) {
516 DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
517 i, vcstatus);
518 print_irq_status_vc(i, vcstatus);
519 } else if (debug_irq) {
520 print_irq_status_vc(i, vcstatus);
521 }
522
523 dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus);
524 /* flush posted write */
525 dsi_read_reg(DSI_VC_IRQSTATUS(i));
526 }
527
528 if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
529 ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
530
531#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
532 dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
533#endif
534
535 dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
536 /* flush posted write */
537 dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
538
539 DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
540 print_irq_status_cio(ciostatus);
541 }
542
543 dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
544 /* flush posted write */
545 dsi_read_reg(DSI_IRQSTATUS);
546
547#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
548 spin_unlock(&dsi.irq_stats_lock);
549#endif
550}
551
552
553static void _dsi_initialize_irq(void)
554{
555 u32 l;
556 int i;
557
558 /* disable all interrupts */
559 dsi_write_reg(DSI_IRQENABLE, 0);
560 for (i = 0; i < 4; ++i)
561 dsi_write_reg(DSI_VC_IRQENABLE(i), 0);
562 dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0);
563
564 /* clear interrupt status */
565 l = dsi_read_reg(DSI_IRQSTATUS);
566 dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK);
567
568 for (i = 0; i < 4; ++i) {
569 l = dsi_read_reg(DSI_VC_IRQSTATUS(i));
570 dsi_write_reg(DSI_VC_IRQSTATUS(i), l);
571 }
572
573 l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
574 dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l);
575
576 /* enable error irqs */
577 l = DSI_IRQ_ERROR_MASK;
578#ifdef DSI_CATCH_MISSING_TE
579 l |= DSI_IRQ_TE_TRIGGER;
580#endif
581 dsi_write_reg(DSI_IRQENABLE, l);
582
583 l = DSI_VC_IRQ_ERROR_MASK;
584 for (i = 0; i < 4; ++i)
585 dsi_write_reg(DSI_VC_IRQENABLE(i), l);
586
587 /* XXX zonda responds incorrectly, causing control error:
588 Exit from LP-ESC mode to LP11 uses wrong transition states on the
589 data lines LP0 and LN0. */
590 dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE,
591 -1 & (~DSI_CIO_IRQ_ERRCONTROL2));
592}
593
594static u32 dsi_get_errors(void)
595{
596 unsigned long flags;
597 u32 e;
598 spin_lock_irqsave(&dsi.errors_lock, flags);
599 e = dsi.errors;
600 dsi.errors = 0;
601 spin_unlock_irqrestore(&dsi.errors_lock, flags);
602 return e;
603}
604
605static void dsi_vc_enable_bta_irq(int channel)
606{
607 u32 l;
608
609 dsi_write_reg(DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA);
610
611 l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
612 l |= DSI_VC_IRQ_BTA;
613 dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
614}
615
616static void dsi_vc_disable_bta_irq(int channel)
617{
618 u32 l;
619
620 l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
621 l &= ~DSI_VC_IRQ_BTA;
622 dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
623}
624
625/* DSI func clock. this could also be DSI2_PLL_FCLK */
626static inline void enable_clocks(bool enable)
627{
628 if (enable)
629 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
630 else
631 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
632}
633
634/* source clock for DSI PLL. this could also be PCLKFREE */
635static inline void dsi_enable_pll_clock(bool enable)
636{
637 if (enable)
638 dss_clk_enable(DSS_CLK_FCK2);
639 else
640 dss_clk_disable(DSS_CLK_FCK2);
641
642 if (enable && dsi.pll_locked) {
643 if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1)
644 DSSERR("cannot lock PLL when enabling clocks\n");
645 }
646}
647
648#ifdef DEBUG
649static void _dsi_print_reset_status(void)
650{
651 u32 l;
652
653 if (!dss_debug)
654 return;
655
656 /* A dummy read using the SCP interface to any DSIPHY register is
657 * required after DSIPHY reset to complete the reset of the DSI complex
658 * I/O. */
659 l = dsi_read_reg(DSI_DSIPHY_CFG5);
660
661 printk(KERN_DEBUG "DSI resets: ");
662
663 l = dsi_read_reg(DSI_PLL_STATUS);
664 printk("PLL (%d) ", FLD_GET(l, 0, 0));
665
666 l = dsi_read_reg(DSI_COMPLEXIO_CFG1);
667 printk("CIO (%d) ", FLD_GET(l, 29, 29));
668
669 l = dsi_read_reg(DSI_DSIPHY_CFG5);
670 printk("PHY (%x, %d, %d, %d)\n",
671 FLD_GET(l, 28, 26),
672 FLD_GET(l, 29, 29),
673 FLD_GET(l, 30, 30),
674 FLD_GET(l, 31, 31));
675}
676#else
677#define _dsi_print_reset_status()
678#endif
679
680static inline int dsi_if_enable(bool enable)
681{
682 DSSDBG("dsi_if_enable(%d)\n", enable);
683
684 enable = enable ? 1 : 0;
685 REG_FLD_MOD(DSI_CTRL, enable, 0, 0); /* IF_EN */
686
687 if (wait_for_bit_change(DSI_CTRL, 0, enable) != enable) {
688 DSSERR("Failed to set dsi_if_enable to %d\n", enable);
689 return -EIO;
690 }
691
692 return 0;
693}
694
695unsigned long dsi_get_dsi1_pll_rate(void)
696{
697 return dsi.current_cinfo.dsi1_pll_fclk;
698}
699
700static unsigned long dsi_get_dsi2_pll_rate(void)
701{
702 return dsi.current_cinfo.dsi2_pll_fclk;
703}
704
705static unsigned long dsi_get_txbyteclkhs(void)
706{
707 return dsi.current_cinfo.clkin4ddr / 16;
708}
709
710static unsigned long dsi_fclk_rate(void)
711{
712 unsigned long r;
713
714 if (dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK) {
715 /* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */
716 r = dss_clk_get_rate(DSS_CLK_FCK1);
717 } else {
718 /* DSI FCLK source is DSI2_PLL_FCLK */
719 r = dsi_get_dsi2_pll_rate();
720 }
721
722 return r;
723}
724
725static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
726{
727 unsigned long dsi_fclk;
728 unsigned lp_clk_div;
729 unsigned long lp_clk;
730
731 lp_clk_div = dssdev->phy.dsi.div.lp_clk_div;
732
733 if (lp_clk_div == 0 || lp_clk_div > LP_DIV_MAX)
734 return -EINVAL;
735
736 dsi_fclk = dsi_fclk_rate();
737
738 lp_clk = dsi_fclk / 2 / lp_clk_div;
739
740 DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
741 dsi.current_cinfo.lp_clk = lp_clk;
742 dsi.current_cinfo.lp_clk_div = lp_clk_div;
743
744 REG_FLD_MOD(DSI_CLK_CTRL, lp_clk_div, 12, 0); /* LP_CLK_DIVISOR */
745
746 REG_FLD_MOD(DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0,
747 21, 21); /* LP_RX_SYNCHRO_ENABLE */
748
749 return 0;
750}
751
752
753enum dsi_pll_power_state {
754 DSI_PLL_POWER_OFF = 0x0,
755 DSI_PLL_POWER_ON_HSCLK = 0x1,
756 DSI_PLL_POWER_ON_ALL = 0x2,
757 DSI_PLL_POWER_ON_DIV = 0x3,
758};
759
760static int dsi_pll_power(enum dsi_pll_power_state state)
761{
762 int t = 0;
763
764 REG_FLD_MOD(DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_CMD */
765
766 /* PLL_PWR_STATUS */
767 while (FLD_GET(dsi_read_reg(DSI_CLK_CTRL), 29, 28) != state) {
768 if (++t > 1000) {
769 DSSERR("Failed to set DSI PLL power mode to %d\n",
770 state);
771 return -ENODEV;
772 }
773 udelay(1);
774 }
775
776 return 0;
777}
778
779/* calculate clock rates using dividers in cinfo */
780static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo)
781{
782 if (cinfo->regn == 0 || cinfo->regn > REGN_MAX)
783 return -EINVAL;
784
785 if (cinfo->regm == 0 || cinfo->regm > REGM_MAX)
786 return -EINVAL;
787
788 if (cinfo->regm3 > REGM3_MAX)
789 return -EINVAL;
790
791 if (cinfo->regm4 > REGM4_MAX)
792 return -EINVAL;
793
794 if (cinfo->use_dss2_fck) {
795 cinfo->clkin = dss_clk_get_rate(DSS_CLK_FCK2);
796 /* XXX it is unclear if highfreq should be used
797 * with DSS2_FCK source also */
798 cinfo->highfreq = 0;
799 } else {
800 cinfo->clkin = dispc_pclk_rate();
801
802 if (cinfo->clkin < 32000000)
803 cinfo->highfreq = 0;
804 else
805 cinfo->highfreq = 1;
806 }
807
808 cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1));
809
810 if (cinfo->fint > FINT_MAX || cinfo->fint < FINT_MIN)
811 return -EINVAL;
812
813 cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
814
815 if (cinfo->clkin4ddr > 1800 * 1000 * 1000)
816 return -EINVAL;
817
818 if (cinfo->regm3 > 0)
819 cinfo->dsi1_pll_fclk = cinfo->clkin4ddr / cinfo->regm3;
820 else
821 cinfo->dsi1_pll_fclk = 0;
822
823 if (cinfo->regm4 > 0)
824 cinfo->dsi2_pll_fclk = cinfo->clkin4ddr / cinfo->regm4;
825 else
826 cinfo->dsi2_pll_fclk = 0;
827
828 return 0;
829}
830
831int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
832 struct dsi_clock_info *dsi_cinfo,
833 struct dispc_clock_info *dispc_cinfo)
834{
835 struct dsi_clock_info cur, best;
836 struct dispc_clock_info best_dispc;
837 int min_fck_per_pck;
838 int match = 0;
839 unsigned long dss_clk_fck2;
840
841 dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_FCK2);
842
843 if (req_pck == dsi.cache_req_pck &&
844 dsi.cache_cinfo.clkin == dss_clk_fck2) {
845 DSSDBG("DSI clock info found from cache\n");
846 *dsi_cinfo = dsi.cache_cinfo;
847 dispc_find_clk_divs(is_tft, req_pck, dsi_cinfo->dsi1_pll_fclk,
848 dispc_cinfo);
849 return 0;
850 }
851
852 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
853
854 if (min_fck_per_pck &&
855 req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
856 DSSERR("Requested pixel clock not possible with the current "
857 "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
858 "the constraint off.\n");
859 min_fck_per_pck = 0;
860 }
861
862 DSSDBG("dsi_pll_calc\n");
863
864retry:
865 memset(&best, 0, sizeof(best));
866 memset(&best_dispc, 0, sizeof(best_dispc));
867
868 memset(&cur, 0, sizeof(cur));
869 cur.clkin = dss_clk_fck2;
870 cur.use_dss2_fck = 1;
871 cur.highfreq = 0;
872
873 /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
874 /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
875 /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
876 for (cur.regn = 1; cur.regn < REGN_MAX; ++cur.regn) {
877 if (cur.highfreq == 0)
878 cur.fint = cur.clkin / cur.regn;
879 else
880 cur.fint = cur.clkin / (2 * cur.regn);
881
882 if (cur.fint > FINT_MAX || cur.fint < FINT_MIN)
883 continue;
884
885 /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
886 for (cur.regm = 1; cur.regm < REGM_MAX; ++cur.regm) {
887 unsigned long a, b;
888
889 a = 2 * cur.regm * (cur.clkin/1000);
890 b = cur.regn * (cur.highfreq + 1);
891 cur.clkin4ddr = a / b * 1000;
892
893 if (cur.clkin4ddr > 1800 * 1000 * 1000)
894 break;
895
896 /* DSI1_PLL_FCLK(MHz) = DSIPHY(MHz) / regm3 < 173MHz */
897 for (cur.regm3 = 1; cur.regm3 < REGM3_MAX;
898 ++cur.regm3) {
899 struct dispc_clock_info cur_dispc;
900 cur.dsi1_pll_fclk = cur.clkin4ddr / cur.regm3;
901
902 /* this will narrow down the search a bit,
903 * but still give pixclocks below what was
904 * requested */
905 if (cur.dsi1_pll_fclk < req_pck)
906 break;
907
908 if (cur.dsi1_pll_fclk > DISPC_MAX_FCK)
909 continue;
910
911 if (min_fck_per_pck &&
912 cur.dsi1_pll_fclk <
913 req_pck * min_fck_per_pck)
914 continue;
915
916 match = 1;
917
918 dispc_find_clk_divs(is_tft, req_pck,
919 cur.dsi1_pll_fclk,
920 &cur_dispc);
921
922 if (abs(cur_dispc.pck - req_pck) <
923 abs(best_dispc.pck - req_pck)) {
924 best = cur;
925 best_dispc = cur_dispc;
926
927 if (cur_dispc.pck == req_pck)
928 goto found;
929 }
930 }
931 }
932 }
933found:
934 if (!match) {
935 if (min_fck_per_pck) {
936 DSSERR("Could not find suitable clock settings.\n"
937 "Turning FCK/PCK constraint off and"
938 "trying again.\n");
939 min_fck_per_pck = 0;
940 goto retry;
941 }
942
943 DSSERR("Could not find suitable clock settings.\n");
944
945 return -EINVAL;
946 }
947
948 /* DSI2_PLL_FCLK (regm4) is not used */
949 best.regm4 = 0;
950 best.dsi2_pll_fclk = 0;
951
952 if (dsi_cinfo)
953 *dsi_cinfo = best;
954 if (dispc_cinfo)
955 *dispc_cinfo = best_dispc;
956
957 dsi.cache_req_pck = req_pck;
958 dsi.cache_clk_freq = 0;
959 dsi.cache_cinfo = best;
960
961 return 0;
962}
963
964int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
965{
966 int r = 0;
967 u32 l;
968 int f;
969
970 DSSDBGF();
971
972 dsi.current_cinfo.fint = cinfo->fint;
973 dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr;
974 dsi.current_cinfo.dsi1_pll_fclk = cinfo->dsi1_pll_fclk;
975 dsi.current_cinfo.dsi2_pll_fclk = cinfo->dsi2_pll_fclk;
976
977 dsi.current_cinfo.regn = cinfo->regn;
978 dsi.current_cinfo.regm = cinfo->regm;
979 dsi.current_cinfo.regm3 = cinfo->regm3;
980 dsi.current_cinfo.regm4 = cinfo->regm4;
981
982 DSSDBG("DSI Fint %ld\n", cinfo->fint);
983
984 DSSDBG("clkin (%s) rate %ld, highfreq %d\n",
985 cinfo->use_dss2_fck ? "dss2_fck" : "pclkfree",
986 cinfo->clkin,
987 cinfo->highfreq);
988
989 /* DSIPHY == CLKIN4DDR */
990 DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu / %d = %lu\n",
991 cinfo->regm,
992 cinfo->regn,
993 cinfo->clkin,
994 cinfo->highfreq + 1,
995 cinfo->clkin4ddr);
996
997 DSSDBG("Data rate on 1 DSI lane %ld Mbps\n",
998 cinfo->clkin4ddr / 1000 / 1000 / 2);
999
1000 DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);
1001
1002 DSSDBG("regm3 = %d, dsi1_pll_fclk = %lu\n",
1003 cinfo->regm3, cinfo->dsi1_pll_fclk);
1004 DSSDBG("regm4 = %d, dsi2_pll_fclk = %lu\n",
1005 cinfo->regm4, cinfo->dsi2_pll_fclk);
1006
1007 REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */
1008
1009 l = dsi_read_reg(DSI_PLL_CONFIGURATION1);
1010 l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */
1011 l = FLD_MOD(l, cinfo->regn - 1, 7, 1); /* DSI_PLL_REGN */
1012 l = FLD_MOD(l, cinfo->regm, 18, 8); /* DSI_PLL_REGM */
1013 l = FLD_MOD(l, cinfo->regm3 > 0 ? cinfo->regm3 - 1 : 0,
1014 22, 19); /* DSI_CLOCK_DIV */
1015 l = FLD_MOD(l, cinfo->regm4 > 0 ? cinfo->regm4 - 1 : 0,
1016 26, 23); /* DSIPROTO_CLOCK_DIV */
1017 dsi_write_reg(DSI_PLL_CONFIGURATION1, l);
1018
1019 BUG_ON(cinfo->fint < 750000 || cinfo->fint > 2100000);
1020 if (cinfo->fint < 1000000)
1021 f = 0x3;
1022 else if (cinfo->fint < 1250000)
1023 f = 0x4;
1024 else if (cinfo->fint < 1500000)
1025 f = 0x5;
1026 else if (cinfo->fint < 1750000)
1027 f = 0x6;
1028 else
1029 f = 0x7;
1030
1031 l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
1032 l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
1033 l = FLD_MOD(l, cinfo->use_dss2_fck ? 0 : 1,
1034 11, 11); /* DSI_PLL_CLKSEL */
1035 l = FLD_MOD(l, cinfo->highfreq,
1036 12, 12); /* DSI_PLL_HIGHFREQ */
1037 l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
1038 l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */
1039 l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */
1040 dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
1041
1042 REG_FLD_MOD(DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
1043
1044 if (wait_for_bit_change(DSI_PLL_GO, 0, 0) != 0) {
1045 DSSERR("dsi pll go bit not going down.\n");
1046 r = -EIO;
1047 goto err;
1048 }
1049
1050 if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1) {
1051 DSSERR("cannot lock PLL\n");
1052 r = -EIO;
1053 goto err;
1054 }
1055
1056 dsi.pll_locked = 1;
1057
1058 l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
1059 l = FLD_MOD(l, 0, 0, 0); /* DSI_PLL_IDLE */
1060 l = FLD_MOD(l, 0, 5, 5); /* DSI_PLL_PLLLPMODE */
1061 l = FLD_MOD(l, 0, 6, 6); /* DSI_PLL_LOWCURRSTBY */
1062 l = FLD_MOD(l, 0, 7, 7); /* DSI_PLL_TIGHTPHASELOCK */
1063 l = FLD_MOD(l, 0, 8, 8); /* DSI_PLL_DRIFTGUARDEN */
1064 l = FLD_MOD(l, 0, 10, 9); /* DSI_PLL_LOCKSEL */
1065 l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
1066 l = FLD_MOD(l, 1, 14, 14); /* DSIPHY_CLKINEN */
1067 l = FLD_MOD(l, 0, 15, 15); /* DSI_BYPASSEN */
1068 l = FLD_MOD(l, 1, 16, 16); /* DSS_CLOCK_EN */
1069 l = FLD_MOD(l, 0, 17, 17); /* DSS_CLOCK_PWDN */
1070 l = FLD_MOD(l, 1, 18, 18); /* DSI_PROTO_CLOCK_EN */
1071 l = FLD_MOD(l, 0, 19, 19); /* DSI_PROTO_CLOCK_PWDN */
1072 l = FLD_MOD(l, 0, 20, 20); /* DSI_HSDIVBYPASS */
1073 dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
1074
1075 DSSDBG("PLL config done\n");
1076err:
1077 return r;
1078}
1079
1080int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
1081 bool enable_hsdiv)
1082{
1083 int r = 0;
1084 enum dsi_pll_power_state pwstate;
1085
1086 DSSDBG("PLL init\n");
1087
1088 enable_clocks(1);
1089 dsi_enable_pll_clock(1);
1090
1091 r = regulator_enable(dsi.vdds_dsi_reg);
1092 if (r)
1093 goto err0;
1094
1095 /* XXX PLL does not come out of reset without this... */
1096 dispc_pck_free_enable(1);
1097
1098 if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) {
1099 DSSERR("PLL not coming out of reset.\n");
1100 r = -ENODEV;
1101 goto err1;
1102 }
1103
1104 /* XXX ... but if left on, we get problems when planes do not
1105 * fill the whole display. No idea about this */
1106 dispc_pck_free_enable(0);
1107
1108 if (enable_hsclk && enable_hsdiv)
1109 pwstate = DSI_PLL_POWER_ON_ALL;
1110 else if (enable_hsclk)
1111 pwstate = DSI_PLL_POWER_ON_HSCLK;
1112 else if (enable_hsdiv)
1113 pwstate = DSI_PLL_POWER_ON_DIV;
1114 else
1115 pwstate = DSI_PLL_POWER_OFF;
1116
1117 r = dsi_pll_power(pwstate);
1118
1119 if (r)
1120 goto err1;
1121
1122 DSSDBG("PLL init done\n");
1123
1124 return 0;
1125err1:
1126 regulator_disable(dsi.vdds_dsi_reg);
1127err0:
1128 enable_clocks(0);
1129 dsi_enable_pll_clock(0);
1130 return r;
1131}
1132
1133void dsi_pll_uninit(void)
1134{
1135 enable_clocks(0);
1136 dsi_enable_pll_clock(0);
1137
1138 dsi.pll_locked = 0;
1139 dsi_pll_power(DSI_PLL_POWER_OFF);
1140 regulator_disable(dsi.vdds_dsi_reg);
1141 DSSDBG("PLL uninit done\n");
1142}
1143
1144void dsi_dump_clocks(struct seq_file *s)
1145{
1146 int clksel;
1147 struct dsi_clock_info *cinfo = &dsi.current_cinfo;
1148
1149 enable_clocks(1);
1150
1151 clksel = REG_GET(DSI_PLL_CONFIGURATION2, 11, 11);
1152
1153 seq_printf(s, "- DSI PLL -\n");
1154
1155 seq_printf(s, "dsi pll source = %s\n",
1156 clksel == 0 ?
1157 "dss2_alwon_fclk" : "pclkfree");
1158
1159 seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
1160
1161 seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n",
1162 cinfo->clkin4ddr, cinfo->regm);
1163
1164 seq_printf(s, "dsi1_pll_fck\t%-16luregm3 %u\t(%s)\n",
1165 cinfo->dsi1_pll_fclk,
1166 cinfo->regm3,
1167 dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
1168 "off" : "on");
1169
1170 seq_printf(s, "dsi2_pll_fck\t%-16luregm4 %u\t(%s)\n",
1171 cinfo->dsi2_pll_fclk,
1172 cinfo->regm4,
1173 dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
1174 "off" : "on");
1175
1176 seq_printf(s, "- DSI -\n");
1177
1178 seq_printf(s, "dsi fclk source = %s\n",
1179 dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
1180 "dss1_alwon_fclk" : "dsi2_pll_fclk");
1181
1182 seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate());
1183
1184 seq_printf(s, "DDR_CLK\t\t%lu\n",
1185 cinfo->clkin4ddr / 4);
1186
1187 seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs());
1188
1189 seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk);
1190
1191 seq_printf(s, "VP_CLK\t\t%lu\n"
1192 "VP_PCLK\t\t%lu\n",
1193 dispc_lclk_rate(),
1194 dispc_pclk_rate());
1195
1196 enable_clocks(0);
1197}
1198
1199#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
1200void dsi_dump_irqs(struct seq_file *s)
1201{
1202 unsigned long flags;
1203 struct dsi_irq_stats stats;
1204
1205 spin_lock_irqsave(&dsi.irq_stats_lock, flags);
1206
1207 stats = dsi.irq_stats;
1208 memset(&dsi.irq_stats, 0, sizeof(dsi.irq_stats));
1209 dsi.irq_stats.last_reset = jiffies;
1210
1211 spin_unlock_irqrestore(&dsi.irq_stats_lock, flags);
1212
1213 seq_printf(s, "period %u ms\n",
1214 jiffies_to_msecs(jiffies - stats.last_reset));
1215
1216 seq_printf(s, "irqs %d\n", stats.irq_count);
1217#define PIS(x) \
1218 seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);
1219
1220 seq_printf(s, "-- DSI interrupts --\n");
1221 PIS(VC0);
1222 PIS(VC1);
1223 PIS(VC2);
1224 PIS(VC3);
1225 PIS(WAKEUP);
1226 PIS(RESYNC);
1227 PIS(PLL_LOCK);
1228 PIS(PLL_UNLOCK);
1229 PIS(PLL_RECALL);
1230 PIS(COMPLEXIO_ERR);
1231 PIS(HS_TX_TIMEOUT);
1232 PIS(LP_RX_TIMEOUT);
1233 PIS(TE_TRIGGER);
1234 PIS(ACK_TRIGGER);
1235 PIS(SYNC_LOST);
1236 PIS(LDO_POWER_GOOD);
1237 PIS(TA_TIMEOUT);
1238#undef PIS
1239
1240#define PIS(x) \
1241 seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \
1242 stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
1243 stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
1244 stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
1245 stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);
1246
1247 seq_printf(s, "-- VC interrupts --\n");
1248 PIS(CS);
1249 PIS(ECC_CORR);
1250 PIS(PACKET_SENT);
1251 PIS(FIFO_TX_OVF);
1252 PIS(FIFO_RX_OVF);
1253 PIS(BTA);
1254 PIS(ECC_NO_CORR);
1255 PIS(FIFO_TX_UDF);
1256 PIS(PP_BUSY_CHANGE);
1257#undef PIS
1258
1259#define PIS(x) \
1260 seq_printf(s, "%-20s %10d\n", #x, \
1261 stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);
1262
1263 seq_printf(s, "-- CIO interrupts --\n");
1264 PIS(ERRSYNCESC1);
1265 PIS(ERRSYNCESC2);
1266 PIS(ERRSYNCESC3);
1267 PIS(ERRESC1);
1268 PIS(ERRESC2);
1269 PIS(ERRESC3);
1270 PIS(ERRCONTROL1);
1271 PIS(ERRCONTROL2);
1272 PIS(ERRCONTROL3);
1273 PIS(STATEULPS1);
1274 PIS(STATEULPS2);
1275 PIS(STATEULPS3);
1276 PIS(ERRCONTENTIONLP0_1);
1277 PIS(ERRCONTENTIONLP1_1);
1278 PIS(ERRCONTENTIONLP0_2);
1279 PIS(ERRCONTENTIONLP1_2);
1280 PIS(ERRCONTENTIONLP0_3);
1281 PIS(ERRCONTENTIONLP1_3);
1282 PIS(ULPSACTIVENOT_ALL0);
1283 PIS(ULPSACTIVENOT_ALL1);
1284#undef PIS
1285}
1286#endif
1287
1288void dsi_dump_regs(struct seq_file *s)
1289{
1290#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r))
1291
1292 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
1293
1294 DUMPREG(DSI_REVISION);
1295 DUMPREG(DSI_SYSCONFIG);
1296 DUMPREG(DSI_SYSSTATUS);
1297 DUMPREG(DSI_IRQSTATUS);
1298 DUMPREG(DSI_IRQENABLE);
1299 DUMPREG(DSI_CTRL);
1300 DUMPREG(DSI_COMPLEXIO_CFG1);
1301 DUMPREG(DSI_COMPLEXIO_IRQ_STATUS);
1302 DUMPREG(DSI_COMPLEXIO_IRQ_ENABLE);
1303 DUMPREG(DSI_CLK_CTRL);
1304 DUMPREG(DSI_TIMING1);
1305 DUMPREG(DSI_TIMING2);
1306 DUMPREG(DSI_VM_TIMING1);
1307 DUMPREG(DSI_VM_TIMING2);
1308 DUMPREG(DSI_VM_TIMING3);
1309 DUMPREG(DSI_CLK_TIMING);
1310 DUMPREG(DSI_TX_FIFO_VC_SIZE);
1311 DUMPREG(DSI_RX_FIFO_VC_SIZE);
1312 DUMPREG(DSI_COMPLEXIO_CFG2);
1313 DUMPREG(DSI_RX_FIFO_VC_FULLNESS);
1314 DUMPREG(DSI_VM_TIMING4);
1315 DUMPREG(DSI_TX_FIFO_VC_EMPTINESS);
1316 DUMPREG(DSI_VM_TIMING5);
1317 DUMPREG(DSI_VM_TIMING6);
1318 DUMPREG(DSI_VM_TIMING7);
1319 DUMPREG(DSI_STOPCLK_TIMING);
1320
1321 DUMPREG(DSI_VC_CTRL(0));
1322 DUMPREG(DSI_VC_TE(0));
1323 DUMPREG(DSI_VC_LONG_PACKET_HEADER(0));
1324 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(0));
1325 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(0));
1326 DUMPREG(DSI_VC_IRQSTATUS(0));
1327 DUMPREG(DSI_VC_IRQENABLE(0));
1328
1329 DUMPREG(DSI_VC_CTRL(1));
1330 DUMPREG(DSI_VC_TE(1));
1331 DUMPREG(DSI_VC_LONG_PACKET_HEADER(1));
1332 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(1));
1333 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(1));
1334 DUMPREG(DSI_VC_IRQSTATUS(1));
1335 DUMPREG(DSI_VC_IRQENABLE(1));
1336
1337 DUMPREG(DSI_VC_CTRL(2));
1338 DUMPREG(DSI_VC_TE(2));
1339 DUMPREG(DSI_VC_LONG_PACKET_HEADER(2));
1340 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(2));
1341 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(2));
1342 DUMPREG(DSI_VC_IRQSTATUS(2));
1343 DUMPREG(DSI_VC_IRQENABLE(2));
1344
1345 DUMPREG(DSI_VC_CTRL(3));
1346 DUMPREG(DSI_VC_TE(3));
1347 DUMPREG(DSI_VC_LONG_PACKET_HEADER(3));
1348 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(3));
1349 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(3));
1350 DUMPREG(DSI_VC_IRQSTATUS(3));
1351 DUMPREG(DSI_VC_IRQENABLE(3));
1352
1353 DUMPREG(DSI_DSIPHY_CFG0);
1354 DUMPREG(DSI_DSIPHY_CFG1);
1355 DUMPREG(DSI_DSIPHY_CFG2);
1356 DUMPREG(DSI_DSIPHY_CFG5);
1357
1358 DUMPREG(DSI_PLL_CONTROL);
1359 DUMPREG(DSI_PLL_STATUS);
1360 DUMPREG(DSI_PLL_GO);
1361 DUMPREG(DSI_PLL_CONFIGURATION1);
1362 DUMPREG(DSI_PLL_CONFIGURATION2);
1363
1364 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
1365#undef DUMPREG
1366}
1367
1368enum dsi_complexio_power_state {
1369 DSI_COMPLEXIO_POWER_OFF = 0x0,
1370 DSI_COMPLEXIO_POWER_ON = 0x1,
1371 DSI_COMPLEXIO_POWER_ULPS = 0x2,
1372};
1373
1374static int dsi_complexio_power(enum dsi_complexio_power_state state)
1375{
1376 int t = 0;
1377
1378 /* PWR_CMD */
1379 REG_FLD_MOD(DSI_COMPLEXIO_CFG1, state, 28, 27);
1380
1381 /* PWR_STATUS */
1382 while (FLD_GET(dsi_read_reg(DSI_COMPLEXIO_CFG1), 26, 25) != state) {
1383 if (++t > 1000) {
1384 DSSERR("failed to set complexio power state to "
1385 "%d\n", state);
1386 return -ENODEV;
1387 }
1388 udelay(1);
1389 }
1390
1391 return 0;
1392}
1393
1394static void dsi_complexio_config(struct omap_dss_device *dssdev)
1395{
1396 u32 r;
1397
1398 int clk_lane = dssdev->phy.dsi.clk_lane;
1399 int data1_lane = dssdev->phy.dsi.data1_lane;
1400 int data2_lane = dssdev->phy.dsi.data2_lane;
1401 int clk_pol = dssdev->phy.dsi.clk_pol;
1402 int data1_pol = dssdev->phy.dsi.data1_pol;
1403 int data2_pol = dssdev->phy.dsi.data2_pol;
1404
1405 r = dsi_read_reg(DSI_COMPLEXIO_CFG1);
1406 r = FLD_MOD(r, clk_lane, 2, 0);
1407 r = FLD_MOD(r, clk_pol, 3, 3);
1408 r = FLD_MOD(r, data1_lane, 6, 4);
1409 r = FLD_MOD(r, data1_pol, 7, 7);
1410 r = FLD_MOD(r, data2_lane, 10, 8);
1411 r = FLD_MOD(r, data2_pol, 11, 11);
1412 dsi_write_reg(DSI_COMPLEXIO_CFG1, r);
1413
1414 /* The configuration of the DSI complex I/O (number of data lanes,
1415 position, differential order) should not be changed while
1416 DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for
1417 the hardware to take into account a new configuration of the complex
1418 I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to
1419 follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1,
1420 then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set
1421 DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the
1422 DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the
1423 DSI complex I/O configuration is unknown. */
1424
1425 /*
1426 REG_FLD_MOD(DSI_CTRL, 1, 0, 0);
1427 REG_FLD_MOD(DSI_CTRL, 0, 0, 0);
1428 REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20);
1429 REG_FLD_MOD(DSI_CTRL, 1, 0, 0);
1430 */
1431}
1432
1433static inline unsigned ns2ddr(unsigned ns)
1434{
1435 /* convert time in ns to ddr ticks, rounding up */
1436 unsigned long ddr_clk = dsi.current_cinfo.clkin4ddr / 4;
1437 return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
1438}
1439
1440static inline unsigned ddr2ns(unsigned ddr)
1441{
1442 unsigned long ddr_clk = dsi.current_cinfo.clkin4ddr / 4;
1443 return ddr * 1000 * 1000 / (ddr_clk / 1000);
1444}
1445
1446static void dsi_complexio_timings(void)
1447{
1448 u32 r;
1449 u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
1450 u32 tlpx_half, tclk_trail, tclk_zero;
1451 u32 tclk_prepare;
1452
1453 /* calculate timings */
1454
1455 /* 1 * DDR_CLK = 2 * UI */
1456
1457 /* min 40ns + 4*UI max 85ns + 6*UI */
1458 ths_prepare = ns2ddr(70) + 2;
1459
1460 /* min 145ns + 10*UI */
1461 ths_prepare_ths_zero = ns2ddr(175) + 2;
1462
1463 /* min max(8*UI, 60ns+4*UI) */
1464 ths_trail = ns2ddr(60) + 5;
1465
1466 /* min 100ns */
1467 ths_exit = ns2ddr(145);
1468
1469 /* tlpx min 50n */
1470 tlpx_half = ns2ddr(25);
1471
1472 /* min 60ns */
1473 tclk_trail = ns2ddr(60) + 2;
1474
1475 /* min 38ns, max 95ns */
1476 tclk_prepare = ns2ddr(65);
1477
1478 /* min tclk-prepare + tclk-zero = 300ns */
1479 tclk_zero = ns2ddr(260);
1480
1481 DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
1482 ths_prepare, ddr2ns(ths_prepare),
1483 ths_prepare_ths_zero, ddr2ns(ths_prepare_ths_zero));
1484 DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
1485 ths_trail, ddr2ns(ths_trail),
1486 ths_exit, ddr2ns(ths_exit));
1487
1488 DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
1489 "tclk_zero %u (%uns)\n",
1490 tlpx_half, ddr2ns(tlpx_half),
1491 tclk_trail, ddr2ns(tclk_trail),
1492 tclk_zero, ddr2ns(tclk_zero));
1493 DSSDBG("tclk_prepare %u (%uns)\n",
1494 tclk_prepare, ddr2ns(tclk_prepare));
1495
1496 /* program timings */
1497
1498 r = dsi_read_reg(DSI_DSIPHY_CFG0);
1499 r = FLD_MOD(r, ths_prepare, 31, 24);
1500 r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
1501 r = FLD_MOD(r, ths_trail, 15, 8);
1502 r = FLD_MOD(r, ths_exit, 7, 0);
1503 dsi_write_reg(DSI_DSIPHY_CFG0, r);
1504
1505 r = dsi_read_reg(DSI_DSIPHY_CFG1);
1506 r = FLD_MOD(r, tlpx_half, 22, 16);
1507 r = FLD_MOD(r, tclk_trail, 15, 8);
1508 r = FLD_MOD(r, tclk_zero, 7, 0);
1509 dsi_write_reg(DSI_DSIPHY_CFG1, r);
1510
1511 r = dsi_read_reg(DSI_DSIPHY_CFG2);
1512 r = FLD_MOD(r, tclk_prepare, 7, 0);
1513 dsi_write_reg(DSI_DSIPHY_CFG2, r);
1514}
1515
1516
1517static int dsi_complexio_init(struct omap_dss_device *dssdev)
1518{
1519 int r = 0;
1520
1521 DSSDBG("dsi_complexio_init\n");
1522
1523 /* CIO_CLK_ICG, enable L3 clk to CIO */
1524 REG_FLD_MOD(DSI_CLK_CTRL, 1, 14, 14);
1525
1526 /* A dummy read using the SCP interface to any DSIPHY register is
1527 * required after DSIPHY reset to complete the reset of the DSI complex
1528 * I/O. */
1529 dsi_read_reg(DSI_DSIPHY_CFG5);
1530
1531 if (wait_for_bit_change(DSI_DSIPHY_CFG5, 30, 1) != 1) {
1532 DSSERR("ComplexIO PHY not coming out of reset.\n");
1533 r = -ENODEV;
1534 goto err;
1535 }
1536
1537 dsi_complexio_config(dssdev);
1538
1539 r = dsi_complexio_power(DSI_COMPLEXIO_POWER_ON);
1540
1541 if (r)
1542 goto err;
1543
1544 if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
1545 DSSERR("ComplexIO not coming out of reset.\n");
1546 r = -ENODEV;
1547 goto err;
1548 }
1549
1550 if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 21, 1) != 1) {
1551 DSSERR("ComplexIO LDO power down.\n");
1552 r = -ENODEV;
1553 goto err;
1554 }
1555
1556 dsi_complexio_timings();
1557
1558 /*
1559 The configuration of the DSI complex I/O (number of data lanes,
1560 position, differential order) should not be changed while
1561 DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. For the
1562 hardware to recognize a new configuration of the complex I/O (done
1563 in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to follow
1564 this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, next
1565 reset the DSS.DSI_CTRL[0] IF_EN to 0, then set DSS.DSI_CLK_CTRL[20]
1566 LP_CLK_ENABLE to 1, and finally, set again the DSS.DSI_CTRL[0] IF_EN
1567 bit to 1. If the sequence is not followed, the DSi complex I/O
1568 configuration is undetermined.
1569 */
1570 dsi_if_enable(1);
1571 dsi_if_enable(0);
1572 REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
1573 dsi_if_enable(1);
1574 dsi_if_enable(0);
1575
1576 DSSDBG("CIO init done\n");
1577err:
1578 return r;
1579}
1580
1581static void dsi_complexio_uninit(void)
1582{
1583 dsi_complexio_power(DSI_COMPLEXIO_POWER_OFF);
1584}
1585
1586static int _dsi_wait_reset(void)
1587{
1588 int t = 0;
1589
1590 while (REG_GET(DSI_SYSSTATUS, 0, 0) == 0) {
1591 if (++t > 5) {
1592 DSSERR("soft reset failed\n");
1593 return -ENODEV;
1594 }
1595 udelay(1);
1596 }
1597
1598 return 0;
1599}
1600
1601static int _dsi_reset(void)
1602{
1603 /* Soft reset */
1604 REG_FLD_MOD(DSI_SYSCONFIG, 1, 1, 1);
1605 return _dsi_wait_reset();
1606}
1607
1608static void dsi_reset_tx_fifo(int channel)
1609{
1610 u32 mask;
1611 u32 l;
1612
1613 /* set fifosize of the channel to 0, then return the old size */
1614 l = dsi_read_reg(DSI_TX_FIFO_VC_SIZE);
1615
1616 mask = FLD_MASK((8 * channel) + 7, (8 * channel) + 4);
1617 dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l & ~mask);
1618
1619 dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l);
1620}
1621
1622static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
1623 enum fifo_size size3, enum fifo_size size4)
1624{
1625 u32 r = 0;
1626 int add = 0;
1627 int i;
1628
1629 dsi.vc[0].fifo_size = size1;
1630 dsi.vc[1].fifo_size = size2;
1631 dsi.vc[2].fifo_size = size3;
1632 dsi.vc[3].fifo_size = size4;
1633
1634 for (i = 0; i < 4; i++) {
1635 u8 v;
1636 int size = dsi.vc[i].fifo_size;
1637
1638 if (add + size > 4) {
1639 DSSERR("Illegal FIFO configuration\n");
1640 BUG();
1641 }
1642
1643 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
1644 r |= v << (8 * i);
1645 /*DSSDBG("TX FIFO vc %d: size %d, add %d\n", i, size, add); */
1646 add += size;
1647 }
1648
1649 dsi_write_reg(DSI_TX_FIFO_VC_SIZE, r);
1650}
1651
1652static void dsi_config_rx_fifo(enum fifo_size size1, enum fifo_size size2,
1653 enum fifo_size size3, enum fifo_size size4)
1654{
1655 u32 r = 0;
1656 int add = 0;
1657 int i;
1658
1659 dsi.vc[0].fifo_size = size1;
1660 dsi.vc[1].fifo_size = size2;
1661 dsi.vc[2].fifo_size = size3;
1662 dsi.vc[3].fifo_size = size4;
1663
1664 for (i = 0; i < 4; i++) {
1665 u8 v;
1666 int size = dsi.vc[i].fifo_size;
1667
1668 if (add + size > 4) {
1669 DSSERR("Illegal FIFO configuration\n");
1670 BUG();
1671 }
1672
1673 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
1674 r |= v << (8 * i);
1675 /*DSSDBG("RX FIFO vc %d: size %d, add %d\n", i, size, add); */
1676 add += size;
1677 }
1678
1679 dsi_write_reg(DSI_RX_FIFO_VC_SIZE, r);
1680}
1681
1682static int dsi_force_tx_stop_mode_io(void)
1683{
1684 u32 r;
1685
1686 r = dsi_read_reg(DSI_TIMING1);
1687 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
1688 dsi_write_reg(DSI_TIMING1, r);
1689
1690 if (wait_for_bit_change(DSI_TIMING1, 15, 0) != 0) {
1691 DSSERR("TX_STOP bit not going down\n");
1692 return -EIO;
1693 }
1694
1695 return 0;
1696}
1697
1698static int dsi_vc_enable(int channel, bool enable)
1699{
1700 DSSDBG("dsi_vc_enable channel %d, enable %d\n",
1701 channel, enable);
1702
1703 enable = enable ? 1 : 0;
1704
1705 REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 0, 0);
1706
1707 if (wait_for_bit_change(DSI_VC_CTRL(channel), 0, enable) != enable) {
1708 DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
1709 return -EIO;
1710 }
1711
1712 return 0;
1713}
1714
1715static void dsi_vc_initial_config(int channel)
1716{
1717 u32 r;
1718
1719 DSSDBGF("%d", channel);
1720
1721 r = dsi_read_reg(DSI_VC_CTRL(channel));
1722
1723 if (FLD_GET(r, 15, 15)) /* VC_BUSY */
1724 DSSERR("VC(%d) busy when trying to configure it!\n",
1725 channel);
1726
1727 r = FLD_MOD(r, 0, 1, 1); /* SOURCE, 0 = L4 */
1728 r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN */
1729 r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */
1730 r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */
1731 r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
1732 r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
1733 r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
1734
1735 r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
1736 r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
1737
1738 dsi_write_reg(DSI_VC_CTRL(channel), r);
1739
1740 dsi.vc[channel].mode = DSI_VC_MODE_L4;
1741}
1742
1743static void dsi_vc_config_l4(int channel)
1744{
1745 if (dsi.vc[channel].mode == DSI_VC_MODE_L4)
1746 return;
1747
1748 DSSDBGF("%d", channel);
1749
1750 dsi_vc_enable(channel, 0);
1751
1752 if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
1753 DSSERR("vc(%d) busy when trying to config for L4\n", channel);
1754
1755 REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
1756
1757 dsi_vc_enable(channel, 1);
1758
1759 dsi.vc[channel].mode = DSI_VC_MODE_L4;
1760}
1761
1762static void dsi_vc_config_vp(int channel)
1763{
1764 if (dsi.vc[channel].mode == DSI_VC_MODE_VP)
1765 return;
1766
1767 DSSDBGF("%d", channel);
1768
1769 dsi_vc_enable(channel, 0);
1770
1771 if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
1772 DSSERR("vc(%d) busy when trying to config for VP\n", channel);
1773
1774 REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */
1775
1776 dsi_vc_enable(channel, 1);
1777
1778 dsi.vc[channel].mode = DSI_VC_MODE_VP;
1779}
1780
1781
1782void omapdss_dsi_vc_enable_hs(int channel, bool enable)
1783{
1784 DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
1785
1786 WARN_ON(!dsi_bus_is_locked());
1787
1788 dsi_vc_enable(channel, 0);
1789 dsi_if_enable(0);
1790
1791 REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 9, 9);
1792
1793 dsi_vc_enable(channel, 1);
1794 dsi_if_enable(1);
1795
1796 dsi_force_tx_stop_mode_io();
1797}
1798EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs);
1799
1800static void dsi_vc_flush_long_data(int channel)
1801{
1802 while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
1803 u32 val;
1804 val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
1805 DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
1806 (val >> 0) & 0xff,
1807 (val >> 8) & 0xff,
1808 (val >> 16) & 0xff,
1809 (val >> 24) & 0xff);
1810 }
1811}
1812
1813static void dsi_show_rx_ack_with_err(u16 err)
1814{
1815 DSSERR("\tACK with ERROR (%#x):\n", err);
1816 if (err & (1 << 0))
1817 DSSERR("\t\tSoT Error\n");
1818 if (err & (1 << 1))
1819 DSSERR("\t\tSoT Sync Error\n");
1820 if (err & (1 << 2))
1821 DSSERR("\t\tEoT Sync Error\n");
1822 if (err & (1 << 3))
1823 DSSERR("\t\tEscape Mode Entry Command Error\n");
1824 if (err & (1 << 4))
1825 DSSERR("\t\tLP Transmit Sync Error\n");
1826 if (err & (1 << 5))
1827 DSSERR("\t\tHS Receive Timeout Error\n");
1828 if (err & (1 << 6))
1829 DSSERR("\t\tFalse Control Error\n");
1830 if (err & (1 << 7))
1831 DSSERR("\t\t(reserved7)\n");
1832 if (err & (1 << 8))
1833 DSSERR("\t\tECC Error, single-bit (corrected)\n");
1834 if (err & (1 << 9))
1835 DSSERR("\t\tECC Error, multi-bit (not corrected)\n");
1836 if (err & (1 << 10))
1837 DSSERR("\t\tChecksum Error\n");
1838 if (err & (1 << 11))
1839 DSSERR("\t\tData type not recognized\n");
1840 if (err & (1 << 12))
1841 DSSERR("\t\tInvalid VC ID\n");
1842 if (err & (1 << 13))
1843 DSSERR("\t\tInvalid Transmission Length\n");
1844 if (err & (1 << 14))
1845 DSSERR("\t\t(reserved14)\n");
1846 if (err & (1 << 15))
1847 DSSERR("\t\tDSI Protocol Violation\n");
1848}
1849
1850static u16 dsi_vc_flush_receive_data(int channel)
1851{
1852 /* RX_FIFO_NOT_EMPTY */
1853 while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
1854 u32 val;
1855 u8 dt;
1856 val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
1857 DSSDBG("\trawval %#08x\n", val);
1858 dt = FLD_GET(val, 5, 0);
1859 if (dt == DSI_DT_RX_ACK_WITH_ERR) {
1860 u16 err = FLD_GET(val, 23, 8);
1861 dsi_show_rx_ack_with_err(err);
1862 } else if (dt == DSI_DT_RX_SHORT_READ_1) {
1863 DSSDBG("\tDCS short response, 1 byte: %#x\n",
1864 FLD_GET(val, 23, 8));
1865 } else if (dt == DSI_DT_RX_SHORT_READ_2) {
1866 DSSDBG("\tDCS short response, 2 byte: %#x\n",
1867 FLD_GET(val, 23, 8));
1868 } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
1869 DSSDBG("\tDCS long response, len %d\n",
1870 FLD_GET(val, 23, 8));
1871 dsi_vc_flush_long_data(channel);
1872 } else {
1873 DSSERR("\tunknown datatype 0x%02x\n", dt);
1874 }
1875 }
1876 return 0;
1877}
1878
1879static int dsi_vc_send_bta(int channel)
1880{
1881 if (dsi.debug_write || dsi.debug_read)
1882 DSSDBG("dsi_vc_send_bta %d\n", channel);
1883
1884 WARN_ON(!dsi_bus_is_locked());
1885
1886 if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */
1887 DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
1888 dsi_vc_flush_receive_data(channel);
1889 }
1890
1891 REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
1892
1893 return 0;
1894}
1895
1896int dsi_vc_send_bta_sync(int channel)
1897{
1898 int r = 0;
1899 u32 err;
1900
1901 INIT_COMPLETION(dsi.bta_completion);
1902
1903 dsi_vc_enable_bta_irq(channel);
1904
1905 r = dsi_vc_send_bta(channel);
1906 if (r)
1907 goto err;
1908
1909 if (wait_for_completion_timeout(&dsi.bta_completion,
1910 msecs_to_jiffies(500)) == 0) {
1911 DSSERR("Failed to receive BTA\n");
1912 r = -EIO;
1913 goto err;
1914 }
1915
1916 err = dsi_get_errors();
1917 if (err) {
1918 DSSERR("Error while sending BTA: %x\n", err);
1919 r = -EIO;
1920 goto err;
1921 }
1922err:
1923 dsi_vc_disable_bta_irq(channel);
1924
1925 return r;
1926}
1927EXPORT_SYMBOL(dsi_vc_send_bta_sync);
1928
1929static inline void dsi_vc_write_long_header(int channel, u8 data_type,
1930 u16 len, u8 ecc)
1931{
1932 u32 val;
1933 u8 data_id;
1934
1935 WARN_ON(!dsi_bus_is_locked());
1936
1937 data_id = data_type | channel << 6;
1938
1939 val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
1940 FLD_VAL(ecc, 31, 24);
1941
1942 dsi_write_reg(DSI_VC_LONG_PACKET_HEADER(channel), val);
1943}
1944
1945static inline void dsi_vc_write_long_payload(int channel,
1946 u8 b1, u8 b2, u8 b3, u8 b4)
1947{
1948 u32 val;
1949
1950 val = b4 << 24 | b3 << 16 | b2 << 8 | b1 << 0;
1951
1952/* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
1953 b1, b2, b3, b4, val); */
1954
1955 dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
1956}
1957
1958static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
1959 u8 ecc)
1960{
1961 /*u32 val; */
1962 int i;
1963 u8 *p;
1964 int r = 0;
1965 u8 b1, b2, b3, b4;
1966
1967 if (dsi.debug_write)
1968 DSSDBG("dsi_vc_send_long, %d bytes\n", len);
1969
1970 /* len + header */
1971 if (dsi.vc[channel].fifo_size * 32 * 4 < len + 4) {
1972 DSSERR("unable to send long packet: packet too long.\n");
1973 return -EINVAL;
1974 }
1975
1976 dsi_vc_config_l4(channel);
1977
1978 dsi_vc_write_long_header(channel, data_type, len, ecc);
1979
1980 p = data;
1981 for (i = 0; i < len >> 2; i++) {
1982 if (dsi.debug_write)
1983 DSSDBG("\tsending full packet %d\n", i);
1984
1985 b1 = *p++;
1986 b2 = *p++;
1987 b3 = *p++;
1988 b4 = *p++;
1989
1990 dsi_vc_write_long_payload(channel, b1, b2, b3, b4);
1991 }
1992
1993 i = len % 4;
1994 if (i) {
1995 b1 = 0; b2 = 0; b3 = 0;
1996
1997 if (dsi.debug_write)
1998 DSSDBG("\tsending remainder bytes %d\n", i);
1999
2000 switch (i) {
2001 case 3:
2002 b1 = *p++;
2003 b2 = *p++;
2004 b3 = *p++;
2005 break;
2006 case 2:
2007 b1 = *p++;
2008 b2 = *p++;
2009 break;
2010 case 1:
2011 b1 = *p++;
2012 break;
2013 }
2014
2015 dsi_vc_write_long_payload(channel, b1, b2, b3, 0);
2016 }
2017
2018 return r;
2019}
2020
2021static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
2022{
2023 u32 r;
2024 u8 data_id;
2025
2026 WARN_ON(!dsi_bus_is_locked());
2027
2028 if (dsi.debug_write)
2029 DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
2030 channel,
2031 data_type, data & 0xff, (data >> 8) & 0xff);
2032
2033 dsi_vc_config_l4(channel);
2034
2035 if (FLD_GET(dsi_read_reg(DSI_VC_CTRL(channel)), 16, 16)) {
2036 DSSERR("ERROR FIFO FULL, aborting transfer\n");
2037 return -EINVAL;
2038 }
2039
2040 data_id = data_type | channel << 6;
2041
2042 r = (data_id << 0) | (data << 8) | (ecc << 24);
2043
2044 dsi_write_reg(DSI_VC_SHORT_PACKET_HEADER(channel), r);
2045
2046 return 0;
2047}
2048
2049int dsi_vc_send_null(int channel)
2050{
2051 u8 nullpkg[] = {0, 0, 0, 0};
2052 return dsi_vc_send_long(channel, DSI_DT_NULL_PACKET, nullpkg, 4, 0);
2053}
2054EXPORT_SYMBOL(dsi_vc_send_null);
2055
2056int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len)
2057{
2058 int r;
2059
2060 BUG_ON(len == 0);
2061
2062 if (len == 1) {
2063 r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_0,
2064 data[0], 0);
2065 } else if (len == 2) {
2066 r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_1,
2067 data[0] | (data[1] << 8), 0);
2068 } else {
2069 /* 0x39 = DCS Long Write */
2070 r = dsi_vc_send_long(channel, DSI_DT_DCS_LONG_WRITE,
2071 data, len, 0);
2072 }
2073
2074 return r;
2075}
2076EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
2077
2078int dsi_vc_dcs_write(int channel, u8 *data, int len)
2079{
2080 int r;
2081
2082 r = dsi_vc_dcs_write_nosync(channel, data, len);
2083 if (r)
2084 goto err;
2085
2086 r = dsi_vc_send_bta_sync(channel);
2087 if (r)
2088 goto err;
2089
2090 return 0;
2091err:
2092 DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n",
2093 channel, data[0], len);
2094 return r;
2095}
2096EXPORT_SYMBOL(dsi_vc_dcs_write);
2097
2098int dsi_vc_dcs_write_0(int channel, u8 dcs_cmd)
2099{
2100 return dsi_vc_dcs_write(channel, &dcs_cmd, 1);
2101}
2102EXPORT_SYMBOL(dsi_vc_dcs_write_0);
2103
2104int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param)
2105{
2106 u8 buf[2];
2107 buf[0] = dcs_cmd;
2108 buf[1] = param;
2109 return dsi_vc_dcs_write(channel, buf, 2);
2110}
2111EXPORT_SYMBOL(dsi_vc_dcs_write_1);
2112
2113int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
2114{
2115 u32 val;
2116 u8 dt;
2117 int r;
2118
2119 if (dsi.debug_read)
2120 DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %x)\n", channel, dcs_cmd);
2121
2122 r = dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0);
2123 if (r)
2124 goto err;
2125
2126 r = dsi_vc_send_bta_sync(channel);
2127 if (r)
2128 goto err;
2129
2130 /* RX_FIFO_NOT_EMPTY */
2131 if (REG_GET(DSI_VC_CTRL(channel), 20, 20) == 0) {
2132 DSSERR("RX fifo empty when trying to read.\n");
2133 r = -EIO;
2134 goto err;
2135 }
2136
2137 val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
2138 if (dsi.debug_read)
2139 DSSDBG("\theader: %08x\n", val);
2140 dt = FLD_GET(val, 5, 0);
2141 if (dt == DSI_DT_RX_ACK_WITH_ERR) {
2142 u16 err = FLD_GET(val, 23, 8);
2143 dsi_show_rx_ack_with_err(err);
2144 r = -EIO;
2145 goto err;
2146
2147 } else if (dt == DSI_DT_RX_SHORT_READ_1) {
2148 u8 data = FLD_GET(val, 15, 8);
2149 if (dsi.debug_read)
2150 DSSDBG("\tDCS short response, 1 byte: %02x\n", data);
2151
2152 if (buflen < 1) {
2153 r = -EIO;
2154 goto err;
2155 }
2156
2157 buf[0] = data;
2158
2159 return 1;
2160 } else if (dt == DSI_DT_RX_SHORT_READ_2) {
2161 u16 data = FLD_GET(val, 23, 8);
2162 if (dsi.debug_read)
2163 DSSDBG("\tDCS short response, 2 byte: %04x\n", data);
2164
2165 if (buflen < 2) {
2166 r = -EIO;
2167 goto err;
2168 }
2169
2170 buf[0] = data & 0xff;
2171 buf[1] = (data >> 8) & 0xff;
2172
2173 return 2;
2174 } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
2175 int w;
2176 int len = FLD_GET(val, 23, 8);
2177 if (dsi.debug_read)
2178 DSSDBG("\tDCS long response, len %d\n", len);
2179
2180 if (len > buflen) {
2181 r = -EIO;
2182 goto err;
2183 }
2184
2185 /* two byte checksum ends the packet, not included in len */
2186 for (w = 0; w < len + 2;) {
2187 int b;
2188 val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
2189 if (dsi.debug_read)
2190 DSSDBG("\t\t%02x %02x %02x %02x\n",
2191 (val >> 0) & 0xff,
2192 (val >> 8) & 0xff,
2193 (val >> 16) & 0xff,
2194 (val >> 24) & 0xff);
2195
2196 for (b = 0; b < 4; ++b) {
2197 if (w < len)
2198 buf[w] = (val >> (b * 8)) & 0xff;
2199 /* we discard the 2 byte checksum */
2200 ++w;
2201 }
2202 }
2203
2204 return len;
2205 } else {
2206 DSSERR("\tunknown datatype 0x%02x\n", dt);
2207 r = -EIO;
2208 goto err;
2209 }
2210
2211 BUG();
2212err:
2213 DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n",
2214 channel, dcs_cmd);
2215 return r;
2216
2217}
2218EXPORT_SYMBOL(dsi_vc_dcs_read);
2219
2220int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data)
2221{
2222 int r;
2223
2224 r = dsi_vc_dcs_read(channel, dcs_cmd, data, 1);
2225
2226 if (r < 0)
2227 return r;
2228
2229 if (r != 1)
2230 return -EIO;
2231
2232 return 0;
2233}
2234EXPORT_SYMBOL(dsi_vc_dcs_read_1);
2235
2236int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data)
2237{
2238 int r;
2239
2240 r = dsi_vc_dcs_read(channel, dcs_cmd, (u8 *)data, 2);
2241
2242 if (r < 0)
2243 return r;
2244
2245 if (r != 2)
2246 return -EIO;
2247
2248 return 0;
2249}
2250EXPORT_SYMBOL(dsi_vc_dcs_read_2);
2251
2252int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
2253{
2254 int r;
2255 r = dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
2256 len, 0);
2257
2258 if (r)
2259 return r;
2260
2261 r = dsi_vc_send_bta_sync(channel);
2262
2263 return r;
2264}
2265EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
2266
2267static void dsi_set_lp_rx_timeout(unsigned long ns)
2268{
2269 u32 r;
2270 unsigned x4, x16;
2271 unsigned long fck;
2272 unsigned long ticks;
2273
2274 /* ticks in DSI_FCK */
2275
2276 fck = dsi_fclk_rate();
2277 ticks = (fck / 1000 / 1000) * ns / 1000;
2278 x4 = 0;
2279 x16 = 0;
2280
2281 if (ticks > 0x1fff) {
2282 ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
2283 x4 = 1;
2284 x16 = 0;
2285 }
2286
2287 if (ticks > 0x1fff) {
2288 ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
2289 x4 = 0;
2290 x16 = 1;
2291 }
2292
2293 if (ticks > 0x1fff) {
2294 ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
2295 x4 = 1;
2296 x16 = 1;
2297 }
2298
2299 if (ticks > 0x1fff) {
2300 DSSWARN("LP_TX_TO over limit, setting it to max\n");
2301 ticks = 0x1fff;
2302 x4 = 1;
2303 x16 = 1;
2304 }
2305
2306 r = dsi_read_reg(DSI_TIMING2);
2307 r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */
2308 r = FLD_MOD(r, x16, 14, 14); /* LP_RX_TO_X16 */
2309 r = FLD_MOD(r, x4, 13, 13); /* LP_RX_TO_X4 */
2310 r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */
2311 dsi_write_reg(DSI_TIMING2, r);
2312
2313 DSSDBG("LP_RX_TO %lu ns (%#lx ticks%s%s)\n",
2314 (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
2315 (fck / 1000 / 1000),
2316 ticks, x4 ? " x4" : "", x16 ? " x16" : "");
2317}
2318
2319static void dsi_set_ta_timeout(unsigned long ns)
2320{
2321 u32 r;
2322 unsigned x8, x16;
2323 unsigned long fck;
2324 unsigned long ticks;
2325
2326 /* ticks in DSI_FCK */
2327 fck = dsi_fclk_rate();
2328 ticks = (fck / 1000 / 1000) * ns / 1000;
2329 x8 = 0;
2330 x16 = 0;
2331
2332 if (ticks > 0x1fff) {
2333 ticks = (fck / 1000 / 1000) * ns / 1000 / 8;
2334 x8 = 1;
2335 x16 = 0;
2336 }
2337
2338 if (ticks > 0x1fff) {
2339 ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
2340 x8 = 0;
2341 x16 = 1;
2342 }
2343
2344 if (ticks > 0x1fff) {
2345 ticks = (fck / 1000 / 1000) * ns / 1000 / (8 * 16);
2346 x8 = 1;
2347 x16 = 1;
2348 }
2349
2350 if (ticks > 0x1fff) {
2351 DSSWARN("TA_TO over limit, setting it to max\n");
2352 ticks = 0x1fff;
2353 x8 = 1;
2354 x16 = 1;
2355 }
2356
2357 r = dsi_read_reg(DSI_TIMING1);
2358 r = FLD_MOD(r, 1, 31, 31); /* TA_TO */
2359 r = FLD_MOD(r, x16, 30, 30); /* TA_TO_X16 */
2360 r = FLD_MOD(r, x8, 29, 29); /* TA_TO_X8 */
2361 r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */
2362 dsi_write_reg(DSI_TIMING1, r);
2363
2364 DSSDBG("TA_TO %lu ns (%#lx ticks%s%s)\n",
2365 (ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1) * 1000) /
2366 (fck / 1000 / 1000),
2367 ticks, x8 ? " x8" : "", x16 ? " x16" : "");
2368}
2369
2370static void dsi_set_stop_state_counter(unsigned long ns)
2371{
2372 u32 r;
2373 unsigned x4, x16;
2374 unsigned long fck;
2375 unsigned long ticks;
2376
2377 /* ticks in DSI_FCK */
2378
2379 fck = dsi_fclk_rate();
2380 ticks = (fck / 1000 / 1000) * ns / 1000;
2381 x4 = 0;
2382 x16 = 0;
2383
2384 if (ticks > 0x1fff) {
2385 ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
2386 x4 = 1;
2387 x16 = 0;
2388 }
2389
2390 if (ticks > 0x1fff) {
2391 ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
2392 x4 = 0;
2393 x16 = 1;
2394 }
2395
2396 if (ticks > 0x1fff) {
2397 ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
2398 x4 = 1;
2399 x16 = 1;
2400 }
2401
2402 if (ticks > 0x1fff) {
2403 DSSWARN("STOP_STATE_COUNTER_IO over limit, "
2404 "setting it to max\n");
2405 ticks = 0x1fff;
2406 x4 = 1;
2407 x16 = 1;
2408 }
2409
2410 r = dsi_read_reg(DSI_TIMING1);
2411 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
2412 r = FLD_MOD(r, x16, 14, 14); /* STOP_STATE_X16_IO */
2413 r = FLD_MOD(r, x4, 13, 13); /* STOP_STATE_X4_IO */
2414 r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */
2415 dsi_write_reg(DSI_TIMING1, r);
2416
2417 DSSDBG("STOP_STATE_COUNTER %lu ns (%#lx ticks%s%s)\n",
2418 (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
2419 (fck / 1000 / 1000),
2420 ticks, x4 ? " x4" : "", x16 ? " x16" : "");
2421}
2422
2423static void dsi_set_hs_tx_timeout(unsigned long ns)
2424{
2425 u32 r;
2426 unsigned x4, x16;
2427 unsigned long fck;
2428 unsigned long ticks;
2429
2430 /* ticks in TxByteClkHS */
2431
2432 fck = dsi_get_txbyteclkhs();
2433 ticks = (fck / 1000 / 1000) * ns / 1000;
2434 x4 = 0;
2435 x16 = 0;
2436
2437 if (ticks > 0x1fff) {
2438 ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
2439 x4 = 1;
2440 x16 = 0;
2441 }
2442
2443 if (ticks > 0x1fff) {
2444 ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
2445 x4 = 0;
2446 x16 = 1;
2447 }
2448
2449 if (ticks > 0x1fff) {
2450 ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
2451 x4 = 1;
2452 x16 = 1;
2453 }
2454
2455 if (ticks > 0x1fff) {
2456 DSSWARN("HS_TX_TO over limit, setting it to max\n");
2457 ticks = 0x1fff;
2458 x4 = 1;
2459 x16 = 1;
2460 }
2461
2462 r = dsi_read_reg(DSI_TIMING2);
2463 r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */
2464 r = FLD_MOD(r, x16, 30, 30); /* HS_TX_TO_X16 */
2465 r = FLD_MOD(r, x4, 29, 29); /* HS_TX_TO_X8 (4 really) */
2466 r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */
2467 dsi_write_reg(DSI_TIMING2, r);
2468
2469 DSSDBG("HS_TX_TO %lu ns (%#lx ticks%s%s)\n",
2470 (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
2471 (fck / 1000 / 1000),
2472 ticks, x4 ? " x4" : "", x16 ? " x16" : "");
2473}
2474static int dsi_proto_config(struct omap_dss_device *dssdev)
2475{
2476 u32 r;
2477 int buswidth = 0;
2478
2479 dsi_config_tx_fifo(DSI_FIFO_SIZE_32,
2480 DSI_FIFO_SIZE_32,
2481 DSI_FIFO_SIZE_32,
2482 DSI_FIFO_SIZE_32);
2483
2484 dsi_config_rx_fifo(DSI_FIFO_SIZE_32,
2485 DSI_FIFO_SIZE_32,
2486 DSI_FIFO_SIZE_32,
2487 DSI_FIFO_SIZE_32);
2488
2489 /* XXX what values for the timeouts? */
2490 dsi_set_stop_state_counter(1000);
2491 dsi_set_ta_timeout(6400000);
2492 dsi_set_lp_rx_timeout(48000);
2493 dsi_set_hs_tx_timeout(1000000);
2494
2495 switch (dssdev->ctrl.pixel_size) {
2496 case 16:
2497 buswidth = 0;
2498 break;
2499 case 18:
2500 buswidth = 1;
2501 break;
2502 case 24:
2503 buswidth = 2;
2504 break;
2505 default:
2506 BUG();
2507 }
2508
2509 r = dsi_read_reg(DSI_CTRL);
2510 r = FLD_MOD(r, 1, 1, 1); /* CS_RX_EN */
2511 r = FLD_MOD(r, 1, 2, 2); /* ECC_RX_EN */
2512 r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */
2513 r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/
2514 r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */
2515 r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */
2516 r = FLD_MOD(r, 2, 13, 12); /* LINE_BUFFER, 2 lines */
2517 r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */
2518 r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */
2519 r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
2520 r = FLD_MOD(r, 0, 25, 25); /* DCS_CMD_CODE, 1=start, 0=continue */
2521
2522 dsi_write_reg(DSI_CTRL, r);
2523
2524 dsi_vc_initial_config(0);
2525 dsi_vc_initial_config(1);
2526 dsi_vc_initial_config(2);
2527 dsi_vc_initial_config(3);
2528
2529 return 0;
2530}
2531
2532static void dsi_proto_timings(struct omap_dss_device *dssdev)
2533{
2534 unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
2535 unsigned tclk_pre, tclk_post;
2536 unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
2537 unsigned ths_trail, ths_exit;
2538 unsigned ddr_clk_pre, ddr_clk_post;
2539 unsigned enter_hs_mode_lat, exit_hs_mode_lat;
2540 unsigned ths_eot;
2541 u32 r;
2542
2543 r = dsi_read_reg(DSI_DSIPHY_CFG0);
2544 ths_prepare = FLD_GET(r, 31, 24);
2545 ths_prepare_ths_zero = FLD_GET(r, 23, 16);
2546 ths_zero = ths_prepare_ths_zero - ths_prepare;
2547 ths_trail = FLD_GET(r, 15, 8);
2548 ths_exit = FLD_GET(r, 7, 0);
2549
2550 r = dsi_read_reg(DSI_DSIPHY_CFG1);
2551 tlpx = FLD_GET(r, 22, 16) * 2;
2552 tclk_trail = FLD_GET(r, 15, 8);
2553 tclk_zero = FLD_GET(r, 7, 0);
2554
2555 r = dsi_read_reg(DSI_DSIPHY_CFG2);
2556 tclk_prepare = FLD_GET(r, 7, 0);
2557
2558 /* min 8*UI */
2559 tclk_pre = 20;
2560 /* min 60ns + 52*UI */
2561 tclk_post = ns2ddr(60) + 26;
2562
2563 /* ths_eot is 2 for 2 datalanes and 4 for 1 datalane */
2564 if (dssdev->phy.dsi.data1_lane != 0 &&
2565 dssdev->phy.dsi.data2_lane != 0)
2566 ths_eot = 2;
2567 else
2568 ths_eot = 4;
2569
2570 ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
2571 4);
2572 ddr_clk_post = DIV_ROUND_UP(tclk_post + ths_trail, 4) + ths_eot;
2573
2574 BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
2575 BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);
2576
2577 r = dsi_read_reg(DSI_CLK_TIMING);
2578 r = FLD_MOD(r, ddr_clk_pre, 15, 8);
2579 r = FLD_MOD(r, ddr_clk_post, 7, 0);
2580 dsi_write_reg(DSI_CLK_TIMING, r);
2581
2582 DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
2583 ddr_clk_pre,
2584 ddr_clk_post);
2585
2586 enter_hs_mode_lat = 1 + DIV_ROUND_UP(tlpx, 4) +
2587 DIV_ROUND_UP(ths_prepare, 4) +
2588 DIV_ROUND_UP(ths_zero + 3, 4);
2589
2590 exit_hs_mode_lat = DIV_ROUND_UP(ths_trail + ths_exit, 4) + 1 + ths_eot;
2591
2592 r = FLD_VAL(enter_hs_mode_lat, 31, 16) |
2593 FLD_VAL(exit_hs_mode_lat, 15, 0);
2594 dsi_write_reg(DSI_VM_TIMING7, r);
2595
2596 DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
2597 enter_hs_mode_lat, exit_hs_mode_lat);
2598}
2599
2600
2601#define DSI_DECL_VARS \
2602 int __dsi_cb = 0; u32 __dsi_cv = 0;
2603
2604#define DSI_FLUSH(ch) \
2605 if (__dsi_cb > 0) { \
2606 /*DSSDBG("sending long packet %#010x\n", __dsi_cv);*/ \
2607 dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \
2608 __dsi_cb = __dsi_cv = 0; \
2609 }
2610
2611#define DSI_PUSH(ch, data) \
2612 do { \
2613 __dsi_cv |= (data) << (__dsi_cb * 8); \
2614 /*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \
2615 if (++__dsi_cb > 3) \
2616 DSI_FLUSH(ch); \
2617 } while (0)
2618
2619static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
2620 int x, int y, int w, int h)
2621{
2622 /* Note: supports only 24bit colors in 32bit container */
2623 int first = 1;
2624 int fifo_stalls = 0;
2625 int max_dsi_packet_size;
2626 int max_data_per_packet;
2627 int max_pixels_per_packet;
2628 int pixels_left;
2629 int bytespp = dssdev->ctrl.pixel_size / 8;
2630 int scr_width;
2631 u32 __iomem *data;
2632 int start_offset;
2633 int horiz_inc;
2634 int current_x;
2635 struct omap_overlay *ovl;
2636
2637 debug_irq = 0;
2638
2639 DSSDBG("dsi_update_screen_l4 (%d,%d %dx%d)\n",
2640 x, y, w, h);
2641
2642 ovl = dssdev->manager->overlays[0];
2643
2644 if (ovl->info.color_mode != OMAP_DSS_COLOR_RGB24U)
2645 return -EINVAL;
2646
2647 if (dssdev->ctrl.pixel_size != 24)
2648 return -EINVAL;
2649
2650 scr_width = ovl->info.screen_width;
2651 data = ovl->info.vaddr;
2652
2653 start_offset = scr_width * y + x;
2654 horiz_inc = scr_width - w;
2655 current_x = x;
2656
2657 /* We need header(4) + DCSCMD(1) + pixels(numpix*bytespp) bytes
2658 * in fifo */
2659
2660 /* When using CPU, max long packet size is TX buffer size */
2661 max_dsi_packet_size = dsi.vc[0].fifo_size * 32 * 4;
2662
2663 /* we seem to get better perf if we divide the tx fifo to half,
2664 and while the other half is being sent, we fill the other half
2665 max_dsi_packet_size /= 2; */
2666
2667 max_data_per_packet = max_dsi_packet_size - 4 - 1;
2668
2669 max_pixels_per_packet = max_data_per_packet / bytespp;
2670
2671 DSSDBG("max_pixels_per_packet %d\n", max_pixels_per_packet);
2672
2673 pixels_left = w * h;
2674
2675 DSSDBG("total pixels %d\n", pixels_left);
2676
2677 data += start_offset;
2678
2679 while (pixels_left > 0) {
2680 /* 0x2c = write_memory_start */
2681 /* 0x3c = write_memory_continue */
2682 u8 dcs_cmd = first ? 0x2c : 0x3c;
2683 int pixels;
2684 DSI_DECL_VARS;
2685 first = 0;
2686
2687#if 1
2688 /* using fifo not empty */
2689 /* TX_FIFO_NOT_EMPTY */
2690 while (FLD_GET(dsi_read_reg(DSI_VC_CTRL(0)), 5, 5)) {
2691 fifo_stalls++;
2692 if (fifo_stalls > 0xfffff) {
2693 DSSERR("fifo stalls overflow, pixels left %d\n",
2694 pixels_left);
2695 dsi_if_enable(0);
2696 return -EIO;
2697 }
2698 udelay(1);
2699 }
2700#elif 1
2701 /* using fifo emptiness */
2702 while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 <
2703 max_dsi_packet_size) {
2704 fifo_stalls++;
2705 if (fifo_stalls > 0xfffff) {
2706 DSSERR("fifo stalls overflow, pixels left %d\n",
2707 pixels_left);
2708 dsi_if_enable(0);
2709 return -EIO;
2710 }
2711 }
2712#else
2713 while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 == 0) {
2714 fifo_stalls++;
2715 if (fifo_stalls > 0xfffff) {
2716 DSSERR("fifo stalls overflow, pixels left %d\n",
2717 pixels_left);
2718 dsi_if_enable(0);
2719 return -EIO;
2720 }
2721 }
2722#endif
2723 pixels = min(max_pixels_per_packet, pixels_left);
2724
2725 pixels_left -= pixels;
2726
2727 dsi_vc_write_long_header(0, DSI_DT_DCS_LONG_WRITE,
2728 1 + pixels * bytespp, 0);
2729
2730 DSI_PUSH(0, dcs_cmd);
2731
2732 while (pixels-- > 0) {
2733 u32 pix = __raw_readl(data++);
2734
2735 DSI_PUSH(0, (pix >> 16) & 0xff);
2736 DSI_PUSH(0, (pix >> 8) & 0xff);
2737 DSI_PUSH(0, (pix >> 0) & 0xff);
2738
2739 current_x++;
2740 if (current_x == x+w) {
2741 current_x = x;
2742 data += horiz_inc;
2743 }
2744 }
2745
2746 DSI_FLUSH(0);
2747 }
2748
2749 return 0;
2750}
2751
2752static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
2753 u16 x, u16 y, u16 w, u16 h)
2754{
2755 unsigned bytespp;
2756 unsigned bytespl;
2757 unsigned bytespf;
2758 unsigned total_len;
2759 unsigned packet_payload;
2760 unsigned packet_len;
2761 u32 l;
2762 const unsigned channel = dsi.update_channel;
2763 /* line buffer is 1024 x 24bits */
2764 /* XXX: for some reason using full buffer size causes considerable TX
2765 * slowdown with update sizes that fill the whole buffer */
2766 const unsigned line_buf_size = 1023 * 3;
2767
2768 DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
2769 x, y, w, h);
2770
2771 dsi_vc_config_vp(channel);
2772
2773 bytespp = dssdev->ctrl.pixel_size / 8;
2774 bytespl = w * bytespp;
2775 bytespf = bytespl * h;
2776
2777 /* NOTE: packet_payload has to be equal to N * bytespl, where N is
2778 * number of lines in a packet. See errata about VP_CLK_RATIO */
2779
2780 if (bytespf < line_buf_size)
2781 packet_payload = bytespf;
2782 else
2783 packet_payload = (line_buf_size) / bytespl * bytespl;
2784
2785 packet_len = packet_payload + 1; /* 1 byte for DCS cmd */
2786 total_len = (bytespf / packet_payload) * packet_len;
2787
2788 if (bytespf % packet_payload)
2789 total_len += (bytespf % packet_payload) + 1;
2790
2791 l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
2792 dsi_write_reg(DSI_VC_TE(channel), l);
2793
2794 dsi_vc_write_long_header(channel, DSI_DT_DCS_LONG_WRITE, packet_len, 0);
2795
2796 if (dsi.te_enabled)
2797 l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
2798 else
2799 l = FLD_MOD(l, 1, 31, 31); /* TE_START */
2800 dsi_write_reg(DSI_VC_TE(channel), l);
2801
2802 /* We put SIDLEMODE to no-idle for the duration of the transfer,
2803 * because DSS interrupts are not capable of waking up the CPU and the
2804 * framedone interrupt could be delayed for quite a long time. I think
2805 * the same goes for any DSS interrupts, but for some reason I have not
2806 * seen the problem anywhere else than here.
2807 */
2808 dispc_disable_sidle();
2809
2810 dsi_perf_mark_start();
2811
2812 schedule_delayed_work(&dsi.framedone_timeout_work,
2813 msecs_to_jiffies(250));
2814
2815 dss_start_update(dssdev);
2816
2817 if (dsi.te_enabled) {
2818 /* disable LP_RX_TO, so that we can receive TE. Time to wait
2819 * for TE is longer than the timer allows */
2820 REG_FLD_MOD(DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
2821
2822 dsi_vc_send_bta(channel);
2823
2824#ifdef DSI_CATCH_MISSING_TE
2825 mod_timer(&dsi.te_timer, jiffies + msecs_to_jiffies(250));
2826#endif
2827 }
2828}
2829
2830#ifdef DSI_CATCH_MISSING_TE
2831static void dsi_te_timeout(unsigned long arg)
2832{
2833 DSSERR("TE not received for 250ms!\n");
2834}
2835#endif
2836
2837static void dsi_framedone_timeout_work_callback(struct work_struct *work)
2838{
2839 int r;
2840 const int channel = dsi.update_channel;
2841
2842 DSSERR("Framedone not received for 250ms!\n");
2843
2844 /* SIDLEMODE back to smart-idle */
2845 dispc_enable_sidle();
2846
2847 if (dsi.te_enabled) {
2848 /* enable LP_RX_TO again after the TE */
2849 REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
2850 }
2851
2852 /* Send BTA after the frame. We need this for the TE to work, as TE
2853 * trigger is only sent for BTAs without preceding packet. Thus we need
2854 * to BTA after the pixel packets so that next BTA will cause TE
2855 * trigger.
2856 *
2857 * This is not needed when TE is not in use, but we do it anyway to
2858 * make sure that the transfer has been completed. It would be more
2859 * optimal, but more complex, to wait only just before starting next
2860 * transfer. */
2861 r = dsi_vc_send_bta_sync(channel);
2862 if (r)
2863 DSSERR("BTA after framedone failed\n");
2864
2865 /* RX_FIFO_NOT_EMPTY */
2866 if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
2867 DSSERR("Received error during frame transfer:\n");
2868 dsi_vc_flush_receive_data(channel);
2869 }
2870
2871 dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data);
2872}
2873
2874static void dsi_framedone_irq_callback(void *data, u32 mask)
2875{
2876 /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
2877 * turns itself off. However, DSI still has the pixels in its buffers,
2878 * and is sending the data.
2879 */
2880
2881 /* SIDLEMODE back to smart-idle */
2882 dispc_enable_sidle();
2883
2884 schedule_work(&dsi.framedone_work);
2885}
2886
2887static void dsi_handle_framedone(void)
2888{
2889 int r;
2890 const int channel = dsi.update_channel;
2891
2892 DSSDBG("FRAMEDONE\n");
2893
2894 if (dsi.te_enabled) {
2895 /* enable LP_RX_TO again after the TE */
2896 REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
2897 }
2898
2899 /* Send BTA after the frame. We need this for the TE to work, as TE
2900 * trigger is only sent for BTAs without preceding packet. Thus we need
2901 * to BTA after the pixel packets so that next BTA will cause TE
2902 * trigger.
2903 *
2904 * This is not needed when TE is not in use, but we do it anyway to
2905 * make sure that the transfer has been completed. It would be more
2906 * optimal, but more complex, to wait only just before starting next
2907 * transfer. */
2908 r = dsi_vc_send_bta_sync(channel);
2909 if (r)
2910 DSSERR("BTA after framedone failed\n");
2911
2912 /* RX_FIFO_NOT_EMPTY */
2913 if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
2914 DSSERR("Received error during frame transfer:\n");
2915 dsi_vc_flush_receive_data(channel);
2916 }
2917
2918#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
2919 dispc_fake_vsync_irq();
2920#endif
2921}
2922
2923static void dsi_framedone_work_callback(struct work_struct *work)
2924{
2925 DSSDBGF();
2926
2927 cancel_delayed_work_sync(&dsi.framedone_timeout_work);
2928
2929 dsi_handle_framedone();
2930
2931 dsi_perf_show("DISPC");
2932
2933 dsi.framedone_callback(0, dsi.framedone_data);
2934}
2935
2936int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
2937 u16 *x, u16 *y, u16 *w, u16 *h)
2938{
2939 u16 dw, dh;
2940
2941 dssdev->driver->get_resolution(dssdev, &dw, &dh);
2942
2943 if (*x > dw || *y > dh)
2944 return -EINVAL;
2945
2946 if (*x + *w > dw)
2947 return -EINVAL;
2948
2949 if (*y + *h > dh)
2950 return -EINVAL;
2951
2952 if (*w == 1)
2953 return -EINVAL;
2954
2955 if (*w == 0 || *h == 0)
2956 return -EINVAL;
2957
2958 dsi_perf_mark_setup();
2959
2960 if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
2961 dss_setup_partial_planes(dssdev, x, y, w, h);
2962 dispc_set_lcd_size(*w, *h);
2963 }
2964
2965 return 0;
2966}
2967EXPORT_SYMBOL(omap_dsi_prepare_update);
2968
2969int omap_dsi_update(struct omap_dss_device *dssdev,
2970 int channel,
2971 u16 x, u16 y, u16 w, u16 h,
2972 void (*callback)(int, void *), void *data)
2973{
2974 dsi.update_channel = channel;
2975
2976 if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
2977 dsi.framedone_callback = callback;
2978 dsi.framedone_data = data;
2979
2980 dsi.update_region.x = x;
2981 dsi.update_region.y = y;
2982 dsi.update_region.w = w;
2983 dsi.update_region.h = h;
2984 dsi.update_region.device = dssdev;
2985
2986 dsi_update_screen_dispc(dssdev, x, y, w, h);
2987 } else {
2988 dsi_update_screen_l4(dssdev, x, y, w, h);
2989 dsi_perf_show("L4");
2990 callback(0, data);
2991 }
2992
2993 return 0;
2994}
2995EXPORT_SYMBOL(omap_dsi_update);
2996
2997/* Display funcs */
2998
2999static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
3000{
3001 int r;
3002
3003 r = omap_dispc_register_isr(dsi_framedone_irq_callback, NULL,
3004 DISPC_IRQ_FRAMEDONE);
3005 if (r) {
3006 DSSERR("can't get FRAMEDONE irq\n");
3007 return r;
3008 }
3009
3010 dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
3011
3012 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_DSI);
3013 dispc_enable_fifohandcheck(1);
3014
3015 dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
3016
3017 {
3018 struct omap_video_timings timings = {
3019 .hsw = 1,
3020 .hfp = 1,
3021 .hbp = 1,
3022 .vsw = 1,
3023 .vfp = 0,
3024 .vbp = 0,
3025 };
3026
3027 dispc_set_lcd_timings(&timings);
3028 }
3029
3030 return 0;
3031}
3032
3033static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
3034{
3035 omap_dispc_unregister_isr(dsi_framedone_irq_callback, NULL,
3036 DISPC_IRQ_FRAMEDONE);
3037}
3038
3039static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
3040{
3041 struct dsi_clock_info cinfo;
3042 int r;
3043
3044 /* we always use DSS2_FCK as input clock */
3045 cinfo.use_dss2_fck = true;
3046 cinfo.regn = dssdev->phy.dsi.div.regn;
3047 cinfo.regm = dssdev->phy.dsi.div.regm;
3048 cinfo.regm3 = dssdev->phy.dsi.div.regm3;
3049 cinfo.regm4 = dssdev->phy.dsi.div.regm4;
3050 r = dsi_calc_clock_rates(&cinfo);
3051 if (r)
3052 return r;
3053
3054 r = dsi_pll_set_clock_div(&cinfo);
3055 if (r) {
3056 DSSERR("Failed to set dsi clocks\n");
3057 return r;
3058 }
3059
3060 return 0;
3061}
3062
3063static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
3064{
3065 struct dispc_clock_info dispc_cinfo;
3066 int r;
3067 unsigned long long fck;
3068
3069 fck = dsi_get_dsi1_pll_rate();
3070
3071 dispc_cinfo.lck_div = dssdev->phy.dsi.div.lck_div;
3072 dispc_cinfo.pck_div = dssdev->phy.dsi.div.pck_div;
3073
3074 r = dispc_calc_clock_rates(fck, &dispc_cinfo);
3075 if (r) {
3076 DSSERR("Failed to calc dispc clocks\n");
3077 return r;
3078 }
3079
3080 r = dispc_set_clock_div(&dispc_cinfo);
3081 if (r) {
3082 DSSERR("Failed to set dispc clocks\n");
3083 return r;
3084 }
3085
3086 return 0;
3087}
3088
3089static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
3090{
3091 int r;
3092
3093 _dsi_print_reset_status();
3094
3095 r = dsi_pll_init(dssdev, true, true);
3096 if (r)
3097 goto err0;
3098
3099 r = dsi_configure_dsi_clocks(dssdev);
3100 if (r)
3101 goto err1;
3102
3103 dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK);
3104 dss_select_dsi_clk_source(DSS_SRC_DSI2_PLL_FCLK);
3105
3106 DSSDBG("PLL OK\n");
3107
3108 r = dsi_configure_dispc_clocks(dssdev);
3109 if (r)
3110 goto err2;
3111
3112 r = dsi_complexio_init(dssdev);
3113 if (r)
3114 goto err2;
3115
3116 _dsi_print_reset_status();
3117
3118 dsi_proto_timings(dssdev);
3119 dsi_set_lp_clk_divisor(dssdev);
3120
3121 if (1)
3122 _dsi_print_reset_status();
3123
3124 r = dsi_proto_config(dssdev);
3125 if (r)
3126 goto err3;
3127
3128 /* enable interface */
3129 dsi_vc_enable(0, 1);
3130 dsi_vc_enable(1, 1);
3131 dsi_vc_enable(2, 1);
3132 dsi_vc_enable(3, 1);
3133 dsi_if_enable(1);
3134 dsi_force_tx_stop_mode_io();
3135
3136 return 0;
3137err3:
3138 dsi_complexio_uninit();
3139err2:
3140 dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
3141 dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
3142err1:
3143 dsi_pll_uninit();
3144err0:
3145 return r;
3146}
3147
3148static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
3149{
3150 dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
3151 dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
3152 dsi_complexio_uninit();
3153 dsi_pll_uninit();
3154}
3155
3156static int dsi_core_init(void)
3157{
3158 /* Autoidle */
3159 REG_FLD_MOD(DSI_SYSCONFIG, 1, 0, 0);
3160
3161 /* ENWAKEUP */
3162 REG_FLD_MOD(DSI_SYSCONFIG, 1, 2, 2);
3163
3164 /* SIDLEMODE smart-idle */
3165 REG_FLD_MOD(DSI_SYSCONFIG, 2, 4, 3);
3166
3167 _dsi_initialize_irq();
3168
3169 return 0;
3170}
3171
3172int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
3173{
3174 int r = 0;
3175
3176 DSSDBG("dsi_display_enable\n");
3177
3178 WARN_ON(!dsi_bus_is_locked());
3179
3180 mutex_lock(&dsi.lock);
3181
3182 r = omap_dss_start_device(dssdev);
3183 if (r) {
3184 DSSERR("failed to start device\n");
3185 goto err0;
3186 }
3187
3188 enable_clocks(1);
3189 dsi_enable_pll_clock(1);
3190
3191 r = _dsi_reset();
3192 if (r)
3193 goto err1;
3194
3195 dsi_core_init();
3196
3197 r = dsi_display_init_dispc(dssdev);
3198 if (r)
3199 goto err1;
3200
3201 r = dsi_display_init_dsi(dssdev);
3202 if (r)
3203 goto err2;
3204
3205 mutex_unlock(&dsi.lock);
3206
3207 return 0;
3208
3209err2:
3210 dsi_display_uninit_dispc(dssdev);
3211err1:
3212 enable_clocks(0);
3213 dsi_enable_pll_clock(0);
3214 omap_dss_stop_device(dssdev);
3215err0:
3216 mutex_unlock(&dsi.lock);
3217 DSSDBG("dsi_display_enable FAILED\n");
3218 return r;
3219}
3220EXPORT_SYMBOL(omapdss_dsi_display_enable);
3221
3222void omapdss_dsi_display_disable(struct omap_dss_device *dssdev)
3223{
3224 DSSDBG("dsi_display_disable\n");
3225
3226 WARN_ON(!dsi_bus_is_locked());
3227
3228 mutex_lock(&dsi.lock);
3229
3230 dsi_display_uninit_dispc(dssdev);
3231
3232 dsi_display_uninit_dsi(dssdev);
3233
3234 enable_clocks(0);
3235 dsi_enable_pll_clock(0);
3236
3237 omap_dss_stop_device(dssdev);
3238
3239 mutex_unlock(&dsi.lock);
3240}
3241EXPORT_SYMBOL(omapdss_dsi_display_disable);
3242
3243int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
3244{
3245 dsi.te_enabled = enable;
3246 return 0;
3247}
3248EXPORT_SYMBOL(omapdss_dsi_enable_te);
3249
3250void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
3251 u32 fifo_size, enum omap_burst_size *burst_size,
3252 u32 *fifo_low, u32 *fifo_high)
3253{
3254 unsigned burst_size_bytes;
3255
3256 *burst_size = OMAP_DSS_BURST_16x32;
3257 burst_size_bytes = 16 * 32 / 8;
3258
3259 *fifo_high = fifo_size - burst_size_bytes;
3260 *fifo_low = fifo_size - burst_size_bytes * 8;
3261}
3262
3263int dsi_init_display(struct omap_dss_device *dssdev)
3264{
3265 DSSDBG("DSI init\n");
3266
3267 /* XXX these should be figured out dynamically */
3268 dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
3269 OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
3270
3271 dsi.vc[0].dssdev = dssdev;
3272 dsi.vc[1].dssdev = dssdev;
3273
3274 return 0;
3275}
3276
3277int dsi_init(struct platform_device *pdev)
3278{
3279 u32 rev;
3280 int r;
3281
3282 spin_lock_init(&dsi.errors_lock);
3283 dsi.errors = 0;
3284
3285#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3286 spin_lock_init(&dsi.irq_stats_lock);
3287 dsi.irq_stats.last_reset = jiffies;
3288#endif
3289
3290 init_completion(&dsi.bta_completion);
3291
3292 mutex_init(&dsi.lock);
3293 sema_init(&dsi.bus_lock, 1);
3294
3295 INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback);
3296 INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work,
3297 dsi_framedone_timeout_work_callback);
3298
3299#ifdef DSI_CATCH_MISSING_TE
3300 init_timer(&dsi.te_timer);
3301 dsi.te_timer.function = dsi_te_timeout;
3302 dsi.te_timer.data = 0;
3303#endif
3304 dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS);
3305 if (!dsi.base) {
3306 DSSERR("can't ioremap DSI\n");
3307 r = -ENOMEM;
3308 goto err1;
3309 }
3310
3311 dsi.vdds_dsi_reg = dss_get_vdds_dsi();
3312 if (IS_ERR(dsi.vdds_dsi_reg)) {
3313 iounmap(dsi.base);
3314 DSSERR("can't get VDDS_DSI regulator\n");
3315 r = PTR_ERR(dsi.vdds_dsi_reg);
3316 goto err2;
3317 }
3318
3319 enable_clocks(1);
3320
3321 rev = dsi_read_reg(DSI_REVISION);
3322 printk(KERN_INFO "OMAP DSI rev %d.%d\n",
3323 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
3324
3325 enable_clocks(0);
3326
3327 return 0;
3328err2:
3329 iounmap(dsi.base);
3330err1:
3331 return r;
3332}
3333
3334void dsi_exit(void)
3335{
3336 iounmap(dsi.base);
3337
3338 DSSDBG("omap_dsi_exit\n");
3339}
3340
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
new file mode 100644
index 000000000000..54344184dd73
--- /dev/null
+++ b/drivers/video/omap2/dss/dss.c
@@ -0,0 +1,621 @@
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 enum dss_clk_source dsi_clk_source;
72 enum dss_clk_source dispc_clk_source;
73
74 u32 ctx[DSS_SZ_REGS / sizeof(u32)];
75} dss;
76
77static int _omap_dss_wait_reset(void);
78
79static inline void dss_write_reg(const struct dss_reg idx, u32 val)
80{
81 __raw_writel(val, dss.base + idx.idx);
82}
83
84static inline u32 dss_read_reg(const struct dss_reg idx)
85{
86 return __raw_readl(dss.base + idx.idx);
87}
88
89#define SR(reg) \
90 dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
91#define RR(reg) \
92 dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
93
94void dss_save_context(void)
95{
96 if (cpu_is_omap24xx())
97 return;
98
99 SR(SYSCONFIG);
100 SR(CONTROL);
101
102#ifdef CONFIG_OMAP2_DSS_SDI
103 SR(SDI_CONTROL);
104 SR(PLL_CONTROL);
105#endif
106}
107
108void dss_restore_context(void)
109{
110 if (_omap_dss_wait_reset())
111 DSSERR("DSS not coming out of reset after sleep\n");
112
113 RR(SYSCONFIG);
114 RR(CONTROL);
115
116#ifdef CONFIG_OMAP2_DSS_SDI
117 RR(SDI_CONTROL);
118 RR(PLL_CONTROL);
119#endif
120}
121
122#undef SR
123#undef RR
124
125void dss_sdi_init(u8 datapairs)
126{
127 u32 l;
128
129 BUG_ON(datapairs > 3 || datapairs < 1);
130
131 l = dss_read_reg(DSS_SDI_CONTROL);
132 l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */
133 l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */
134 l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */
135 dss_write_reg(DSS_SDI_CONTROL, l);
136
137 l = dss_read_reg(DSS_PLL_CONTROL);
138 l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */
139 l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */
140 l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */
141 dss_write_reg(DSS_PLL_CONTROL, l);
142}
143
144int dss_sdi_enable(void)
145{
146 unsigned long timeout;
147
148 dispc_pck_free_enable(1);
149
150 /* Reset SDI PLL */
151 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
152 udelay(1); /* wait 2x PCLK */
153
154 /* Lock SDI PLL */
155 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
156
157 /* Waiting for PLL lock request to complete */
158 timeout = jiffies + msecs_to_jiffies(500);
159 while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
160 if (time_after_eq(jiffies, timeout)) {
161 DSSERR("PLL lock request timed out\n");
162 goto err1;
163 }
164 }
165
166 /* Clearing PLL_GO bit */
167 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
168
169 /* Waiting for PLL to lock */
170 timeout = jiffies + msecs_to_jiffies(500);
171 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
172 if (time_after_eq(jiffies, timeout)) {
173 DSSERR("PLL lock timed out\n");
174 goto err1;
175 }
176 }
177
178 dispc_lcd_enable_signal(1);
179
180 /* Waiting for SDI reset to complete */
181 timeout = jiffies + msecs_to_jiffies(500);
182 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
183 if (time_after_eq(jiffies, timeout)) {
184 DSSERR("SDI reset timed out\n");
185 goto err2;
186 }
187 }
188
189 return 0;
190
191 err2:
192 dispc_lcd_enable_signal(0);
193 err1:
194 /* Reset SDI PLL */
195 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
196
197 dispc_pck_free_enable(0);
198
199 return -ETIMEDOUT;
200}
201
202void dss_sdi_disable(void)
203{
204 dispc_lcd_enable_signal(0);
205
206 dispc_pck_free_enable(0);
207
208 /* Reset SDI PLL */
209 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
210}
211
212void dss_dump_clocks(struct seq_file *s)
213{
214 unsigned long dpll4_ck_rate;
215 unsigned long dpll4_m4_ck_rate;
216
217 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
218
219 dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
220 dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
221
222 seq_printf(s, "- DSS -\n");
223
224 seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
225
226 seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n",
227 dpll4_ck_rate,
228 dpll4_ck_rate / dpll4_m4_ck_rate,
229 dss_clk_get_rate(DSS_CLK_FCK1));
230
231 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
232}
233
234void dss_dump_regs(struct seq_file *s)
235{
236#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
237
238 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
239
240 DUMPREG(DSS_REVISION);
241 DUMPREG(DSS_SYSCONFIG);
242 DUMPREG(DSS_SYSSTATUS);
243 DUMPREG(DSS_IRQSTATUS);
244 DUMPREG(DSS_CONTROL);
245 DUMPREG(DSS_SDI_CONTROL);
246 DUMPREG(DSS_PLL_CONTROL);
247 DUMPREG(DSS_SDI_STATUS);
248
249 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
250#undef DUMPREG
251}
252
253void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
254{
255 int b;
256
257 BUG_ON(clk_src != DSS_SRC_DSI1_PLL_FCLK &&
258 clk_src != DSS_SRC_DSS1_ALWON_FCLK);
259
260 b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
261
262 REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */
263
264 dss.dispc_clk_source = clk_src;
265}
266
267void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
268{
269 int b;
270
271 BUG_ON(clk_src != DSS_SRC_DSI2_PLL_FCLK &&
272 clk_src != DSS_SRC_DSS1_ALWON_FCLK);
273
274 b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
275
276 REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */
277
278 dss.dsi_clk_source = clk_src;
279}
280
281enum dss_clk_source dss_get_dispc_clk_source(void)
282{
283 return dss.dispc_clk_source;
284}
285
286enum dss_clk_source dss_get_dsi_clk_source(void)
287{
288 return dss.dsi_clk_source;
289}
290
291/* calculate clock rates using dividers in cinfo */
292int dss_calc_clock_rates(struct dss_clock_info *cinfo)
293{
294 unsigned long prate;
295
296 if (cinfo->fck_div > 16 || cinfo->fck_div == 0)
297 return -EINVAL;
298
299 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
300
301 cinfo->fck = prate / cinfo->fck_div;
302
303 return 0;
304}
305
306int dss_set_clock_div(struct dss_clock_info *cinfo)
307{
308 unsigned long prate;
309 int r;
310
311 if (cpu_is_omap34xx()) {
312 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
313 DSSDBG("dpll4_m4 = %ld\n", prate);
314
315 r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
316 if (r)
317 return r;
318 }
319
320 DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
321
322 return 0;
323}
324
325int dss_get_clock_div(struct dss_clock_info *cinfo)
326{
327 cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK1);
328
329 if (cpu_is_omap34xx()) {
330 unsigned long prate;
331 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
332 cinfo->fck_div = prate / (cinfo->fck / 2);
333 } else {
334 cinfo->fck_div = 0;
335 }
336
337 return 0;
338}
339
340unsigned long dss_get_dpll4_rate(void)
341{
342 if (cpu_is_omap34xx())
343 return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
344 else
345 return 0;
346}
347
348int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
349 struct dss_clock_info *dss_cinfo,
350 struct dispc_clock_info *dispc_cinfo)
351{
352 unsigned long prate;
353 struct dss_clock_info best_dss;
354 struct dispc_clock_info best_dispc;
355
356 unsigned long fck;
357
358 u16 fck_div;
359
360 int match = 0;
361 int min_fck_per_pck;
362
363 prate = dss_get_dpll4_rate();
364
365 fck = dss_clk_get_rate(DSS_CLK_FCK1);
366 if (req_pck == dss.cache_req_pck &&
367 ((cpu_is_omap34xx() && prate == dss.cache_prate) ||
368 dss.cache_dss_cinfo.fck == fck)) {
369 DSSDBG("dispc clock info found from cache.\n");
370 *dss_cinfo = dss.cache_dss_cinfo;
371 *dispc_cinfo = dss.cache_dispc_cinfo;
372 return 0;
373 }
374
375 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
376
377 if (min_fck_per_pck &&
378 req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
379 DSSERR("Requested pixel clock not possible with the current "
380 "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
381 "the constraint off.\n");
382 min_fck_per_pck = 0;
383 }
384
385retry:
386 memset(&best_dss, 0, sizeof(best_dss));
387 memset(&best_dispc, 0, sizeof(best_dispc));
388
389 if (cpu_is_omap24xx()) {
390 struct dispc_clock_info cur_dispc;
391 /* XXX can we change the clock on omap2? */
392 fck = dss_clk_get_rate(DSS_CLK_FCK1);
393 fck_div = 1;
394
395 dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
396 match = 1;
397
398 best_dss.fck = fck;
399 best_dss.fck_div = fck_div;
400
401 best_dispc = cur_dispc;
402
403 goto found;
404 } else if (cpu_is_omap34xx()) {
405 for (fck_div = 16; fck_div > 0; --fck_div) {
406 struct dispc_clock_info cur_dispc;
407
408 fck = prate / fck_div * 2;
409
410 if (fck > DISPC_MAX_FCK)
411 continue;
412
413 if (min_fck_per_pck &&
414 fck < req_pck * min_fck_per_pck)
415 continue;
416
417 match = 1;
418
419 dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
420
421 if (abs(cur_dispc.pck - req_pck) <
422 abs(best_dispc.pck - req_pck)) {
423
424 best_dss.fck = fck;
425 best_dss.fck_div = fck_div;
426
427 best_dispc = cur_dispc;
428
429 if (cur_dispc.pck == req_pck)
430 goto found;
431 }
432 }
433 } else {
434 BUG();
435 }
436
437found:
438 if (!match) {
439 if (min_fck_per_pck) {
440 DSSERR("Could not find suitable clock settings.\n"
441 "Turning FCK/PCK constraint off and"
442 "trying again.\n");
443 min_fck_per_pck = 0;
444 goto retry;
445 }
446
447 DSSERR("Could not find suitable clock settings.\n");
448
449 return -EINVAL;
450 }
451
452 if (dss_cinfo)
453 *dss_cinfo = best_dss;
454 if (dispc_cinfo)
455 *dispc_cinfo = best_dispc;
456
457 dss.cache_req_pck = req_pck;
458 dss.cache_prate = prate;
459 dss.cache_dss_cinfo = best_dss;
460 dss.cache_dispc_cinfo = best_dispc;
461
462 return 0;
463}
464
465
466
467static irqreturn_t dss_irq_handler_omap2(int irq, void *arg)
468{
469 dispc_irq_handler();
470
471 return IRQ_HANDLED;
472}
473
474static irqreturn_t dss_irq_handler_omap3(int irq, void *arg)
475{
476 u32 irqstatus;
477
478 irqstatus = dss_read_reg(DSS_IRQSTATUS);
479
480 if (irqstatus & (1<<0)) /* DISPC_IRQ */
481 dispc_irq_handler();
482#ifdef CONFIG_OMAP2_DSS_DSI
483 if (irqstatus & (1<<1)) /* DSI_IRQ */
484 dsi_irq_handler();
485#endif
486
487 return IRQ_HANDLED;
488}
489
490static int _omap_dss_wait_reset(void)
491{
492 int t = 0;
493
494 while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) {
495 if (++t > 1000) {
496 DSSERR("soft reset failed\n");
497 return -ENODEV;
498 }
499 udelay(1);
500 }
501
502 return 0;
503}
504
505static int _omap_dss_reset(void)
506{
507 /* Soft reset */
508 REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1);
509 return _omap_dss_wait_reset();
510}
511
512void dss_set_venc_output(enum omap_dss_venc_type type)
513{
514 int l = 0;
515
516 if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
517 l = 0;
518 else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
519 l = 1;
520 else
521 BUG();
522
523 /* venc out selection. 0 = comp, 1 = svideo */
524 REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
525}
526
527void dss_set_dac_pwrdn_bgz(bool enable)
528{
529 REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
530}
531
532int dss_init(bool skip_init)
533{
534 int r;
535 u32 rev;
536
537 dss.base = ioremap(DSS_BASE, DSS_SZ_REGS);
538 if (!dss.base) {
539 DSSERR("can't ioremap DSS\n");
540 r = -ENOMEM;
541 goto fail0;
542 }
543
544 if (!skip_init) {
545 /* disable LCD and DIGIT output. This seems to fix the synclost
546 * problem that we get, if the bootloader starts the DSS and
547 * the kernel resets it */
548 omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
549
550 /* We need to wait here a bit, otherwise we sometimes start to
551 * get synclost errors, and after that only power cycle will
552 * restore DSS functionality. I have no idea why this happens.
553 * And we have to wait _before_ resetting the DSS, but after
554 * enabling clocks.
555 */
556 msleep(50);
557
558 _omap_dss_reset();
559 }
560
561 /* autoidle */
562 REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
563
564 /* Select DPLL */
565 REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
566
567#ifdef CONFIG_OMAP2_DSS_VENC
568 REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
569 REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
570 REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
571#endif
572
573 r = request_irq(INT_24XX_DSS_IRQ,
574 cpu_is_omap24xx()
575 ? dss_irq_handler_omap2
576 : dss_irq_handler_omap3,
577 0, "OMAP DSS", NULL);
578
579 if (r < 0) {
580 DSSERR("omap2 dss: request_irq failed\n");
581 goto fail1;
582 }
583
584 if (cpu_is_omap34xx()) {
585 dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
586 if (IS_ERR(dss.dpll4_m4_ck)) {
587 DSSERR("Failed to get dpll4_m4_ck\n");
588 r = PTR_ERR(dss.dpll4_m4_ck);
589 goto fail2;
590 }
591 }
592
593 dss.dsi_clk_source = DSS_SRC_DSS1_ALWON_FCLK;
594 dss.dispc_clk_source = DSS_SRC_DSS1_ALWON_FCLK;
595
596 dss_save_context();
597
598 rev = dss_read_reg(DSS_REVISION);
599 printk(KERN_INFO "OMAP DSS rev %d.%d\n",
600 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
601
602 return 0;
603
604fail2:
605 free_irq(INT_24XX_DSS_IRQ, NULL);
606fail1:
607 iounmap(dss.base);
608fail0:
609 return r;
610}
611
612void dss_exit(void)
613{
614 if (cpu_is_omap34xx())
615 clk_put(dss.dpll4_m4_ck);
616
617 free_irq(INT_24XX_DSS_IRQ, NULL);
618
619 iounmap(dss.base);
620}
621
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
new file mode 100644
index 000000000000..24326a5fd292
--- /dev/null
+++ b/drivers/video/omap2/dss/dss.h
@@ -0,0 +1,395 @@
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
122enum dss_clk_source {
123 DSS_SRC_DSI1_PLL_FCLK,
124 DSS_SRC_DSI2_PLL_FCLK,
125 DSS_SRC_DSS1_ALWON_FCLK,
126};
127
128struct dss_clock_info {
129 /* rates that we get with dividers below */
130 unsigned long fck;
131
132 /* dividers */
133 u16 fck_div;
134};
135
136struct dispc_clock_info {
137 /* rates that we get with dividers below */
138 unsigned long lck;
139 unsigned long pck;
140
141 /* dividers */
142 u16 lck_div;
143 u16 pck_div;
144};
145
146struct dsi_clock_info {
147 /* rates that we get with dividers below */
148 unsigned long fint;
149 unsigned long clkin4ddr;
150 unsigned long clkin;
151 unsigned long dsi1_pll_fclk;
152 unsigned long dsi2_pll_fclk;
153
154 unsigned long lp_clk;
155
156 /* dividers */
157 u16 regn;
158 u16 regm;
159 u16 regm3;
160 u16 regm4;
161
162 u16 lp_clk_div;
163
164 u8 highfreq;
165 bool use_dss2_fck;
166};
167
168struct seq_file;
169struct platform_device;
170
171/* core */
172void dss_clk_enable(enum dss_clock clks);
173void dss_clk_disable(enum dss_clock clks);
174unsigned long dss_clk_get_rate(enum dss_clock clk);
175int dss_need_ctx_restore(void);
176void dss_dump_clocks(struct seq_file *s);
177struct bus_type *dss_get_bus(void);
178struct regulator *dss_get_vdds_dsi(void);
179struct regulator *dss_get_vdds_sdi(void);
180struct regulator *dss_get_vdda_dac(void);
181
182/* display */
183int dss_suspend_all_devices(void);
184int dss_resume_all_devices(void);
185void dss_disable_all_devices(void);
186
187void dss_init_device(struct platform_device *pdev,
188 struct omap_dss_device *dssdev);
189void dss_uninit_device(struct platform_device *pdev,
190 struct omap_dss_device *dssdev);
191bool dss_use_replication(struct omap_dss_device *dssdev,
192 enum omap_color_mode mode);
193void default_get_overlay_fifo_thresholds(enum omap_plane plane,
194 u32 fifo_size, enum omap_burst_size *burst_size,
195 u32 *fifo_low, u32 *fifo_high);
196
197/* manager */
198int dss_init_overlay_managers(struct platform_device *pdev);
199void dss_uninit_overlay_managers(struct platform_device *pdev);
200int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
201void dss_setup_partial_planes(struct omap_dss_device *dssdev,
202 u16 *x, u16 *y, u16 *w, u16 *h);
203void dss_start_update(struct omap_dss_device *dssdev);
204
205/* overlay */
206void dss_init_overlays(struct platform_device *pdev);
207void dss_uninit_overlays(struct platform_device *pdev);
208int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev);
209void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
210#ifdef L4_EXAMPLE
211void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr);
212#endif
213void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
214
215/* DSS */
216int dss_init(bool skip_init);
217void dss_exit(void);
218
219void dss_save_context(void);
220void dss_restore_context(void);
221
222void dss_dump_regs(struct seq_file *s);
223
224void dss_sdi_init(u8 datapairs);
225int dss_sdi_enable(void);
226void dss_sdi_disable(void);
227
228void dss_select_dispc_clk_source(enum dss_clk_source clk_src);
229void dss_select_dsi_clk_source(enum dss_clk_source clk_src);
230enum dss_clk_source dss_get_dispc_clk_source(void);
231enum dss_clk_source dss_get_dsi_clk_source(void);
232
233void dss_set_venc_output(enum omap_dss_venc_type type);
234void dss_set_dac_pwrdn_bgz(bool enable);
235
236unsigned long dss_get_dpll4_rate(void);
237int dss_calc_clock_rates(struct dss_clock_info *cinfo);
238int dss_set_clock_div(struct dss_clock_info *cinfo);
239int dss_get_clock_div(struct dss_clock_info *cinfo);
240int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
241 struct dss_clock_info *dss_cinfo,
242 struct dispc_clock_info *dispc_cinfo);
243
244/* SDI */
245int sdi_init(bool skip_init);
246void sdi_exit(void);
247int sdi_init_display(struct omap_dss_device *display);
248
249/* DSI */
250int dsi_init(struct platform_device *pdev);
251void dsi_exit(void);
252
253void dsi_dump_clocks(struct seq_file *s);
254void dsi_dump_irqs(struct seq_file *s);
255void dsi_dump_regs(struct seq_file *s);
256
257void dsi_save_context(void);
258void dsi_restore_context(void);
259
260int dsi_init_display(struct omap_dss_device *display);
261void dsi_irq_handler(void);
262unsigned long dsi_get_dsi1_pll_rate(void);
263int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo);
264int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
265 struct dsi_clock_info *cinfo,
266 struct dispc_clock_info *dispc_cinfo);
267int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
268 bool enable_hsdiv);
269void dsi_pll_uninit(void);
270void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
271 u32 fifo_size, enum omap_burst_size *burst_size,
272 u32 *fifo_low, u32 *fifo_high);
273
274/* DPI */
275int dpi_init(struct platform_device *pdev);
276void dpi_exit(void);
277int dpi_init_display(struct omap_dss_device *dssdev);
278
279/* DISPC */
280int dispc_init(void);
281void dispc_exit(void);
282void dispc_dump_clocks(struct seq_file *s);
283void dispc_dump_irqs(struct seq_file *s);
284void dispc_dump_regs(struct seq_file *s);
285void dispc_irq_handler(void);
286void dispc_fake_vsync_irq(void);
287
288void dispc_save_context(void);
289void dispc_restore_context(void);
290
291void dispc_enable_sidle(void);
292void dispc_disable_sidle(void);
293
294void dispc_lcd_enable_signal_polarity(bool act_high);
295void dispc_lcd_enable_signal(bool enable);
296void dispc_pck_free_enable(bool enable);
297void dispc_enable_fifohandcheck(bool enable);
298
299void dispc_set_lcd_size(u16 width, u16 height);
300void dispc_set_digit_size(u16 width, u16 height);
301u32 dispc_get_plane_fifo_size(enum omap_plane plane);
302void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
303void dispc_enable_fifomerge(bool enable);
304void dispc_set_burst_size(enum omap_plane plane,
305 enum omap_burst_size burst_size);
306
307void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr);
308void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
309void dispc_set_plane_pos(enum omap_plane plane, u16 x, u16 y);
310void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height);
311void dispc_set_channel_out(enum omap_plane plane,
312 enum omap_channel channel_out);
313
314int dispc_setup_plane(enum omap_plane plane,
315 u32 paddr, u16 screen_width,
316 u16 pos_x, u16 pos_y,
317 u16 width, u16 height,
318 u16 out_width, u16 out_height,
319 enum omap_color_mode color_mode,
320 bool ilace,
321 enum omap_dss_rotation_type rotation_type,
322 u8 rotation, bool mirror,
323 u8 global_alpha);
324
325bool dispc_go_busy(enum omap_channel channel);
326void dispc_go(enum omap_channel channel);
327void dispc_enable_channel(enum omap_channel channel, bool enable);
328bool dispc_is_channel_enabled(enum omap_channel channel);
329int dispc_enable_plane(enum omap_plane plane, bool enable);
330void dispc_enable_replication(enum omap_plane plane, bool enable);
331
332void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode);
333void dispc_set_tft_data_lines(u8 data_lines);
334void dispc_set_lcd_display_type(enum omap_lcd_display_type type);
335void dispc_set_loadmode(enum omap_dss_load_mode mode);
336
337void dispc_set_default_color(enum omap_channel channel, u32 color);
338u32 dispc_get_default_color(enum omap_channel channel);
339void dispc_set_trans_key(enum omap_channel ch,
340 enum omap_dss_trans_key_type type,
341 u32 trans_key);
342void dispc_get_trans_key(enum omap_channel ch,
343 enum omap_dss_trans_key_type *type,
344 u32 *trans_key);
345void dispc_enable_trans_key(enum omap_channel ch, bool enable);
346void dispc_enable_alpha_blending(enum omap_channel ch, bool enable);
347bool dispc_trans_key_enabled(enum omap_channel ch);
348bool dispc_alpha_blending_enabled(enum omap_channel ch);
349
350bool dispc_lcd_timings_ok(struct omap_video_timings *timings);
351void dispc_set_lcd_timings(struct omap_video_timings *timings);
352unsigned long dispc_fclk_rate(void);
353unsigned long dispc_lclk_rate(void);
354unsigned long dispc_pclk_rate(void);
355void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb);
356void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
357 struct dispc_clock_info *cinfo);
358int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
359 struct dispc_clock_info *cinfo);
360int dispc_set_clock_div(struct dispc_clock_info *cinfo);
361int dispc_get_clock_div(struct dispc_clock_info *cinfo);
362
363
364/* VENC */
365int venc_init(struct platform_device *pdev);
366void venc_exit(void);
367void venc_dump_regs(struct seq_file *s);
368int venc_init_display(struct omap_dss_device *display);
369
370/* RFBI */
371int rfbi_init(void);
372void rfbi_exit(void);
373void rfbi_dump_regs(struct seq_file *s);
374
375int rfbi_configure(int rfbi_module, int bpp, int lines);
376void rfbi_enable_rfbi(bool enable);
377void rfbi_transfer_area(u16 width, u16 height,
378 void (callback)(void *data), void *data);
379void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
380unsigned long rfbi_get_max_tx_rate(void);
381int rfbi_init_display(struct omap_dss_device *display);
382
383
384#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
385static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
386{
387 int b;
388 for (b = 0; b < 32; ++b) {
389 if (irqstatus & (1 << b))
390 irq_arr[b]++;
391 }
392}
393#endif
394
395#endif
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
new file mode 100644
index 000000000000..0820986d4a68
--- /dev/null
+++ b/drivers/video/omap2/dss/manager.c
@@ -0,0 +1,1520 @@
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/spinlock.h>
30#include <linux/jiffies.h>
31
32#include <plat/display.h>
33#include <plat/cpu.h>
34
35#include "dss.h"
36
37static int num_managers;
38static struct list_head manager_list;
39
40static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
41{
42 return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
43}
44
45static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
46{
47 return snprintf(buf, PAGE_SIZE, "%s\n",
48 mgr->device ? mgr->device->name : "<none>");
49}
50
51static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
52 const char *buf, size_t size)
53{
54 int r = 0;
55 size_t len = size;
56 struct omap_dss_device *dssdev = NULL;
57
58 int match(struct omap_dss_device *dssdev, void *data)
59 {
60 const char *str = data;
61 return sysfs_streq(dssdev->name, str);
62 }
63
64 if (buf[size-1] == '\n')
65 --len;
66
67 if (len > 0)
68 dssdev = omap_dss_find_device((void *)buf, match);
69
70 if (len > 0 && dssdev == NULL)
71 return -EINVAL;
72
73 if (dssdev)
74 DSSDBG("display %s found\n", dssdev->name);
75
76 if (mgr->device) {
77 r = mgr->unset_device(mgr);
78 if (r) {
79 DSSERR("failed to unset display\n");
80 goto put_device;
81 }
82 }
83
84 if (dssdev) {
85 r = mgr->set_device(mgr, dssdev);
86 if (r) {
87 DSSERR("failed to set manager\n");
88 goto put_device;
89 }
90
91 r = mgr->apply(mgr);
92 if (r) {
93 DSSERR("failed to apply dispc config\n");
94 goto put_device;
95 }
96 }
97
98put_device:
99 if (dssdev)
100 omap_dss_put_device(dssdev);
101
102 return r ? r : size;
103}
104
105static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
106 char *buf)
107{
108 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.default_color);
109}
110
111static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
112 const char *buf, size_t size)
113{
114 struct omap_overlay_manager_info info;
115 u32 color;
116 int r;
117
118 if (sscanf(buf, "%d", &color) != 1)
119 return -EINVAL;
120
121 mgr->get_manager_info(mgr, &info);
122
123 info.default_color = color;
124
125 r = mgr->set_manager_info(mgr, &info);
126 if (r)
127 return r;
128
129 r = mgr->apply(mgr);
130 if (r)
131 return r;
132
133 return size;
134}
135
136static const char *trans_key_type_str[] = {
137 "gfx-destination",
138 "video-source",
139};
140
141static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
142 char *buf)
143{
144 enum omap_dss_trans_key_type key_type;
145
146 key_type = mgr->info.trans_key_type;
147 BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
148
149 return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
150}
151
152static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
153 const char *buf, size_t size)
154{
155 enum omap_dss_trans_key_type key_type;
156 struct omap_overlay_manager_info info;
157 int r;
158
159 for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
160 key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
161 if (sysfs_streq(buf, trans_key_type_str[key_type]))
162 break;
163 }
164
165 if (key_type == ARRAY_SIZE(trans_key_type_str))
166 return -EINVAL;
167
168 mgr->get_manager_info(mgr, &info);
169
170 info.trans_key_type = key_type;
171
172 r = mgr->set_manager_info(mgr, &info);
173 if (r)
174 return r;
175
176 r = mgr->apply(mgr);
177 if (r)
178 return r;
179
180 return size;
181}
182
183static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
184 char *buf)
185{
186 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_key);
187}
188
189static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
190 const char *buf, size_t size)
191{
192 struct omap_overlay_manager_info info;
193 u32 key_value;
194 int r;
195
196 if (sscanf(buf, "%d", &key_value) != 1)
197 return -EINVAL;
198
199 mgr->get_manager_info(mgr, &info);
200
201 info.trans_key = key_value;
202
203 r = mgr->set_manager_info(mgr, &info);
204 if (r)
205 return r;
206
207 r = mgr->apply(mgr);
208 if (r)
209 return r;
210
211 return size;
212}
213
214static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
215 char *buf)
216{
217 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled);
218}
219
220static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
221 const char *buf, size_t size)
222{
223 struct omap_overlay_manager_info info;
224 int enable;
225 int r;
226
227 if (sscanf(buf, "%d", &enable) != 1)
228 return -EINVAL;
229
230 mgr->get_manager_info(mgr, &info);
231
232 info.trans_enabled = enable ? true : false;
233
234 r = mgr->set_manager_info(mgr, &info);
235 if (r)
236 return r;
237
238 r = mgr->apply(mgr);
239 if (r)
240 return r;
241
242 return size;
243}
244
245static ssize_t manager_alpha_blending_enabled_show(
246 struct omap_overlay_manager *mgr, char *buf)
247{
248 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.alpha_enabled);
249}
250
251static ssize_t manager_alpha_blending_enabled_store(
252 struct omap_overlay_manager *mgr,
253 const char *buf, size_t size)
254{
255 struct omap_overlay_manager_info info;
256 int enable;
257 int r;
258
259 if (sscanf(buf, "%d", &enable) != 1)
260 return -EINVAL;
261
262 mgr->get_manager_info(mgr, &info);
263
264 info.alpha_enabled = enable ? true : false;
265
266 r = mgr->set_manager_info(mgr, &info);
267 if (r)
268 return r;
269
270 r = mgr->apply(mgr);
271 if (r)
272 return r;
273
274 return size;
275}
276
277struct manager_attribute {
278 struct attribute attr;
279 ssize_t (*show)(struct omap_overlay_manager *, char *);
280 ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
281};
282
283#define MANAGER_ATTR(_name, _mode, _show, _store) \
284 struct manager_attribute manager_attr_##_name = \
285 __ATTR(_name, _mode, _show, _store)
286
287static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
288static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
289 manager_display_show, manager_display_store);
290static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
291 manager_default_color_show, manager_default_color_store);
292static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
293 manager_trans_key_type_show, manager_trans_key_type_store);
294static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
295 manager_trans_key_value_show, manager_trans_key_value_store);
296static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
297 manager_trans_key_enabled_show,
298 manager_trans_key_enabled_store);
299static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
300 manager_alpha_blending_enabled_show,
301 manager_alpha_blending_enabled_store);
302
303
304static struct attribute *manager_sysfs_attrs[] = {
305 &manager_attr_name.attr,
306 &manager_attr_display.attr,
307 &manager_attr_default_color.attr,
308 &manager_attr_trans_key_type.attr,
309 &manager_attr_trans_key_value.attr,
310 &manager_attr_trans_key_enabled.attr,
311 &manager_attr_alpha_blending_enabled.attr,
312 NULL
313};
314
315static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
316 char *buf)
317{
318 struct omap_overlay_manager *manager;
319 struct manager_attribute *manager_attr;
320
321 manager = container_of(kobj, struct omap_overlay_manager, kobj);
322 manager_attr = container_of(attr, struct manager_attribute, attr);
323
324 if (!manager_attr->show)
325 return -ENOENT;
326
327 return manager_attr->show(manager, buf);
328}
329
330static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
331 const char *buf, size_t size)
332{
333 struct omap_overlay_manager *manager;
334 struct manager_attribute *manager_attr;
335
336 manager = container_of(kobj, struct omap_overlay_manager, kobj);
337 manager_attr = container_of(attr, struct manager_attribute, attr);
338
339 if (!manager_attr->store)
340 return -ENOENT;
341
342 return manager_attr->store(manager, buf, size);
343}
344
345static const struct sysfs_ops manager_sysfs_ops = {
346 .show = manager_attr_show,
347 .store = manager_attr_store,
348};
349
350static struct kobj_type manager_ktype = {
351 .sysfs_ops = &manager_sysfs_ops,
352 .default_attrs = manager_sysfs_attrs,
353};
354
355/*
356 * We have 4 levels of cache for the dispc settings. First two are in SW and
357 * the latter two in HW.
358 *
359 * +--------------------+
360 * |overlay/manager_info|
361 * +--------------------+
362 * v
363 * apply()
364 * v
365 * +--------------------+
366 * | dss_cache |
367 * +--------------------+
368 * v
369 * configure()
370 * v
371 * +--------------------+
372 * | shadow registers |
373 * +--------------------+
374 * v
375 * VFP or lcd/digit_enable
376 * v
377 * +--------------------+
378 * | registers |
379 * +--------------------+
380 */
381
382struct overlay_cache_data {
383 /* If true, cache changed, but not written to shadow registers. Set
384 * in apply(), cleared when registers written. */
385 bool dirty;
386 /* If true, shadow registers contain changed values not yet in real
387 * registers. Set when writing to shadow registers, cleared at
388 * VSYNC/EVSYNC */
389 bool shadow_dirty;
390
391 bool enabled;
392
393 u32 paddr;
394 void __iomem *vaddr;
395 u16 screen_width;
396 u16 width;
397 u16 height;
398 enum omap_color_mode color_mode;
399 u8 rotation;
400 enum omap_dss_rotation_type rotation_type;
401 bool mirror;
402
403 u16 pos_x;
404 u16 pos_y;
405 u16 out_width; /* if 0, out_width == width */
406 u16 out_height; /* if 0, out_height == height */
407 u8 global_alpha;
408
409 enum omap_channel channel;
410 bool replication;
411 bool ilace;
412
413 enum omap_burst_size burst_size;
414 u32 fifo_low;
415 u32 fifo_high;
416
417 bool manual_update;
418};
419
420struct manager_cache_data {
421 /* If true, cache changed, but not written to shadow registers. Set
422 * in apply(), cleared when registers written. */
423 bool dirty;
424 /* If true, shadow registers contain changed values not yet in real
425 * registers. Set when writing to shadow registers, cleared at
426 * VSYNC/EVSYNC */
427 bool shadow_dirty;
428
429 u32 default_color;
430
431 enum omap_dss_trans_key_type trans_key_type;
432 u32 trans_key;
433 bool trans_enabled;
434
435 bool alpha_enabled;
436
437 bool manual_upd_display;
438 bool manual_update;
439 bool do_manual_update;
440
441 /* manual update region */
442 u16 x, y, w, h;
443};
444
445static struct {
446 spinlock_t lock;
447 struct overlay_cache_data overlay_cache[3];
448 struct manager_cache_data manager_cache[2];
449
450 bool irq_enabled;
451} dss_cache;
452
453
454
455static int omap_dss_set_device(struct omap_overlay_manager *mgr,
456 struct omap_dss_device *dssdev)
457{
458 int i;
459 int r;
460
461 if (dssdev->manager) {
462 DSSERR("display '%s' already has a manager '%s'\n",
463 dssdev->name, dssdev->manager->name);
464 return -EINVAL;
465 }
466
467 if ((mgr->supported_displays & dssdev->type) == 0) {
468 DSSERR("display '%s' does not support manager '%s'\n",
469 dssdev->name, mgr->name);
470 return -EINVAL;
471 }
472
473 for (i = 0; i < mgr->num_overlays; i++) {
474 struct omap_overlay *ovl = mgr->overlays[i];
475
476 if (ovl->manager != mgr || !ovl->info.enabled)
477 continue;
478
479 r = dss_check_overlay(ovl, dssdev);
480 if (r)
481 return r;
482 }
483
484 dssdev->manager = mgr;
485 mgr->device = dssdev;
486 mgr->device_changed = true;
487
488 return 0;
489}
490
491static int omap_dss_unset_device(struct omap_overlay_manager *mgr)
492{
493 if (!mgr->device) {
494 DSSERR("failed to unset display, display not set.\n");
495 return -EINVAL;
496 }
497
498 mgr->device->manager = NULL;
499 mgr->device = NULL;
500 mgr->device_changed = true;
501
502 return 0;
503}
504
505static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
506{
507 unsigned long timeout = msecs_to_jiffies(500);
508 u32 irq;
509
510 if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC)
511 irq = DISPC_IRQ_EVSYNC_ODD;
512 else
513 irq = DISPC_IRQ_VSYNC;
514
515 return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
516}
517
518static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
519{
520 unsigned long timeout = msecs_to_jiffies(500);
521 struct manager_cache_data *mc;
522 enum omap_channel channel;
523 u32 irq;
524 int r;
525 int i;
526 struct omap_dss_device *dssdev = mgr->device;
527
528 if (!dssdev)
529 return 0;
530
531 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
532 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
533 channel = OMAP_DSS_CHANNEL_DIGIT;
534 } else {
535 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
536 enum omap_dss_update_mode mode;
537 mode = dssdev->driver->get_update_mode(dssdev);
538 if (mode != OMAP_DSS_UPDATE_AUTO)
539 return 0;
540
541 irq = DISPC_IRQ_FRAMEDONE;
542 } else {
543 irq = DISPC_IRQ_VSYNC;
544 }
545 channel = OMAP_DSS_CHANNEL_LCD;
546 }
547
548 mc = &dss_cache.manager_cache[mgr->id];
549 i = 0;
550 while (1) {
551 unsigned long flags;
552 bool shadow_dirty, dirty;
553
554 spin_lock_irqsave(&dss_cache.lock, flags);
555 dirty = mc->dirty;
556 shadow_dirty = mc->shadow_dirty;
557 spin_unlock_irqrestore(&dss_cache.lock, flags);
558
559 if (!dirty && !shadow_dirty) {
560 r = 0;
561 break;
562 }
563
564 /* 4 iterations is the worst case:
565 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
566 * 2 - first VSYNC, dirty = true
567 * 3 - dirty = false, shadow_dirty = true
568 * 4 - shadow_dirty = false */
569 if (i++ == 3) {
570 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
571 mgr->id);
572 r = 0;
573 break;
574 }
575
576 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
577 if (r == -ERESTARTSYS)
578 break;
579
580 if (r) {
581 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
582 break;
583 }
584 }
585
586 return r;
587}
588
589int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
590{
591 unsigned long timeout = msecs_to_jiffies(500);
592 enum omap_channel channel;
593 struct overlay_cache_data *oc;
594 struct omap_dss_device *dssdev;
595 u32 irq;
596 int r;
597 int i;
598
599 if (!ovl->manager || !ovl->manager->device)
600 return 0;
601
602 dssdev = ovl->manager->device;
603
604 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
605 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
606 channel = OMAP_DSS_CHANNEL_DIGIT;
607 } else {
608 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
609 enum omap_dss_update_mode mode;
610 mode = dssdev->driver->get_update_mode(dssdev);
611 if (mode != OMAP_DSS_UPDATE_AUTO)
612 return 0;
613
614 irq = DISPC_IRQ_FRAMEDONE;
615 } else {
616 irq = DISPC_IRQ_VSYNC;
617 }
618 channel = OMAP_DSS_CHANNEL_LCD;
619 }
620
621 oc = &dss_cache.overlay_cache[ovl->id];
622 i = 0;
623 while (1) {
624 unsigned long flags;
625 bool shadow_dirty, dirty;
626
627 spin_lock_irqsave(&dss_cache.lock, flags);
628 dirty = oc->dirty;
629 shadow_dirty = oc->shadow_dirty;
630 spin_unlock_irqrestore(&dss_cache.lock, flags);
631
632 if (!dirty && !shadow_dirty) {
633 r = 0;
634 break;
635 }
636
637 /* 4 iterations is the worst case:
638 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
639 * 2 - first VSYNC, dirty = true
640 * 3 - dirty = false, shadow_dirty = true
641 * 4 - shadow_dirty = false */
642 if (i++ == 3) {
643 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
644 ovl->id);
645 r = 0;
646 break;
647 }
648
649 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
650 if (r == -ERESTARTSYS)
651 break;
652
653 if (r) {
654 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
655 break;
656 }
657 }
658
659 return r;
660}
661
662static int overlay_enabled(struct omap_overlay *ovl)
663{
664 return ovl->info.enabled && ovl->manager && ovl->manager->device;
665}
666
667/* Is rect1 a subset of rect2? */
668static bool rectangle_subset(int x1, int y1, int w1, int h1,
669 int x2, int y2, int w2, int h2)
670{
671 if (x1 < x2 || y1 < y2)
672 return false;
673
674 if (x1 + w1 > x2 + w2)
675 return false;
676
677 if (y1 + h1 > y2 + h2)
678 return false;
679
680 return true;
681}
682
683/* Do rect1 and rect2 overlap? */
684static bool rectangle_intersects(int x1, int y1, int w1, int h1,
685 int x2, int y2, int w2, int h2)
686{
687 if (x1 >= x2 + w2)
688 return false;
689
690 if (x2 >= x1 + w1)
691 return false;
692
693 if (y1 >= y2 + h2)
694 return false;
695
696 if (y2 >= y1 + h1)
697 return false;
698
699 return true;
700}
701
702static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
703{
704 if (oc->out_width != 0 && oc->width != oc->out_width)
705 return true;
706
707 if (oc->out_height != 0 && oc->height != oc->out_height)
708 return true;
709
710 return false;
711}
712
713static int configure_overlay(enum omap_plane plane)
714{
715 struct overlay_cache_data *c;
716 struct manager_cache_data *mc;
717 u16 outw, outh;
718 u16 x, y, w, h;
719 u32 paddr;
720 int r;
721
722 DSSDBGF("%d", plane);
723
724 c = &dss_cache.overlay_cache[plane];
725
726 if (!c->enabled) {
727 dispc_enable_plane(plane, 0);
728 return 0;
729 }
730
731 mc = &dss_cache.manager_cache[c->channel];
732
733 x = c->pos_x;
734 y = c->pos_y;
735 w = c->width;
736 h = c->height;
737 outw = c->out_width == 0 ? c->width : c->out_width;
738 outh = c->out_height == 0 ? c->height : c->out_height;
739 paddr = c->paddr;
740
741 if (c->manual_update && mc->do_manual_update) {
742 unsigned bpp;
743 /* If the overlay is outside the update region, disable it */
744 if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
745 x, y, outw, outh)) {
746 dispc_enable_plane(plane, 0);
747 return 0;
748 }
749
750 switch (c->color_mode) {
751 case OMAP_DSS_COLOR_RGB16:
752 case OMAP_DSS_COLOR_ARGB16:
753 case OMAP_DSS_COLOR_YUV2:
754 case OMAP_DSS_COLOR_UYVY:
755 bpp = 16;
756 break;
757
758 case OMAP_DSS_COLOR_RGB24P:
759 bpp = 24;
760 break;
761
762 case OMAP_DSS_COLOR_RGB24U:
763 case OMAP_DSS_COLOR_ARGB32:
764 case OMAP_DSS_COLOR_RGBA32:
765 case OMAP_DSS_COLOR_RGBX32:
766 bpp = 32;
767 break;
768
769 default:
770 BUG();
771 }
772
773 if (dispc_is_overlay_scaled(c)) {
774 /* If the overlay is scaled, the update area has
775 * already been enlarged to cover the whole overlay. We
776 * only need to adjust x/y here */
777 x = c->pos_x - mc->x;
778 y = c->pos_y - mc->y;
779 } else {
780 if (mc->x > c->pos_x) {
781 x = 0;
782 w -= (mc->x - c->pos_x);
783 paddr += (mc->x - c->pos_x) * bpp / 8;
784 } else {
785 x = c->pos_x - mc->x;
786 }
787
788 if (mc->y > c->pos_y) {
789 y = 0;
790 h -= (mc->y - c->pos_y);
791 paddr += (mc->y - c->pos_y) * c->screen_width *
792 bpp / 8;
793 } else {
794 y = c->pos_y - mc->y;
795 }
796
797 if (mc->w < (x+w))
798 w -= (x+w) - (mc->w);
799
800 if (mc->h < (y+h))
801 h -= (y+h) - (mc->h);
802
803 outw = w;
804 outh = h;
805 }
806 }
807
808 r = dispc_setup_plane(plane,
809 paddr,
810 c->screen_width,
811 x, y,
812 w, h,
813 outw, outh,
814 c->color_mode,
815 c->ilace,
816 c->rotation_type,
817 c->rotation,
818 c->mirror,
819 c->global_alpha);
820
821 if (r) {
822 /* this shouldn't happen */
823 DSSERR("dispc_setup_plane failed for ovl %d\n", plane);
824 dispc_enable_plane(plane, 0);
825 return r;
826 }
827
828 dispc_enable_replication(plane, c->replication);
829
830 dispc_set_burst_size(plane, c->burst_size);
831 dispc_setup_plane_fifo(plane, c->fifo_low, c->fifo_high);
832
833 dispc_enable_plane(plane, 1);
834
835 return 0;
836}
837
838static void configure_manager(enum omap_channel channel)
839{
840 struct manager_cache_data *c;
841
842 DSSDBGF("%d", channel);
843
844 c = &dss_cache.manager_cache[channel];
845
846 dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
847 dispc_enable_trans_key(channel, c->trans_enabled);
848 dispc_enable_alpha_blending(channel, c->alpha_enabled);
849}
850
851/* configure_dispc() tries to write values from cache to shadow registers.
852 * It writes only to those managers/overlays that are not busy.
853 * returns 0 if everything could be written to shadow registers.
854 * returns 1 if not everything could be written to shadow registers. */
855static int configure_dispc(void)
856{
857 struct overlay_cache_data *oc;
858 struct manager_cache_data *mc;
859 const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
860 const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
861 int i;
862 int r;
863 bool mgr_busy[2];
864 bool mgr_go[2];
865 bool busy;
866
867 r = 0;
868 busy = false;
869
870 mgr_busy[0] = dispc_go_busy(0);
871 mgr_busy[1] = dispc_go_busy(1);
872 mgr_go[0] = false;
873 mgr_go[1] = false;
874
875 /* Commit overlay settings */
876 for (i = 0; i < num_ovls; ++i) {
877 oc = &dss_cache.overlay_cache[i];
878 mc = &dss_cache.manager_cache[oc->channel];
879
880 if (!oc->dirty)
881 continue;
882
883 if (oc->manual_update && !mc->do_manual_update)
884 continue;
885
886 if (mgr_busy[oc->channel]) {
887 busy = true;
888 continue;
889 }
890
891 r = configure_overlay(i);
892 if (r)
893 DSSERR("configure_overlay %d failed\n", i);
894
895 oc->dirty = false;
896 oc->shadow_dirty = true;
897 mgr_go[oc->channel] = true;
898 }
899
900 /* Commit manager settings */
901 for (i = 0; i < num_mgrs; ++i) {
902 mc = &dss_cache.manager_cache[i];
903
904 if (!mc->dirty)
905 continue;
906
907 if (mc->manual_update && !mc->do_manual_update)
908 continue;
909
910 if (mgr_busy[i]) {
911 busy = true;
912 continue;
913 }
914
915 configure_manager(i);
916 mc->dirty = false;
917 mc->shadow_dirty = true;
918 mgr_go[i] = true;
919 }
920
921 /* set GO */
922 for (i = 0; i < num_mgrs; ++i) {
923 mc = &dss_cache.manager_cache[i];
924
925 if (!mgr_go[i])
926 continue;
927
928 /* We don't need GO with manual update display. LCD iface will
929 * always be turned off after frame, and new settings will be
930 * taken in to use at next update */
931 if (!mc->manual_upd_display)
932 dispc_go(i);
933 }
934
935 if (busy)
936 r = 1;
937 else
938 r = 0;
939
940 return r;
941}
942
943/* Configure dispc for partial update. Return possibly modified update
944 * area */
945void dss_setup_partial_planes(struct omap_dss_device *dssdev,
946 u16 *xi, u16 *yi, u16 *wi, u16 *hi)
947{
948 struct overlay_cache_data *oc;
949 struct manager_cache_data *mc;
950 const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
951 struct omap_overlay_manager *mgr;
952 int i;
953 u16 x, y, w, h;
954 unsigned long flags;
955
956 x = *xi;
957 y = *yi;
958 w = *wi;
959 h = *hi;
960
961 DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n",
962 *xi, *yi, *wi, *hi);
963
964 mgr = dssdev->manager;
965
966 if (!mgr) {
967 DSSDBG("no manager\n");
968 return;
969 }
970
971 spin_lock_irqsave(&dss_cache.lock, flags);
972
973 /* We need to show the whole overlay if it is scaled. So look for
974 * those, and make the update area larger if found.
975 * Also mark the overlay cache dirty */
976 for (i = 0; i < num_ovls; ++i) {
977 unsigned x1, y1, x2, y2;
978 unsigned outw, outh;
979
980 oc = &dss_cache.overlay_cache[i];
981
982 if (oc->channel != mgr->id)
983 continue;
984
985 oc->dirty = true;
986
987 if (!oc->enabled)
988 continue;
989
990 if (!dispc_is_overlay_scaled(oc))
991 continue;
992
993 outw = oc->out_width == 0 ? oc->width : oc->out_width;
994 outh = oc->out_height == 0 ? oc->height : oc->out_height;
995
996 /* is the overlay outside the update region? */
997 if (!rectangle_intersects(x, y, w, h,
998 oc->pos_x, oc->pos_y,
999 outw, outh))
1000 continue;
1001
1002 /* if the overlay totally inside the update region? */
1003 if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
1004 x, y, w, h))
1005 continue;
1006
1007 if (x > oc->pos_x)
1008 x1 = oc->pos_x;
1009 else
1010 x1 = x;
1011
1012 if (y > oc->pos_y)
1013 y1 = oc->pos_y;
1014 else
1015 y1 = y;
1016
1017 if ((x + w) < (oc->pos_x + outw))
1018 x2 = oc->pos_x + outw;
1019 else
1020 x2 = x + w;
1021
1022 if ((y + h) < (oc->pos_y + outh))
1023 y2 = oc->pos_y + outh;
1024 else
1025 y2 = y + h;
1026
1027 x = x1;
1028 y = y1;
1029 w = x2 - x1;
1030 h = y2 - y1;
1031
1032 DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n",
1033 i, x, y, w, h);
1034 }
1035
1036 mc = &dss_cache.manager_cache[mgr->id];
1037 mc->do_manual_update = true;
1038 mc->x = x;
1039 mc->y = y;
1040 mc->w = w;
1041 mc->h = h;
1042
1043 configure_dispc();
1044
1045 mc->do_manual_update = false;
1046
1047 spin_unlock_irqrestore(&dss_cache.lock, flags);
1048
1049 *xi = x;
1050 *yi = y;
1051 *wi = w;
1052 *hi = h;
1053}
1054
1055void dss_start_update(struct omap_dss_device *dssdev)
1056{
1057 struct manager_cache_data *mc;
1058 struct overlay_cache_data *oc;
1059 const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
1060 const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
1061 struct omap_overlay_manager *mgr;
1062 int i;
1063
1064 mgr = dssdev->manager;
1065
1066 for (i = 0; i < num_ovls; ++i) {
1067 oc = &dss_cache.overlay_cache[i];
1068 if (oc->channel != mgr->id)
1069 continue;
1070
1071 oc->shadow_dirty = false;
1072 }
1073
1074 for (i = 0; i < num_mgrs; ++i) {
1075 mc = &dss_cache.manager_cache[i];
1076 if (mgr->id != i)
1077 continue;
1078
1079 mc->shadow_dirty = false;
1080 }
1081
1082 dssdev->manager->enable(dssdev->manager);
1083}
1084
1085static void dss_apply_irq_handler(void *data, u32 mask)
1086{
1087 struct manager_cache_data *mc;
1088 struct overlay_cache_data *oc;
1089 const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
1090 const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
1091 int i, r;
1092 bool mgr_busy[2];
1093
1094 mgr_busy[0] = dispc_go_busy(0);
1095 mgr_busy[1] = dispc_go_busy(1);
1096
1097 spin_lock(&dss_cache.lock);
1098
1099 for (i = 0; i < num_ovls; ++i) {
1100 oc = &dss_cache.overlay_cache[i];
1101 if (!mgr_busy[oc->channel])
1102 oc->shadow_dirty = false;
1103 }
1104
1105 for (i = 0; i < num_mgrs; ++i) {
1106 mc = &dss_cache.manager_cache[i];
1107 if (!mgr_busy[i])
1108 mc->shadow_dirty = false;
1109 }
1110
1111 r = configure_dispc();
1112 if (r == 1)
1113 goto end;
1114
1115 /* re-read busy flags */
1116 mgr_busy[0] = dispc_go_busy(0);
1117 mgr_busy[1] = dispc_go_busy(1);
1118
1119 /* keep running as long as there are busy managers, so that
1120 * we can collect overlay-applied information */
1121 for (i = 0; i < num_mgrs; ++i) {
1122 if (mgr_busy[i])
1123 goto end;
1124 }
1125
1126 omap_dispc_unregister_isr(dss_apply_irq_handler, NULL,
1127 DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1128 DISPC_IRQ_EVSYNC_EVEN);
1129 dss_cache.irq_enabled = false;
1130
1131end:
1132 spin_unlock(&dss_cache.lock);
1133}
1134
1135static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
1136{
1137 struct overlay_cache_data *oc;
1138 struct manager_cache_data *mc;
1139 int i;
1140 struct omap_overlay *ovl;
1141 int num_planes_enabled = 0;
1142 bool use_fifomerge;
1143 unsigned long flags;
1144 int r;
1145
1146 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
1147
1148 spin_lock_irqsave(&dss_cache.lock, flags);
1149
1150 /* Configure overlays */
1151 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1152 struct omap_dss_device *dssdev;
1153
1154 ovl = omap_dss_get_overlay(i);
1155
1156 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1157 continue;
1158
1159 oc = &dss_cache.overlay_cache[ovl->id];
1160
1161 if (!overlay_enabled(ovl)) {
1162 if (oc->enabled) {
1163 oc->enabled = false;
1164 oc->dirty = true;
1165 }
1166 continue;
1167 }
1168
1169 if (!ovl->info_dirty) {
1170 if (oc->enabled)
1171 ++num_planes_enabled;
1172 continue;
1173 }
1174
1175 dssdev = ovl->manager->device;
1176
1177 if (dss_check_overlay(ovl, dssdev)) {
1178 if (oc->enabled) {
1179 oc->enabled = false;
1180 oc->dirty = true;
1181 }
1182 continue;
1183 }
1184
1185 ovl->info_dirty = false;
1186 oc->dirty = true;
1187
1188 oc->paddr = ovl->info.paddr;
1189 oc->vaddr = ovl->info.vaddr;
1190 oc->screen_width = ovl->info.screen_width;
1191 oc->width = ovl->info.width;
1192 oc->height = ovl->info.height;
1193 oc->color_mode = ovl->info.color_mode;
1194 oc->rotation = ovl->info.rotation;
1195 oc->rotation_type = ovl->info.rotation_type;
1196 oc->mirror = ovl->info.mirror;
1197 oc->pos_x = ovl->info.pos_x;
1198 oc->pos_y = ovl->info.pos_y;
1199 oc->out_width = ovl->info.out_width;
1200 oc->out_height = ovl->info.out_height;
1201 oc->global_alpha = ovl->info.global_alpha;
1202
1203 oc->replication =
1204 dss_use_replication(dssdev, ovl->info.color_mode);
1205
1206 oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
1207
1208 oc->channel = ovl->manager->id;
1209
1210 oc->enabled = true;
1211
1212 oc->manual_update =
1213 dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
1214 dssdev->driver->get_update_mode(dssdev) !=
1215 OMAP_DSS_UPDATE_AUTO;
1216
1217 ++num_planes_enabled;
1218 }
1219
1220 /* Configure managers */
1221 list_for_each_entry(mgr, &manager_list, list) {
1222 struct omap_dss_device *dssdev;
1223
1224 if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC))
1225 continue;
1226
1227 mc = &dss_cache.manager_cache[mgr->id];
1228
1229 if (mgr->device_changed) {
1230 mgr->device_changed = false;
1231 mgr->info_dirty = true;
1232 }
1233
1234 if (!mgr->info_dirty)
1235 continue;
1236
1237 if (!mgr->device)
1238 continue;
1239
1240 dssdev = mgr->device;
1241
1242 mgr->info_dirty = false;
1243 mc->dirty = true;
1244
1245 mc->default_color = mgr->info.default_color;
1246 mc->trans_key_type = mgr->info.trans_key_type;
1247 mc->trans_key = mgr->info.trans_key;
1248 mc->trans_enabled = mgr->info.trans_enabled;
1249 mc->alpha_enabled = mgr->info.alpha_enabled;
1250
1251 mc->manual_upd_display =
1252 dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
1253
1254 mc->manual_update =
1255 dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
1256 dssdev->driver->get_update_mode(dssdev) !=
1257 OMAP_DSS_UPDATE_AUTO;
1258 }
1259
1260 /* XXX TODO: Try to get fifomerge working. The problem is that it
1261 * affects both managers, not individually but at the same time. This
1262 * means the change has to be well synchronized. I guess the proper way
1263 * is to have a two step process for fifo merge:
1264 * fifomerge enable:
1265 * 1. disable other planes, leaving one plane enabled
1266 * 2. wait until the planes are disabled on HW
1267 * 3. config merged fifo thresholds, enable fifomerge
1268 * fifomerge disable:
1269 * 1. config unmerged fifo thresholds, disable fifomerge
1270 * 2. wait until fifo changes are in HW
1271 * 3. enable planes
1272 */
1273 use_fifomerge = false;
1274
1275 /* Configure overlay fifos */
1276 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1277 struct omap_dss_device *dssdev;
1278 u32 size;
1279
1280 ovl = omap_dss_get_overlay(i);
1281
1282 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1283 continue;
1284
1285 oc = &dss_cache.overlay_cache[ovl->id];
1286
1287 if (!oc->enabled)
1288 continue;
1289
1290 dssdev = ovl->manager->device;
1291
1292 size = dispc_get_plane_fifo_size(ovl->id);
1293 if (use_fifomerge)
1294 size *= 3;
1295
1296 switch (dssdev->type) {
1297 case OMAP_DISPLAY_TYPE_DPI:
1298 case OMAP_DISPLAY_TYPE_DBI:
1299 case OMAP_DISPLAY_TYPE_SDI:
1300 case OMAP_DISPLAY_TYPE_VENC:
1301 default_get_overlay_fifo_thresholds(ovl->id, size,
1302 &oc->burst_size, &oc->fifo_low,
1303 &oc->fifo_high);
1304 break;
1305#ifdef CONFIG_OMAP2_DSS_DSI
1306 case OMAP_DISPLAY_TYPE_DSI:
1307 dsi_get_overlay_fifo_thresholds(ovl->id, size,
1308 &oc->burst_size, &oc->fifo_low,
1309 &oc->fifo_high);
1310 break;
1311#endif
1312 default:
1313 BUG();
1314 }
1315 }
1316
1317 r = 0;
1318 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
1319 if (!dss_cache.irq_enabled) {
1320 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL,
1321 DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1322 DISPC_IRQ_EVSYNC_EVEN);
1323 dss_cache.irq_enabled = true;
1324 }
1325 configure_dispc();
1326 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
1327
1328 spin_unlock_irqrestore(&dss_cache.lock, flags);
1329
1330 return r;
1331}
1332
1333static int dss_check_manager(struct omap_overlay_manager *mgr)
1334{
1335 /* OMAP supports only graphics source transparency color key and alpha
1336 * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */
1337
1338 if (mgr->info.alpha_enabled && mgr->info.trans_enabled &&
1339 mgr->info.trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST)
1340 return -EINVAL;
1341
1342 return 0;
1343}
1344
1345static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
1346 struct omap_overlay_manager_info *info)
1347{
1348 int r;
1349 struct omap_overlay_manager_info old_info;
1350
1351 old_info = mgr->info;
1352 mgr->info = *info;
1353
1354 r = dss_check_manager(mgr);
1355 if (r) {
1356 mgr->info = old_info;
1357 return r;
1358 }
1359
1360 mgr->info_dirty = true;
1361
1362 return 0;
1363}
1364
1365static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
1366 struct omap_overlay_manager_info *info)
1367{
1368 *info = mgr->info;
1369}
1370
1371static int dss_mgr_enable(struct omap_overlay_manager *mgr)
1372{
1373 dispc_enable_channel(mgr->id, 1);
1374 return 0;
1375}
1376
1377static int dss_mgr_disable(struct omap_overlay_manager *mgr)
1378{
1379 dispc_enable_channel(mgr->id, 0);
1380 return 0;
1381}
1382
1383static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
1384{
1385 ++num_managers;
1386 list_add_tail(&manager->list, &manager_list);
1387}
1388
1389int dss_init_overlay_managers(struct platform_device *pdev)
1390{
1391 int i, r;
1392
1393 spin_lock_init(&dss_cache.lock);
1394
1395 INIT_LIST_HEAD(&manager_list);
1396
1397 num_managers = 0;
1398
1399 for (i = 0; i < 2; ++i) {
1400 struct omap_overlay_manager *mgr;
1401 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1402
1403 BUG_ON(mgr == NULL);
1404
1405 switch (i) {
1406 case 0:
1407 mgr->name = "lcd";
1408 mgr->id = OMAP_DSS_CHANNEL_LCD;
1409 mgr->supported_displays =
1410 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
1411 OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI;
1412 break;
1413 case 1:
1414 mgr->name = "tv";
1415 mgr->id = OMAP_DSS_CHANNEL_DIGIT;
1416 mgr->supported_displays = OMAP_DISPLAY_TYPE_VENC;
1417 break;
1418 }
1419
1420 mgr->set_device = &omap_dss_set_device;
1421 mgr->unset_device = &omap_dss_unset_device;
1422 mgr->apply = &omap_dss_mgr_apply;
1423 mgr->set_manager_info = &omap_dss_mgr_set_info;
1424 mgr->get_manager_info = &omap_dss_mgr_get_info;
1425 mgr->wait_for_go = &dss_mgr_wait_for_go;
1426 mgr->wait_for_vsync = &dss_mgr_wait_for_vsync;
1427
1428 mgr->enable = &dss_mgr_enable;
1429 mgr->disable = &dss_mgr_disable;
1430
1431 mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
1432
1433 dss_overlay_setup_dispc_manager(mgr);
1434
1435 omap_dss_add_overlay_manager(mgr);
1436
1437 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1438 &pdev->dev.kobj, "manager%d", i);
1439
1440 if (r) {
1441 DSSERR("failed to create sysfs file\n");
1442 continue;
1443 }
1444 }
1445
1446#ifdef L4_EXAMPLE
1447 {
1448 int omap_dss_mgr_apply_l4(struct omap_overlay_manager *mgr)
1449 {
1450 DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name);
1451
1452 return 0;
1453 }
1454
1455 struct omap_overlay_manager *mgr;
1456 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1457
1458 BUG_ON(mgr == NULL);
1459
1460 mgr->name = "l4";
1461 mgr->supported_displays =
1462 OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI;
1463
1464 mgr->set_device = &omap_dss_set_device;
1465 mgr->unset_device = &omap_dss_unset_device;
1466 mgr->apply = &omap_dss_mgr_apply_l4;
1467 mgr->set_manager_info = &omap_dss_mgr_set_info;
1468 mgr->get_manager_info = &omap_dss_mgr_get_info;
1469
1470 dss_overlay_setup_l4_manager(mgr);
1471
1472 omap_dss_add_overlay_manager(mgr);
1473
1474 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1475 &pdev->dev.kobj, "managerl4");
1476
1477 if (r)
1478 DSSERR("failed to create sysfs file\n");
1479 }
1480#endif
1481
1482 return 0;
1483}
1484
1485void dss_uninit_overlay_managers(struct platform_device *pdev)
1486{
1487 struct omap_overlay_manager *mgr;
1488
1489 while (!list_empty(&manager_list)) {
1490 mgr = list_first_entry(&manager_list,
1491 struct omap_overlay_manager, list);
1492 list_del(&mgr->list);
1493 kobject_del(&mgr->kobj);
1494 kobject_put(&mgr->kobj);
1495 kfree(mgr);
1496 }
1497
1498 num_managers = 0;
1499}
1500
1501int omap_dss_get_num_overlay_managers(void)
1502{
1503 return num_managers;
1504}
1505EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
1506
1507struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
1508{
1509 int i = 0;
1510 struct omap_overlay_manager *mgr;
1511
1512 list_for_each_entry(mgr, &manager_list, list) {
1513 if (i++ == num)
1514 return mgr;
1515 }
1516
1517 return NULL;
1518}
1519EXPORT_SYMBOL(omap_dss_get_overlay_manager);
1520
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
new file mode 100644
index 000000000000..82336583adef
--- /dev/null
+++ b/drivers/video/omap2/dss/overlay.c
@@ -0,0 +1,681 @@
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/kobject.h>
30#include <linux/platform_device.h>
31#include <linux/delay.h>
32#include <linux/slab.h>
33
34#include <plat/display.h>
35#include <plat/cpu.h>
36
37#include "dss.h"
38
39static int num_overlays;
40static struct list_head overlay_list;
41
42static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
43{
44 return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
45}
46
47static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
48{
49 return snprintf(buf, PAGE_SIZE, "%s\n",
50 ovl->manager ? ovl->manager->name : "<none>");
51}
52
53static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
54 size_t size)
55{
56 int i, r;
57 struct omap_overlay_manager *mgr = NULL;
58 struct omap_overlay_manager *old_mgr;
59 int len = size;
60
61 if (buf[size-1] == '\n')
62 --len;
63
64 if (len > 0) {
65 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
66 mgr = omap_dss_get_overlay_manager(i);
67
68 if (strncmp(buf, mgr->name, len) == 0)
69 break;
70
71 mgr = NULL;
72 }
73 }
74
75 if (len > 0 && mgr == NULL)
76 return -EINVAL;
77
78 if (mgr)
79 DSSDBG("manager %s found\n", mgr->name);
80
81 if (mgr == ovl->manager)
82 return size;
83
84 old_mgr = ovl->manager;
85
86 /* detach old manager */
87 if (old_mgr) {
88 r = ovl->unset_manager(ovl);
89 if (r) {
90 DSSERR("detach failed\n");
91 return r;
92 }
93
94 r = old_mgr->apply(old_mgr);
95 if (r)
96 return r;
97 }
98
99 if (mgr) {
100 r = ovl->set_manager(ovl, mgr);
101 if (r) {
102 DSSERR("Failed to attach overlay\n");
103 return r;
104 }
105
106 r = mgr->apply(mgr);
107 if (r)
108 return r;
109 }
110
111 return size;
112}
113
114static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
115{
116 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
117 ovl->info.width, ovl->info.height);
118}
119
120static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
121{
122 return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width);
123}
124
125static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
126{
127 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
128 ovl->info.pos_x, ovl->info.pos_y);
129}
130
131static ssize_t overlay_position_store(struct omap_overlay *ovl,
132 const char *buf, size_t size)
133{
134 int r;
135 char *last;
136 struct omap_overlay_info info;
137
138 ovl->get_overlay_info(ovl, &info);
139
140 info.pos_x = simple_strtoul(buf, &last, 10);
141 ++last;
142 if (last - buf >= size)
143 return -EINVAL;
144
145 info.pos_y = simple_strtoul(last, &last, 10);
146
147 r = ovl->set_overlay_info(ovl, &info);
148 if (r)
149 return r;
150
151 if (ovl->manager) {
152 r = ovl->manager->apply(ovl->manager);
153 if (r)
154 return r;
155 }
156
157 return size;
158}
159
160static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
161{
162 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
163 ovl->info.out_width, ovl->info.out_height);
164}
165
166static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
167 const char *buf, size_t size)
168{
169 int r;
170 char *last;
171 struct omap_overlay_info info;
172
173 ovl->get_overlay_info(ovl, &info);
174
175 info.out_width = simple_strtoul(buf, &last, 10);
176 ++last;
177 if (last - buf >= size)
178 return -EINVAL;
179
180 info.out_height = simple_strtoul(last, &last, 10);
181
182 r = ovl->set_overlay_info(ovl, &info);
183 if (r)
184 return r;
185
186 if (ovl->manager) {
187 r = ovl->manager->apply(ovl->manager);
188 if (r)
189 return r;
190 }
191
192 return size;
193}
194
195static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
196{
197 return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled);
198}
199
200static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
201 size_t size)
202{
203 int r;
204 struct omap_overlay_info info;
205
206 ovl->get_overlay_info(ovl, &info);
207
208 info.enabled = simple_strtoul(buf, NULL, 10);
209
210 r = ovl->set_overlay_info(ovl, &info);
211 if (r)
212 return r;
213
214 if (ovl->manager) {
215 r = ovl->manager->apply(ovl->manager);
216 if (r)
217 return r;
218 }
219
220 return size;
221}
222
223static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
224{
225 return snprintf(buf, PAGE_SIZE, "%d\n",
226 ovl->info.global_alpha);
227}
228
229static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
230 const char *buf, size_t size)
231{
232 int r;
233 struct omap_overlay_info info;
234
235 ovl->get_overlay_info(ovl, &info);
236
237 /* Video1 plane does not support global alpha
238 * to always make it 255 completely opaque
239 */
240 if (ovl->id == OMAP_DSS_VIDEO1)
241 info.global_alpha = 255;
242 else
243 info.global_alpha = simple_strtoul(buf, NULL, 10);
244
245 r = ovl->set_overlay_info(ovl, &info);
246 if (r)
247 return r;
248
249 if (ovl->manager) {
250 r = ovl->manager->apply(ovl->manager);
251 if (r)
252 return r;
253 }
254
255 return size;
256}
257
258struct overlay_attribute {
259 struct attribute attr;
260 ssize_t (*show)(struct omap_overlay *, char *);
261 ssize_t (*store)(struct omap_overlay *, const char *, size_t);
262};
263
264#define OVERLAY_ATTR(_name, _mode, _show, _store) \
265 struct overlay_attribute overlay_attr_##_name = \
266 __ATTR(_name, _mode, _show, _store)
267
268static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
269static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
270 overlay_manager_show, overlay_manager_store);
271static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
272static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
273static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
274 overlay_position_show, overlay_position_store);
275static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
276 overlay_output_size_show, overlay_output_size_store);
277static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
278 overlay_enabled_show, overlay_enabled_store);
279static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
280 overlay_global_alpha_show, overlay_global_alpha_store);
281
282static struct attribute *overlay_sysfs_attrs[] = {
283 &overlay_attr_name.attr,
284 &overlay_attr_manager.attr,
285 &overlay_attr_input_size.attr,
286 &overlay_attr_screen_width.attr,
287 &overlay_attr_position.attr,
288 &overlay_attr_output_size.attr,
289 &overlay_attr_enabled.attr,
290 &overlay_attr_global_alpha.attr,
291 NULL
292};
293
294static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
295 char *buf)
296{
297 struct omap_overlay *overlay;
298 struct overlay_attribute *overlay_attr;
299
300 overlay = container_of(kobj, struct omap_overlay, kobj);
301 overlay_attr = container_of(attr, struct overlay_attribute, attr);
302
303 if (!overlay_attr->show)
304 return -ENOENT;
305
306 return overlay_attr->show(overlay, buf);
307}
308
309static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
310 const char *buf, size_t size)
311{
312 struct omap_overlay *overlay;
313 struct overlay_attribute *overlay_attr;
314
315 overlay = container_of(kobj, struct omap_overlay, kobj);
316 overlay_attr = container_of(attr, struct overlay_attribute, attr);
317
318 if (!overlay_attr->store)
319 return -ENOENT;
320
321 return overlay_attr->store(overlay, buf, size);
322}
323
324static const struct sysfs_ops overlay_sysfs_ops = {
325 .show = overlay_attr_show,
326 .store = overlay_attr_store,
327};
328
329static struct kobj_type overlay_ktype = {
330 .sysfs_ops = &overlay_sysfs_ops,
331 .default_attrs = overlay_sysfs_attrs,
332};
333
334/* Check if overlay parameters are compatible with display */
335int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
336{
337 struct omap_overlay_info *info;
338 u16 outw, outh;
339 u16 dw, dh;
340
341 if (!dssdev)
342 return 0;
343
344 if (!ovl->info.enabled)
345 return 0;
346
347 info = &ovl->info;
348
349 if (info->paddr == 0) {
350 DSSDBG("check_overlay failed: paddr 0\n");
351 return -EINVAL;
352 }
353
354 dssdev->driver->get_resolution(dssdev, &dw, &dh);
355
356 DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n",
357 ovl->id,
358 info->pos_x, info->pos_y,
359 info->width, info->height,
360 info->out_width, info->out_height,
361 dw, dh);
362
363 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
364 outw = info->width;
365 outh = info->height;
366 } else {
367 if (info->out_width == 0)
368 outw = info->width;
369 else
370 outw = info->out_width;
371
372 if (info->out_height == 0)
373 outh = info->height;
374 else
375 outh = info->out_height;
376 }
377
378 if (dw < info->pos_x + outw) {
379 DSSDBG("check_overlay failed 1: %d < %d + %d\n",
380 dw, info->pos_x, outw);
381 return -EINVAL;
382 }
383
384 if (dh < info->pos_y + outh) {
385 DSSDBG("check_overlay failed 2: %d < %d + %d\n",
386 dh, info->pos_y, outh);
387 return -EINVAL;
388 }
389
390 if ((ovl->supported_modes & info->color_mode) == 0) {
391 DSSERR("overlay doesn't support mode %d\n", info->color_mode);
392 return -EINVAL;
393 }
394
395 return 0;
396}
397
398static int dss_ovl_set_overlay_info(struct omap_overlay *ovl,
399 struct omap_overlay_info *info)
400{
401 int r;
402 struct omap_overlay_info old_info;
403
404 old_info = ovl->info;
405 ovl->info = *info;
406
407 if (ovl->manager) {
408 r = dss_check_overlay(ovl, ovl->manager->device);
409 if (r) {
410 ovl->info = old_info;
411 return r;
412 }
413 }
414
415 ovl->info_dirty = true;
416
417 return 0;
418}
419
420static void dss_ovl_get_overlay_info(struct omap_overlay *ovl,
421 struct omap_overlay_info *info)
422{
423 *info = ovl->info;
424}
425
426static int dss_ovl_wait_for_go(struct omap_overlay *ovl)
427{
428 return dss_mgr_wait_for_go_ovl(ovl);
429}
430
431static int omap_dss_set_manager(struct omap_overlay *ovl,
432 struct omap_overlay_manager *mgr)
433{
434 if (!mgr)
435 return -EINVAL;
436
437 if (ovl->manager) {
438 DSSERR("overlay '%s' already has a manager '%s'\n",
439 ovl->name, ovl->manager->name);
440 return -EINVAL;
441 }
442
443 if (ovl->info.enabled) {
444 DSSERR("overlay has to be disabled to change the manager\n");
445 return -EINVAL;
446 }
447
448 ovl->manager = mgr;
449
450 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
451 /* XXX: on manual update display, in auto update mode, a bug happens
452 * here. When an overlay is first enabled on LCD, then it's disabled,
453 * and the manager is changed to TV, we sometimes get SYNC_LOST_DIGIT
454 * errors. Waiting before changing the channel_out fixes it. I'm
455 * guessing that the overlay is still somehow being used for the LCD,
456 * but I don't understand how or why. */
457 msleep(40);
458 dispc_set_channel_out(ovl->id, mgr->id);
459 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
460
461 return 0;
462}
463
464static int omap_dss_unset_manager(struct omap_overlay *ovl)
465{
466 int r;
467
468 if (!ovl->manager) {
469 DSSERR("failed to detach overlay: manager not set\n");
470 return -EINVAL;
471 }
472
473 if (ovl->info.enabled) {
474 DSSERR("overlay has to be disabled to unset the manager\n");
475 return -EINVAL;
476 }
477
478 r = ovl->wait_for_go(ovl);
479 if (r)
480 return r;
481
482 ovl->manager = NULL;
483
484 return 0;
485}
486
487int omap_dss_get_num_overlays(void)
488{
489 return num_overlays;
490}
491EXPORT_SYMBOL(omap_dss_get_num_overlays);
492
493struct omap_overlay *omap_dss_get_overlay(int num)
494{
495 int i = 0;
496 struct omap_overlay *ovl;
497
498 list_for_each_entry(ovl, &overlay_list, list) {
499 if (i++ == num)
500 return ovl;
501 }
502
503 return NULL;
504}
505EXPORT_SYMBOL(omap_dss_get_overlay);
506
507static void omap_dss_add_overlay(struct omap_overlay *overlay)
508{
509 ++num_overlays;
510 list_add_tail(&overlay->list, &overlay_list);
511}
512
513static struct omap_overlay *dispc_overlays[3];
514
515void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr)
516{
517 mgr->num_overlays = 3;
518 mgr->overlays = dispc_overlays;
519}
520
521#ifdef L4_EXAMPLE
522static struct omap_overlay *l4_overlays[1];
523void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr)
524{
525 mgr->num_overlays = 1;
526 mgr->overlays = l4_overlays;
527}
528#endif
529
530void dss_init_overlays(struct platform_device *pdev)
531{
532 int i, r;
533
534 INIT_LIST_HEAD(&overlay_list);
535
536 num_overlays = 0;
537
538 for (i = 0; i < 3; ++i) {
539 struct omap_overlay *ovl;
540 ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
541
542 BUG_ON(ovl == NULL);
543
544 switch (i) {
545 case 0:
546 ovl->name = "gfx";
547 ovl->id = OMAP_DSS_GFX;
548 ovl->supported_modes = cpu_is_omap34xx() ?
549 OMAP_DSS_COLOR_GFX_OMAP3 :
550 OMAP_DSS_COLOR_GFX_OMAP2;
551 ovl->caps = OMAP_DSS_OVL_CAP_DISPC;
552 ovl->info.global_alpha = 255;
553 break;
554 case 1:
555 ovl->name = "vid1";
556 ovl->id = OMAP_DSS_VIDEO1;
557 ovl->supported_modes = cpu_is_omap34xx() ?
558 OMAP_DSS_COLOR_VID1_OMAP3 :
559 OMAP_DSS_COLOR_VID_OMAP2;
560 ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
561 OMAP_DSS_OVL_CAP_DISPC;
562 ovl->info.global_alpha = 255;
563 break;
564 case 2:
565 ovl->name = "vid2";
566 ovl->id = OMAP_DSS_VIDEO2;
567 ovl->supported_modes = cpu_is_omap34xx() ?
568 OMAP_DSS_COLOR_VID2_OMAP3 :
569 OMAP_DSS_COLOR_VID_OMAP2;
570 ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
571 OMAP_DSS_OVL_CAP_DISPC;
572 ovl->info.global_alpha = 255;
573 break;
574 }
575
576 ovl->set_manager = &omap_dss_set_manager;
577 ovl->unset_manager = &omap_dss_unset_manager;
578 ovl->set_overlay_info = &dss_ovl_set_overlay_info;
579 ovl->get_overlay_info = &dss_ovl_get_overlay_info;
580 ovl->wait_for_go = &dss_ovl_wait_for_go;
581
582 omap_dss_add_overlay(ovl);
583
584 r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
585 &pdev->dev.kobj, "overlay%d", i);
586
587 if (r) {
588 DSSERR("failed to create sysfs file\n");
589 continue;
590 }
591
592 dispc_overlays[i] = ovl;
593 }
594
595#ifdef L4_EXAMPLE
596 {
597 struct omap_overlay *ovl;
598 ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
599
600 BUG_ON(ovl == NULL);
601
602 ovl->name = "l4";
603 ovl->supported_modes = OMAP_DSS_COLOR_RGB24U;
604
605 ovl->set_manager = &omap_dss_set_manager;
606 ovl->unset_manager = &omap_dss_unset_manager;
607 ovl->set_overlay_info = &dss_ovl_set_overlay_info;
608 ovl->get_overlay_info = &dss_ovl_get_overlay_info;
609
610 omap_dss_add_overlay(ovl);
611
612 r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
613 &pdev->dev.kobj, "overlayl4");
614
615 if (r)
616 DSSERR("failed to create sysfs file\n");
617
618 l4_overlays[0] = ovl;
619 }
620#endif
621}
622
623/* connect overlays to the new device, if not already connected. if force
624 * selected, connect always. */
625void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
626{
627 int i;
628 struct omap_overlay_manager *lcd_mgr;
629 struct omap_overlay_manager *tv_mgr;
630 struct omap_overlay_manager *mgr = NULL;
631
632 lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD);
633 tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV);
634
635 if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
636 if (!lcd_mgr->device || force) {
637 if (lcd_mgr->device)
638 lcd_mgr->unset_device(lcd_mgr);
639 lcd_mgr->set_device(lcd_mgr, dssdev);
640 mgr = lcd_mgr;
641 }
642 }
643
644 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
645 if (!tv_mgr->device || force) {
646 if (tv_mgr->device)
647 tv_mgr->unset_device(tv_mgr);
648 tv_mgr->set_device(tv_mgr, dssdev);
649 mgr = tv_mgr;
650 }
651 }
652
653 if (mgr) {
654 for (i = 0; i < 3; i++) {
655 struct omap_overlay *ovl;
656 ovl = omap_dss_get_overlay(i);
657 if (!ovl->manager || force) {
658 if (ovl->manager)
659 omap_dss_unset_manager(ovl);
660 omap_dss_set_manager(ovl, mgr);
661 }
662 }
663 }
664}
665
666void dss_uninit_overlays(struct platform_device *pdev)
667{
668 struct omap_overlay *ovl;
669
670 while (!list_empty(&overlay_list)) {
671 ovl = list_first_entry(&overlay_list,
672 struct omap_overlay, list);
673 list_del(&ovl->list);
674 kobject_del(&ovl->kobj);
675 kobject_put(&ovl->kobj);
676 kfree(ovl);
677 }
678
679 num_overlays = 0;
680}
681
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
new file mode 100644
index 000000000000..cc23f53cc62d
--- /dev/null
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -0,0 +1,1056 @@
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/vmalloc.h>
28#include <linux/clk.h>
29#include <linux/io.h>
30#include <linux/delay.h>
31#include <linux/kfifo.h>
32#include <linux/ktime.h>
33#include <linux/hrtimer.h>
34#include <linux/seq_file.h>
35
36#include <plat/display.h>
37#include "dss.h"
38
39#define RFBI_BASE 0x48050800
40
41struct rfbi_reg { u16 idx; };
42
43#define RFBI_REG(idx) ((const struct rfbi_reg) { idx })
44
45#define RFBI_REVISION RFBI_REG(0x0000)
46#define RFBI_SYSCONFIG RFBI_REG(0x0010)
47#define RFBI_SYSSTATUS RFBI_REG(0x0014)
48#define RFBI_CONTROL RFBI_REG(0x0040)
49#define RFBI_PIXEL_CNT RFBI_REG(0x0044)
50#define RFBI_LINE_NUMBER RFBI_REG(0x0048)
51#define RFBI_CMD RFBI_REG(0x004c)
52#define RFBI_PARAM RFBI_REG(0x0050)
53#define RFBI_DATA RFBI_REG(0x0054)
54#define RFBI_READ RFBI_REG(0x0058)
55#define RFBI_STATUS RFBI_REG(0x005c)
56
57#define RFBI_CONFIG(n) RFBI_REG(0x0060 + (n)*0x18)
58#define RFBI_ONOFF_TIME(n) RFBI_REG(0x0064 + (n)*0x18)
59#define RFBI_CYCLE_TIME(n) RFBI_REG(0x0068 + (n)*0x18)
60#define RFBI_DATA_CYCLE1(n) RFBI_REG(0x006c + (n)*0x18)
61#define RFBI_DATA_CYCLE2(n) RFBI_REG(0x0070 + (n)*0x18)
62#define RFBI_DATA_CYCLE3(n) RFBI_REG(0x0074 + (n)*0x18)
63
64#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090)
65#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094)
66
67#define REG_FLD_MOD(idx, val, start, end) \
68 rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
69
70/* To work around an RFBI transfer rate limitation */
71#define OMAP_RFBI_RATE_LIMIT 1
72
73enum omap_rfbi_cycleformat {
74 OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0,
75 OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1,
76 OMAP_DSS_RFBI_CYCLEFORMAT_3_1 = 2,
77 OMAP_DSS_RFBI_CYCLEFORMAT_3_2 = 3,
78};
79
80enum omap_rfbi_datatype {
81 OMAP_DSS_RFBI_DATATYPE_12 = 0,
82 OMAP_DSS_RFBI_DATATYPE_16 = 1,
83 OMAP_DSS_RFBI_DATATYPE_18 = 2,
84 OMAP_DSS_RFBI_DATATYPE_24 = 3,
85};
86
87enum omap_rfbi_parallelmode {
88 OMAP_DSS_RFBI_PARALLELMODE_8 = 0,
89 OMAP_DSS_RFBI_PARALLELMODE_9 = 1,
90 OMAP_DSS_RFBI_PARALLELMODE_12 = 2,
91 OMAP_DSS_RFBI_PARALLELMODE_16 = 3,
92};
93
94enum update_cmd {
95 RFBI_CMD_UPDATE = 0,
96 RFBI_CMD_SYNC = 1,
97};
98
99static int rfbi_convert_timings(struct rfbi_timings *t);
100static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
101
102static struct {
103 void __iomem *base;
104
105 unsigned long l4_khz;
106
107 enum omap_rfbi_datatype datatype;
108 enum omap_rfbi_parallelmode parallelmode;
109
110 enum omap_rfbi_te_mode te_mode;
111 int te_enabled;
112
113 void (*framedone_callback)(void *data);
114 void *framedone_callback_data;
115
116 struct omap_dss_device *dssdev[2];
117
118 struct kfifo cmd_fifo;
119 spinlock_t cmd_lock;
120 struct completion cmd_done;
121 atomic_t cmd_fifo_full;
122 atomic_t cmd_pending;
123} rfbi;
124
125struct update_region {
126 u16 x;
127 u16 y;
128 u16 w;
129 u16 h;
130};
131
132static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
133{
134 __raw_writel(val, rfbi.base + idx.idx);
135}
136
137static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
138{
139 return __raw_readl(rfbi.base + idx.idx);
140}
141
142static void rfbi_enable_clocks(bool enable)
143{
144 if (enable)
145 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
146 else
147 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
148}
149
150void omap_rfbi_write_command(const void *buf, u32 len)
151{
152 rfbi_enable_clocks(1);
153 switch (rfbi.parallelmode) {
154 case OMAP_DSS_RFBI_PARALLELMODE_8:
155 {
156 const u8 *b = buf;
157 for (; len; len--)
158 rfbi_write_reg(RFBI_CMD, *b++);
159 break;
160 }
161
162 case OMAP_DSS_RFBI_PARALLELMODE_16:
163 {
164 const u16 *w = buf;
165 BUG_ON(len & 1);
166 for (; len; len -= 2)
167 rfbi_write_reg(RFBI_CMD, *w++);
168 break;
169 }
170
171 case OMAP_DSS_RFBI_PARALLELMODE_9:
172 case OMAP_DSS_RFBI_PARALLELMODE_12:
173 default:
174 BUG();
175 }
176 rfbi_enable_clocks(0);
177}
178EXPORT_SYMBOL(omap_rfbi_write_command);
179
180void omap_rfbi_read_data(void *buf, u32 len)
181{
182 rfbi_enable_clocks(1);
183 switch (rfbi.parallelmode) {
184 case OMAP_DSS_RFBI_PARALLELMODE_8:
185 {
186 u8 *b = buf;
187 for (; len; len--) {
188 rfbi_write_reg(RFBI_READ, 0);
189 *b++ = rfbi_read_reg(RFBI_READ);
190 }
191 break;
192 }
193
194 case OMAP_DSS_RFBI_PARALLELMODE_16:
195 {
196 u16 *w = buf;
197 BUG_ON(len & ~1);
198 for (; len; len -= 2) {
199 rfbi_write_reg(RFBI_READ, 0);
200 *w++ = rfbi_read_reg(RFBI_READ);
201 }
202 break;
203 }
204
205 case OMAP_DSS_RFBI_PARALLELMODE_9:
206 case OMAP_DSS_RFBI_PARALLELMODE_12:
207 default:
208 BUG();
209 }
210 rfbi_enable_clocks(0);
211}
212EXPORT_SYMBOL(omap_rfbi_read_data);
213
214void omap_rfbi_write_data(const void *buf, u32 len)
215{
216 rfbi_enable_clocks(1);
217 switch (rfbi.parallelmode) {
218 case OMAP_DSS_RFBI_PARALLELMODE_8:
219 {
220 const u8 *b = buf;
221 for (; len; len--)
222 rfbi_write_reg(RFBI_PARAM, *b++);
223 break;
224 }
225
226 case OMAP_DSS_RFBI_PARALLELMODE_16:
227 {
228 const u16 *w = buf;
229 BUG_ON(len & 1);
230 for (; len; len -= 2)
231 rfbi_write_reg(RFBI_PARAM, *w++);
232 break;
233 }
234
235 case OMAP_DSS_RFBI_PARALLELMODE_9:
236 case OMAP_DSS_RFBI_PARALLELMODE_12:
237 default:
238 BUG();
239
240 }
241 rfbi_enable_clocks(0);
242}
243EXPORT_SYMBOL(omap_rfbi_write_data);
244
245void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
246 u16 x, u16 y,
247 u16 w, u16 h)
248{
249 int start_offset = scr_width * y + x;
250 int horiz_offset = scr_width - w;
251 int i;
252
253 rfbi_enable_clocks(1);
254
255 if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
256 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
257 const u16 __iomem *pd = buf;
258 pd += start_offset;
259
260 for (; h; --h) {
261 for (i = 0; i < w; ++i) {
262 const u8 __iomem *b = (const u8 __iomem *)pd;
263 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
264 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
265 ++pd;
266 }
267 pd += horiz_offset;
268 }
269 } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_24 &&
270 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
271 const u32 __iomem *pd = buf;
272 pd += start_offset;
273
274 for (; h; --h) {
275 for (i = 0; i < w; ++i) {
276 const u8 __iomem *b = (const u8 __iomem *)pd;
277 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+2));
278 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
279 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
280 ++pd;
281 }
282 pd += horiz_offset;
283 }
284 } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
285 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_16) {
286 const u16 __iomem *pd = buf;
287 pd += start_offset;
288
289 for (; h; --h) {
290 for (i = 0; i < w; ++i) {
291 rfbi_write_reg(RFBI_PARAM, __raw_readw(pd));
292 ++pd;
293 }
294 pd += horiz_offset;
295 }
296 } else {
297 BUG();
298 }
299
300 rfbi_enable_clocks(0);
301}
302EXPORT_SYMBOL(omap_rfbi_write_pixels);
303
304void rfbi_transfer_area(u16 width, u16 height,
305 void (callback)(void *data), void *data)
306{
307 u32 l;
308
309 /*BUG_ON(callback == 0);*/
310 BUG_ON(rfbi.framedone_callback != NULL);
311
312 DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
313
314 dispc_set_lcd_size(width, height);
315
316 dispc_enable_channel(OMAP_DSS_CHANNEL_LCD, true);
317
318 rfbi.framedone_callback = callback;
319 rfbi.framedone_callback_data = data;
320
321 rfbi_enable_clocks(1);
322
323 rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
324
325 l = rfbi_read_reg(RFBI_CONTROL);
326 l = FLD_MOD(l, 1, 0, 0); /* enable */
327 if (!rfbi.te_enabled)
328 l = FLD_MOD(l, 1, 4, 4); /* ITE */
329
330 rfbi_write_reg(RFBI_CONTROL, l);
331}
332
333static void framedone_callback(void *data, u32 mask)
334{
335 void (*callback)(void *data);
336
337 DSSDBG("FRAMEDONE\n");
338
339 REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
340
341 rfbi_enable_clocks(0);
342
343 callback = rfbi.framedone_callback;
344 rfbi.framedone_callback = NULL;
345
346 if (callback != NULL)
347 callback(rfbi.framedone_callback_data);
348
349 atomic_set(&rfbi.cmd_pending, 0);
350}
351
352#if 1 /* VERBOSE */
353static void rfbi_print_timings(void)
354{
355 u32 l;
356 u32 time;
357
358 l = rfbi_read_reg(RFBI_CONFIG(0));
359 time = 1000000000 / rfbi.l4_khz;
360 if (l & (1 << 4))
361 time *= 2;
362
363 DSSDBG("Tick time %u ps\n", time);
364 l = rfbi_read_reg(RFBI_ONOFF_TIME(0));
365 DSSDBG("CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
366 "REONTIME %d, REOFFTIME %d\n",
367 l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
368 (l >> 20) & 0x0f, (l >> 24) & 0x3f);
369
370 l = rfbi_read_reg(RFBI_CYCLE_TIME(0));
371 DSSDBG("WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
372 "ACCESSTIME %d\n",
373 (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
374 (l >> 22) & 0x3f);
375}
376#else
377static void rfbi_print_timings(void) {}
378#endif
379
380
381
382
383static u32 extif_clk_period;
384
385static inline unsigned long round_to_extif_ticks(unsigned long ps, int div)
386{
387 int bus_tick = extif_clk_period * div;
388 return (ps + bus_tick - 1) / bus_tick * bus_tick;
389}
390
391static int calc_reg_timing(struct rfbi_timings *t, int div)
392{
393 t->clk_div = div;
394
395 t->cs_on_time = round_to_extif_ticks(t->cs_on_time, div);
396
397 t->we_on_time = round_to_extif_ticks(t->we_on_time, div);
398 t->we_off_time = round_to_extif_ticks(t->we_off_time, div);
399 t->we_cycle_time = round_to_extif_ticks(t->we_cycle_time, div);
400
401 t->re_on_time = round_to_extif_ticks(t->re_on_time, div);
402 t->re_off_time = round_to_extif_ticks(t->re_off_time, div);
403 t->re_cycle_time = round_to_extif_ticks(t->re_cycle_time, div);
404
405 t->access_time = round_to_extif_ticks(t->access_time, div);
406 t->cs_off_time = round_to_extif_ticks(t->cs_off_time, div);
407 t->cs_pulse_width = round_to_extif_ticks(t->cs_pulse_width, div);
408
409 DSSDBG("[reg]cson %d csoff %d reon %d reoff %d\n",
410 t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
411 DSSDBG("[reg]weon %d weoff %d recyc %d wecyc %d\n",
412 t->we_on_time, t->we_off_time, t->re_cycle_time,
413 t->we_cycle_time);
414 DSSDBG("[reg]rdaccess %d cspulse %d\n",
415 t->access_time, t->cs_pulse_width);
416
417 return rfbi_convert_timings(t);
418}
419
420static int calc_extif_timings(struct rfbi_timings *t)
421{
422 u32 max_clk_div;
423 int div;
424
425 rfbi_get_clk_info(&extif_clk_period, &max_clk_div);
426 for (div = 1; div <= max_clk_div; div++) {
427 if (calc_reg_timing(t, div) == 0)
428 break;
429 }
430
431 if (div <= max_clk_div)
432 return 0;
433
434 DSSERR("can't setup timings\n");
435 return -1;
436}
437
438
439void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
440{
441 int r;
442
443 if (!t->converted) {
444 r = calc_extif_timings(t);
445 if (r < 0)
446 DSSERR("Failed to calc timings\n");
447 }
448
449 BUG_ON(!t->converted);
450
451 rfbi_enable_clocks(1);
452 rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]);
453 rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]);
454
455 /* TIMEGRANULARITY */
456 REG_FLD_MOD(RFBI_CONFIG(rfbi_module),
457 (t->tim[2] ? 1 : 0), 4, 4);
458
459 rfbi_print_timings();
460 rfbi_enable_clocks(0);
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
476#ifdef OMAP_RFBI_RATE_LIMIT
477unsigned long rfbi_get_max_tx_rate(void)
478{
479 unsigned long l4_rate, dss1_rate;
480 int min_l4_ticks = 0;
481 int i;
482
483 /* According to TI this can't be calculated so make the
484 * adjustments for a couple of known frequencies and warn for
485 * others.
486 */
487 static const struct {
488 unsigned long l4_clk; /* HZ */
489 unsigned long dss1_clk; /* HZ */
490 unsigned long min_l4_ticks;
491 } ftab[] = {
492 { 55, 132, 7, }, /* 7.86 MPix/s */
493 { 110, 110, 12, }, /* 9.16 MPix/s */
494 { 110, 132, 10, }, /* 11 Mpix/s */
495 { 120, 120, 10, }, /* 12 Mpix/s */
496 { 133, 133, 10, }, /* 13.3 Mpix/s */
497 };
498
499 l4_rate = rfbi.l4_khz / 1000;
500 dss1_rate = dss_clk_get_rate(DSS_CLK_FCK1) / 1000000;
501
502 for (i = 0; i < ARRAY_SIZE(ftab); i++) {
503 /* Use a window instead of an exact match, to account
504 * for different DPLL multiplier / divider pairs.
505 */
506 if (abs(ftab[i].l4_clk - l4_rate) < 3 &&
507 abs(ftab[i].dss1_clk - dss1_rate) < 3) {
508 min_l4_ticks = ftab[i].min_l4_ticks;
509 break;
510 }
511 }
512 if (i == ARRAY_SIZE(ftab)) {
513 /* Can't be sure, return anyway the maximum not
514 * rate-limited. This might cause a problem only for the
515 * tearing synchronisation.
516 */
517 DSSERR("can't determine maximum RFBI transfer rate\n");
518 return rfbi.l4_khz * 1000;
519 }
520 return rfbi.l4_khz * 1000 / min_l4_ticks;
521}
522#else
523int rfbi_get_max_tx_rate(void)
524{
525 return rfbi.l4_khz * 1000;
526}
527#endif
528
529static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
530{
531 *clk_period = 1000000000 / rfbi.l4_khz;
532 *max_clk_div = 2;
533}
534
535static int rfbi_convert_timings(struct rfbi_timings *t)
536{
537 u32 l;
538 int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
539 int actim, recyc, wecyc;
540 int div = t->clk_div;
541
542 if (div <= 0 || div > 2)
543 return -1;
544
545 /* Make sure that after conversion it still holds that:
546 * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
547 * csoff > cson, csoff >= max(weoff, reoff), actim > reon
548 */
549 weon = ps_to_rfbi_ticks(t->we_on_time, div);
550 weoff = ps_to_rfbi_ticks(t->we_off_time, div);
551 if (weoff <= weon)
552 weoff = weon + 1;
553 if (weon > 0x0f)
554 return -1;
555 if (weoff > 0x3f)
556 return -1;
557
558 reon = ps_to_rfbi_ticks(t->re_on_time, div);
559 reoff = ps_to_rfbi_ticks(t->re_off_time, div);
560 if (reoff <= reon)
561 reoff = reon + 1;
562 if (reon > 0x0f)
563 return -1;
564 if (reoff > 0x3f)
565 return -1;
566
567 cson = ps_to_rfbi_ticks(t->cs_on_time, div);
568 csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
569 if (csoff <= cson)
570 csoff = cson + 1;
571 if (csoff < max(weoff, reoff))
572 csoff = max(weoff, reoff);
573 if (cson > 0x0f)
574 return -1;
575 if (csoff > 0x3f)
576 return -1;
577
578 l = cson;
579 l |= csoff << 4;
580 l |= weon << 10;
581 l |= weoff << 14;
582 l |= reon << 20;
583 l |= reoff << 24;
584
585 t->tim[0] = l;
586
587 actim = ps_to_rfbi_ticks(t->access_time, div);
588 if (actim <= reon)
589 actim = reon + 1;
590 if (actim > 0x3f)
591 return -1;
592
593 wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
594 if (wecyc < weoff)
595 wecyc = weoff;
596 if (wecyc > 0x3f)
597 return -1;
598
599 recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
600 if (recyc < reoff)
601 recyc = reoff;
602 if (recyc > 0x3f)
603 return -1;
604
605 cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
606 if (cs_pulse > 0x3f)
607 return -1;
608
609 l = wecyc;
610 l |= recyc << 6;
611 l |= cs_pulse << 12;
612 l |= actim << 22;
613
614 t->tim[1] = l;
615
616 t->tim[2] = div - 1;
617
618 t->converted = 1;
619
620 return 0;
621}
622
623/* xxx FIX module selection missing */
624int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
625 unsigned hs_pulse_time, unsigned vs_pulse_time,
626 int hs_pol_inv, int vs_pol_inv, int extif_div)
627{
628 int hs, vs;
629 int min;
630 u32 l;
631
632 hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
633 vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
634 if (hs < 2)
635 return -EDOM;
636 if (mode == OMAP_DSS_RFBI_TE_MODE_2)
637 min = 2;
638 else /* OMAP_DSS_RFBI_TE_MODE_1 */
639 min = 4;
640 if (vs < min)
641 return -EDOM;
642 if (vs == hs)
643 return -EINVAL;
644 rfbi.te_mode = mode;
645 DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n",
646 mode, hs, vs, hs_pol_inv, vs_pol_inv);
647
648 rfbi_enable_clocks(1);
649 rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
650 rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
651
652 l = rfbi_read_reg(RFBI_CONFIG(0));
653 if (hs_pol_inv)
654 l &= ~(1 << 21);
655 else
656 l |= 1 << 21;
657 if (vs_pol_inv)
658 l &= ~(1 << 20);
659 else
660 l |= 1 << 20;
661 rfbi_enable_clocks(0);
662
663 return 0;
664}
665EXPORT_SYMBOL(omap_rfbi_setup_te);
666
667/* xxx FIX module selection missing */
668int omap_rfbi_enable_te(bool enable, unsigned line)
669{
670 u32 l;
671
672 DSSDBG("te %d line %d mode %d\n", enable, line, rfbi.te_mode);
673 if (line > (1 << 11) - 1)
674 return -EINVAL;
675
676 rfbi_enable_clocks(1);
677 l = rfbi_read_reg(RFBI_CONFIG(0));
678 l &= ~(0x3 << 2);
679 if (enable) {
680 rfbi.te_enabled = 1;
681 l |= rfbi.te_mode << 2;
682 } else
683 rfbi.te_enabled = 0;
684 rfbi_write_reg(RFBI_CONFIG(0), l);
685 rfbi_write_reg(RFBI_LINE_NUMBER, line);
686 rfbi_enable_clocks(0);
687
688 return 0;
689}
690EXPORT_SYMBOL(omap_rfbi_enable_te);
691
692#if 0
693static void rfbi_enable_config(int enable1, int enable2)
694{
695 u32 l;
696 int cs = 0;
697
698 if (enable1)
699 cs |= 1<<0;
700 if (enable2)
701 cs |= 1<<1;
702
703 rfbi_enable_clocks(1);
704
705 l = rfbi_read_reg(RFBI_CONTROL);
706
707 l = FLD_MOD(l, cs, 3, 2);
708 l = FLD_MOD(l, 0, 1, 1);
709
710 rfbi_write_reg(RFBI_CONTROL, l);
711
712
713 l = rfbi_read_reg(RFBI_CONFIG(0));
714 l = FLD_MOD(l, 0, 3, 2); /* TRIGGERMODE: ITE */
715 /*l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
716 /*l |= FLD_VAL(0, 8, 7); */ /* L4FORMAT, 1pix/L4 */
717
718 l = FLD_MOD(l, 0, 16, 16); /* A0POLARITY */
719 l = FLD_MOD(l, 1, 20, 20); /* TE_VSYNC_POLARITY */
720 l = FLD_MOD(l, 1, 21, 21); /* HSYNCPOLARITY */
721
722 l = FLD_MOD(l, OMAP_DSS_RFBI_PARALLELMODE_8, 1, 0);
723 rfbi_write_reg(RFBI_CONFIG(0), l);
724
725 rfbi_enable_clocks(0);
726}
727#endif
728
729int rfbi_configure(int rfbi_module, int bpp, int lines)
730{
731 u32 l;
732 int cycle1 = 0, cycle2 = 0, cycle3 = 0;
733 enum omap_rfbi_cycleformat cycleformat;
734 enum omap_rfbi_datatype datatype;
735 enum omap_rfbi_parallelmode parallelmode;
736
737 switch (bpp) {
738 case 12:
739 datatype = OMAP_DSS_RFBI_DATATYPE_12;
740 break;
741 case 16:
742 datatype = OMAP_DSS_RFBI_DATATYPE_16;
743 break;
744 case 18:
745 datatype = OMAP_DSS_RFBI_DATATYPE_18;
746 break;
747 case 24:
748 datatype = OMAP_DSS_RFBI_DATATYPE_24;
749 break;
750 default:
751 BUG();
752 return 1;
753 }
754 rfbi.datatype = datatype;
755
756 switch (lines) {
757 case 8:
758 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_8;
759 break;
760 case 9:
761 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_9;
762 break;
763 case 12:
764 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_12;
765 break;
766 case 16:
767 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_16;
768 break;
769 default:
770 BUG();
771 return 1;
772 }
773 rfbi.parallelmode = parallelmode;
774
775 if ((bpp % lines) == 0) {
776 switch (bpp / lines) {
777 case 1:
778 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_1_1;
779 break;
780 case 2:
781 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_2_1;
782 break;
783 case 3:
784 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_1;
785 break;
786 default:
787 BUG();
788 return 1;
789 }
790 } else if ((2 * bpp % lines) == 0) {
791 if ((2 * bpp / lines) == 3)
792 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_2;
793 else {
794 BUG();
795 return 1;
796 }
797 } else {
798 BUG();
799 return 1;
800 }
801
802 switch (cycleformat) {
803 case OMAP_DSS_RFBI_CYCLEFORMAT_1_1:
804 cycle1 = lines;
805 break;
806
807 case OMAP_DSS_RFBI_CYCLEFORMAT_2_1:
808 cycle1 = lines;
809 cycle2 = lines;
810 break;
811
812 case OMAP_DSS_RFBI_CYCLEFORMAT_3_1:
813 cycle1 = lines;
814 cycle2 = lines;
815 cycle3 = lines;
816 break;
817
818 case OMAP_DSS_RFBI_CYCLEFORMAT_3_2:
819 cycle1 = lines;
820 cycle2 = (lines / 2) | ((lines / 2) << 16);
821 cycle3 = (lines << 16);
822 break;
823 }
824
825 rfbi_enable_clocks(1);
826
827 REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */
828
829 l = 0;
830 l |= FLD_VAL(parallelmode, 1, 0);
831 l |= FLD_VAL(0, 3, 2); /* TRIGGERMODE: ITE */
832 l |= FLD_VAL(0, 4, 4); /* TIMEGRANULARITY */
833 l |= FLD_VAL(datatype, 6, 5);
834 /* l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
835 l |= FLD_VAL(0, 8, 7); /* L4FORMAT, 1pix/L4 */
836 l |= FLD_VAL(cycleformat, 10, 9);
837 l |= FLD_VAL(0, 12, 11); /* UNUSEDBITS */
838 l |= FLD_VAL(0, 16, 16); /* A0POLARITY */
839 l |= FLD_VAL(0, 17, 17); /* REPOLARITY */
840 l |= FLD_VAL(0, 18, 18); /* WEPOLARITY */
841 l |= FLD_VAL(0, 19, 19); /* CSPOLARITY */
842 l |= FLD_VAL(1, 20, 20); /* TE_VSYNC_POLARITY */
843 l |= FLD_VAL(1, 21, 21); /* HSYNCPOLARITY */
844 rfbi_write_reg(RFBI_CONFIG(rfbi_module), l);
845
846 rfbi_write_reg(RFBI_DATA_CYCLE1(rfbi_module), cycle1);
847 rfbi_write_reg(RFBI_DATA_CYCLE2(rfbi_module), cycle2);
848 rfbi_write_reg(RFBI_DATA_CYCLE3(rfbi_module), cycle3);
849
850
851 l = rfbi_read_reg(RFBI_CONTROL);
852 l = FLD_MOD(l, rfbi_module+1, 3, 2); /* Select CSx */
853 l = FLD_MOD(l, 0, 1, 1); /* clear bypass */
854 rfbi_write_reg(RFBI_CONTROL, l);
855
856
857 DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n",
858 bpp, lines, cycle1, cycle2, cycle3);
859
860 rfbi_enable_clocks(0);
861
862 return 0;
863}
864EXPORT_SYMBOL(rfbi_configure);
865
866int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
867 u16 *x, u16 *y, u16 *w, u16 *h)
868{
869 u16 dw, dh;
870
871 dssdev->driver->get_resolution(dssdev, &dw, &dh);
872
873 if (*x > dw || *y > dh)
874 return -EINVAL;
875
876 if (*x + *w > dw)
877 return -EINVAL;
878
879 if (*y + *h > dh)
880 return -EINVAL;
881
882 if (*w == 1)
883 return -EINVAL;
884
885 if (*w == 0 || *h == 0)
886 return -EINVAL;
887
888 if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
889 dss_setup_partial_planes(dssdev, x, y, w, h);
890 dispc_set_lcd_size(*w, *h);
891 }
892
893 return 0;
894}
895EXPORT_SYMBOL(omap_rfbi_prepare_update);
896
897int omap_rfbi_update(struct omap_dss_device *dssdev,
898 u16 x, u16 y, u16 w, u16 h,
899 void (*callback)(void *), void *data)
900{
901 if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
902 rfbi_transfer_area(w, h, callback, data);
903 } else {
904 struct omap_overlay *ovl;
905 void __iomem *addr;
906 int scr_width;
907
908 ovl = dssdev->manager->overlays[0];
909 scr_width = ovl->info.screen_width;
910 addr = ovl->info.vaddr;
911
912 omap_rfbi_write_pixels(addr, scr_width, x, y, w, h);
913
914 callback(data);
915 }
916
917 return 0;
918}
919EXPORT_SYMBOL(omap_rfbi_update);
920
921void rfbi_dump_regs(struct seq_file *s)
922{
923#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
924
925 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
926
927 DUMPREG(RFBI_REVISION);
928 DUMPREG(RFBI_SYSCONFIG);
929 DUMPREG(RFBI_SYSSTATUS);
930 DUMPREG(RFBI_CONTROL);
931 DUMPREG(RFBI_PIXEL_CNT);
932 DUMPREG(RFBI_LINE_NUMBER);
933 DUMPREG(RFBI_CMD);
934 DUMPREG(RFBI_PARAM);
935 DUMPREG(RFBI_DATA);
936 DUMPREG(RFBI_READ);
937 DUMPREG(RFBI_STATUS);
938
939 DUMPREG(RFBI_CONFIG(0));
940 DUMPREG(RFBI_ONOFF_TIME(0));
941 DUMPREG(RFBI_CYCLE_TIME(0));
942 DUMPREG(RFBI_DATA_CYCLE1(0));
943 DUMPREG(RFBI_DATA_CYCLE2(0));
944 DUMPREG(RFBI_DATA_CYCLE3(0));
945
946 DUMPREG(RFBI_CONFIG(1));
947 DUMPREG(RFBI_ONOFF_TIME(1));
948 DUMPREG(RFBI_CYCLE_TIME(1));
949 DUMPREG(RFBI_DATA_CYCLE1(1));
950 DUMPREG(RFBI_DATA_CYCLE2(1));
951 DUMPREG(RFBI_DATA_CYCLE3(1));
952
953 DUMPREG(RFBI_VSYNC_WIDTH);
954 DUMPREG(RFBI_HSYNC_WIDTH);
955
956 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
957#undef DUMPREG
958}
959
960int rfbi_init(void)
961{
962 u32 rev;
963 u32 l;
964
965 spin_lock_init(&rfbi.cmd_lock);
966
967 init_completion(&rfbi.cmd_done);
968 atomic_set(&rfbi.cmd_fifo_full, 0);
969 atomic_set(&rfbi.cmd_pending, 0);
970
971 rfbi.base = ioremap(RFBI_BASE, SZ_256);
972 if (!rfbi.base) {
973 DSSERR("can't ioremap RFBI\n");
974 return -ENOMEM;
975 }
976
977 rfbi_enable_clocks(1);
978
979 msleep(10);
980
981 rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
982
983 /* Enable autoidle and smart-idle */
984 l = rfbi_read_reg(RFBI_SYSCONFIG);
985 l |= (1 << 0) | (2 << 3);
986 rfbi_write_reg(RFBI_SYSCONFIG, l);
987
988 rev = rfbi_read_reg(RFBI_REVISION);
989 printk(KERN_INFO "OMAP RFBI rev %d.%d\n",
990 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
991
992 rfbi_enable_clocks(0);
993
994 return 0;
995}
996
997void rfbi_exit(void)
998{
999 DSSDBG("rfbi_exit\n");
1000
1001 iounmap(rfbi.base);
1002}
1003
1004int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
1005{
1006 int r;
1007
1008 r = omap_dss_start_device(dssdev);
1009 if (r) {
1010 DSSERR("failed to start device\n");
1011 goto err0;
1012 }
1013
1014 r = omap_dispc_register_isr(framedone_callback, NULL,
1015 DISPC_IRQ_FRAMEDONE);
1016 if (r) {
1017 DSSERR("can't get FRAMEDONE irq\n");
1018 goto err1;
1019 }
1020
1021 dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
1022
1023 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_RFBI);
1024
1025 dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
1026
1027 rfbi_configure(dssdev->phy.rfbi.channel,
1028 dssdev->ctrl.pixel_size,
1029 dssdev->phy.rfbi.data_lines);
1030
1031 rfbi_set_timings(dssdev->phy.rfbi.channel,
1032 &dssdev->ctrl.rfbi_timings);
1033
1034
1035 return 0;
1036err1:
1037 omap_dss_stop_device(dssdev);
1038err0:
1039 return r;
1040}
1041EXPORT_SYMBOL(omapdss_rfbi_display_enable);
1042
1043void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
1044{
1045 omap_dispc_unregister_isr(framedone_callback, NULL,
1046 DISPC_IRQ_FRAMEDONE);
1047 omap_dss_stop_device(dssdev);
1048}
1049EXPORT_SYMBOL(omapdss_rfbi_display_disable);
1050
1051int rfbi_init_display(struct omap_dss_device *dssdev)
1052{
1053 rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
1054 dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
1055 return 0;
1056}
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
new file mode 100644
index 000000000000..12eb4042dd82
--- /dev/null
+++ b/drivers/video/omap2/dss/sdi.c
@@ -0,0 +1,176 @@
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/clk.h>
24#include <linux/delay.h>
25#include <linux/err.h>
26
27#include <plat/display.h>
28#include "dss.h"
29
30static struct {
31 bool skip_init;
32 bool update_enabled;
33} sdi;
34
35static void sdi_basic_init(void)
36{
37 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
38
39 dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
40 dispc_set_tft_data_lines(24);
41 dispc_lcd_enable_signal_polarity(1);
42}
43
44int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
45{
46 struct omap_video_timings *t = &dssdev->panel.timings;
47 struct dss_clock_info dss_cinfo;
48 struct dispc_clock_info dispc_cinfo;
49 u16 lck_div, pck_div;
50 unsigned long fck;
51 unsigned long pck;
52 int r;
53
54 r = omap_dss_start_device(dssdev);
55 if (r) {
56 DSSERR("failed to start device\n");
57 goto err0;
58 }
59
60 /* In case of skip_init sdi_init has already enabled the clocks */
61 if (!sdi.skip_init)
62 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
63
64 sdi_basic_init();
65
66 /* 15.5.9.1.2 */
67 dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF;
68
69 dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
70 dssdev->panel.acb);
71
72 if (!sdi.skip_init) {
73 r = dss_calc_clock_div(1, t->pixel_clock * 1000,
74 &dss_cinfo, &dispc_cinfo);
75 } else {
76 r = dss_get_clock_div(&dss_cinfo);
77 r = dispc_get_clock_div(&dispc_cinfo);
78 }
79
80 if (r)
81 goto err2;
82
83 fck = dss_cinfo.fck;
84 lck_div = dispc_cinfo.lck_div;
85 pck_div = dispc_cinfo.pck_div;
86
87 pck = fck / lck_div / pck_div / 1000;
88
89 if (pck != t->pixel_clock) {
90 DSSWARN("Could not find exact pixel clock. Requested %d kHz, "
91 "got %lu kHz\n",
92 t->pixel_clock, pck);
93
94 t->pixel_clock = pck;
95 }
96
97
98 dispc_set_lcd_timings(t);
99
100 r = dss_set_clock_div(&dss_cinfo);
101 if (r)
102 goto err2;
103
104 r = dispc_set_clock_div(&dispc_cinfo);
105 if (r)
106 goto err2;
107
108 if (!sdi.skip_init) {
109 dss_sdi_init(dssdev->phy.sdi.datapairs);
110 r = dss_sdi_enable();
111 if (r)
112 goto err1;
113 mdelay(2);
114 }
115
116 dssdev->manager->enable(dssdev->manager);
117
118 if (dssdev->driver->enable) {
119 r = dssdev->driver->enable(dssdev);
120 if (r)
121 goto err3;
122 }
123
124 sdi.skip_init = 0;
125
126 return 0;
127err3:
128 dssdev->manager->disable(dssdev->manager);
129err2:
130 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
131err1:
132 omap_dss_stop_device(dssdev);
133err0:
134 return r;
135}
136EXPORT_SYMBOL(omapdss_sdi_display_enable);
137
138void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
139{
140 if (dssdev->driver->disable)
141 dssdev->driver->disable(dssdev);
142
143 dssdev->manager->disable(dssdev->manager);
144
145 dss_sdi_disable();
146
147 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
148
149 omap_dss_stop_device(dssdev);
150}
151EXPORT_SYMBOL(omapdss_sdi_display_disable);
152
153int sdi_init_display(struct omap_dss_device *dssdev)
154{
155 DSSDBG("SDI init\n");
156
157 return 0;
158}
159
160int sdi_init(bool skip_init)
161{
162 /* we store this for first display enable, then clear it */
163 sdi.skip_init = skip_init;
164
165 /*
166 * Enable clocks already here, otherwise there would be a toggle
167 * of them until sdi_display_enable is called.
168 */
169 if (skip_init)
170 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
171 return 0;
172}
173
174void sdi_exit(void)
175{
176}
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
new file mode 100644
index 000000000000..f0ba5732d84a
--- /dev/null
+++ b/drivers/video/omap2/dss/venc.c
@@ -0,0 +1,755 @@
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
37#include <plat/display.h>
38#include <plat/cpu.h>
39
40#include "dss.h"
41
42#define VENC_BASE 0x48050C00
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 .pixel_clock = 13500,
269 .hsw = 64,
270 .hfp = 12,
271 .hbp = 68,
272 .vsw = 5,
273 .vfp = 5,
274 .vbp = 41,
275};
276EXPORT_SYMBOL(omap_dss_pal_timings);
277
278const struct omap_video_timings omap_dss_ntsc_timings = {
279 .x_res = 720,
280 .y_res = 482,
281 .pixel_clock = 13500,
282 .hsw = 64,
283 .hfp = 16,
284 .hbp = 58,
285 .vsw = 6,
286 .vfp = 6,
287 .vbp = 31,
288};
289EXPORT_SYMBOL(omap_dss_ntsc_timings);
290
291static struct {
292 void __iomem *base;
293 struct mutex venc_lock;
294 u32 wss_data;
295 struct regulator *vdda_dac_reg;
296} venc;
297
298static inline void venc_write_reg(int idx, u32 val)
299{
300 __raw_writel(val, venc.base + idx);
301}
302
303static inline u32 venc_read_reg(int idx)
304{
305 u32 l = __raw_readl(venc.base + idx);
306 return l;
307}
308
309static void venc_write_config(const struct venc_config *config)
310{
311 DSSDBG("write venc conf\n");
312
313 venc_write_reg(VENC_LLEN, config->llen);
314 venc_write_reg(VENC_FLENS, config->flens);
315 venc_write_reg(VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);
316 venc_write_reg(VENC_C_PHASE, config->c_phase);
317 venc_write_reg(VENC_GAIN_U, config->gain_u);
318 venc_write_reg(VENC_GAIN_V, config->gain_v);
319 venc_write_reg(VENC_GAIN_Y, config->gain_y);
320 venc_write_reg(VENC_BLACK_LEVEL, config->black_level);
321 venc_write_reg(VENC_BLANK_LEVEL, config->blank_level);
322 venc_write_reg(VENC_M_CONTROL, config->m_control);
323 venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
324 venc.wss_data);
325 venc_write_reg(VENC_S_CARR, config->s_carr);
326 venc_write_reg(VENC_L21__WC_CTL, config->l21__wc_ctl);
327 venc_write_reg(VENC_SAVID__EAVID, config->savid__eavid);
328 venc_write_reg(VENC_FLEN__FAL, config->flen__fal);
329 venc_write_reg(VENC_LAL__PHASE_RESET, config->lal__phase_reset);
330 venc_write_reg(VENC_HS_INT_START_STOP_X, config->hs_int_start_stop_x);
331 venc_write_reg(VENC_HS_EXT_START_STOP_X, config->hs_ext_start_stop_x);
332 venc_write_reg(VENC_VS_INT_START_X, config->vs_int_start_x);
333 venc_write_reg(VENC_VS_INT_STOP_X__VS_INT_START_Y,
334 config->vs_int_stop_x__vs_int_start_y);
335 venc_write_reg(VENC_VS_INT_STOP_Y__VS_EXT_START_X,
336 config->vs_int_stop_y__vs_ext_start_x);
337 venc_write_reg(VENC_VS_EXT_STOP_X__VS_EXT_START_Y,
338 config->vs_ext_stop_x__vs_ext_start_y);
339 venc_write_reg(VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);
340 venc_write_reg(VENC_AVID_START_STOP_X, config->avid_start_stop_x);
341 venc_write_reg(VENC_AVID_START_STOP_Y, config->avid_start_stop_y);
342 venc_write_reg(VENC_FID_INT_START_X__FID_INT_START_Y,
343 config->fid_int_start_x__fid_int_start_y);
344 venc_write_reg(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,
345 config->fid_int_offset_y__fid_ext_start_x);
346 venc_write_reg(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,
347 config->fid_ext_start_y__fid_ext_offset_y);
348
349 venc_write_reg(VENC_DAC_B__DAC_C, venc_read_reg(VENC_DAC_B__DAC_C));
350 venc_write_reg(VENC_VIDOUT_CTRL, config->vidout_ctrl);
351 venc_write_reg(VENC_HFLTR_CTRL, config->hfltr_ctrl);
352 venc_write_reg(VENC_X_COLOR, config->x_color);
353 venc_write_reg(VENC_LINE21, config->line21);
354 venc_write_reg(VENC_LN_SEL, config->ln_sel);
355 venc_write_reg(VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);
356 venc_write_reg(VENC_TVDETGP_INT_START_STOP_X,
357 config->tvdetgp_int_start_stop_x);
358 venc_write_reg(VENC_TVDETGP_INT_START_STOP_Y,
359 config->tvdetgp_int_start_stop_y);
360 venc_write_reg(VENC_GEN_CTRL, config->gen_ctrl);
361 venc_write_reg(VENC_F_CONTROL, config->f_control);
362 venc_write_reg(VENC_SYNC_CTRL, config->sync_ctrl);
363}
364
365static void venc_reset(void)
366{
367 int t = 1000;
368
369 venc_write_reg(VENC_F_CONTROL, 1<<8);
370 while (venc_read_reg(VENC_F_CONTROL) & (1<<8)) {
371 if (--t == 0) {
372 DSSERR("Failed to reset venc\n");
373 return;
374 }
375 }
376
377 /* the magical sleep that makes things work */
378 msleep(20);
379}
380
381static void venc_enable_clocks(int enable)
382{
383 if (enable)
384 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
385 DSS_CLK_96M);
386 else
387 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
388 DSS_CLK_96M);
389}
390
391static const struct venc_config *venc_timings_to_config(
392 struct omap_video_timings *timings)
393{
394 if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
395 return &venc_config_pal_trm;
396
397 if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
398 return &venc_config_ntsc_trm;
399
400 BUG();
401}
402
403static void venc_power_on(struct omap_dss_device *dssdev)
404{
405 u32 l;
406
407 venc_enable_clocks(1);
408
409 venc_reset();
410 venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
411
412 dss_set_venc_output(dssdev->phy.venc.type);
413 dss_set_dac_pwrdn_bgz(1);
414
415 l = 0;
416
417 if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
418 l |= 1 << 1;
419 else /* S-Video */
420 l |= (1 << 0) | (1 << 2);
421
422 if (dssdev->phy.venc.invert_polarity == false)
423 l |= 1 << 3;
424
425 venc_write_reg(VENC_OUTPUT_CONTROL, l);
426
427 dispc_set_digit_size(dssdev->panel.timings.x_res,
428 dssdev->panel.timings.y_res/2);
429
430 regulator_enable(venc.vdda_dac_reg);
431
432 if (dssdev->platform_enable)
433 dssdev->platform_enable(dssdev);
434
435 dssdev->manager->enable(dssdev->manager);
436}
437
438static void venc_power_off(struct omap_dss_device *dssdev)
439{
440 venc_write_reg(VENC_OUTPUT_CONTROL, 0);
441 dss_set_dac_pwrdn_bgz(0);
442
443 dssdev->manager->disable(dssdev->manager);
444
445 if (dssdev->platform_disable)
446 dssdev->platform_disable(dssdev);
447
448 regulator_disable(venc.vdda_dac_reg);
449
450 venc_enable_clocks(0);
451}
452
453
454
455
456
457/* driver */
458static int venc_panel_probe(struct omap_dss_device *dssdev)
459{
460 dssdev->panel.timings = omap_dss_pal_timings;
461
462 return 0;
463}
464
465static void venc_panel_remove(struct omap_dss_device *dssdev)
466{
467}
468
469static int venc_panel_enable(struct omap_dss_device *dssdev)
470{
471 int r = 0;
472
473 DSSDBG("venc_enable_display\n");
474
475 mutex_lock(&venc.venc_lock);
476
477 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
478 r = -EINVAL;
479 goto err1;
480 }
481
482 if (dssdev->platform_enable) {
483 r = dssdev->platform_enable(dssdev);
484 if (r)
485 goto err2;
486 }
487
488 venc_power_on(dssdev);
489
490 venc.wss_data = 0;
491
492 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
493
494 /* wait couple of vsyncs until enabling the LCD */
495 msleep(50);
496
497 mutex_unlock(&venc.venc_lock);
498
499 return r;
500err2:
501 venc_power_off(dssdev);
502err1:
503 mutex_unlock(&venc.venc_lock);
504 return r;
505}
506
507static void venc_panel_disable(struct omap_dss_device *dssdev)
508{
509 DSSDBG("venc_disable_display\n");
510
511 mutex_lock(&venc.venc_lock);
512
513 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
514 goto end;
515
516 if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
517 /* suspended is the same as disabled with venc */
518 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
519 goto end;
520 }
521
522 venc_power_off(dssdev);
523
524 /* wait at least 5 vsyncs after disabling the LCD */
525 msleep(100);
526
527 if (dssdev->platform_disable)
528 dssdev->platform_disable(dssdev);
529
530 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
531end:
532 mutex_unlock(&venc.venc_lock);
533}
534
535static int venc_panel_suspend(struct omap_dss_device *dssdev)
536{
537 venc_panel_disable(dssdev);
538 return 0;
539}
540
541static int venc_panel_resume(struct omap_dss_device *dssdev)
542{
543 return venc_panel_enable(dssdev);
544}
545
546static enum omap_dss_update_mode venc_get_update_mode(
547 struct omap_dss_device *dssdev)
548{
549 return OMAP_DSS_UPDATE_AUTO;
550}
551
552static int venc_set_update_mode(struct omap_dss_device *dssdev,
553 enum omap_dss_update_mode mode)
554{
555 if (mode != OMAP_DSS_UPDATE_AUTO)
556 return -EINVAL;
557 return 0;
558}
559
560static void venc_get_timings(struct omap_dss_device *dssdev,
561 struct omap_video_timings *timings)
562{
563 *timings = dssdev->panel.timings;
564}
565
566static void venc_set_timings(struct omap_dss_device *dssdev,
567 struct omap_video_timings *timings)
568{
569 DSSDBG("venc_set_timings\n");
570
571 /* Reset WSS data when the TV standard changes. */
572 if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings)))
573 venc.wss_data = 0;
574
575 dssdev->panel.timings = *timings;
576 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
577 /* turn the venc off and on to get new timings to use */
578 venc_panel_disable(dssdev);
579 venc_panel_enable(dssdev);
580 }
581}
582
583static int venc_check_timings(struct omap_dss_device *dssdev,
584 struct omap_video_timings *timings)
585{
586 DSSDBG("venc_check_timings\n");
587
588 if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
589 return 0;
590
591 if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
592 return 0;
593
594 return -EINVAL;
595}
596
597static u32 venc_get_wss(struct omap_dss_device *dssdev)
598{
599 /* Invert due to VENC_L21_WC_CTL:INV=1 */
600 return (venc.wss_data >> 8) ^ 0xfffff;
601}
602
603static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
604{
605 const struct venc_config *config;
606
607 DSSDBG("venc_set_wss\n");
608
609 mutex_lock(&venc.venc_lock);
610
611 config = venc_timings_to_config(&dssdev->panel.timings);
612
613 /* Invert due to VENC_L21_WC_CTL:INV=1 */
614 venc.wss_data = (wss ^ 0xfffff) << 8;
615
616 venc_enable_clocks(1);
617
618 venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
619 venc.wss_data);
620
621 venc_enable_clocks(0);
622
623 mutex_unlock(&venc.venc_lock);
624
625 return 0;
626}
627
628static struct omap_dss_driver venc_driver = {
629 .probe = venc_panel_probe,
630 .remove = venc_panel_remove,
631
632 .enable = venc_panel_enable,
633 .disable = venc_panel_disable,
634 .suspend = venc_panel_suspend,
635 .resume = venc_panel_resume,
636
637 .get_resolution = omapdss_default_get_resolution,
638 .get_recommended_bpp = omapdss_default_get_recommended_bpp,
639
640 .set_update_mode = venc_set_update_mode,
641 .get_update_mode = venc_get_update_mode,
642
643 .get_timings = venc_get_timings,
644 .set_timings = venc_set_timings,
645 .check_timings = venc_check_timings,
646
647 .get_wss = venc_get_wss,
648 .set_wss = venc_set_wss,
649
650 .driver = {
651 .name = "venc",
652 .owner = THIS_MODULE,
653 },
654};
655/* driver end */
656
657
658
659int venc_init(struct platform_device *pdev)
660{
661 u8 rev_id;
662
663 mutex_init(&venc.venc_lock);
664
665 venc.wss_data = 0;
666
667 venc.base = ioremap(VENC_BASE, SZ_1K);
668 if (!venc.base) {
669 DSSERR("can't ioremap VENC\n");
670 return -ENOMEM;
671 }
672
673 venc.vdda_dac_reg = dss_get_vdda_dac();
674 if (IS_ERR(venc.vdda_dac_reg)) {
675 iounmap(venc.base);
676 DSSERR("can't get VDDA_DAC regulator\n");
677 return PTR_ERR(venc.vdda_dac_reg);
678 }
679
680 venc_enable_clocks(1);
681
682 rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
683 printk(KERN_INFO "OMAP VENC rev %d\n", rev_id);
684
685 venc_enable_clocks(0);
686
687 return omap_dss_register_driver(&venc_driver);
688}
689
690void venc_exit(void)
691{
692 omap_dss_unregister_driver(&venc_driver);
693
694 iounmap(venc.base);
695}
696
697int venc_init_display(struct omap_dss_device *dssdev)
698{
699 DSSDBG("init_display\n");
700
701 return 0;
702}
703
704void venc_dump_regs(struct seq_file *s)
705{
706#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
707
708 venc_enable_clocks(1);
709
710 DUMPREG(VENC_F_CONTROL);
711 DUMPREG(VENC_VIDOUT_CTRL);
712 DUMPREG(VENC_SYNC_CTRL);
713 DUMPREG(VENC_LLEN);
714 DUMPREG(VENC_FLENS);
715 DUMPREG(VENC_HFLTR_CTRL);
716 DUMPREG(VENC_CC_CARR_WSS_CARR);
717 DUMPREG(VENC_C_PHASE);
718 DUMPREG(VENC_GAIN_U);
719 DUMPREG(VENC_GAIN_V);
720 DUMPREG(VENC_GAIN_Y);
721 DUMPREG(VENC_BLACK_LEVEL);
722 DUMPREG(VENC_BLANK_LEVEL);
723 DUMPREG(VENC_X_COLOR);
724 DUMPREG(VENC_M_CONTROL);
725 DUMPREG(VENC_BSTAMP_WSS_DATA);
726 DUMPREG(VENC_S_CARR);
727 DUMPREG(VENC_LINE21);
728 DUMPREG(VENC_LN_SEL);
729 DUMPREG(VENC_L21__WC_CTL);
730 DUMPREG(VENC_HTRIGGER_VTRIGGER);
731 DUMPREG(VENC_SAVID__EAVID);
732 DUMPREG(VENC_FLEN__FAL);
733 DUMPREG(VENC_LAL__PHASE_RESET);
734 DUMPREG(VENC_HS_INT_START_STOP_X);
735 DUMPREG(VENC_HS_EXT_START_STOP_X);
736 DUMPREG(VENC_VS_INT_START_X);
737 DUMPREG(VENC_VS_INT_STOP_X__VS_INT_START_Y);
738 DUMPREG(VENC_VS_INT_STOP_Y__VS_EXT_START_X);
739 DUMPREG(VENC_VS_EXT_STOP_X__VS_EXT_START_Y);
740 DUMPREG(VENC_VS_EXT_STOP_Y);
741 DUMPREG(VENC_AVID_START_STOP_X);
742 DUMPREG(VENC_AVID_START_STOP_Y);
743 DUMPREG(VENC_FID_INT_START_X__FID_INT_START_Y);
744 DUMPREG(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);
745 DUMPREG(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);
746 DUMPREG(VENC_TVDETGP_INT_START_STOP_X);
747 DUMPREG(VENC_TVDETGP_INT_START_STOP_Y);
748 DUMPREG(VENC_GEN_CTRL);
749 DUMPREG(VENC_OUTPUT_CONTROL);
750 DUMPREG(VENC_OUTPUT_TEST);
751
752 venc_enable_clocks(0);
753
754#undef DUMPREG
755}
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
new file mode 100644
index 000000000000..43496d6c377f
--- /dev/null
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -0,0 +1,28 @@
1menuconfig FB_OMAP2
2 tristate "OMAP2/3 frame buffer support (EXPERIMENTAL)"
3 depends on FB && OMAP2_DSS
4
5 select OMAP2_VRAM
6 select OMAP2_VRFB
7 select FB_CFB_FILLRECT
8 select FB_CFB_COPYAREA
9 select FB_CFB_IMAGEBLIT
10 help
11 Frame buffer driver for OMAP2/3 based boards.
12
13config FB_OMAP2_DEBUG_SUPPORT
14 bool "Debug support for OMAP2/3 FB"
15 default y
16 depends on FB_OMAP2
17 help
18 Support for debug output. You have to enable the actual printing
19 with 'debug' module parameter.
20
21config FB_OMAP2_NUM_FBS
22 int "Number of framebuffers"
23 range 1 10
24 default 3
25 depends on FB_OMAP2
26 help
27 Select the number of framebuffers created. OMAP2/3 has 3 overlays
28 so normally this would be 3.
diff --git a/drivers/video/omap2/omapfb/Makefile b/drivers/video/omap2/omapfb/Makefile
new file mode 100644
index 000000000000..51c2e00d9bf8
--- /dev/null
+++ b/drivers/video/omap2/omapfb/Makefile
@@ -0,0 +1,2 @@
1obj-$(CONFIG_FB_OMAP2) += omapfb.o
2omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
new file mode 100644
index 000000000000..1ffa760b8545
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -0,0 +1,785 @@
1/*
2 * linux/drivers/video/omap2/omapfb-ioctl.c
3 *
4 * Copyright (C) 2008 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#include <linux/fb.h>
24#include <linux/device.h>
25#include <linux/uaccess.h>
26#include <linux/platform_device.h>
27#include <linux/mm.h>
28#include <linux/omapfb.h>
29#include <linux/vmalloc.h>
30
31#include <plat/display.h>
32#include <plat/vrfb.h>
33#include <plat/vram.h>
34
35#include "omapfb.h"
36
37static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
38{
39 struct omapfb_info *ofbi = FB2OFB(fbi);
40 struct omapfb2_device *fbdev = ofbi->fbdev;
41 struct omap_overlay *ovl;
42 struct omap_overlay_info info;
43 int r = 0;
44
45 DBG("omapfb_setup_plane\n");
46
47 if (ofbi->num_overlays != 1) {
48 r = -EINVAL;
49 goto out;
50 }
51
52 /* XXX uses only the first overlay */
53 ovl = ofbi->overlays[0];
54
55 if (pi->enabled && !ofbi->region.size) {
56 /*
57 * This plane's memory was freed, can't enable it
58 * until it's reallocated.
59 */
60 r = -EINVAL;
61 goto out;
62 }
63
64 ovl->get_overlay_info(ovl, &info);
65
66 info.pos_x = pi->pos_x;
67 info.pos_y = pi->pos_y;
68 info.out_width = pi->out_width;
69 info.out_height = pi->out_height;
70 info.enabled = pi->enabled;
71
72 r = ovl->set_overlay_info(ovl, &info);
73 if (r)
74 goto out;
75
76 if (ovl->manager) {
77 r = ovl->manager->apply(ovl->manager);
78 if (r)
79 goto out;
80 }
81
82out:
83 if (r)
84 dev_err(fbdev->dev, "setup_plane failed\n");
85 return r;
86}
87
88static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
89{
90 struct omapfb_info *ofbi = FB2OFB(fbi);
91
92 if (ofbi->num_overlays != 1) {
93 memset(pi, 0, sizeof(*pi));
94 } else {
95 struct omap_overlay_info *ovli;
96 struct omap_overlay *ovl;
97
98 ovl = ofbi->overlays[0];
99 ovli = &ovl->info;
100
101 pi->pos_x = ovli->pos_x;
102 pi->pos_y = ovli->pos_y;
103 pi->enabled = ovli->enabled;
104 pi->channel_out = 0; /* xxx */
105 pi->mirror = 0;
106 pi->out_width = ovli->out_width;
107 pi->out_height = ovli->out_height;
108 }
109
110 return 0;
111}
112
113static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
114{
115 struct omapfb_info *ofbi = FB2OFB(fbi);
116 struct omapfb2_device *fbdev = ofbi->fbdev;
117 struct omapfb2_mem_region *rg;
118 int r, i;
119 size_t size;
120
121 if (mi->type > OMAPFB_MEMTYPE_MAX)
122 return -EINVAL;
123
124 size = PAGE_ALIGN(mi->size);
125
126 rg = &ofbi->region;
127
128 for (i = 0; i < ofbi->num_overlays; i++) {
129 if (ofbi->overlays[i]->info.enabled)
130 return -EBUSY;
131 }
132
133 if (rg->size != size || rg->type != mi->type) {
134 r = omapfb_realloc_fbmem(fbi, size, mi->type);
135 if (r) {
136 dev_err(fbdev->dev, "realloc fbmem failed\n");
137 return r;
138 }
139 }
140
141 return 0;
142}
143
144static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
145{
146 struct omapfb_info *ofbi = FB2OFB(fbi);
147 struct omapfb2_mem_region *rg;
148
149 rg = &ofbi->region;
150 memset(mi, 0, sizeof(*mi));
151
152 mi->size = rg->size;
153 mi->type = rg->type;
154
155 return 0;
156}
157
158static int omapfb_update_window_nolock(struct fb_info *fbi,
159 u32 x, u32 y, u32 w, u32 h)
160{
161 struct omap_dss_device *display = fb2display(fbi);
162 u16 dw, dh;
163
164 if (!display)
165 return 0;
166
167 if (w == 0 || h == 0)
168 return 0;
169
170 display->driver->get_resolution(display, &dw, &dh);
171
172 if (x + w > dw || y + h > dh)
173 return -EINVAL;
174
175 return display->driver->update(display, x, y, w, h);
176}
177
178/* This function is exported for SGX driver use */
179int omapfb_update_window(struct fb_info *fbi,
180 u32 x, u32 y, u32 w, u32 h)
181{
182 struct omapfb_info *ofbi = FB2OFB(fbi);
183 struct omapfb2_device *fbdev = ofbi->fbdev;
184 int r;
185
186 omapfb_lock(fbdev);
187 lock_fb_info(fbi);
188
189 r = omapfb_update_window_nolock(fbi, x, y, w, h);
190
191 unlock_fb_info(fbi);
192 omapfb_unlock(fbdev);
193
194 return r;
195}
196EXPORT_SYMBOL(omapfb_update_window);
197
198static int omapfb_set_update_mode(struct fb_info *fbi,
199 enum omapfb_update_mode mode)
200{
201 struct omap_dss_device *display = fb2display(fbi);
202 enum omap_dss_update_mode um;
203 int r;
204
205 if (!display || !display->driver->set_update_mode)
206 return -EINVAL;
207
208 switch (mode) {
209 case OMAPFB_UPDATE_DISABLED:
210 um = OMAP_DSS_UPDATE_DISABLED;
211 break;
212
213 case OMAPFB_AUTO_UPDATE:
214 um = OMAP_DSS_UPDATE_AUTO;
215 break;
216
217 case OMAPFB_MANUAL_UPDATE:
218 um = OMAP_DSS_UPDATE_MANUAL;
219 break;
220
221 default:
222 return -EINVAL;
223 }
224
225 r = display->driver->set_update_mode(display, um);
226
227 return r;
228}
229
230static int omapfb_get_update_mode(struct fb_info *fbi,
231 enum omapfb_update_mode *mode)
232{
233 struct omap_dss_device *display = fb2display(fbi);
234 enum omap_dss_update_mode m;
235
236 if (!display)
237 return -EINVAL;
238
239 if (!display->driver->get_update_mode) {
240 *mode = OMAPFB_AUTO_UPDATE;
241 return 0;
242 }
243
244 m = display->driver->get_update_mode(display);
245
246 switch (m) {
247 case OMAP_DSS_UPDATE_DISABLED:
248 *mode = OMAPFB_UPDATE_DISABLED;
249 break;
250 case OMAP_DSS_UPDATE_AUTO:
251 *mode = OMAPFB_AUTO_UPDATE;
252 break;
253 case OMAP_DSS_UPDATE_MANUAL:
254 *mode = OMAPFB_MANUAL_UPDATE;
255 break;
256 default:
257 BUG();
258 }
259
260 return 0;
261}
262
263/* XXX this color key handling is a hack... */
264static struct omapfb_color_key omapfb_color_keys[2];
265
266static int _omapfb_set_color_key(struct omap_overlay_manager *mgr,
267 struct omapfb_color_key *ck)
268{
269 struct omap_overlay_manager_info info;
270 enum omap_dss_trans_key_type kt;
271 int r;
272
273 mgr->get_manager_info(mgr, &info);
274
275 if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {
276 info.trans_enabled = false;
277 omapfb_color_keys[mgr->id] = *ck;
278
279 r = mgr->set_manager_info(mgr, &info);
280 if (r)
281 return r;
282
283 r = mgr->apply(mgr);
284
285 return r;
286 }
287
288 switch (ck->key_type) {
289 case OMAPFB_COLOR_KEY_GFX_DST:
290 kt = OMAP_DSS_COLOR_KEY_GFX_DST;
291 break;
292 case OMAPFB_COLOR_KEY_VID_SRC:
293 kt = OMAP_DSS_COLOR_KEY_VID_SRC;
294 break;
295 default:
296 return -EINVAL;
297 }
298
299 info.default_color = ck->background;
300 info.trans_key = ck->trans_key;
301 info.trans_key_type = kt;
302 info.trans_enabled = true;
303
304 omapfb_color_keys[mgr->id] = *ck;
305
306 r = mgr->set_manager_info(mgr, &info);
307 if (r)
308 return r;
309
310 r = mgr->apply(mgr);
311
312 return r;
313}
314
315static int omapfb_set_color_key(struct fb_info *fbi,
316 struct omapfb_color_key *ck)
317{
318 struct omapfb_info *ofbi = FB2OFB(fbi);
319 struct omapfb2_device *fbdev = ofbi->fbdev;
320 int r;
321 int i;
322 struct omap_overlay_manager *mgr = NULL;
323
324 omapfb_lock(fbdev);
325
326 for (i = 0; i < ofbi->num_overlays; i++) {
327 if (ofbi->overlays[i]->manager) {
328 mgr = ofbi->overlays[i]->manager;
329 break;
330 }
331 }
332
333 if (!mgr) {
334 r = -EINVAL;
335 goto err;
336 }
337
338 r = _omapfb_set_color_key(mgr, ck);
339err:
340 omapfb_unlock(fbdev);
341
342 return r;
343}
344
345static int omapfb_get_color_key(struct fb_info *fbi,
346 struct omapfb_color_key *ck)
347{
348 struct omapfb_info *ofbi = FB2OFB(fbi);
349 struct omapfb2_device *fbdev = ofbi->fbdev;
350 struct omap_overlay_manager *mgr = NULL;
351 int r = 0;
352 int i;
353
354 omapfb_lock(fbdev);
355
356 for (i = 0; i < ofbi->num_overlays; i++) {
357 if (ofbi->overlays[i]->manager) {
358 mgr = ofbi->overlays[i]->manager;
359 break;
360 }
361 }
362
363 if (!mgr) {
364 r = -EINVAL;
365 goto err;
366 }
367
368 *ck = omapfb_color_keys[mgr->id];
369err:
370 omapfb_unlock(fbdev);
371
372 return r;
373}
374
375static int omapfb_memory_read(struct fb_info *fbi,
376 struct omapfb_memory_read *mr)
377{
378 struct omap_dss_device *display = fb2display(fbi);
379 void *buf;
380 int r;
381
382 if (!display || !display->driver->memory_read)
383 return -ENOENT;
384
385 if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
386 return -EFAULT;
387
388 if (mr->w * mr->h * 3 > mr->buffer_size)
389 return -EINVAL;
390
391 buf = vmalloc(mr->buffer_size);
392 if (!buf) {
393 DBG("vmalloc failed\n");
394 return -ENOMEM;
395 }
396
397 r = display->driver->memory_read(display, buf, mr->buffer_size,
398 mr->x, mr->y, mr->w, mr->h);
399
400 if (r > 0) {
401 if (copy_to_user(mr->buffer, buf, mr->buffer_size))
402 r = -EFAULT;
403 }
404
405 vfree(buf);
406
407 return r;
408}
409
410static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,
411 struct omapfb_ovl_colormode *mode)
412{
413 int ovl_idx = mode->overlay_idx;
414 int mode_idx = mode->mode_idx;
415 struct omap_overlay *ovl;
416 enum omap_color_mode supported_modes;
417 struct fb_var_screeninfo var;
418 int i;
419
420 if (ovl_idx >= fbdev->num_overlays)
421 return -ENODEV;
422 ovl = fbdev->overlays[ovl_idx];
423 supported_modes = ovl->supported_modes;
424
425 mode_idx = mode->mode_idx;
426
427 for (i = 0; i < sizeof(supported_modes) * 8; i++) {
428 if (!(supported_modes & (1 << i)))
429 continue;
430 /*
431 * It's possible that the FB doesn't support a mode
432 * that is supported by the overlay, so call the
433 * following here.
434 */
435 if (dss_mode_to_fb_mode(1 << i, &var) < 0)
436 continue;
437
438 mode_idx--;
439 if (mode_idx < 0)
440 break;
441 }
442
443 if (i == sizeof(supported_modes) * 8)
444 return -ENOENT;
445
446 mode->bits_per_pixel = var.bits_per_pixel;
447 mode->nonstd = var.nonstd;
448 mode->red = var.red;
449 mode->green = var.green;
450 mode->blue = var.blue;
451 mode->transp = var.transp;
452
453 return 0;
454}
455
456static int omapfb_wait_for_go(struct fb_info *fbi)
457{
458 struct omapfb_info *ofbi = FB2OFB(fbi);
459 int r = 0;
460 int i;
461
462 for (i = 0; i < ofbi->num_overlays; ++i) {
463 struct omap_overlay *ovl = ofbi->overlays[i];
464 r = ovl->wait_for_go(ovl);
465 if (r)
466 break;
467 }
468
469 return r;
470}
471
472int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
473{
474 struct omapfb_info *ofbi = FB2OFB(fbi);
475 struct omapfb2_device *fbdev = ofbi->fbdev;
476 struct omap_dss_device *display = fb2display(fbi);
477
478 union {
479 struct omapfb_update_window_old uwnd_o;
480 struct omapfb_update_window uwnd;
481 struct omapfb_plane_info plane_info;
482 struct omapfb_caps caps;
483 struct omapfb_mem_info mem_info;
484 struct omapfb_color_key color_key;
485 struct omapfb_ovl_colormode ovl_colormode;
486 enum omapfb_update_mode update_mode;
487 int test_num;
488 struct omapfb_memory_read memory_read;
489 struct omapfb_vram_info vram_info;
490 struct omapfb_tearsync_info tearsync_info;
491 struct omapfb_display_info display_info;
492 } p;
493
494 int r = 0;
495
496 switch (cmd) {
497 case OMAPFB_SYNC_GFX:
498 DBG("ioctl SYNC_GFX\n");
499 if (!display || !display->driver->sync) {
500 /* DSS1 never returns an error here, so we neither */
501 /*r = -EINVAL;*/
502 break;
503 }
504
505 r = display->driver->sync(display);
506 break;
507
508 case OMAPFB_UPDATE_WINDOW_OLD:
509 DBG("ioctl UPDATE_WINDOW_OLD\n");
510 if (!display || !display->driver->update) {
511 r = -EINVAL;
512 break;
513 }
514
515 if (copy_from_user(&p.uwnd_o,
516 (void __user *)arg,
517 sizeof(p.uwnd_o))) {
518 r = -EFAULT;
519 break;
520 }
521
522 r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y,
523 p.uwnd_o.width, p.uwnd_o.height);
524 break;
525
526 case OMAPFB_UPDATE_WINDOW:
527 DBG("ioctl UPDATE_WINDOW\n");
528 if (!display || !display->driver->update) {
529 r = -EINVAL;
530 break;
531 }
532
533 if (copy_from_user(&p.uwnd, (void __user *)arg,
534 sizeof(p.uwnd))) {
535 r = -EFAULT;
536 break;
537 }
538
539 r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y,
540 p.uwnd.width, p.uwnd.height);
541 break;
542
543 case OMAPFB_SETUP_PLANE:
544 DBG("ioctl SETUP_PLANE\n");
545 if (copy_from_user(&p.plane_info, (void __user *)arg,
546 sizeof(p.plane_info)))
547 r = -EFAULT;
548 else
549 r = omapfb_setup_plane(fbi, &p.plane_info);
550 break;
551
552 case OMAPFB_QUERY_PLANE:
553 DBG("ioctl QUERY_PLANE\n");
554 r = omapfb_query_plane(fbi, &p.plane_info);
555 if (r < 0)
556 break;
557 if (copy_to_user((void __user *)arg, &p.plane_info,
558 sizeof(p.plane_info)))
559 r = -EFAULT;
560 break;
561
562 case OMAPFB_SETUP_MEM:
563 DBG("ioctl SETUP_MEM\n");
564 if (copy_from_user(&p.mem_info, (void __user *)arg,
565 sizeof(p.mem_info)))
566 r = -EFAULT;
567 else
568 r = omapfb_setup_mem(fbi, &p.mem_info);
569 break;
570
571 case OMAPFB_QUERY_MEM:
572 DBG("ioctl QUERY_MEM\n");
573 r = omapfb_query_mem(fbi, &p.mem_info);
574 if (r < 0)
575 break;
576 if (copy_to_user((void __user *)arg, &p.mem_info,
577 sizeof(p.mem_info)))
578 r = -EFAULT;
579 break;
580
581 case OMAPFB_GET_CAPS:
582 DBG("ioctl GET_CAPS\n");
583 if (!display) {
584 r = -EINVAL;
585 break;
586 }
587
588 memset(&p.caps, 0, sizeof(p.caps));
589 if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
590 p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE;
591 if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM)
592 p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC;
593
594 if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
595 r = -EFAULT;
596 break;
597
598 case OMAPFB_GET_OVERLAY_COLORMODE:
599 DBG("ioctl GET_OVERLAY_COLORMODE\n");
600 if (copy_from_user(&p.ovl_colormode, (void __user *)arg,
601 sizeof(p.ovl_colormode))) {
602 r = -EFAULT;
603 break;
604 }
605 r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);
606 if (r < 0)
607 break;
608 if (copy_to_user((void __user *)arg, &p.ovl_colormode,
609 sizeof(p.ovl_colormode)))
610 r = -EFAULT;
611 break;
612
613 case OMAPFB_SET_UPDATE_MODE:
614 DBG("ioctl SET_UPDATE_MODE\n");
615 if (get_user(p.update_mode, (int __user *)arg))
616 r = -EFAULT;
617 else
618 r = omapfb_set_update_mode(fbi, p.update_mode);
619 break;
620
621 case OMAPFB_GET_UPDATE_MODE:
622 DBG("ioctl GET_UPDATE_MODE\n");
623 r = omapfb_get_update_mode(fbi, &p.update_mode);
624 if (r)
625 break;
626 if (put_user(p.update_mode,
627 (enum omapfb_update_mode __user *)arg))
628 r = -EFAULT;
629 break;
630
631 case OMAPFB_SET_COLOR_KEY:
632 DBG("ioctl SET_COLOR_KEY\n");
633 if (copy_from_user(&p.color_key, (void __user *)arg,
634 sizeof(p.color_key)))
635 r = -EFAULT;
636 else
637 r = omapfb_set_color_key(fbi, &p.color_key);
638 break;
639
640 case OMAPFB_GET_COLOR_KEY:
641 DBG("ioctl GET_COLOR_KEY\n");
642 r = omapfb_get_color_key(fbi, &p.color_key);
643 if (r)
644 break;
645 if (copy_to_user((void __user *)arg, &p.color_key,
646 sizeof(p.color_key)))
647 r = -EFAULT;
648 break;
649
650 case OMAPFB_WAITFORVSYNC:
651 DBG("ioctl WAITFORVSYNC\n");
652 if (!display) {
653 r = -EINVAL;
654 break;
655 }
656
657 r = display->manager->wait_for_vsync(display->manager);
658 break;
659
660 case OMAPFB_WAITFORGO:
661 DBG("ioctl WAITFORGO\n");
662 if (!display) {
663 r = -EINVAL;
664 break;
665 }
666
667 r = omapfb_wait_for_go(fbi);
668 break;
669
670 /* LCD and CTRL tests do the same thing for backward
671 * compatibility */
672 case OMAPFB_LCD_TEST:
673 DBG("ioctl LCD_TEST\n");
674 if (get_user(p.test_num, (int __user *)arg)) {
675 r = -EFAULT;
676 break;
677 }
678 if (!display || !display->driver->run_test) {
679 r = -EINVAL;
680 break;
681 }
682
683 r = display->driver->run_test(display, p.test_num);
684
685 break;
686
687 case OMAPFB_CTRL_TEST:
688 DBG("ioctl CTRL_TEST\n");
689 if (get_user(p.test_num, (int __user *)arg)) {
690 r = -EFAULT;
691 break;
692 }
693 if (!display || !display->driver->run_test) {
694 r = -EINVAL;
695 break;
696 }
697
698 r = display->driver->run_test(display, p.test_num);
699
700 break;
701
702 case OMAPFB_MEMORY_READ:
703 DBG("ioctl MEMORY_READ\n");
704
705 if (copy_from_user(&p.memory_read, (void __user *)arg,
706 sizeof(p.memory_read))) {
707 r = -EFAULT;
708 break;
709 }
710
711 r = omapfb_memory_read(fbi, &p.memory_read);
712
713 break;
714
715 case OMAPFB_GET_VRAM_INFO: {
716 unsigned long vram, free, largest;
717
718 DBG("ioctl GET_VRAM_INFO\n");
719
720 omap_vram_get_info(&vram, &free, &largest);
721 p.vram_info.total = vram;
722 p.vram_info.free = free;
723 p.vram_info.largest_free_block = largest;
724
725 if (copy_to_user((void __user *)arg, &p.vram_info,
726 sizeof(p.vram_info)))
727 r = -EFAULT;
728 break;
729 }
730
731 case OMAPFB_SET_TEARSYNC: {
732 DBG("ioctl SET_TEARSYNC\n");
733
734 if (copy_from_user(&p.tearsync_info, (void __user *)arg,
735 sizeof(p.tearsync_info))) {
736 r = -EFAULT;
737 break;
738 }
739
740 if (!display->driver->enable_te) {
741 r = -ENODEV;
742 break;
743 }
744
745 r = display->driver->enable_te(display,
746 !!p.tearsync_info.enabled);
747
748 break;
749 }
750
751 case OMAPFB_GET_DISPLAY_INFO: {
752 u16 xres, yres;
753
754 DBG("ioctl GET_DISPLAY_INFO\n");
755
756 if (display == NULL) {
757 r = -ENODEV;
758 break;
759 }
760
761 display->driver->get_resolution(display, &xres, &yres);
762
763 p.display_info.xres = xres;
764 p.display_info.yres = yres;
765 p.display_info.width = 0;
766 p.display_info.height = 0;
767
768 if (copy_to_user((void __user *)arg, &p.display_info,
769 sizeof(p.display_info)))
770 r = -EFAULT;
771 break;
772 }
773
774 default:
775 dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
776 r = -EINVAL;
777 }
778
779 if (r < 0)
780 DBG("ioctl failed: %d\n", r);
781
782 return r;
783}
784
785
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
new file mode 100644
index 000000000000..4b4506da96da
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -0,0 +1,2287 @@
1/*
2 * linux/drivers/video/omap2/omapfb-main.c
3 *
4 * Copyright (C) 2008 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#include <linux/module.h>
24#include <linux/delay.h>
25#include <linux/slab.h>
26#include <linux/fb.h>
27#include <linux/dma-mapping.h>
28#include <linux/vmalloc.h>
29#include <linux/device.h>
30#include <linux/platform_device.h>
31#include <linux/omapfb.h>
32
33#include <plat/display.h>
34#include <plat/vram.h>
35#include <plat/vrfb.h>
36
37#include "omapfb.h"
38
39#define MODULE_NAME "omapfb"
40
41#define OMAPFB_PLANE_XRES_MIN 8
42#define OMAPFB_PLANE_YRES_MIN 8
43
44static char *def_mode;
45static char *def_vram;
46static int def_vrfb;
47static int def_rotate;
48static int def_mirror;
49
50#ifdef DEBUG
51unsigned int omapfb_debug;
52module_param_named(debug, omapfb_debug, bool, 0644);
53static unsigned int omapfb_test_pattern;
54module_param_named(test, omapfb_test_pattern, bool, 0644);
55#endif
56
57static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
58static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
59 struct omap_dss_device *dssdev);
60
61#ifdef DEBUG
62static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
63{
64 struct fb_var_screeninfo *var = &fbi->var;
65 struct fb_fix_screeninfo *fix = &fbi->fix;
66 void __iomem *addr = fbi->screen_base;
67 const unsigned bytespp = var->bits_per_pixel >> 3;
68 const unsigned line_len = fix->line_length / bytespp;
69
70 int r = (color >> 16) & 0xff;
71 int g = (color >> 8) & 0xff;
72 int b = (color >> 0) & 0xff;
73
74 if (var->bits_per_pixel == 16) {
75 u16 __iomem *p = (u16 __iomem *)addr;
76 p += y * line_len + x;
77
78 r = r * 32 / 256;
79 g = g * 64 / 256;
80 b = b * 32 / 256;
81
82 __raw_writew((r << 11) | (g << 5) | (b << 0), p);
83 } else if (var->bits_per_pixel == 24) {
84 u8 __iomem *p = (u8 __iomem *)addr;
85 p += (y * line_len + x) * 3;
86
87 __raw_writeb(b, p + 0);
88 __raw_writeb(g, p + 1);
89 __raw_writeb(r, p + 2);
90 } else if (var->bits_per_pixel == 32) {
91 u32 __iomem *p = (u32 __iomem *)addr;
92 p += y * line_len + x;
93 __raw_writel(color, p);
94 }
95}
96
97static void fill_fb(struct fb_info *fbi)
98{
99 struct fb_var_screeninfo *var = &fbi->var;
100 const short w = var->xres_virtual;
101 const short h = var->yres_virtual;
102 void __iomem *addr = fbi->screen_base;
103 int y, x;
104
105 if (!addr)
106 return;
107
108 DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);
109
110 for (y = 0; y < h; y++) {
111 for (x = 0; x < w; x++) {
112 if (x < 20 && y < 20)
113 draw_pixel(fbi, x, y, 0xffffff);
114 else if (x < 20 && (y > 20 && y < h - 20))
115 draw_pixel(fbi, x, y, 0xff);
116 else if (y < 20 && (x > 20 && x < w - 20))
117 draw_pixel(fbi, x, y, 0xff00);
118 else if (x > w - 20 && (y > 20 && y < h - 20))
119 draw_pixel(fbi, x, y, 0xff0000);
120 else if (y > h - 20 && (x > 20 && x < w - 20))
121 draw_pixel(fbi, x, y, 0xffff00);
122 else if (x == 20 || x == w - 20 ||
123 y == 20 || y == h - 20)
124 draw_pixel(fbi, x, y, 0xffffff);
125 else if (x == y || w - x == h - y)
126 draw_pixel(fbi, x, y, 0xff00ff);
127 else if (w - x == y || x == h - y)
128 draw_pixel(fbi, x, y, 0x00ffff);
129 else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) {
130 int t = x * 3 / w;
131 unsigned r = 0, g = 0, b = 0;
132 unsigned c;
133 if (var->bits_per_pixel == 16) {
134 if (t == 0)
135 b = (y % 32) * 256 / 32;
136 else if (t == 1)
137 g = (y % 64) * 256 / 64;
138 else if (t == 2)
139 r = (y % 32) * 256 / 32;
140 } else {
141 if (t == 0)
142 b = (y % 256);
143 else if (t == 1)
144 g = (y % 256);
145 else if (t == 2)
146 r = (y % 256);
147 }
148 c = (r << 16) | (g << 8) | (b << 0);
149 draw_pixel(fbi, x, y, c);
150 } else {
151 draw_pixel(fbi, x, y, 0);
152 }
153 }
154 }
155}
156#endif
157
158static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
159{
160 const struct vrfb *vrfb = &ofbi->region.vrfb;
161 unsigned offset;
162
163 switch (rot) {
164 case FB_ROTATE_UR:
165 offset = 0;
166 break;
167 case FB_ROTATE_CW:
168 offset = vrfb->yoffset;
169 break;
170 case FB_ROTATE_UD:
171 offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;
172 break;
173 case FB_ROTATE_CCW:
174 offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;
175 break;
176 default:
177 BUG();
178 }
179
180 offset *= vrfb->bytespp;
181
182 return offset;
183}
184
185static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot)
186{
187 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
188 return ofbi->region.vrfb.paddr[rot]
189 + omapfb_get_vrfb_offset(ofbi, rot);
190 } else {
191 return ofbi->region.paddr;
192 }
193}
194
195static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi)
196{
197 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
198 return ofbi->region.vrfb.paddr[0];
199 else
200 return ofbi->region.paddr;
201}
202
203static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi)
204{
205 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
206 return ofbi->region.vrfb.vaddr[0];
207 else
208 return ofbi->region.vaddr;
209}
210
211static struct omapfb_colormode omapfb_colormodes[] = {
212 {
213 .dssmode = OMAP_DSS_COLOR_UYVY,
214 .bits_per_pixel = 16,
215 .nonstd = OMAPFB_COLOR_YUV422,
216 }, {
217 .dssmode = OMAP_DSS_COLOR_YUV2,
218 .bits_per_pixel = 16,
219 .nonstd = OMAPFB_COLOR_YUY422,
220 }, {
221 .dssmode = OMAP_DSS_COLOR_ARGB16,
222 .bits_per_pixel = 16,
223 .red = { .length = 4, .offset = 8, .msb_right = 0 },
224 .green = { .length = 4, .offset = 4, .msb_right = 0 },
225 .blue = { .length = 4, .offset = 0, .msb_right = 0 },
226 .transp = { .length = 4, .offset = 12, .msb_right = 0 },
227 }, {
228 .dssmode = OMAP_DSS_COLOR_RGB16,
229 .bits_per_pixel = 16,
230 .red = { .length = 5, .offset = 11, .msb_right = 0 },
231 .green = { .length = 6, .offset = 5, .msb_right = 0 },
232 .blue = { .length = 5, .offset = 0, .msb_right = 0 },
233 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
234 }, {
235 .dssmode = OMAP_DSS_COLOR_RGB24P,
236 .bits_per_pixel = 24,
237 .red = { .length = 8, .offset = 16, .msb_right = 0 },
238 .green = { .length = 8, .offset = 8, .msb_right = 0 },
239 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
240 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
241 }, {
242 .dssmode = OMAP_DSS_COLOR_RGB24U,
243 .bits_per_pixel = 32,
244 .red = { .length = 8, .offset = 16, .msb_right = 0 },
245 .green = { .length = 8, .offset = 8, .msb_right = 0 },
246 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
247 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
248 }, {
249 .dssmode = OMAP_DSS_COLOR_ARGB32,
250 .bits_per_pixel = 32,
251 .red = { .length = 8, .offset = 16, .msb_right = 0 },
252 .green = { .length = 8, .offset = 8, .msb_right = 0 },
253 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
254 .transp = { .length = 8, .offset = 24, .msb_right = 0 },
255 }, {
256 .dssmode = OMAP_DSS_COLOR_RGBA32,
257 .bits_per_pixel = 32,
258 .red = { .length = 8, .offset = 24, .msb_right = 0 },
259 .green = { .length = 8, .offset = 16, .msb_right = 0 },
260 .blue = { .length = 8, .offset = 8, .msb_right = 0 },
261 .transp = { .length = 8, .offset = 0, .msb_right = 0 },
262 }, {
263 .dssmode = OMAP_DSS_COLOR_RGBX32,
264 .bits_per_pixel = 32,
265 .red = { .length = 8, .offset = 24, .msb_right = 0 },
266 .green = { .length = 8, .offset = 16, .msb_right = 0 },
267 .blue = { .length = 8, .offset = 8, .msb_right = 0 },
268 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
269 },
270};
271
272static bool cmp_var_to_colormode(struct fb_var_screeninfo *var,
273 struct omapfb_colormode *color)
274{
275 bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)
276 {
277 return f1->length == f2->length &&
278 f1->offset == f2->offset &&
279 f1->msb_right == f2->msb_right;
280 }
281
282 if (var->bits_per_pixel == 0 ||
283 var->red.length == 0 ||
284 var->blue.length == 0 ||
285 var->green.length == 0)
286 return 0;
287
288 return var->bits_per_pixel == color->bits_per_pixel &&
289 cmp_component(&var->red, &color->red) &&
290 cmp_component(&var->green, &color->green) &&
291 cmp_component(&var->blue, &color->blue) &&
292 cmp_component(&var->transp, &color->transp);
293}
294
295static void assign_colormode_to_var(struct fb_var_screeninfo *var,
296 struct omapfb_colormode *color)
297{
298 var->bits_per_pixel = color->bits_per_pixel;
299 var->nonstd = color->nonstd;
300 var->red = color->red;
301 var->green = color->green;
302 var->blue = color->blue;
303 var->transp = color->transp;
304}
305
306static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var,
307 enum omap_color_mode *mode)
308{
309 enum omap_color_mode dssmode;
310 int i;
311
312 /* first match with nonstd field */
313 if (var->nonstd) {
314 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
315 struct omapfb_colormode *m = &omapfb_colormodes[i];
316 if (var->nonstd == m->nonstd) {
317 assign_colormode_to_var(var, m);
318 *mode = m->dssmode;
319 return 0;
320 }
321 }
322
323 return -EINVAL;
324 }
325
326 /* then try exact match of bpp and colors */
327 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
328 struct omapfb_colormode *m = &omapfb_colormodes[i];
329 if (cmp_var_to_colormode(var, m)) {
330 assign_colormode_to_var(var, m);
331 *mode = m->dssmode;
332 return 0;
333 }
334 }
335
336 /* match with bpp if user has not filled color fields
337 * properly */
338 switch (var->bits_per_pixel) {
339 case 1:
340 dssmode = OMAP_DSS_COLOR_CLUT1;
341 break;
342 case 2:
343 dssmode = OMAP_DSS_COLOR_CLUT2;
344 break;
345 case 4:
346 dssmode = OMAP_DSS_COLOR_CLUT4;
347 break;
348 case 8:
349 dssmode = OMAP_DSS_COLOR_CLUT8;
350 break;
351 case 12:
352 dssmode = OMAP_DSS_COLOR_RGB12U;
353 break;
354 case 16:
355 dssmode = OMAP_DSS_COLOR_RGB16;
356 break;
357 case 24:
358 dssmode = OMAP_DSS_COLOR_RGB24P;
359 break;
360 case 32:
361 dssmode = OMAP_DSS_COLOR_RGB24U;
362 break;
363 default:
364 return -EINVAL;
365 }
366
367 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
368 struct omapfb_colormode *m = &omapfb_colormodes[i];
369 if (dssmode == m->dssmode) {
370 assign_colormode_to_var(var, m);
371 *mode = m->dssmode;
372 return 0;
373 }
374 }
375
376 return -EINVAL;
377}
378
379static int check_fb_res_bounds(struct fb_var_screeninfo *var)
380{
381 int xres_min = OMAPFB_PLANE_XRES_MIN;
382 int xres_max = 2048;
383 int yres_min = OMAPFB_PLANE_YRES_MIN;
384 int yres_max = 2048;
385
386 /* XXX: some applications seem to set virtual res to 0. */
387 if (var->xres_virtual == 0)
388 var->xres_virtual = var->xres;
389
390 if (var->yres_virtual == 0)
391 var->yres_virtual = var->yres;
392
393 if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)
394 return -EINVAL;
395
396 if (var->xres < xres_min)
397 var->xres = xres_min;
398 if (var->yres < yres_min)
399 var->yres = yres_min;
400 if (var->xres > xres_max)
401 var->xres = xres_max;
402 if (var->yres > yres_max)
403 var->yres = yres_max;
404
405 if (var->xres > var->xres_virtual)
406 var->xres = var->xres_virtual;
407 if (var->yres > var->yres_virtual)
408 var->yres = var->yres_virtual;
409
410 return 0;
411}
412
413static void shrink_height(unsigned long max_frame_size,
414 struct fb_var_screeninfo *var)
415{
416 DBG("can't fit FB into memory, reducing y\n");
417 var->yres_virtual = max_frame_size /
418 (var->xres_virtual * var->bits_per_pixel >> 3);
419
420 if (var->yres_virtual < OMAPFB_PLANE_YRES_MIN)
421 var->yres_virtual = OMAPFB_PLANE_YRES_MIN;
422
423 if (var->yres > var->yres_virtual)
424 var->yres = var->yres_virtual;
425}
426
427static void shrink_width(unsigned long max_frame_size,
428 struct fb_var_screeninfo *var)
429{
430 DBG("can't fit FB into memory, reducing x\n");
431 var->xres_virtual = max_frame_size / var->yres_virtual /
432 (var->bits_per_pixel >> 3);
433
434 if (var->xres_virtual < OMAPFB_PLANE_XRES_MIN)
435 var->xres_virtual = OMAPFB_PLANE_XRES_MIN;
436
437 if (var->xres > var->xres_virtual)
438 var->xres = var->xres_virtual;
439}
440
441static int check_vrfb_fb_size(unsigned long region_size,
442 const struct fb_var_screeninfo *var)
443{
444 unsigned long min_phys_size = omap_vrfb_min_phys_size(var->xres_virtual,
445 var->yres_virtual, var->bits_per_pixel >> 3);
446
447 return min_phys_size > region_size ? -EINVAL : 0;
448}
449
450static int check_fb_size(const struct omapfb_info *ofbi,
451 struct fb_var_screeninfo *var)
452{
453 unsigned long max_frame_size = ofbi->region.size;
454 int bytespp = var->bits_per_pixel >> 3;
455 unsigned long line_size = var->xres_virtual * bytespp;
456
457 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
458 /* One needs to check for both VRFB and OMAPFB limitations. */
459 if (check_vrfb_fb_size(max_frame_size, var))
460 shrink_height(omap_vrfb_max_height(
461 max_frame_size, var->xres_virtual, bytespp) *
462 line_size, var);
463
464 if (check_vrfb_fb_size(max_frame_size, var)) {
465 DBG("cannot fit FB to memory\n");
466 return -EINVAL;
467 }
468
469 return 0;
470 }
471
472 DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);
473
474 if (line_size * var->yres_virtual > max_frame_size)
475 shrink_height(max_frame_size, var);
476
477 if (line_size * var->yres_virtual > max_frame_size) {
478 shrink_width(max_frame_size, var);
479 line_size = var->xres_virtual * bytespp;
480 }
481
482 if (line_size * var->yres_virtual > max_frame_size) {
483 DBG("cannot fit FB to memory\n");
484 return -EINVAL;
485 }
486
487 return 0;
488}
489
490/*
491 * Consider if VRFB assisted rotation is in use and if the virtual space for
492 * the zero degree view needs to be mapped. The need for mapping also acts as
493 * the trigger for setting up the hardware on the context in question. This
494 * ensures that one does not attempt to access the virtual view before the
495 * hardware is serving the address translations.
496 */
497static int setup_vrfb_rotation(struct fb_info *fbi)
498{
499 struct omapfb_info *ofbi = FB2OFB(fbi);
500 struct omapfb2_mem_region *rg = &ofbi->region;
501 struct vrfb *vrfb = &rg->vrfb;
502 struct fb_var_screeninfo *var = &fbi->var;
503 struct fb_fix_screeninfo *fix = &fbi->fix;
504 unsigned bytespp;
505 bool yuv_mode;
506 enum omap_color_mode mode;
507 int r;
508 bool reconf;
509
510 if (!rg->size || ofbi->rotation_type != OMAP_DSS_ROT_VRFB)
511 return 0;
512
513 DBG("setup_vrfb_rotation\n");
514
515 r = fb_mode_to_dss_mode(var, &mode);
516 if (r)
517 return r;
518
519 bytespp = var->bits_per_pixel >> 3;
520
521 yuv_mode = mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY;
522
523 /* We need to reconfigure VRFB if the resolution changes, if yuv mode
524 * is enabled/disabled, or if bytes per pixel changes */
525
526 /* XXX we shouldn't allow this when framebuffer is mmapped */
527
528 reconf = false;
529
530 if (yuv_mode != vrfb->yuv_mode)
531 reconf = true;
532 else if (bytespp != vrfb->bytespp)
533 reconf = true;
534 else if (vrfb->xres != var->xres_virtual ||
535 vrfb->yres != var->yres_virtual)
536 reconf = true;
537
538 if (vrfb->vaddr[0] && reconf) {
539 fbi->screen_base = NULL;
540 fix->smem_start = 0;
541 fix->smem_len = 0;
542 iounmap(vrfb->vaddr[0]);
543 vrfb->vaddr[0] = NULL;
544 DBG("setup_vrfb_rotation: reset fb\n");
545 }
546
547 if (vrfb->vaddr[0])
548 return 0;
549
550 omap_vrfb_setup(&rg->vrfb, rg->paddr,
551 var->xres_virtual,
552 var->yres_virtual,
553 bytespp, yuv_mode);
554
555 /* Now one can ioremap the 0 angle view */
556 r = omap_vrfb_map_angle(vrfb, var->yres_virtual, 0);
557 if (r)
558 return r;
559
560 /* used by open/write in fbmem.c */
561 fbi->screen_base = ofbi->region.vrfb.vaddr[0];
562
563 fix->smem_start = ofbi->region.vrfb.paddr[0];
564
565 switch (var->nonstd) {
566 case OMAPFB_COLOR_YUV422:
567 case OMAPFB_COLOR_YUY422:
568 fix->line_length =
569 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
570 break;
571 default:
572 fix->line_length =
573 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
574 break;
575 }
576
577 fix->smem_len = var->yres_virtual * fix->line_length;
578
579 return 0;
580}
581
582int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
583 struct fb_var_screeninfo *var)
584{
585 int i;
586
587 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
588 struct omapfb_colormode *mode = &omapfb_colormodes[i];
589 if (dssmode == mode->dssmode) {
590 assign_colormode_to_var(var, mode);
591 return 0;
592 }
593 }
594 return -ENOENT;
595}
596
597void set_fb_fix(struct fb_info *fbi)
598{
599 struct fb_fix_screeninfo *fix = &fbi->fix;
600 struct fb_var_screeninfo *var = &fbi->var;
601 struct omapfb_info *ofbi = FB2OFB(fbi);
602 struct omapfb2_mem_region *rg = &ofbi->region;
603
604 DBG("set_fb_fix\n");
605
606 /* used by open/write in fbmem.c */
607 fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
608
609 /* used by mmap in fbmem.c */
610 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
611 switch (var->nonstd) {
612 case OMAPFB_COLOR_YUV422:
613 case OMAPFB_COLOR_YUY422:
614 fix->line_length =
615 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
616 break;
617 default:
618 fix->line_length =
619 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
620 break;
621 }
622
623 fix->smem_len = var->yres_virtual * fix->line_length;
624 } else {
625 fix->line_length =
626 (var->xres_virtual * var->bits_per_pixel) >> 3;
627 fix->smem_len = rg->size;
628 }
629
630 fix->smem_start = omapfb_get_region_paddr(ofbi);
631
632 fix->type = FB_TYPE_PACKED_PIXELS;
633
634 if (var->nonstd)
635 fix->visual = FB_VISUAL_PSEUDOCOLOR;
636 else {
637 switch (var->bits_per_pixel) {
638 case 32:
639 case 24:
640 case 16:
641 case 12:
642 fix->visual = FB_VISUAL_TRUECOLOR;
643 /* 12bpp is stored in 16 bits */
644 break;
645 case 1:
646 case 2:
647 case 4:
648 case 8:
649 fix->visual = FB_VISUAL_PSEUDOCOLOR;
650 break;
651 }
652 }
653
654 fix->accel = FB_ACCEL_NONE;
655
656 fix->xpanstep = 1;
657 fix->ypanstep = 1;
658}
659
660/* check new var and possibly modify it to be ok */
661int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
662{
663 struct omapfb_info *ofbi = FB2OFB(fbi);
664 struct omap_dss_device *display = fb2display(fbi);
665 enum omap_color_mode mode = 0;
666 int i;
667 int r;
668
669 DBG("check_fb_var %d\n", ofbi->id);
670
671 if (ofbi->region.size == 0)
672 return 0;
673
674 r = fb_mode_to_dss_mode(var, &mode);
675 if (r) {
676 DBG("cannot convert var to omap dss mode\n");
677 return r;
678 }
679
680 for (i = 0; i < ofbi->num_overlays; ++i) {
681 if ((ofbi->overlays[i]->supported_modes & mode) == 0) {
682 DBG("invalid mode\n");
683 return -EINVAL;
684 }
685 }
686
687 if (var->rotate < 0 || var->rotate > 3)
688 return -EINVAL;
689
690 if (check_fb_res_bounds(var))
691 return -EINVAL;
692
693 if (check_fb_size(ofbi, var))
694 return -EINVAL;
695
696 if (var->xres + var->xoffset > var->xres_virtual)
697 var->xoffset = var->xres_virtual - var->xres;
698 if (var->yres + var->yoffset > var->yres_virtual)
699 var->yoffset = var->yres_virtual - var->yres;
700
701 DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n",
702 var->xres, var->yres,
703 var->xres_virtual, var->yres_virtual);
704
705 var->height = -1;
706 var->width = -1;
707 var->grayscale = 0;
708
709 if (display && display->driver->get_timings) {
710 struct omap_video_timings timings;
711 display->driver->get_timings(display, &timings);
712
713 /* pixclock in ps, the rest in pixclock */
714 var->pixclock = timings.pixel_clock != 0 ?
715 KHZ2PICOS(timings.pixel_clock) :
716 0;
717 var->left_margin = timings.hfp;
718 var->right_margin = timings.hbp;
719 var->upper_margin = timings.vfp;
720 var->lower_margin = timings.vbp;
721 var->hsync_len = timings.hsw;
722 var->vsync_len = timings.vsw;
723 } else {
724 var->pixclock = 0;
725 var->left_margin = 0;
726 var->right_margin = 0;
727 var->upper_margin = 0;
728 var->lower_margin = 0;
729 var->hsync_len = 0;
730 var->vsync_len = 0;
731 }
732
733 /* TODO: get these from panel->config */
734 var->vmode = FB_VMODE_NONINTERLACED;
735 var->sync = 0;
736
737 return 0;
738}
739
740/*
741 * ---------------------------------------------------------------------------
742 * fbdev framework callbacks
743 * ---------------------------------------------------------------------------
744 */
745static int omapfb_open(struct fb_info *fbi, int user)
746{
747 return 0;
748}
749
750static int omapfb_release(struct fb_info *fbi, int user)
751{
752#if 0
753 struct omapfb_info *ofbi = FB2OFB(fbi);
754 struct omapfb2_device *fbdev = ofbi->fbdev;
755 struct omap_dss_device *display = fb2display(fbi);
756
757 DBG("Closing fb with plane index %d\n", ofbi->id);
758
759 omapfb_lock(fbdev);
760
761 if (display && display->get_update_mode && display->update) {
762 /* XXX this update should be removed, I think. But it's
763 * good for debugging */
764 if (display->get_update_mode(display) ==
765 OMAP_DSS_UPDATE_MANUAL) {
766 u16 w, h;
767
768 if (display->sync)
769 display->sync(display);
770
771 display->get_resolution(display, &w, &h);
772 display->update(display, 0, 0, w, h);
773 }
774 }
775
776 if (display && display->sync)
777 display->sync(display);
778
779 omapfb_unlock(fbdev);
780#endif
781 return 0;
782}
783
784static unsigned calc_rotation_offset_dma(const struct fb_var_screeninfo *var,
785 const struct fb_fix_screeninfo *fix, int rotation)
786{
787 unsigned offset;
788
789 offset = var->yoffset * fix->line_length +
790 var->xoffset * (var->bits_per_pixel >> 3);
791
792 return offset;
793}
794
795static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var,
796 const struct fb_fix_screeninfo *fix, int rotation)
797{
798 unsigned offset;
799
800 if (rotation == FB_ROTATE_UD)
801 offset = (var->yres_virtual - var->yres) *
802 fix->line_length;
803 else if (rotation == FB_ROTATE_CW)
804 offset = (var->yres_virtual - var->yres) *
805 (var->bits_per_pixel >> 3);
806 else
807 offset = 0;
808
809 if (rotation == FB_ROTATE_UR)
810 offset += var->yoffset * fix->line_length +
811 var->xoffset * (var->bits_per_pixel >> 3);
812 else if (rotation == FB_ROTATE_UD)
813 offset -= var->yoffset * fix->line_length +
814 var->xoffset * (var->bits_per_pixel >> 3);
815 else if (rotation == FB_ROTATE_CW)
816 offset -= var->xoffset * fix->line_length +
817 var->yoffset * (var->bits_per_pixel >> 3);
818 else if (rotation == FB_ROTATE_CCW)
819 offset += var->xoffset * fix->line_length +
820 var->yoffset * (var->bits_per_pixel >> 3);
821
822 return offset;
823}
824
825
826/* setup overlay according to the fb */
827static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
828 u16 posx, u16 posy, u16 outw, u16 outh)
829{
830 int r = 0;
831 struct omapfb_info *ofbi = FB2OFB(fbi);
832 struct fb_var_screeninfo *var = &fbi->var;
833 struct fb_fix_screeninfo *fix = &fbi->fix;
834 enum omap_color_mode mode = 0;
835 int offset;
836 u32 data_start_p;
837 void __iomem *data_start_v;
838 struct omap_overlay_info info;
839 int xres, yres;
840 int screen_width;
841 int mirror;
842 int rotation = var->rotate;
843 int i;
844
845 for (i = 0; i < ofbi->num_overlays; i++) {
846 if (ovl != ofbi->overlays[i])
847 continue;
848
849 rotation = (rotation + ofbi->rotation[i]) % 4;
850 break;
851 }
852
853 DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
854 posx, posy, outw, outh);
855
856 if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {
857 xres = var->yres;
858 yres = var->xres;
859 } else {
860 xres = var->xres;
861 yres = var->yres;
862 }
863
864
865 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
866 data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
867 data_start_v = NULL;
868 } else {
869 data_start_p = omapfb_get_region_paddr(ofbi);
870 data_start_v = omapfb_get_region_vaddr(ofbi);
871 }
872
873 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
874 offset = calc_rotation_offset_vrfb(var, fix, rotation);
875 else
876 offset = calc_rotation_offset_dma(var, fix, rotation);
877
878 data_start_p += offset;
879 data_start_v += offset;
880
881 if (offset)
882 DBG("offset %d, %d = %d\n",
883 var->xoffset, var->yoffset, offset);
884
885 DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);
886
887 r = fb_mode_to_dss_mode(var, &mode);
888 if (r) {
889 DBG("fb_mode_to_dss_mode failed");
890 goto err;
891 }
892
893 switch (var->nonstd) {
894 case OMAPFB_COLOR_YUV422:
895 case OMAPFB_COLOR_YUY422:
896 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
897 screen_width = fix->line_length
898 / (var->bits_per_pixel >> 2);
899 break;
900 }
901 default:
902 screen_width = fix->line_length / (var->bits_per_pixel >> 3);
903 break;
904 }
905
906 ovl->get_overlay_info(ovl, &info);
907
908 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
909 mirror = 0;
910 else
911 mirror = ofbi->mirror;
912
913 info.paddr = data_start_p;
914 info.vaddr = data_start_v;
915 info.screen_width = screen_width;
916 info.width = xres;
917 info.height = yres;
918 info.color_mode = mode;
919 info.rotation_type = ofbi->rotation_type;
920 info.rotation = rotation;
921 info.mirror = mirror;
922
923 info.pos_x = posx;
924 info.pos_y = posy;
925 info.out_width = outw;
926 info.out_height = outh;
927
928 r = ovl->set_overlay_info(ovl, &info);
929 if (r) {
930 DBG("ovl->setup_overlay_info failed\n");
931 goto err;
932 }
933
934 return 0;
935
936err:
937 DBG("setup_overlay failed\n");
938 return r;
939}
940
941/* apply var to the overlay */
942int omapfb_apply_changes(struct fb_info *fbi, int init)
943{
944 int r = 0;
945 struct omapfb_info *ofbi = FB2OFB(fbi);
946 struct fb_var_screeninfo *var = &fbi->var;
947 struct omap_overlay *ovl;
948 u16 posx, posy;
949 u16 outw, outh;
950 int i;
951
952#ifdef DEBUG
953 if (omapfb_test_pattern)
954 fill_fb(fbi);
955#endif
956
957 for (i = 0; i < ofbi->num_overlays; i++) {
958 ovl = ofbi->overlays[i];
959
960 DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
961
962 if (ofbi->region.size == 0) {
963 /* the fb is not available. disable the overlay */
964 omapfb_overlay_enable(ovl, 0);
965 if (!init && ovl->manager)
966 ovl->manager->apply(ovl->manager);
967 continue;
968 }
969
970 if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
971 int rotation = (var->rotate + ofbi->rotation[i]) % 4;
972 if (rotation == FB_ROTATE_CW ||
973 rotation == FB_ROTATE_CCW) {
974 outw = var->yres;
975 outh = var->xres;
976 } else {
977 outw = var->xres;
978 outh = var->yres;
979 }
980 } else {
981 outw = ovl->info.out_width;
982 outh = ovl->info.out_height;
983 }
984
985 if (init) {
986 posx = 0;
987 posy = 0;
988 } else {
989 posx = ovl->info.pos_x;
990 posy = ovl->info.pos_y;
991 }
992
993 r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
994 if (r)
995 goto err;
996
997 if (!init && ovl->manager)
998 ovl->manager->apply(ovl->manager);
999 }
1000 return 0;
1001err:
1002 DBG("apply_changes failed\n");
1003 return r;
1004}
1005
1006/* checks var and eventually tweaks it to something supported,
1007 * DO NOT MODIFY PAR */
1008static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
1009{
1010 int r;
1011
1012 DBG("check_var(%d)\n", FB2OFB(fbi)->id);
1013
1014 r = check_fb_var(fbi, var);
1015
1016 return r;
1017}
1018
1019/* set the video mode according to info->var */
1020static int omapfb_set_par(struct fb_info *fbi)
1021{
1022 int r;
1023
1024 DBG("set_par(%d)\n", FB2OFB(fbi)->id);
1025
1026 set_fb_fix(fbi);
1027
1028 r = setup_vrfb_rotation(fbi);
1029 if (r)
1030 return r;
1031
1032 r = omapfb_apply_changes(fbi, 0);
1033
1034 return r;
1035}
1036
1037static int omapfb_pan_display(struct fb_var_screeninfo *var,
1038 struct fb_info *fbi)
1039{
1040 struct fb_var_screeninfo new_var;
1041 int r;
1042
1043 DBG("pan_display(%d)\n", FB2OFB(fbi)->id);
1044
1045 if (var->xoffset == fbi->var.xoffset &&
1046 var->yoffset == fbi->var.yoffset)
1047 return 0;
1048
1049 new_var = fbi->var;
1050 new_var.xoffset = var->xoffset;
1051 new_var.yoffset = var->yoffset;
1052
1053 fbi->var = new_var;
1054
1055 r = omapfb_apply_changes(fbi, 0);
1056
1057 return r;
1058}
1059
1060static void mmap_user_open(struct vm_area_struct *vma)
1061{
1062 struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
1063
1064 atomic_inc(&ofbi->map_count);
1065}
1066
1067static void mmap_user_close(struct vm_area_struct *vma)
1068{
1069 struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
1070
1071 atomic_dec(&ofbi->map_count);
1072}
1073
1074static struct vm_operations_struct mmap_user_ops = {
1075 .open = mmap_user_open,
1076 .close = mmap_user_close,
1077};
1078
1079static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
1080{
1081 struct omapfb_info *ofbi = FB2OFB(fbi);
1082 struct fb_fix_screeninfo *fix = &fbi->fix;
1083 unsigned long off;
1084 unsigned long start;
1085 u32 len;
1086
1087 if (vma->vm_end - vma->vm_start == 0)
1088 return 0;
1089 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1090 return -EINVAL;
1091 off = vma->vm_pgoff << PAGE_SHIFT;
1092
1093 start = omapfb_get_region_paddr(ofbi);
1094 len = fix->smem_len;
1095 if (off >= len)
1096 return -EINVAL;
1097 if ((vma->vm_end - vma->vm_start + off) > len)
1098 return -EINVAL;
1099
1100 off += start;
1101
1102 DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
1103
1104 vma->vm_pgoff = off >> PAGE_SHIFT;
1105 vma->vm_flags |= VM_IO | VM_RESERVED;
1106 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1107 vma->vm_ops = &mmap_user_ops;
1108 vma->vm_private_data = ofbi;
1109 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
1110 vma->vm_end - vma->vm_start, vma->vm_page_prot))
1111 return -EAGAIN;
1112 /* vm_ops.open won't be called for mmap itself. */
1113 atomic_inc(&ofbi->map_count);
1114 return 0;
1115}
1116
1117/* Store a single color palette entry into a pseudo palette or the hardware
1118 * palette if one is available. For now we support only 16bpp and thus store
1119 * the entry only to the pseudo palette.
1120 */
1121static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
1122 u_int blue, u_int transp, int update_hw_pal)
1123{
1124 /*struct omapfb_info *ofbi = FB2OFB(fbi);*/
1125 /*struct omapfb2_device *fbdev = ofbi->fbdev;*/
1126 struct fb_var_screeninfo *var = &fbi->var;
1127 int r = 0;
1128
1129 enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */
1130
1131 /*switch (plane->color_mode) {*/
1132 switch (mode) {
1133 case OMAPFB_COLOR_YUV422:
1134 case OMAPFB_COLOR_YUV420:
1135 case OMAPFB_COLOR_YUY422:
1136 r = -EINVAL;
1137 break;
1138 case OMAPFB_COLOR_CLUT_8BPP:
1139 case OMAPFB_COLOR_CLUT_4BPP:
1140 case OMAPFB_COLOR_CLUT_2BPP:
1141 case OMAPFB_COLOR_CLUT_1BPP:
1142 /*
1143 if (fbdev->ctrl->setcolreg)
1144 r = fbdev->ctrl->setcolreg(regno, red, green, blue,
1145 transp, update_hw_pal);
1146 */
1147 /* Fallthrough */
1148 r = -EINVAL;
1149 break;
1150 case OMAPFB_COLOR_RGB565:
1151 case OMAPFB_COLOR_RGB444:
1152 case OMAPFB_COLOR_RGB24P:
1153 case OMAPFB_COLOR_RGB24U:
1154 if (r != 0)
1155 break;
1156
1157 if (regno < 0) {
1158 r = -EINVAL;
1159 break;
1160 }
1161
1162 if (regno < 16) {
1163 u16 pal;
1164 pal = ((red >> (16 - var->red.length)) <<
1165 var->red.offset) |
1166 ((green >> (16 - var->green.length)) <<
1167 var->green.offset) |
1168 (blue >> (16 - var->blue.length));
1169 ((u32 *)(fbi->pseudo_palette))[regno] = pal;
1170 }
1171 break;
1172 default:
1173 BUG();
1174 }
1175 return r;
1176}
1177
1178static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
1179 u_int transp, struct fb_info *info)
1180{
1181 DBG("setcolreg\n");
1182
1183 return _setcolreg(info, regno, red, green, blue, transp, 1);
1184}
1185
1186static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1187{
1188 int count, index, r;
1189 u16 *red, *green, *blue, *transp;
1190 u16 trans = 0xffff;
1191
1192 DBG("setcmap\n");
1193
1194 red = cmap->red;
1195 green = cmap->green;
1196 blue = cmap->blue;
1197 transp = cmap->transp;
1198 index = cmap->start;
1199
1200 for (count = 0; count < cmap->len; count++) {
1201 if (transp)
1202 trans = *transp++;
1203 r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
1204 count == cmap->len - 1);
1205 if (r != 0)
1206 return r;
1207 }
1208
1209 return 0;
1210}
1211
1212static int omapfb_blank(int blank, struct fb_info *fbi)
1213{
1214 struct omapfb_info *ofbi = FB2OFB(fbi);
1215 struct omapfb2_device *fbdev = ofbi->fbdev;
1216 struct omap_dss_device *display = fb2display(fbi);
1217 int do_update = 0;
1218 int r = 0;
1219
1220 omapfb_lock(fbdev);
1221
1222 switch (blank) {
1223 case FB_BLANK_UNBLANK:
1224 if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
1225 goto exit;
1226
1227 if (display->driver->resume)
1228 r = display->driver->resume(display);
1229
1230 if (r == 0 && display->driver->get_update_mode &&
1231 display->driver->get_update_mode(display) ==
1232 OMAP_DSS_UPDATE_MANUAL)
1233 do_update = 1;
1234
1235 break;
1236
1237 case FB_BLANK_NORMAL:
1238 /* FB_BLANK_NORMAL could be implemented.
1239 * Needs DSS additions. */
1240 case FB_BLANK_VSYNC_SUSPEND:
1241 case FB_BLANK_HSYNC_SUSPEND:
1242 case FB_BLANK_POWERDOWN:
1243 if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
1244 goto exit;
1245
1246 if (display->driver->suspend)
1247 r = display->driver->suspend(display);
1248
1249 break;
1250
1251 default:
1252 r = -EINVAL;
1253 }
1254
1255exit:
1256 omapfb_unlock(fbdev);
1257
1258 if (r == 0 && do_update && display->driver->update) {
1259 u16 w, h;
1260 display->driver->get_resolution(display, &w, &h);
1261
1262 r = display->driver->update(display, 0, 0, w, h);
1263 }
1264
1265 return r;
1266}
1267
1268#if 0
1269/* XXX fb_read and fb_write are needed for VRFB */
1270ssize_t omapfb_write(struct fb_info *info, const char __user *buf,
1271 size_t count, loff_t *ppos)
1272{
1273 DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
1274 /* XXX needed for VRFB */
1275 return count;
1276}
1277#endif
1278
1279static struct fb_ops omapfb_ops = {
1280 .owner = THIS_MODULE,
1281 .fb_open = omapfb_open,
1282 .fb_release = omapfb_release,
1283 .fb_fillrect = cfb_fillrect,
1284 .fb_copyarea = cfb_copyarea,
1285 .fb_imageblit = cfb_imageblit,
1286 .fb_blank = omapfb_blank,
1287 .fb_ioctl = omapfb_ioctl,
1288 .fb_check_var = omapfb_check_var,
1289 .fb_set_par = omapfb_set_par,
1290 .fb_pan_display = omapfb_pan_display,
1291 .fb_mmap = omapfb_mmap,
1292 .fb_setcolreg = omapfb_setcolreg,
1293 .fb_setcmap = omapfb_setcmap,
1294 /*.fb_write = omapfb_write,*/
1295};
1296
1297static void omapfb_free_fbmem(struct fb_info *fbi)
1298{
1299 struct omapfb_info *ofbi = FB2OFB(fbi);
1300 struct omapfb2_device *fbdev = ofbi->fbdev;
1301 struct omapfb2_mem_region *rg;
1302
1303 rg = &ofbi->region;
1304
1305 if (rg->paddr)
1306 if (omap_vram_free(rg->paddr, rg->size))
1307 dev_err(fbdev->dev, "VRAM FREE failed\n");
1308
1309 if (rg->vaddr)
1310 iounmap(rg->vaddr);
1311
1312 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1313 /* unmap the 0 angle rotation */
1314 if (rg->vrfb.vaddr[0]) {
1315 iounmap(rg->vrfb.vaddr[0]);
1316 omap_vrfb_release_ctx(&rg->vrfb);
1317 rg->vrfb.vaddr[0] = NULL;
1318 }
1319 }
1320
1321 rg->vaddr = NULL;
1322 rg->paddr = 0;
1323 rg->alloc = 0;
1324 rg->size = 0;
1325}
1326
1327static void clear_fb_info(struct fb_info *fbi)
1328{
1329 memset(&fbi->var, 0, sizeof(fbi->var));
1330 memset(&fbi->fix, 0, sizeof(fbi->fix));
1331 strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
1332}
1333
1334static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
1335{
1336 int i;
1337
1338 DBG("free all fbmem\n");
1339
1340 for (i = 0; i < fbdev->num_fbs; i++) {
1341 struct fb_info *fbi = fbdev->fbs[i];
1342 omapfb_free_fbmem(fbi);
1343 clear_fb_info(fbi);
1344 }
1345
1346 return 0;
1347}
1348
1349static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
1350 unsigned long paddr)
1351{
1352 struct omapfb_info *ofbi = FB2OFB(fbi);
1353 struct omapfb2_device *fbdev = ofbi->fbdev;
1354 struct omapfb2_mem_region *rg;
1355 void __iomem *vaddr;
1356 int r;
1357
1358 rg = &ofbi->region;
1359 memset(rg, 0, sizeof(*rg));
1360
1361 size = PAGE_ALIGN(size);
1362
1363 if (!paddr) {
1364 DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
1365 r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr);
1366 } else {
1367 DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
1368 ofbi->id);
1369 r = omap_vram_reserve(paddr, size);
1370 }
1371
1372 if (r) {
1373 dev_err(fbdev->dev, "failed to allocate framebuffer\n");
1374 return -ENOMEM;
1375 }
1376
1377 if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {
1378 vaddr = ioremap_wc(paddr, size);
1379
1380 if (!vaddr) {
1381 dev_err(fbdev->dev, "failed to ioremap framebuffer\n");
1382 omap_vram_free(paddr, size);
1383 return -ENOMEM;
1384 }
1385
1386 DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);
1387 } else {
1388 r = omap_vrfb_request_ctx(&rg->vrfb);
1389 if (r) {
1390 dev_err(fbdev->dev, "vrfb create ctx failed\n");
1391 return r;
1392 }
1393
1394 vaddr = NULL;
1395 }
1396
1397 rg->paddr = paddr;
1398 rg->vaddr = vaddr;
1399 rg->size = size;
1400 rg->alloc = 1;
1401
1402 return 0;
1403}
1404
1405/* allocate fbmem using display resolution as reference */
1406static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
1407 unsigned long paddr)
1408{
1409 struct omapfb_info *ofbi = FB2OFB(fbi);
1410 struct omapfb2_device *fbdev = ofbi->fbdev;
1411 struct omap_dss_device *display;
1412 int bytespp;
1413
1414 display = fb2display(fbi);
1415
1416 if (!display)
1417 return 0;
1418
1419 switch (omapfb_get_recommended_bpp(fbdev, display)) {
1420 case 16:
1421 bytespp = 2;
1422 break;
1423 case 24:
1424 bytespp = 4;
1425 break;
1426 default:
1427 bytespp = 4;
1428 break;
1429 }
1430
1431 if (!size) {
1432 u16 w, h;
1433
1434 display->driver->get_resolution(display, &w, &h);
1435
1436 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1437 size = max(omap_vrfb_min_phys_size(w, h, bytespp),
1438 omap_vrfb_min_phys_size(h, w, bytespp));
1439
1440 DBG("adjusting fb mem size for VRFB, %u -> %lu\n",
1441 w * h * bytespp, size);
1442 } else {
1443 size = w * h * bytespp;
1444 }
1445 }
1446
1447 if (!size)
1448 return 0;
1449
1450 return omapfb_alloc_fbmem(fbi, size, paddr);
1451}
1452
1453static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt)
1454{
1455 enum omap_color_mode mode;
1456
1457 switch (fmt) {
1458 case OMAPFB_COLOR_RGB565:
1459 mode = OMAP_DSS_COLOR_RGB16;
1460 break;
1461 case OMAPFB_COLOR_YUV422:
1462 mode = OMAP_DSS_COLOR_YUV2;
1463 break;
1464 case OMAPFB_COLOR_CLUT_8BPP:
1465 mode = OMAP_DSS_COLOR_CLUT8;
1466 break;
1467 case OMAPFB_COLOR_CLUT_4BPP:
1468 mode = OMAP_DSS_COLOR_CLUT4;
1469 break;
1470 case OMAPFB_COLOR_CLUT_2BPP:
1471 mode = OMAP_DSS_COLOR_CLUT2;
1472 break;
1473 case OMAPFB_COLOR_CLUT_1BPP:
1474 mode = OMAP_DSS_COLOR_CLUT1;
1475 break;
1476 case OMAPFB_COLOR_RGB444:
1477 mode = OMAP_DSS_COLOR_RGB12U;
1478 break;
1479 case OMAPFB_COLOR_YUY422:
1480 mode = OMAP_DSS_COLOR_UYVY;
1481 break;
1482 case OMAPFB_COLOR_ARGB16:
1483 mode = OMAP_DSS_COLOR_ARGB16;
1484 break;
1485 case OMAPFB_COLOR_RGB24U:
1486 mode = OMAP_DSS_COLOR_RGB24U;
1487 break;
1488 case OMAPFB_COLOR_RGB24P:
1489 mode = OMAP_DSS_COLOR_RGB24P;
1490 break;
1491 case OMAPFB_COLOR_ARGB32:
1492 mode = OMAP_DSS_COLOR_ARGB32;
1493 break;
1494 case OMAPFB_COLOR_RGBA32:
1495 mode = OMAP_DSS_COLOR_RGBA32;
1496 break;
1497 case OMAPFB_COLOR_RGBX32:
1498 mode = OMAP_DSS_COLOR_RGBX32;
1499 break;
1500 default:
1501 mode = -EINVAL;
1502 }
1503
1504 return mode;
1505}
1506
1507static int omapfb_parse_vram_param(const char *param, int max_entries,
1508 unsigned long *sizes, unsigned long *paddrs)
1509{
1510 int fbnum;
1511 unsigned long size;
1512 unsigned long paddr = 0;
1513 char *p, *start;
1514
1515 start = (char *)param;
1516
1517 while (1) {
1518 p = start;
1519
1520 fbnum = simple_strtoul(p, &p, 10);
1521
1522 if (p == param)
1523 return -EINVAL;
1524
1525 if (*p != ':')
1526 return -EINVAL;
1527
1528 if (fbnum >= max_entries)
1529 return -EINVAL;
1530
1531 size = memparse(p + 1, &p);
1532
1533 if (!size)
1534 return -EINVAL;
1535
1536 paddr = 0;
1537
1538 if (*p == '@') {
1539 paddr = simple_strtoul(p + 1, &p, 16);
1540
1541 if (!paddr)
1542 return -EINVAL;
1543
1544 }
1545
1546 paddrs[fbnum] = paddr;
1547 sizes[fbnum] = size;
1548
1549 if (*p == 0)
1550 break;
1551
1552 if (*p != ',')
1553 return -EINVAL;
1554
1555 ++p;
1556
1557 start = p;
1558 }
1559
1560 return 0;
1561}
1562
1563static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
1564{
1565 int i, r;
1566 unsigned long vram_sizes[10];
1567 unsigned long vram_paddrs[10];
1568
1569 memset(&vram_sizes, 0, sizeof(vram_sizes));
1570 memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1571
1572 if (def_vram && omapfb_parse_vram_param(def_vram, 10,
1573 vram_sizes, vram_paddrs)) {
1574 dev_err(fbdev->dev, "failed to parse vram parameter\n");
1575
1576 memset(&vram_sizes, 0, sizeof(vram_sizes));
1577 memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1578 }
1579
1580 if (fbdev->dev->platform_data) {
1581 struct omapfb_platform_data *opd;
1582 opd = fbdev->dev->platform_data;
1583 for (i = 0; i < opd->mem_desc.region_cnt; ++i) {
1584 if (!vram_sizes[i]) {
1585 unsigned long size;
1586 unsigned long paddr;
1587
1588 size = opd->mem_desc.region[i].size;
1589 paddr = opd->mem_desc.region[i].paddr;
1590
1591 vram_sizes[i] = size;
1592 vram_paddrs[i] = paddr;
1593 }
1594 }
1595 }
1596
1597 for (i = 0; i < fbdev->num_fbs; i++) {
1598 /* allocate memory automatically only for fb0, or if
1599 * excplicitly defined with vram or plat data option */
1600 if (i == 0 || vram_sizes[i] != 0) {
1601 r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
1602 vram_sizes[i], vram_paddrs[i]);
1603
1604 if (r)
1605 return r;
1606 }
1607 }
1608
1609 for (i = 0; i < fbdev->num_fbs; i++) {
1610 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1611 struct omapfb2_mem_region *rg;
1612 rg = &ofbi->region;
1613
1614 DBG("region%d phys %08x virt %p size=%lu\n",
1615 i,
1616 rg->paddr,
1617 rg->vaddr,
1618 rg->size);
1619 }
1620
1621 return 0;
1622}
1623
1624int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
1625{
1626 struct omapfb_info *ofbi = FB2OFB(fbi);
1627 struct omapfb2_device *fbdev = ofbi->fbdev;
1628 struct omap_dss_device *display = fb2display(fbi);
1629 struct omapfb2_mem_region *rg = &ofbi->region;
1630 unsigned long old_size = rg->size;
1631 unsigned long old_paddr = rg->paddr;
1632 int old_type = rg->type;
1633 int r;
1634
1635 if (type > OMAPFB_MEMTYPE_MAX)
1636 return -EINVAL;
1637
1638 size = PAGE_ALIGN(size);
1639
1640 if (old_size == size && old_type == type)
1641 return 0;
1642
1643 if (display && display->driver->sync)
1644 display->driver->sync(display);
1645
1646 omapfb_free_fbmem(fbi);
1647
1648 if (size == 0) {
1649 clear_fb_info(fbi);
1650 return 0;
1651 }
1652
1653 r = omapfb_alloc_fbmem(fbi, size, 0);
1654
1655 if (r) {
1656 if (old_size)
1657 omapfb_alloc_fbmem(fbi, old_size, old_paddr);
1658
1659 if (rg->size == 0)
1660 clear_fb_info(fbi);
1661
1662 return r;
1663 }
1664
1665 if (old_size == size)
1666 return 0;
1667
1668 if (old_size == 0) {
1669 DBG("initializing fb %d\n", ofbi->id);
1670 r = omapfb_fb_init(fbdev, fbi);
1671 if (r) {
1672 DBG("omapfb_fb_init failed\n");
1673 goto err;
1674 }
1675 r = omapfb_apply_changes(fbi, 1);
1676 if (r) {
1677 DBG("omapfb_apply_changes failed\n");
1678 goto err;
1679 }
1680 } else {
1681 struct fb_var_screeninfo new_var;
1682 memcpy(&new_var, &fbi->var, sizeof(new_var));
1683 r = check_fb_var(fbi, &new_var);
1684 if (r)
1685 goto err;
1686 memcpy(&fbi->var, &new_var, sizeof(fbi->var));
1687 set_fb_fix(fbi);
1688 r = setup_vrfb_rotation(fbi);
1689 if (r)
1690 goto err;
1691 }
1692
1693 return 0;
1694err:
1695 omapfb_free_fbmem(fbi);
1696 clear_fb_info(fbi);
1697 return r;
1698}
1699
1700/* initialize fb_info, var, fix to something sane based on the display */
1701static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
1702{
1703 struct fb_var_screeninfo *var = &fbi->var;
1704 struct omap_dss_device *display = fb2display(fbi);
1705 struct omapfb_info *ofbi = FB2OFB(fbi);
1706 int r = 0;
1707
1708 fbi->fbops = &omapfb_ops;
1709 fbi->flags = FBINFO_FLAG_DEFAULT;
1710 fbi->pseudo_palette = fbdev->pseudo_palette;
1711
1712 if (ofbi->region.size == 0) {
1713 clear_fb_info(fbi);
1714 return 0;
1715 }
1716
1717 var->nonstd = 0;
1718 var->bits_per_pixel = 0;
1719
1720 var->rotate = def_rotate;
1721
1722 /*
1723 * Check if there is a default color format set in the board file,
1724 * and use this format instead the default deducted from the
1725 * display bpp.
1726 */
1727 if (fbdev->dev->platform_data) {
1728 struct omapfb_platform_data *opd;
1729 int id = ofbi->id;
1730
1731 opd = fbdev->dev->platform_data;
1732 if (opd->mem_desc.region[id].format_used) {
1733 enum omap_color_mode mode;
1734 enum omapfb_color_format format;
1735
1736 format = opd->mem_desc.region[id].format;
1737 mode = fb_format_to_dss_mode(format);
1738 if (mode < 0) {
1739 r = mode;
1740 goto err;
1741 }
1742 r = dss_mode_to_fb_mode(mode, var);
1743 if (r < 0)
1744 goto err;
1745 }
1746 }
1747
1748 if (display) {
1749 u16 w, h;
1750 int rotation = (var->rotate + ofbi->rotation[0]) % 4;
1751
1752 display->driver->get_resolution(display, &w, &h);
1753
1754 if (rotation == FB_ROTATE_CW ||
1755 rotation == FB_ROTATE_CCW) {
1756 var->xres = h;
1757 var->yres = w;
1758 } else {
1759 var->xres = w;
1760 var->yres = h;
1761 }
1762
1763 var->xres_virtual = var->xres;
1764 var->yres_virtual = var->yres;
1765
1766 if (!var->bits_per_pixel) {
1767 switch (omapfb_get_recommended_bpp(fbdev, display)) {
1768 case 16:
1769 var->bits_per_pixel = 16;
1770 break;
1771 case 24:
1772 var->bits_per_pixel = 32;
1773 break;
1774 default:
1775 dev_err(fbdev->dev, "illegal display "
1776 "bpp\n");
1777 return -EINVAL;
1778 }
1779 }
1780 } else {
1781 /* if there's no display, let's just guess some basic values */
1782 var->xres = 320;
1783 var->yres = 240;
1784 var->xres_virtual = var->xres;
1785 var->yres_virtual = var->yres;
1786 if (!var->bits_per_pixel)
1787 var->bits_per_pixel = 16;
1788 }
1789
1790 r = check_fb_var(fbi, var);
1791 if (r)
1792 goto err;
1793
1794 set_fb_fix(fbi);
1795 r = setup_vrfb_rotation(fbi);
1796 if (r)
1797 goto err;
1798
1799 r = fb_alloc_cmap(&fbi->cmap, 256, 0);
1800 if (r)
1801 dev_err(fbdev->dev, "unable to allocate color map memory\n");
1802
1803err:
1804 return r;
1805}
1806
1807static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
1808{
1809 fb_dealloc_cmap(&fbi->cmap);
1810}
1811
1812
1813static void omapfb_free_resources(struct omapfb2_device *fbdev)
1814{
1815 int i;
1816
1817 DBG("free_resources\n");
1818
1819 if (fbdev == NULL)
1820 return;
1821
1822 for (i = 0; i < fbdev->num_fbs; i++)
1823 unregister_framebuffer(fbdev->fbs[i]);
1824
1825 /* free the reserved fbmem */
1826 omapfb_free_all_fbmem(fbdev);
1827
1828 for (i = 0; i < fbdev->num_fbs; i++) {
1829 fbinfo_cleanup(fbdev, fbdev->fbs[i]);
1830 framebuffer_release(fbdev->fbs[i]);
1831 }
1832
1833 for (i = 0; i < fbdev->num_displays; i++) {
1834 if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
1835 fbdev->displays[i]->driver->disable(fbdev->displays[i]);
1836
1837 omap_dss_put_device(fbdev->displays[i]);
1838 }
1839
1840 dev_set_drvdata(fbdev->dev, NULL);
1841 kfree(fbdev);
1842}
1843
1844static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
1845{
1846 int r, i;
1847
1848 fbdev->num_fbs = 0;
1849
1850 DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);
1851
1852 /* allocate fb_infos */
1853 for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
1854 struct fb_info *fbi;
1855 struct omapfb_info *ofbi;
1856
1857 fbi = framebuffer_alloc(sizeof(struct omapfb_info),
1858 fbdev->dev);
1859
1860 if (fbi == NULL) {
1861 dev_err(fbdev->dev,
1862 "unable to allocate memory for plane info\n");
1863 return -ENOMEM;
1864 }
1865
1866 clear_fb_info(fbi);
1867
1868 fbdev->fbs[i] = fbi;
1869
1870 ofbi = FB2OFB(fbi);
1871 ofbi->fbdev = fbdev;
1872 ofbi->id = i;
1873
1874 /* assign these early, so that fb alloc can use them */
1875 ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
1876 OMAP_DSS_ROT_DMA;
1877 ofbi->mirror = def_mirror;
1878
1879 fbdev->num_fbs++;
1880 }
1881
1882 DBG("fb_infos allocated\n");
1883
1884 /* assign overlays for the fbs */
1885 for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
1886 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1887
1888 ofbi->overlays[0] = fbdev->overlays[i];
1889 ofbi->num_overlays = 1;
1890 }
1891
1892 /* allocate fb memories */
1893 r = omapfb_allocate_all_fbs(fbdev);
1894 if (r) {
1895 dev_err(fbdev->dev, "failed to allocate fbmem\n");
1896 return r;
1897 }
1898
1899 DBG("fbmems allocated\n");
1900
1901 /* setup fb_infos */
1902 for (i = 0; i < fbdev->num_fbs; i++) {
1903 r = omapfb_fb_init(fbdev, fbdev->fbs[i]);
1904 if (r) {
1905 dev_err(fbdev->dev, "failed to setup fb_info\n");
1906 return r;
1907 }
1908 }
1909
1910 DBG("fb_infos initialized\n");
1911
1912 for (i = 0; i < fbdev->num_fbs; i++) {
1913 r = register_framebuffer(fbdev->fbs[i]);
1914 if (r != 0) {
1915 dev_err(fbdev->dev,
1916 "registering framebuffer %d failed\n", i);
1917 return r;
1918 }
1919 }
1920
1921 DBG("framebuffers registered\n");
1922
1923 for (i = 0; i < fbdev->num_fbs; i++) {
1924 r = omapfb_apply_changes(fbdev->fbs[i], 1);
1925 if (r) {
1926 dev_err(fbdev->dev, "failed to change mode\n");
1927 return r;
1928 }
1929 }
1930
1931 DBG("create sysfs for fbs\n");
1932 r = omapfb_create_sysfs(fbdev);
1933 if (r) {
1934 dev_err(fbdev->dev, "failed to create sysfs entries\n");
1935 return r;
1936 }
1937
1938 /* Enable fb0 */
1939 if (fbdev->num_fbs > 0) {
1940 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
1941
1942 if (ofbi->num_overlays > 0) {
1943 struct omap_overlay *ovl = ofbi->overlays[0];
1944
1945 r = omapfb_overlay_enable(ovl, 1);
1946
1947 if (r) {
1948 dev_err(fbdev->dev,
1949 "failed to enable overlay\n");
1950 return r;
1951 }
1952 }
1953 }
1954
1955 DBG("create_framebuffers done\n");
1956
1957 return 0;
1958}
1959
1960static int omapfb_mode_to_timings(const char *mode_str,
1961 struct omap_video_timings *timings, u8 *bpp)
1962{
1963 struct fb_info fbi;
1964 struct fb_var_screeninfo var;
1965 struct fb_ops fbops;
1966 int r;
1967
1968#ifdef CONFIG_OMAP2_DSS_VENC
1969 if (strcmp(mode_str, "pal") == 0) {
1970 *timings = omap_dss_pal_timings;
1971 *bpp = 0;
1972 return 0;
1973 } else if (strcmp(mode_str, "ntsc") == 0) {
1974 *timings = omap_dss_ntsc_timings;
1975 *bpp = 0;
1976 return 0;
1977 }
1978#endif
1979
1980 /* this is quite a hack, but I wanted to use the modedb and for
1981 * that we need fb_info and var, so we create dummy ones */
1982
1983 memset(&fbi, 0, sizeof(fbi));
1984 memset(&var, 0, sizeof(var));
1985 memset(&fbops, 0, sizeof(fbops));
1986 fbi.fbops = &fbops;
1987
1988 r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24);
1989
1990 if (r != 0) {
1991 timings->pixel_clock = PICOS2KHZ(var.pixclock);
1992 timings->hfp = var.left_margin;
1993 timings->hbp = var.right_margin;
1994 timings->vfp = var.upper_margin;
1995 timings->vbp = var.lower_margin;
1996 timings->hsw = var.hsync_len;
1997 timings->vsw = var.vsync_len;
1998 timings->x_res = var.xres;
1999 timings->y_res = var.yres;
2000
2001 switch (var.bits_per_pixel) {
2002 case 16:
2003 *bpp = 16;
2004 break;
2005 case 24:
2006 case 32:
2007 default:
2008 *bpp = 24;
2009 break;
2010 }
2011
2012 return 0;
2013 } else {
2014 return -EINVAL;
2015 }
2016}
2017
2018static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
2019 struct omap_dss_device *display, char *mode_str)
2020{
2021 int r;
2022 u8 bpp;
2023 struct omap_video_timings timings;
2024
2025 r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
2026 if (r)
2027 return r;
2028
2029 fbdev->bpp_overrides[fbdev->num_bpp_overrides].dssdev = display;
2030 fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp;
2031 ++fbdev->num_bpp_overrides;
2032
2033 if (!display->driver->check_timings || !display->driver->set_timings)
2034 return -EINVAL;
2035
2036 r = display->driver->check_timings(display, &timings);
2037 if (r)
2038 return r;
2039
2040 display->driver->set_timings(display, &timings);
2041
2042 return 0;
2043}
2044
2045static int omapfb_get_recommended_bpp(struct omapfb2_device *fbdev,
2046 struct omap_dss_device *dssdev)
2047{
2048 int i;
2049
2050 BUG_ON(dssdev->driver->get_recommended_bpp == NULL);
2051
2052 for (i = 0; i < fbdev->num_bpp_overrides; ++i) {
2053 if (dssdev == fbdev->bpp_overrides[i].dssdev)
2054 return fbdev->bpp_overrides[i].bpp;
2055 }
2056
2057 return dssdev->driver->get_recommended_bpp(dssdev);
2058}
2059
2060static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
2061{
2062 char *str, *options, *this_opt;
2063 int r = 0;
2064
2065 str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL);
2066 strcpy(str, def_mode);
2067 options = str;
2068
2069 while (!r && (this_opt = strsep(&options, ",")) != NULL) {
2070 char *p, *display_str, *mode_str;
2071 struct omap_dss_device *display;
2072 int i;
2073
2074 p = strchr(this_opt, ':');
2075 if (!p) {
2076 r = -EINVAL;
2077 break;
2078 }
2079
2080 *p = 0;
2081 display_str = this_opt;
2082 mode_str = p + 1;
2083
2084 display = NULL;
2085 for (i = 0; i < fbdev->num_displays; ++i) {
2086 if (strcmp(fbdev->displays[i]->name,
2087 display_str) == 0) {
2088 display = fbdev->displays[i];
2089 break;
2090 }
2091 }
2092
2093 if (!display) {
2094 r = -EINVAL;
2095 break;
2096 }
2097
2098 r = omapfb_set_def_mode(fbdev, display, mode_str);
2099 if (r)
2100 break;
2101 }
2102
2103 kfree(str);
2104
2105 return r;
2106}
2107
2108static int omapfb_probe(struct platform_device *pdev)
2109{
2110 struct omapfb2_device *fbdev = NULL;
2111 int r = 0;
2112 int i;
2113 struct omap_overlay *ovl;
2114 struct omap_dss_device *def_display;
2115 struct omap_dss_device *dssdev;
2116
2117 DBG("omapfb_probe\n");
2118
2119 if (pdev->num_resources != 0) {
2120 dev_err(&pdev->dev, "probed for an unknown device\n");
2121 r = -ENODEV;
2122 goto err0;
2123 }
2124
2125 fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL);
2126 if (fbdev == NULL) {
2127 r = -ENOMEM;
2128 goto err0;
2129 }
2130
2131 mutex_init(&fbdev->mtx);
2132
2133 fbdev->dev = &pdev->dev;
2134 platform_set_drvdata(pdev, fbdev);
2135
2136 r = 0;
2137 fbdev->num_displays = 0;
2138 dssdev = NULL;
2139 for_each_dss_dev(dssdev) {
2140 omap_dss_get_device(dssdev);
2141
2142 if (!dssdev->driver) {
2143 dev_err(&pdev->dev, "no driver for display\n");
2144 r = -ENODEV;
2145 }
2146
2147 fbdev->displays[fbdev->num_displays++] = dssdev;
2148 }
2149
2150 if (r)
2151 goto cleanup;
2152
2153 if (fbdev->num_displays == 0) {
2154 dev_err(&pdev->dev, "no displays\n");
2155 r = -EINVAL;
2156 goto cleanup;
2157 }
2158
2159 fbdev->num_overlays = omap_dss_get_num_overlays();
2160 for (i = 0; i < fbdev->num_overlays; i++)
2161 fbdev->overlays[i] = omap_dss_get_overlay(i);
2162
2163 fbdev->num_managers = omap_dss_get_num_overlay_managers();
2164 for (i = 0; i < fbdev->num_managers; i++)
2165 fbdev->managers[i] = omap_dss_get_overlay_manager(i);
2166
2167 if (def_mode && strlen(def_mode) > 0) {
2168 if (omapfb_parse_def_modes(fbdev))
2169 dev_warn(&pdev->dev, "cannot parse default modes\n");
2170 }
2171
2172 r = omapfb_create_framebuffers(fbdev);
2173 if (r)
2174 goto cleanup;
2175
2176 for (i = 0; i < fbdev->num_managers; i++) {
2177 struct omap_overlay_manager *mgr;
2178 mgr = fbdev->managers[i];
2179 r = mgr->apply(mgr);
2180 if (r)
2181 dev_warn(fbdev->dev, "failed to apply dispc config\n");
2182 }
2183
2184 DBG("mgr->apply'ed\n");
2185
2186 /* gfx overlay should be the default one. find a display
2187 * connected to that, and use it as default display */
2188 ovl = omap_dss_get_overlay(0);
2189 if (ovl->manager && ovl->manager->device) {
2190 def_display = ovl->manager->device;
2191 } else {
2192 dev_warn(&pdev->dev, "cannot find default display\n");
2193 def_display = NULL;
2194 }
2195
2196 if (def_display) {
2197 struct omap_dss_driver *dssdrv = def_display->driver;
2198
2199 r = def_display->driver->enable(def_display);
2200 if (r) {
2201 dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
2202 def_display->name);
2203 goto cleanup;
2204 }
2205
2206 if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
2207 u16 w, h;
2208 if (dssdrv->enable_te)
2209 dssdrv->enable_te(def_display, 1);
2210 if (dssdrv->set_update_mode)
2211 dssdrv->set_update_mode(def_display,
2212 OMAP_DSS_UPDATE_MANUAL);
2213
2214 dssdrv->get_resolution(def_display, &w, &h);
2215 def_display->driver->update(def_display, 0, 0, w, h);
2216 } else {
2217 if (dssdrv->set_update_mode)
2218 dssdrv->set_update_mode(def_display,
2219 OMAP_DSS_UPDATE_AUTO);
2220 }
2221 }
2222
2223 return 0;
2224
2225cleanup:
2226 omapfb_free_resources(fbdev);
2227err0:
2228 dev_err(&pdev->dev, "failed to setup omapfb\n");
2229 return r;
2230}
2231
2232static int omapfb_remove(struct platform_device *pdev)
2233{
2234 struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
2235
2236 /* FIXME: wait till completion of pending events */
2237
2238 omapfb_remove_sysfs(fbdev);
2239
2240 omapfb_free_resources(fbdev);
2241
2242 return 0;
2243}
2244
2245static struct platform_driver omapfb_driver = {
2246 .probe = omapfb_probe,
2247 .remove = omapfb_remove,
2248 .driver = {
2249 .name = "omapfb",
2250 .owner = THIS_MODULE,
2251 },
2252};
2253
2254static int __init omapfb_init(void)
2255{
2256 DBG("omapfb_init\n");
2257
2258 if (platform_driver_register(&omapfb_driver)) {
2259 printk(KERN_ERR "failed to register omapfb driver\n");
2260 return -ENODEV;
2261 }
2262
2263 return 0;
2264}
2265
2266static void __exit omapfb_exit(void)
2267{
2268 DBG("omapfb_exit\n");
2269 platform_driver_unregister(&omapfb_driver);
2270}
2271
2272module_param_named(mode, def_mode, charp, 0);
2273module_param_named(vram, def_vram, charp, 0);
2274module_param_named(rotate, def_rotate, int, 0);
2275module_param_named(vrfb, def_vrfb, bool, 0);
2276module_param_named(mirror, def_mirror, bool, 0);
2277
2278/* late_initcall to let panel/ctrl drivers loaded first.
2279 * I guess better option would be a more dynamic approach,
2280 * so that omapfb reacts to new panels when they are loaded */
2281late_initcall(omapfb_init);
2282/*module_init(omapfb_init);*/
2283module_exit(omapfb_exit);
2284
2285MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
2286MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
2287MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c
new file mode 100644
index 000000000000..62bb88f5c192
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
@@ -0,0 +1,507 @@
1/*
2 * linux/drivers/video/omap2/omapfb-sysfs.c
3 *
4 * Copyright (C) 2008 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#include <linux/fb.h>
24#include <linux/sysfs.h>
25#include <linux/device.h>
26#include <linux/uaccess.h>
27#include <linux/platform_device.h>
28#include <linux/kernel.h>
29#include <linux/mm.h>
30#include <linux/omapfb.h>
31
32#include <plat/display.h>
33#include <plat/vrfb.h>
34
35#include "omapfb.h"
36
37static ssize_t show_rotate_type(struct device *dev,
38 struct device_attribute *attr, char *buf)
39{
40 struct fb_info *fbi = dev_get_drvdata(dev);
41 struct omapfb_info *ofbi = FB2OFB(fbi);
42
43 return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
44}
45
46static ssize_t store_rotate_type(struct device *dev,
47 struct device_attribute *attr,
48 const char *buf, size_t count)
49{
50 struct fb_info *fbi = dev_get_drvdata(dev);
51 struct omapfb_info *ofbi = FB2OFB(fbi);
52 enum omap_dss_rotation_type rot_type;
53 int r;
54
55 rot_type = simple_strtoul(buf, NULL, 0);
56
57 if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
58 return -EINVAL;
59
60 lock_fb_info(fbi);
61
62 r = 0;
63 if (rot_type == ofbi->rotation_type)
64 goto out;
65
66 if (ofbi->region.size) {
67 r = -EBUSY;
68 goto out;
69 }
70
71 ofbi->rotation_type = rot_type;
72
73 /*
74 * Since the VRAM for this FB is not allocated at the moment we don't
75 * need to do any further parameter checking at this point.
76 */
77out:
78 unlock_fb_info(fbi);
79
80 return r ? r : count;
81}
82
83
84static ssize_t show_mirror(struct device *dev,
85 struct device_attribute *attr, char *buf)
86{
87 struct fb_info *fbi = dev_get_drvdata(dev);
88 struct omapfb_info *ofbi = FB2OFB(fbi);
89
90 return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
91}
92
93static ssize_t store_mirror(struct device *dev,
94 struct device_attribute *attr,
95 const char *buf, size_t count)
96{
97 struct fb_info *fbi = dev_get_drvdata(dev);
98 struct omapfb_info *ofbi = FB2OFB(fbi);
99 bool mirror;
100 int r;
101 struct fb_var_screeninfo new_var;
102
103 mirror = simple_strtoul(buf, NULL, 0);
104
105 if (mirror != 0 && mirror != 1)
106 return -EINVAL;
107
108 lock_fb_info(fbi);
109
110 ofbi->mirror = mirror;
111
112 memcpy(&new_var, &fbi->var, sizeof(new_var));
113 r = check_fb_var(fbi, &new_var);
114 if (r)
115 goto out;
116 memcpy(&fbi->var, &new_var, sizeof(fbi->var));
117
118 set_fb_fix(fbi);
119
120 r = omapfb_apply_changes(fbi, 0);
121 if (r)
122 goto out;
123
124 r = count;
125out:
126 unlock_fb_info(fbi);
127
128 return r;
129}
130
131static ssize_t show_overlays(struct device *dev,
132 struct device_attribute *attr, char *buf)
133{
134 struct fb_info *fbi = dev_get_drvdata(dev);
135 struct omapfb_info *ofbi = FB2OFB(fbi);
136 struct omapfb2_device *fbdev = ofbi->fbdev;
137 ssize_t l = 0;
138 int t;
139
140 omapfb_lock(fbdev);
141 lock_fb_info(fbi);
142
143 for (t = 0; t < ofbi->num_overlays; t++) {
144 struct omap_overlay *ovl = ofbi->overlays[t];
145 int ovlnum;
146
147 for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
148 if (ovl == fbdev->overlays[ovlnum])
149 break;
150
151 l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
152 t == 0 ? "" : ",", ovlnum);
153 }
154
155 l += snprintf(buf + l, PAGE_SIZE - l, "\n");
156
157 unlock_fb_info(fbi);
158 omapfb_unlock(fbdev);
159
160 return l;
161}
162
163static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
164 struct omap_overlay *ovl)
165{
166 int i, t;
167
168 for (i = 0; i < fbdev->num_fbs; i++) {
169 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
170
171 for (t = 0; t < ofbi->num_overlays; t++) {
172 if (ofbi->overlays[t] == ovl)
173 return ofbi;
174 }
175 }
176
177 return NULL;
178}
179
180static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
181 const char *buf, size_t count)
182{
183 struct fb_info *fbi = dev_get_drvdata(dev);
184 struct omapfb_info *ofbi = FB2OFB(fbi);
185 struct omapfb2_device *fbdev = ofbi->fbdev;
186 struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
187 struct omap_overlay *ovl;
188 int num_ovls, r, i;
189 int len;
190 bool added = false;
191
192 num_ovls = 0;
193
194 len = strlen(buf);
195 if (buf[len - 1] == '\n')
196 len = len - 1;
197
198 omapfb_lock(fbdev);
199 lock_fb_info(fbi);
200
201 if (len > 0) {
202 char *p = (char *)buf;
203 int ovlnum;
204
205 while (p < buf + len) {
206 int found;
207 if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
208 r = -EINVAL;
209 goto out;
210 }
211
212 ovlnum = simple_strtoul(p, &p, 0);
213 if (ovlnum > fbdev->num_overlays) {
214 r = -EINVAL;
215 goto out;
216 }
217
218 found = 0;
219 for (i = 0; i < num_ovls; ++i) {
220 if (ovls[i] == fbdev->overlays[ovlnum]) {
221 found = 1;
222 break;
223 }
224 }
225
226 if (!found)
227 ovls[num_ovls++] = fbdev->overlays[ovlnum];
228
229 p++;
230 }
231 }
232
233 for (i = 0; i < num_ovls; ++i) {
234 struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
235 if (ofbi2 && ofbi2 != ofbi) {
236 dev_err(fbdev->dev, "overlay already in use\n");
237 r = -EINVAL;
238 goto out;
239 }
240 }
241
242 /* detach unused overlays */
243 for (i = 0; i < ofbi->num_overlays; ++i) {
244 int t, found;
245
246 ovl = ofbi->overlays[i];
247
248 found = 0;
249
250 for (t = 0; t < num_ovls; ++t) {
251 if (ovl == ovls[t]) {
252 found = 1;
253 break;
254 }
255 }
256
257 if (found)
258 continue;
259
260 DBG("detaching %d\n", ofbi->overlays[i]->id);
261
262 omapfb_overlay_enable(ovl, 0);
263
264 if (ovl->manager)
265 ovl->manager->apply(ovl->manager);
266
267 for (t = i + 1; t < ofbi->num_overlays; t++) {
268 ofbi->rotation[t-1] = ofbi->rotation[t];
269 ofbi->overlays[t-1] = ofbi->overlays[t];
270 }
271
272 ofbi->num_overlays--;
273 i--;
274 }
275
276 for (i = 0; i < num_ovls; ++i) {
277 int t, found;
278
279 ovl = ovls[i];
280
281 found = 0;
282
283 for (t = 0; t < ofbi->num_overlays; ++t) {
284 if (ovl == ofbi->overlays[t]) {
285 found = 1;
286 break;
287 }
288 }
289
290 if (found)
291 continue;
292 ofbi->rotation[ofbi->num_overlays] = 0;
293 ofbi->overlays[ofbi->num_overlays++] = ovl;
294
295 added = true;
296 }
297
298 if (added) {
299 r = omapfb_apply_changes(fbi, 0);
300 if (r)
301 goto out;
302 }
303
304 r = count;
305out:
306 unlock_fb_info(fbi);
307 omapfb_unlock(fbdev);
308
309 return r;
310}
311
312static ssize_t show_overlays_rotate(struct device *dev,
313 struct device_attribute *attr, char *buf)
314{
315 struct fb_info *fbi = dev_get_drvdata(dev);
316 struct omapfb_info *ofbi = FB2OFB(fbi);
317 ssize_t l = 0;
318 int t;
319
320 lock_fb_info(fbi);
321
322 for (t = 0; t < ofbi->num_overlays; t++) {
323 l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
324 t == 0 ? "" : ",", ofbi->rotation[t]);
325 }
326
327 l += snprintf(buf + l, PAGE_SIZE - l, "\n");
328
329 unlock_fb_info(fbi);
330
331 return l;
332}
333
334static ssize_t store_overlays_rotate(struct device *dev,
335 struct device_attribute *attr, const char *buf, size_t count)
336{
337 struct fb_info *fbi = dev_get_drvdata(dev);
338 struct omapfb_info *ofbi = FB2OFB(fbi);
339 int num_ovls = 0, r, i;
340 int len;
341 bool changed = false;
342 u8 rotation[OMAPFB_MAX_OVL_PER_FB];
343
344 len = strlen(buf);
345 if (buf[len - 1] == '\n')
346 len = len - 1;
347
348 lock_fb_info(fbi);
349
350 if (len > 0) {
351 char *p = (char *)buf;
352
353 while (p < buf + len) {
354 int rot;
355
356 if (num_ovls == ofbi->num_overlays) {
357 r = -EINVAL;
358 goto out;
359 }
360
361 rot = simple_strtoul(p, &p, 0);
362 if (rot < 0 || rot > 3) {
363 r = -EINVAL;
364 goto out;
365 }
366
367 if (ofbi->rotation[num_ovls] != rot)
368 changed = true;
369
370 rotation[num_ovls++] = rot;
371
372 p++;
373 }
374 }
375
376 if (num_ovls != ofbi->num_overlays) {
377 r = -EINVAL;
378 goto out;
379 }
380
381 if (changed) {
382 for (i = 0; i < num_ovls; ++i)
383 ofbi->rotation[i] = rotation[i];
384
385 r = omapfb_apply_changes(fbi, 0);
386 if (r)
387 goto out;
388
389 /* FIXME error handling? */
390 }
391
392 r = count;
393out:
394 unlock_fb_info(fbi);
395
396 return r;
397}
398
399static ssize_t show_size(struct device *dev,
400 struct device_attribute *attr, char *buf)
401{
402 struct fb_info *fbi = dev_get_drvdata(dev);
403 struct omapfb_info *ofbi = FB2OFB(fbi);
404
405 return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size);
406}
407
408static ssize_t store_size(struct device *dev, struct device_attribute *attr,
409 const char *buf, size_t count)
410{
411 struct fb_info *fbi = dev_get_drvdata(dev);
412 struct omapfb_info *ofbi = FB2OFB(fbi);
413 unsigned long size;
414 int r;
415 int i;
416
417 size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
418
419 lock_fb_info(fbi);
420
421 for (i = 0; i < ofbi->num_overlays; i++) {
422 if (ofbi->overlays[i]->info.enabled) {
423 r = -EBUSY;
424 goto out;
425 }
426 }
427
428 if (size != ofbi->region.size) {
429 r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type);
430 if (r) {
431 dev_err(dev, "realloc fbmem failed\n");
432 goto out;
433 }
434 }
435
436 r = count;
437out:
438 unlock_fb_info(fbi);
439
440 return r;
441}
442
443static ssize_t show_phys(struct device *dev,
444 struct device_attribute *attr, char *buf)
445{
446 struct fb_info *fbi = dev_get_drvdata(dev);
447 struct omapfb_info *ofbi = FB2OFB(fbi);
448
449 return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr);
450}
451
452static ssize_t show_virt(struct device *dev,
453 struct device_attribute *attr, char *buf)
454{
455 struct fb_info *fbi = dev_get_drvdata(dev);
456 struct omapfb_info *ofbi = FB2OFB(fbi);
457
458 return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr);
459}
460
461static struct device_attribute omapfb_attrs[] = {
462 __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
463 store_rotate_type),
464 __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
465 __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
466 __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
467 __ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
468 store_overlays_rotate),
469 __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
470 __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
471};
472
473int omapfb_create_sysfs(struct omapfb2_device *fbdev)
474{
475 int i;
476 int r;
477
478 DBG("create sysfs for fbs\n");
479 for (i = 0; i < fbdev->num_fbs; i++) {
480 int t;
481 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
482 r = device_create_file(fbdev->fbs[i]->dev,
483 &omapfb_attrs[t]);
484
485 if (r) {
486 dev_err(fbdev->dev, "failed to create sysfs "
487 "file\n");
488 return r;
489 }
490 }
491 }
492
493 return 0;
494}
495
496void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
497{
498 int i, t;
499
500 DBG("remove sysfs for fbs\n");
501 for (i = 0; i < fbdev->num_fbs; i++) {
502 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
503 device_remove_file(fbdev->fbs[i]->dev,
504 &omapfb_attrs[t]);
505 }
506}
507
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
new file mode 100644
index 000000000000..cd54fdbfd8bb
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -0,0 +1,155 @@
1/*
2 * linux/drivers/video/omap2/omapfb.h
3 *
4 * Copyright (C) 2008 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 __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
24#define __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
25
26#ifdef CONFIG_FB_OMAP2_DEBUG_SUPPORT
27#define DEBUG
28#endif
29
30#include <plat/display.h>
31
32#ifdef DEBUG
33extern unsigned int omapfb_debug;
34#define DBG(format, ...) \
35 if (omapfb_debug) \
36 printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__)
37#else
38#define DBG(format, ...)
39#endif
40
41#define FB2OFB(fb_info) ((struct omapfb_info *)(fb_info->par))
42
43/* max number of overlays to which a framebuffer data can be direct */
44#define OMAPFB_MAX_OVL_PER_FB 3
45
46struct omapfb2_mem_region {
47 u32 paddr;
48 void __iomem *vaddr;
49 struct vrfb vrfb;
50 unsigned long size;
51 u8 type; /* OMAPFB_PLANE_MEM_* */
52 bool alloc; /* allocated by the driver */
53 bool map; /* kernel mapped by the driver */
54};
55
56/* appended to fb_info */
57struct omapfb_info {
58 int id;
59 struct omapfb2_mem_region region;
60 atomic_t map_count;
61 int num_overlays;
62 struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB];
63 struct omapfb2_device *fbdev;
64 enum omap_dss_rotation_type rotation_type;
65 u8 rotation[OMAPFB_MAX_OVL_PER_FB];
66 bool mirror;
67};
68
69struct omapfb2_device {
70 struct device *dev;
71 struct mutex mtx;
72
73 u32 pseudo_palette[17];
74
75 int state;
76
77 unsigned num_fbs;
78 struct fb_info *fbs[10];
79
80 unsigned num_displays;
81 struct omap_dss_device *displays[10];
82 unsigned num_overlays;
83 struct omap_overlay *overlays[10];
84 unsigned num_managers;
85 struct omap_overlay_manager *managers[10];
86
87 unsigned num_bpp_overrides;
88 struct {
89 struct omap_dss_device *dssdev;
90 u8 bpp;
91 } bpp_overrides[10];
92};
93
94struct omapfb_colormode {
95 enum omap_color_mode dssmode;
96 u32 bits_per_pixel;
97 u32 nonstd;
98 struct fb_bitfield red;
99 struct fb_bitfield green;
100 struct fb_bitfield blue;
101 struct fb_bitfield transp;
102};
103
104void set_fb_fix(struct fb_info *fbi);
105int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var);
106int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type);
107int omapfb_apply_changes(struct fb_info *fbi, int init);
108
109int omapfb_create_sysfs(struct omapfb2_device *fbdev);
110void omapfb_remove_sysfs(struct omapfb2_device *fbdev);
111
112int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg);
113
114int omapfb_update_window(struct fb_info *fbi,
115 u32 x, u32 y, u32 w, u32 h);
116
117int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
118 struct fb_var_screeninfo *var);
119
120/* find the display connected to this fb, if any */
121static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
122{
123 struct omapfb_info *ofbi = FB2OFB(fbi);
124 int i;
125
126 /* XXX: returns the display connected to first attached overlay */
127 for (i = 0; i < ofbi->num_overlays; i++) {
128 if (ofbi->overlays[i]->manager)
129 return ofbi->overlays[i]->manager->device;
130 }
131
132 return NULL;
133}
134
135static inline void omapfb_lock(struct omapfb2_device *fbdev)
136{
137 mutex_lock(&fbdev->mtx);
138}
139
140static inline void omapfb_unlock(struct omapfb2_device *fbdev)
141{
142 mutex_unlock(&fbdev->mtx);
143}
144
145static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
146 int enable)
147{
148 struct omap_overlay_info info;
149
150 ovl->get_overlay_info(ovl, &info);
151 info.enabled = enable;
152 return ovl->set_overlay_info(ovl, &info);
153}
154
155#endif
diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c
new file mode 100644
index 000000000000..3b1237ad85ed
--- /dev/null
+++ b/drivers/video/omap2/vram.c
@@ -0,0 +1,657 @@
1/*
2 * VRAM manager for OMAP
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
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21/*#define DEBUG*/
22
23#include <linux/kernel.h>
24#include <linux/mm.h>
25#include <linux/list.h>
26#include <linux/slab.h>
27#include <linux/seq_file.h>
28#include <linux/bootmem.h>
29#include <linux/completion.h>
30#include <linux/debugfs.h>
31#include <linux/jiffies.h>
32#include <linux/module.h>
33
34#include <asm/setup.h>
35
36#include <plat/sram.h>
37#include <plat/vram.h>
38#include <plat/dma.h>
39
40#ifdef DEBUG
41#define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__)
42#else
43#define DBG(format, ...)
44#endif
45
46#define OMAP2_SRAM_START 0x40200000
47/* Maximum size, in reality this is smaller if SRAM is partially locked. */
48#define OMAP2_SRAM_SIZE 0xa0000 /* 640k */
49
50/* postponed regions are used to temporarily store region information at boot
51 * time when we cannot yet allocate the region list */
52#define MAX_POSTPONED_REGIONS 10
53
54static bool vram_initialized;
55static int postponed_cnt;
56static struct {
57 unsigned long paddr;
58 size_t size;
59} postponed_regions[MAX_POSTPONED_REGIONS];
60
61struct vram_alloc {
62 struct list_head list;
63 unsigned long paddr;
64 unsigned pages;
65};
66
67struct vram_region {
68 struct list_head list;
69 struct list_head alloc_list;
70 unsigned long paddr;
71 unsigned pages;
72};
73
74static DEFINE_MUTEX(region_mutex);
75static LIST_HEAD(region_list);
76
77static inline int region_mem_type(unsigned long paddr)
78{
79 if (paddr >= OMAP2_SRAM_START &&
80 paddr < OMAP2_SRAM_START + OMAP2_SRAM_SIZE)
81 return OMAP_VRAM_MEMTYPE_SRAM;
82 else
83 return OMAP_VRAM_MEMTYPE_SDRAM;
84}
85
86static struct vram_region *omap_vram_create_region(unsigned long paddr,
87 unsigned pages)
88{
89 struct vram_region *rm;
90
91 rm = kzalloc(sizeof(*rm), GFP_KERNEL);
92
93 if (rm) {
94 INIT_LIST_HEAD(&rm->alloc_list);
95 rm->paddr = paddr;
96 rm->pages = pages;
97 }
98
99 return rm;
100}
101
102#if 0
103static void omap_vram_free_region(struct vram_region *vr)
104{
105 list_del(&vr->list);
106 kfree(vr);
107}
108#endif
109
110static struct vram_alloc *omap_vram_create_allocation(struct vram_region *vr,
111 unsigned long paddr, unsigned pages)
112{
113 struct vram_alloc *va;
114 struct vram_alloc *new;
115
116 new = kzalloc(sizeof(*va), GFP_KERNEL);
117
118 if (!new)
119 return NULL;
120
121 new->paddr = paddr;
122 new->pages = pages;
123
124 list_for_each_entry(va, &vr->alloc_list, list) {
125 if (va->paddr > new->paddr)
126 break;
127 }
128
129 list_add_tail(&new->list, &va->list);
130
131 return new;
132}
133
134static void omap_vram_free_allocation(struct vram_alloc *va)
135{
136 list_del(&va->list);
137 kfree(va);
138}
139
140int omap_vram_add_region(unsigned long paddr, size_t size)
141{
142 struct vram_region *rm;
143 unsigned pages;
144
145 if (vram_initialized) {
146 DBG("adding region paddr %08lx size %d\n",
147 paddr, size);
148
149 size &= PAGE_MASK;
150 pages = size >> PAGE_SHIFT;
151
152 rm = omap_vram_create_region(paddr, pages);
153 if (rm == NULL)
154 return -ENOMEM;
155
156 list_add(&rm->list, &region_list);
157 } else {
158 if (postponed_cnt == MAX_POSTPONED_REGIONS)
159 return -ENOMEM;
160
161 postponed_regions[postponed_cnt].paddr = paddr;
162 postponed_regions[postponed_cnt].size = size;
163
164 ++postponed_cnt;
165 }
166 return 0;
167}
168
169int omap_vram_free(unsigned long paddr, size_t size)
170{
171 struct vram_region *rm;
172 struct vram_alloc *alloc;
173 unsigned start, end;
174
175 DBG("free mem paddr %08lx size %d\n", paddr, size);
176
177 size = PAGE_ALIGN(size);
178
179 mutex_lock(&region_mutex);
180
181 list_for_each_entry(rm, &region_list, list) {
182 list_for_each_entry(alloc, &rm->alloc_list, list) {
183 start = alloc->paddr;
184 end = alloc->paddr + (alloc->pages >> PAGE_SHIFT);
185
186 if (start >= paddr && end < paddr + size)
187 goto found;
188 }
189 }
190
191 mutex_unlock(&region_mutex);
192 return -EINVAL;
193
194found:
195 omap_vram_free_allocation(alloc);
196
197 mutex_unlock(&region_mutex);
198 return 0;
199}
200EXPORT_SYMBOL(omap_vram_free);
201
202static int _omap_vram_reserve(unsigned long paddr, unsigned pages)
203{
204 struct vram_region *rm;
205 struct vram_alloc *alloc;
206 size_t size;
207
208 size = pages << PAGE_SHIFT;
209
210 list_for_each_entry(rm, &region_list, list) {
211 unsigned long start, end;
212
213 DBG("checking region %lx %d\n", rm->paddr, rm->pages);
214
215 if (region_mem_type(rm->paddr) != region_mem_type(paddr))
216 continue;
217
218 start = rm->paddr;
219 end = start + (rm->pages << PAGE_SHIFT) - 1;
220 if (start > paddr || end < paddr + size - 1)
221 continue;
222
223 DBG("block ok, checking allocs\n");
224
225 list_for_each_entry(alloc, &rm->alloc_list, list) {
226 end = alloc->paddr - 1;
227
228 if (start <= paddr && end >= paddr + size - 1)
229 goto found;
230
231 start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
232 }
233
234 end = rm->paddr + (rm->pages << PAGE_SHIFT) - 1;
235
236 if (!(start <= paddr && end >= paddr + size - 1))
237 continue;
238found:
239 DBG("found area start %lx, end %lx\n", start, end);
240
241 if (omap_vram_create_allocation(rm, paddr, pages) == NULL)
242 return -ENOMEM;
243
244 return 0;
245 }
246
247 return -ENOMEM;
248}
249
250int omap_vram_reserve(unsigned long paddr, size_t size)
251{
252 unsigned pages;
253 int r;
254
255 DBG("reserve mem paddr %08lx size %d\n", paddr, size);
256
257 size = PAGE_ALIGN(size);
258 pages = size >> PAGE_SHIFT;
259
260 mutex_lock(&region_mutex);
261
262 r = _omap_vram_reserve(paddr, pages);
263
264 mutex_unlock(&region_mutex);
265
266 return r;
267}
268EXPORT_SYMBOL(omap_vram_reserve);
269
270static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data)
271{
272 struct completion *compl = data;
273 complete(compl);
274}
275
276static int _omap_vram_clear(u32 paddr, unsigned pages)
277{
278 struct completion compl;
279 unsigned elem_count;
280 unsigned frame_count;
281 int r;
282 int lch;
283
284 init_completion(&compl);
285
286 r = omap_request_dma(OMAP_DMA_NO_DEVICE, "VRAM DMA",
287 _omap_vram_dma_cb,
288 &compl, &lch);
289 if (r) {
290 pr_err("VRAM: request_dma failed for memory clear\n");
291 return -EBUSY;
292 }
293
294 elem_count = pages * PAGE_SIZE / 4;
295 frame_count = 1;
296
297 omap_set_dma_transfer_params(lch, OMAP_DMA_DATA_TYPE_S32,
298 elem_count, frame_count,
299 OMAP_DMA_SYNC_ELEMENT,
300 0, 0);
301
302 omap_set_dma_dest_params(lch, 0, OMAP_DMA_AMODE_POST_INC,
303 paddr, 0, 0);
304
305 omap_set_dma_color_mode(lch, OMAP_DMA_CONSTANT_FILL, 0x000000);
306
307 omap_start_dma(lch);
308
309 if (wait_for_completion_timeout(&compl, msecs_to_jiffies(1000)) == 0) {
310 omap_stop_dma(lch);
311 pr_err("VRAM: dma timeout while clearing memory\n");
312 r = -EIO;
313 goto err;
314 }
315
316 r = 0;
317err:
318 omap_free_dma(lch);
319
320 return r;
321}
322
323static int _omap_vram_alloc(int mtype, unsigned pages, unsigned long *paddr)
324{
325 struct vram_region *rm;
326 struct vram_alloc *alloc;
327
328 list_for_each_entry(rm, &region_list, list) {
329 unsigned long start, end;
330
331 DBG("checking region %lx %d\n", rm->paddr, rm->pages);
332
333 if (region_mem_type(rm->paddr) != mtype)
334 continue;
335
336 start = rm->paddr;
337
338 list_for_each_entry(alloc, &rm->alloc_list, list) {
339 end = alloc->paddr;
340
341 if (end - start >= pages << PAGE_SHIFT)
342 goto found;
343
344 start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
345 }
346
347 end = rm->paddr + (rm->pages << PAGE_SHIFT);
348found:
349 if (end - start < pages << PAGE_SHIFT)
350 continue;
351
352 DBG("found %lx, end %lx\n", start, end);
353
354 alloc = omap_vram_create_allocation(rm, start, pages);
355 if (alloc == NULL)
356 return -ENOMEM;
357
358 *paddr = start;
359
360 _omap_vram_clear(start, pages);
361
362 return 0;
363 }
364
365 return -ENOMEM;
366}
367
368int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr)
369{
370 unsigned pages;
371 int r;
372
373 BUG_ON(mtype > OMAP_VRAM_MEMTYPE_MAX || !size);
374
375 DBG("alloc mem type %d size %d\n", mtype, size);
376
377 size = PAGE_ALIGN(size);
378 pages = size >> PAGE_SHIFT;
379
380 mutex_lock(&region_mutex);
381
382 r = _omap_vram_alloc(mtype, pages, paddr);
383
384 mutex_unlock(&region_mutex);
385
386 return r;
387}
388EXPORT_SYMBOL(omap_vram_alloc);
389
390void omap_vram_get_info(unsigned long *vram,
391 unsigned long *free_vram,
392 unsigned long *largest_free_block)
393{
394 struct vram_region *vr;
395 struct vram_alloc *va;
396
397 *vram = 0;
398 *free_vram = 0;
399 *largest_free_block = 0;
400
401 mutex_lock(&region_mutex);
402
403 list_for_each_entry(vr, &region_list, list) {
404 unsigned free;
405 unsigned long pa;
406
407 pa = vr->paddr;
408 *vram += vr->pages << PAGE_SHIFT;
409
410 list_for_each_entry(va, &vr->alloc_list, list) {
411 free = va->paddr - pa;
412 *free_vram += free;
413 if (free > *largest_free_block)
414 *largest_free_block = free;
415 pa = va->paddr + (va->pages << PAGE_SHIFT);
416 }
417
418 free = vr->paddr + (vr->pages << PAGE_SHIFT) - pa;
419 *free_vram += free;
420 if (free > *largest_free_block)
421 *largest_free_block = free;
422 }
423
424 mutex_unlock(&region_mutex);
425}
426EXPORT_SYMBOL(omap_vram_get_info);
427
428#if defined(CONFIG_DEBUG_FS)
429static int vram_debug_show(struct seq_file *s, void *unused)
430{
431 struct vram_region *vr;
432 struct vram_alloc *va;
433 unsigned size;
434
435 mutex_lock(&region_mutex);
436
437 list_for_each_entry(vr, &region_list, list) {
438 size = vr->pages << PAGE_SHIFT;
439 seq_printf(s, "%08lx-%08lx (%d bytes)\n",
440 vr->paddr, vr->paddr + size - 1,
441 size);
442
443 list_for_each_entry(va, &vr->alloc_list, list) {
444 size = va->pages << PAGE_SHIFT;
445 seq_printf(s, " %08lx-%08lx (%d bytes)\n",
446 va->paddr, va->paddr + size - 1,
447 size);
448 }
449 }
450
451 mutex_unlock(&region_mutex);
452
453 return 0;
454}
455
456static int vram_debug_open(struct inode *inode, struct file *file)
457{
458 return single_open(file, vram_debug_show, inode->i_private);
459}
460
461static const struct file_operations vram_debug_fops = {
462 .open = vram_debug_open,
463 .read = seq_read,
464 .llseek = seq_lseek,
465 .release = single_release,
466};
467
468static int __init omap_vram_create_debugfs(void)
469{
470 struct dentry *d;
471
472 d = debugfs_create_file("vram", S_IRUGO, NULL,
473 NULL, &vram_debug_fops);
474 if (IS_ERR(d))
475 return PTR_ERR(d);
476
477 return 0;
478}
479#endif
480
481static __init int omap_vram_init(void)
482{
483 int i;
484
485 vram_initialized = 1;
486
487 for (i = 0; i < postponed_cnt; i++)
488 omap_vram_add_region(postponed_regions[i].paddr,
489 postponed_regions[i].size);
490
491#ifdef CONFIG_DEBUG_FS
492 if (omap_vram_create_debugfs())
493 pr_err("VRAM: Failed to create debugfs file\n");
494#endif
495
496 return 0;
497}
498
499arch_initcall(omap_vram_init);
500
501/* boottime vram alloc stuff */
502
503/* set from board file */
504static u32 omap_vram_sram_start __initdata;
505static u32 omap_vram_sram_size __initdata;
506
507/* set from board file */
508static u32 omap_vram_sdram_start __initdata;
509static u32 omap_vram_sdram_size __initdata;
510
511/* set from kernel cmdline */
512static u32 omap_vram_def_sdram_size __initdata;
513static u32 omap_vram_def_sdram_start __initdata;
514
515static int __init omap_vram_early_vram(char *p)
516{
517 omap_vram_def_sdram_size = memparse(p, &p);
518 if (*p == ',')
519 omap_vram_def_sdram_start = simple_strtoul(p + 1, &p, 16);
520 return 0;
521}
522early_param("vram", omap_vram_early_vram);
523
524/*
525 * Called from map_io. We need to call to this early enough so that we
526 * can reserve the fixed SDRAM regions before VM could get hold of them.
527 */
528void __init omap_vram_reserve_sdram(void)
529{
530 struct bootmem_data *bdata;
531 unsigned long sdram_start, sdram_size;
532 u32 paddr;
533 u32 size = 0;
534
535 /* cmdline arg overrides the board file definition */
536 if (omap_vram_def_sdram_size) {
537 size = omap_vram_def_sdram_size;
538 paddr = omap_vram_def_sdram_start;
539 }
540
541 if (!size) {
542 size = omap_vram_sdram_size;
543 paddr = omap_vram_sdram_start;
544 }
545
546#ifdef CONFIG_OMAP2_VRAM_SIZE
547 if (!size) {
548 size = CONFIG_OMAP2_VRAM_SIZE * 1024 * 1024;
549 paddr = 0;
550 }
551#endif
552
553 if (!size)
554 return;
555
556 size = PAGE_ALIGN(size);
557
558 bdata = NODE_DATA(0)->bdata;
559 sdram_start = bdata->node_min_pfn << PAGE_SHIFT;
560 sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start;
561
562 if (paddr) {
563 if ((paddr & ~PAGE_MASK) || paddr < sdram_start ||
564 paddr + size > sdram_start + sdram_size) {
565 pr_err("Illegal SDRAM region for VRAM\n");
566 return;
567 }
568
569 if (reserve_bootmem(paddr, size, BOOTMEM_EXCLUSIVE) < 0) {
570 pr_err("FB: failed to reserve VRAM\n");
571 return;
572 }
573 } else {
574 if (size > sdram_size) {
575 pr_err("Illegal SDRAM size for VRAM\n");
576 return;
577 }
578
579 paddr = virt_to_phys(alloc_bootmem_pages(size));
580 BUG_ON(paddr & ~PAGE_MASK);
581 }
582
583 omap_vram_add_region(paddr, size);
584
585 pr_info("Reserving %u bytes SDRAM for VRAM\n", size);
586}
587
588/*
589 * Called at sram init time, before anything is pushed to the SRAM stack.
590 * Because of the stack scheme, we will allocate everything from the
591 * start of the lowest address region to the end of SRAM. This will also
592 * include padding for page alignment and possible holes between regions.
593 *
594 * As opposed to the SDRAM case, we'll also do any dynamic allocations at
595 * this point, since the driver built as a module would have problem with
596 * freeing / reallocating the regions.
597 */
598unsigned long __init omap_vram_reserve_sram(unsigned long sram_pstart,
599 unsigned long sram_vstart,
600 unsigned long sram_size,
601 unsigned long pstart_avail,
602 unsigned long size_avail)
603{
604 unsigned long pend_avail;
605 unsigned long reserved;
606 u32 paddr;
607 u32 size;
608
609 paddr = omap_vram_sram_start;
610 size = omap_vram_sram_size;
611
612 if (!size)
613 return 0;
614
615 reserved = 0;
616 pend_avail = pstart_avail + size_avail;
617
618 if (!paddr) {
619 /* Dynamic allocation */
620 if ((size_avail & PAGE_MASK) < size) {
621 pr_err("Not enough SRAM for VRAM\n");
622 return 0;
623 }
624 size_avail = (size_avail - size) & PAGE_MASK;
625 paddr = pstart_avail + size_avail;
626 }
627
628 if (paddr < sram_pstart ||
629 paddr + size > sram_pstart + sram_size) {
630 pr_err("Illegal SRAM region for VRAM\n");
631 return 0;
632 }
633
634 /* Reserve everything above the start of the region. */
635 if (pend_avail - paddr > reserved)
636 reserved = pend_avail - paddr;
637 size_avail = pend_avail - reserved - pstart_avail;
638
639 omap_vram_add_region(paddr, size);
640
641 if (reserved)
642 pr_info("Reserving %lu bytes SRAM for VRAM\n", reserved);
643
644 return reserved;
645}
646
647void __init omap_vram_set_sdram_vram(u32 size, u32 start)
648{
649 omap_vram_sdram_start = start;
650 omap_vram_sdram_size = size;
651}
652
653void __init omap_vram_set_sram_vram(u32 size, u32 start)
654{
655 omap_vram_sram_start = start;
656 omap_vram_sram_size = size;
657}
diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c
new file mode 100644
index 000000000000..fd2271600370
--- /dev/null
+++ b/drivers/video/omap2/vrfb.c
@@ -0,0 +1,315 @@
1/*
2 * VRFB Rotation Engine
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
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21/*#define DEBUG*/
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/ioport.h>
26#include <linux/io.h>
27#include <linux/bitops.h>
28#include <linux/mutex.h>
29
30#include <mach/io.h>
31#include <plat/vrfb.h>
32#include <plat/sdrc.h>
33
34#ifdef DEBUG
35#define DBG(format, ...) pr_debug("VRFB: " format, ## __VA_ARGS__)
36#else
37#define DBG(format, ...)
38#endif
39
40#define SMS_ROT_VIRT_BASE(context, rot) \
41 (((context >= 4) ? 0xD0000000 : 0x70000000) \
42 + (0x4000000 * (context)) \
43 + (0x1000000 * (rot)))
44
45#define OMAP_VRFB_SIZE (2048 * 2048 * 4)
46
47#define VRFB_PAGE_WIDTH_EXP 5 /* Assuming SDRAM pagesize= 1024 */
48#define VRFB_PAGE_HEIGHT_EXP 5 /* 1024 = 2^5 * 2^5 */
49#define VRFB_PAGE_WIDTH (1 << VRFB_PAGE_WIDTH_EXP)
50#define VRFB_PAGE_HEIGHT (1 << VRFB_PAGE_HEIGHT_EXP)
51#define SMS_IMAGEHEIGHT_OFFSET 16
52#define SMS_IMAGEWIDTH_OFFSET 0
53#define SMS_PH_OFFSET 8
54#define SMS_PW_OFFSET 4
55#define SMS_PS_OFFSET 0
56
57#define VRFB_NUM_CTXS 12
58/* bitmap of reserved contexts */
59static unsigned long ctx_map;
60
61static DEFINE_MUTEX(ctx_lock);
62
63/*
64 * Access to this happens from client drivers or the PM core after wake-up.
65 * For the first case we require locking at the driver level, for the second
66 * we don't need locking, since no drivers will run until after the wake-up
67 * has finished.
68 */
69static struct {
70 u32 physical_ba;
71 u32 control;
72 u32 size;
73} vrfb_hw_context[VRFB_NUM_CTXS];
74
75static inline void restore_hw_context(int ctx)
76{
77 omap2_sms_write_rot_control(vrfb_hw_context[ctx].control, ctx);
78 omap2_sms_write_rot_size(vrfb_hw_context[ctx].size, ctx);
79 omap2_sms_write_rot_physical_ba(vrfb_hw_context[ctx].physical_ba, ctx);
80}
81
82static u32 get_image_width_roundup(u16 width, u8 bytespp)
83{
84 unsigned long stride = width * bytespp;
85 unsigned long ceil_pages_per_stride = (stride / VRFB_PAGE_WIDTH) +
86 (stride % VRFB_PAGE_WIDTH != 0);
87
88 return ceil_pages_per_stride * VRFB_PAGE_WIDTH / bytespp;
89}
90
91/*
92 * This the extra space needed in the VRFB physical area for VRFB to safely wrap
93 * any memory accesses to the invisible part of the virtual view to the physical
94 * area.
95 */
96static inline u32 get_extra_physical_size(u16 image_width_roundup, u8 bytespp)
97{
98 return (OMAP_VRFB_LINE_LEN - image_width_roundup) * VRFB_PAGE_HEIGHT *
99 bytespp;
100}
101
102void omap_vrfb_restore_context(void)
103{
104 int i;
105 unsigned long map = ctx_map;
106
107 for (i = ffs(map); i; i = ffs(map)) {
108 /* i=1..32 */
109 i--;
110 map &= ~(1 << i);
111 restore_hw_context(i);
112 }
113}
114
115void omap_vrfb_adjust_size(u16 *width, u16 *height,
116 u8 bytespp)
117{
118 *width = ALIGN(*width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
119 *height = ALIGN(*height, VRFB_PAGE_HEIGHT);
120}
121EXPORT_SYMBOL(omap_vrfb_adjust_size);
122
123u32 omap_vrfb_min_phys_size(u16 width, u16 height, u8 bytespp)
124{
125 unsigned long image_width_roundup = get_image_width_roundup(width,
126 bytespp);
127
128 if (image_width_roundup > OMAP_VRFB_LINE_LEN)
129 return 0;
130
131 return (width * height * bytespp) + get_extra_physical_size(
132 image_width_roundup, bytespp);
133}
134EXPORT_SYMBOL(omap_vrfb_min_phys_size);
135
136u16 omap_vrfb_max_height(u32 phys_size, u16 width, u8 bytespp)
137{
138 unsigned long image_width_roundup = get_image_width_roundup(width,
139 bytespp);
140 unsigned long height;
141 unsigned long extra;
142
143 if (image_width_roundup > OMAP_VRFB_LINE_LEN)
144 return 0;
145
146 extra = get_extra_physical_size(image_width_roundup, bytespp);
147
148 if (phys_size < extra)
149 return 0;
150
151 height = (phys_size - extra) / (width * bytespp);
152
153 /* Virtual views provided by VRFB are limited to 2048x2048. */
154 return min_t(unsigned long, height, 2048);
155}
156EXPORT_SYMBOL(omap_vrfb_max_height);
157
158void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
159 u16 width, u16 height,
160 unsigned bytespp, bool yuv_mode)
161{
162 unsigned pixel_size_exp;
163 u16 vrfb_width;
164 u16 vrfb_height;
165 u8 ctx = vrfb->context;
166 u32 size;
167 u32 control;
168
169 DBG("omapfb_set_vrfb(%d, %lx, %dx%d, %d, %d)\n", ctx, paddr,
170 width, height, bytespp, yuv_mode);
171
172 /* For YUV2 and UYVY modes VRFB needs to handle pixels a bit
173 * differently. See TRM. */
174 if (yuv_mode) {
175 bytespp *= 2;
176 width /= 2;
177 }
178
179 if (bytespp == 4)
180 pixel_size_exp = 2;
181 else if (bytespp == 2)
182 pixel_size_exp = 1;
183 else
184 BUG();
185
186 vrfb_width = ALIGN(width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
187 vrfb_height = ALIGN(height, VRFB_PAGE_HEIGHT);
188
189 DBG("vrfb w %u, h %u bytespp %d\n", vrfb_width, vrfb_height, bytespp);
190
191 size = vrfb_width << SMS_IMAGEWIDTH_OFFSET;
192 size |= vrfb_height << SMS_IMAGEHEIGHT_OFFSET;
193
194 control = pixel_size_exp << SMS_PS_OFFSET;
195 control |= VRFB_PAGE_WIDTH_EXP << SMS_PW_OFFSET;
196 control |= VRFB_PAGE_HEIGHT_EXP << SMS_PH_OFFSET;
197
198 vrfb_hw_context[ctx].physical_ba = paddr;
199 vrfb_hw_context[ctx].size = size;
200 vrfb_hw_context[ctx].control = control;
201
202 omap2_sms_write_rot_physical_ba(paddr, ctx);
203 omap2_sms_write_rot_size(size, ctx);
204 omap2_sms_write_rot_control(control, ctx);
205
206 DBG("vrfb offset pixels %d, %d\n",
207 vrfb_width - width, vrfb_height - height);
208
209 vrfb->xres = width;
210 vrfb->yres = height;
211 vrfb->xoffset = vrfb_width - width;
212 vrfb->yoffset = vrfb_height - height;
213 vrfb->bytespp = bytespp;
214 vrfb->yuv_mode = yuv_mode;
215}
216EXPORT_SYMBOL(omap_vrfb_setup);
217
218int omap_vrfb_map_angle(struct vrfb *vrfb, u16 height, u8 rot)
219{
220 unsigned long size = height * OMAP_VRFB_LINE_LEN * vrfb->bytespp;
221
222 vrfb->vaddr[rot] = ioremap_wc(vrfb->paddr[rot], size);
223
224 if (!vrfb->vaddr[rot]) {
225 printk(KERN_ERR "vrfb: ioremap failed\n");
226 return -ENOMEM;
227 }
228
229 DBG("ioremapped vrfb area %d of size %lu into %p\n", rot, size,
230 vrfb->vaddr[rot]);
231
232 return 0;
233}
234EXPORT_SYMBOL(omap_vrfb_map_angle);
235
236void omap_vrfb_release_ctx(struct vrfb *vrfb)
237{
238 int rot;
239 int ctx = vrfb->context;
240
241 if (ctx == 0xff)
242 return;
243
244 DBG("release ctx %d\n", ctx);
245
246 mutex_lock(&ctx_lock);
247
248 BUG_ON(!(ctx_map & (1 << ctx)));
249
250 clear_bit(ctx, &ctx_map);
251
252 for (rot = 0; rot < 4; ++rot) {
253 if (vrfb->paddr[rot]) {
254 release_mem_region(vrfb->paddr[rot], OMAP_VRFB_SIZE);
255 vrfb->paddr[rot] = 0;
256 }
257 }
258
259 vrfb->context = 0xff;
260
261 mutex_unlock(&ctx_lock);
262}
263EXPORT_SYMBOL(omap_vrfb_release_ctx);
264
265int omap_vrfb_request_ctx(struct vrfb *vrfb)
266{
267 int rot;
268 u32 paddr;
269 u8 ctx;
270 int r;
271
272 DBG("request ctx\n");
273
274 mutex_lock(&ctx_lock);
275
276 for (ctx = 0; ctx < VRFB_NUM_CTXS; ++ctx)
277 if ((ctx_map & (1 << ctx)) == 0)
278 break;
279
280 if (ctx == VRFB_NUM_CTXS) {
281 pr_err("vrfb: no free contexts\n");
282 r = -EBUSY;
283 goto out;
284 }
285
286 DBG("found free ctx %d\n", ctx);
287
288 set_bit(ctx, &ctx_map);
289
290 memset(vrfb, 0, sizeof(*vrfb));
291
292 vrfb->context = ctx;
293
294 for (rot = 0; rot < 4; ++rot) {
295 paddr = SMS_ROT_VIRT_BASE(ctx, rot);
296 if (!request_mem_region(paddr, OMAP_VRFB_SIZE, "vrfb")) {
297 pr_err("vrfb: failed to reserve VRFB "
298 "area for ctx %d, rotation %d\n",
299 ctx, rot * 90);
300 omap_vrfb_release_ctx(vrfb);
301 r = -ENOMEM;
302 goto out;
303 }
304
305 vrfb->paddr[rot] = paddr;
306
307 DBG("VRFB %d/%d: %lx\n", ctx, rot*90, vrfb->paddr[rot]);
308 }
309
310 r = 0;
311out:
312 mutex_unlock(&ctx_lock);
313 return r;
314}
315EXPORT_SYMBOL(omap_vrfb_request_ctx);