aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-11 00:55:17 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-11 00:55:17 -0500
commitaa2cf420593b67cc93de7a3f675b2a88eba0505f (patch)
treedfb3c73a8a3987c3b3ba08083f379ebc90942e03
parentd71cb81af3817193bc605de061da0499934263a6 (diff)
parent178ff4c9175db447f93b7343954b1d44707c881b (diff)
Merge branch 'for-linus' of git://gitorious.org/linux-omap-dss2/linux
* 'for-linus' of git://gitorious.org/linux-omap-dss2/linux: MAINTAINERS: Add OMAP2/3 DSS and OMAPFB maintainer OMAP: SDP: Enable DSS2 for OMAP3 SDP board OMAP: DSS2: Taal DSI command mode panel driver OMAP: DSS2: Add generic and Sharp panel drivers OMAP: DSS2: omapfb driver OMAP: DSS2: DSI driver OMAP: DSS2: SDI driver OMAP: DSS2: RFBI driver OMAP: DSS2: Video encoder driver OMAP: DSS2: DPI driver OMAP: DSS2: DISPC OMAP: DSS2: Add more core files OMAP: DSS2: Display Subsystem Driver core OMAP: DSS2: Documentation for DSS2 OMAP: Add support for VRFB rotation engine OMAP: Add VRAM manager OMAP: OMAPFB: add omapdss device OMAP: OMAPFB: split omapfb.h OMAP2: Add funcs for writing SMS_ROT_* registers
-rw-r--r--Documentation/arm/OMAP/DSS317
-rw-r--r--MAINTAINERS17
-rw-r--r--arch/arm/configs/omap_3430sdp_defconfig28
-rw-r--r--arch/arm/mach-omap1/board-nokia770.c2
-rw-r--r--arch/arm/mach-omap2/board-3430sdp.c167
-rw-r--r--arch/arm/mach-omap2/clock24xx.c8
-rw-r--r--arch/arm/mach-omap2/clock34xx.c14
-rw-r--r--arch/arm/mach-omap2/io.c4
-rw-r--r--arch/arm/mach-omap2/sdrc.c16
-rw-r--r--arch/arm/plat-omap/fb.c49
-rw-r--r--arch/arm/plat-omap/include/plat/display.h575
-rw-r--r--arch/arm/plat-omap/include/plat/sdrc.h9
-rw-r--r--arch/arm/plat-omap/include/plat/vram.h62
-rw-r--r--arch/arm/plat-omap/include/plat/vrfb.h50
-rw-r--r--arch/arm/plat-omap/sram.c8
-rw-r--r--drivers/video/Kconfig1
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/omap/Kconfig5
-rw-r--r--drivers/video/omap/blizzard.c2
-rw-r--r--drivers/video/omap/dispc.c21
-rw-r--r--drivers/video/omap/hwa742.c3
-rw-r--r--drivers/video/omap/lcd_2430sdp.c3
-rw-r--r--drivers/video/omap/lcd_ams_delta.c3
-rw-r--r--drivers/video/omap/lcd_apollon.c3
-rw-r--r--drivers/video/omap/lcd_h3.c2
-rw-r--r--drivers/video/omap/lcd_h4.c2
-rw-r--r--drivers/video/omap/lcd_htcherald.c2
-rw-r--r--drivers/video/omap/lcd_inn1510.c2
-rw-r--r--drivers/video/omap/lcd_inn1610.c2
-rw-r--r--drivers/video/omap/lcd_ldp.c3
-rw-r--r--drivers/video/omap/lcd_mipid.c3
-rw-r--r--drivers/video/omap/lcd_omap2evm.c3
-rw-r--r--drivers/video/omap/lcd_omap3beagle.c4
-rw-r--r--drivers/video/omap/lcd_omap3evm.c3
-rw-r--r--drivers/video/omap/lcd_osk.c2
-rw-r--r--drivers/video/omap/lcd_overo.c3
-rw-r--r--drivers/video/omap/lcd_palmte.c2
-rw-r--r--drivers/video/omap/lcd_palmtt.c2
-rw-r--r--drivers/video/omap/lcd_palmz71.c2
-rw-r--r--drivers/video/omap/lcdc.c3
-rw-r--r--drivers/video/omap/omapfb.h (renamed from arch/arm/plat-omap/include/plat/omapfb.h)191
-rw-r--r--drivers/video/omap/omapfb_main.c2
-rw-r--r--drivers/video/omap/rfbi.c3
-rw-r--r--drivers/video/omap/sossi.c3
-rw-r--r--drivers/video/omap2/Kconfig9
-rw-r--r--drivers/video/omap2/Makefile6
-rw-r--r--drivers/video/omap2/displays/Kconfig22
-rw-r--r--drivers/video/omap2/displays/Makefile4
-rw-r--r--drivers/video/omap2/displays/panel-generic.c104
-rw-r--r--drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c153
-rw-r--r--drivers/video/omap2/displays/panel-taal.c1003
-rw-r--r--drivers/video/omap2/dss/Kconfig89
-rw-r--r--drivers/video/omap2/dss/Makefile6
-rw-r--r--drivers/video/omap2/dss/core.c919
-rw-r--r--drivers/video/omap2/dss/dispc.c3091
-rw-r--r--drivers/video/omap2/dss/display.c671
-rw-r--r--drivers/video/omap2/dss/dpi.c399
-rw-r--r--drivers/video/omap2/dss/dsi.c3710
-rw-r--r--drivers/video/omap2/dss/dss.c596
-rw-r--r--drivers/video/omap2/dss/dss.h370
-rw-r--r--drivers/video/omap2/dss/manager.c1487
-rw-r--r--drivers/video/omap2/dss/overlay.c680
-rw-r--r--drivers/video/omap2/dss/rfbi.c1309
-rw-r--r--drivers/video/omap2/dss/sdi.c277
-rw-r--r--drivers/video/omap2/dss/venc.c797
-rw-r--r--drivers/video/omap2/omapfb/Kconfig37
-rw-r--r--drivers/video/omap2/omapfb/Makefile2
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c755
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c2261
-rw-r--r--drivers/video/omap2/omapfb/omapfb-sysfs.c507
-rw-r--r--drivers/video/omap2/omapfb/omapfb.h146
-rw-r--r--drivers/video/omap2/vram.c655
-rw-r--r--drivers/video/omap2/vrfb.c315
-rw-r--r--include/linux/omapfb.h251
74 files changed, 21991 insertions, 247 deletions
diff --git a/Documentation/arm/OMAP/DSS b/Documentation/arm/OMAP/DSS
new file mode 100644
index 000000000000..0af0e9eed5d6
--- /dev/null
+++ b/Documentation/arm/OMAP/DSS
@@ -0,0 +1,317 @@
1OMAP2/3 Display Subsystem
2-------------------------
3
4This is an almost total rewrite of the OMAP FB driver in drivers/video/omap
5(let's call it DSS1). The main differences between DSS1 and DSS2 are DSI,
6TV-out and multiple display support, but there are lots of small improvements
7also.
8
9The DSS2 driver (omapdss module) is in arch/arm/plat-omap/dss/, and the FB,
10panel and controller drivers are in drivers/video/omap2/. DSS1 and DSS2 live
11currently side by side, you can choose which one to use.
12
13Features
14--------
15
16Working and tested features include:
17
18- MIPI DPI (parallel) output
19- MIPI DSI output in command mode
20- MIPI DBI (RFBI) output
21- SDI output
22- TV output
23- All pieces can be compiled as a module or inside kernel
24- Use DISPC to update any of the outputs
25- Use CPU to update RFBI or DSI output
26- OMAP DISPC planes
27- RGB16, RGB24 packed, RGB24 unpacked
28- YUV2, UYVY
29- Scaling
30- Adjusting DSS FCK to find a good pixel clock
31- Use DSI DPLL to create DSS FCK
32
33Tested boards include:
34- OMAP3 SDP board
35- Beagle board
36- N810
37
38omapdss driver
39--------------
40
41The DSS driver does not itself have any support for Linux framebuffer, V4L or
42such like the current ones, but it has an internal kernel API that upper level
43drivers can use.
44
45The DSS driver models OMAP's overlays, overlay managers and displays in a
46flexible way to enable non-common multi-display configuration. In addition to
47modelling the hardware overlays, omapdss supports virtual overlays and overlay
48managers. These can be used when updating a display with CPU or system DMA.
49
50Panel and controller drivers
51----------------------------
52
53The drivers implement panel or controller specific functionality and are not
54usually visible to users except through omapfb driver. They register
55themselves to the DSS driver.
56
57omapfb driver
58-------------
59
60The omapfb driver implements arbitrary number of standard linux framebuffers.
61These framebuffers can be routed flexibly to any overlays, thus allowing very
62dynamic display architecture.
63
64The driver exports some omapfb specific ioctls, which are compatible with the
65ioctls in the old driver.
66
67The rest of the non standard features are exported via sysfs. Whether the final
68implementation will use sysfs, or ioctls, is still open.
69
70V4L2 drivers
71------------
72
73V4L2 is being implemented in TI.
74
75From omapdss point of view the V4L2 drivers should be similar to framebuffer
76driver.
77
78Architecture
79--------------------
80
81Some clarification what the different components do:
82
83 - Framebuffer is a memory area inside OMAP's SRAM/SDRAM that contains the
84 pixel data for the image. Framebuffer has width and height and color
85 depth.
86 - Overlay defines where the pixels are read from and where they go on the
87 screen. The overlay may be smaller than framebuffer, thus displaying only
88 part of the framebuffer. The position of the overlay may be changed if
89 the overlay is smaller than the display.
90 - Overlay manager combines the overlays in to one image and feeds them to
91 display.
92 - Display is the actual physical display device.
93
94A framebuffer can be connected to multiple overlays to show the same pixel data
95on all of the overlays. Note that in this case the overlay input sizes must be
96the same, but, in case of video overlays, the output size can be different. Any
97framebuffer can be connected to any overlay.
98
99An overlay can be connected to one overlay manager. Also DISPC overlays can be
100connected only to DISPC overlay managers, and virtual overlays can be only
101connected to virtual overlays.
102
103An overlay manager can be connected to one display. There are certain
104restrictions which kinds of displays an overlay manager can be connected:
105
106 - DISPC TV overlay manager can be only connected to TV display.
107 - Virtual overlay managers can only be connected to DBI or DSI displays.
108 - DISPC LCD overlay manager can be connected to all displays, except TV
109 display.
110
111Sysfs
112-----
113The sysfs interface is mainly used for testing. I don't think sysfs
114interface is the best for this in the final version, but I don't quite know
115what would be the best interfaces for these things.
116
117The sysfs interface is divided to two parts: DSS and FB.
118
119/sys/class/graphics/fb? directory:
120mirror 0=off, 1=on
121rotate Rotation 0-3 for 0, 90, 180, 270 degrees
122rotate_type 0 = DMA rotation, 1 = VRFB rotation
123overlays List of overlay numbers to which framebuffer pixels go
124phys_addr Physical address of the framebuffer
125virt_addr Virtual address of the framebuffer
126size Size of the framebuffer
127
128/sys/devices/platform/omapdss/overlay? directory:
129enabled 0=off, 1=on
130input_size width,height (ie. the framebuffer size)
131manager Destination overlay manager name
132name
133output_size width,height
134position x,y
135screen_width width
136global_alpha global alpha 0-255 0=transparent 255=opaque
137
138/sys/devices/platform/omapdss/manager? directory:
139display Destination display
140name
141alpha_blending_enabled 0=off, 1=on
142trans_key_enabled 0=off, 1=on
143trans_key_type gfx-destination, video-source
144trans_key_value transparency color key (RGB24)
145default_color default background color (RGB24)
146
147/sys/devices/platform/omapdss/display? directory:
148ctrl_name Controller name
149mirror 0=off, 1=on
150update_mode 0=off, 1=auto, 2=manual
151enabled 0=off, 1=on
152name
153rotate Rotation 0-3 for 0, 90, 180, 270 degrees
154timings Display timings (pixclock,xres/hfp/hbp/hsw,yres/vfp/vbp/vsw)
155 When writing, two special timings are accepted for tv-out:
156 "pal" and "ntsc"
157panel_name
158tear_elim Tearing elimination 0=off, 1=on
159
160There are also some debugfs files at <debugfs>/omapdss/ which show information
161about clocks and registers.
162
163Examples
164--------
165
166The following definitions have been made for the examples below:
167
168ovl0=/sys/devices/platform/omapdss/overlay0
169ovl1=/sys/devices/platform/omapdss/overlay1
170ovl2=/sys/devices/platform/omapdss/overlay2
171
172mgr0=/sys/devices/platform/omapdss/manager0
173mgr1=/sys/devices/platform/omapdss/manager1
174
175lcd=/sys/devices/platform/omapdss/display0
176dvi=/sys/devices/platform/omapdss/display1
177tv=/sys/devices/platform/omapdss/display2
178
179fb0=/sys/class/graphics/fb0
180fb1=/sys/class/graphics/fb1
181fb2=/sys/class/graphics/fb2
182
183Default setup on OMAP3 SDP
184--------------------------
185
186Here's the default setup on OMAP3 SDP board. All planes go to LCD. DVI
187and TV-out are not in use. The columns from left to right are:
188framebuffers, overlays, overlay managers, displays. Framebuffers are
189handled by omapfb, and the rest by the DSS.
190
191FB0 --- GFX -\ DVI
192FB1 --- VID1 --+- LCD ---- LCD
193FB2 --- VID2 -/ TV ----- TV
194
195Example: Switch from LCD to DVI
196----------------------
197
198w=`cat $dvi/timings | cut -d "," -f 2 | cut -d "/" -f 1`
199h=`cat $dvi/timings | cut -d "," -f 3 | cut -d "/" -f 1`
200
201echo "0" > $lcd/enabled
202echo "" > $mgr0/display
203fbset -fb /dev/fb0 -xres $w -yres $h -vxres $w -vyres $h
204# at this point you have to switch the dvi/lcd dip-switch from the omap board
205echo "dvi" > $mgr0/display
206echo "1" > $dvi/enabled
207
208After this the configuration looks like:
209
210FB0 --- GFX -\ -- DVI
211FB1 --- VID1 --+- LCD -/ LCD
212FB2 --- VID2 -/ TV ----- TV
213
214Example: Clone GFX overlay to LCD and TV
215-------------------------------
216
217w=`cat $tv/timings | cut -d "," -f 2 | cut -d "/" -f 1`
218h=`cat $tv/timings | cut -d "," -f 3 | cut -d "/" -f 1`
219
220echo "0" > $ovl0/enabled
221echo "0" > $ovl1/enabled
222
223echo "" > $fb1/overlays
224echo "0,1" > $fb0/overlays
225
226echo "$w,$h" > $ovl1/output_size
227echo "tv" > $ovl1/manager
228
229echo "1" > $ovl0/enabled
230echo "1" > $ovl1/enabled
231
232echo "1" > $tv/enabled
233
234After this the configuration looks like (only relevant parts shown):
235
236FB0 +-- GFX ---- LCD ---- LCD
237 \- VID1 ---- TV ---- TV
238
239Misc notes
240----------
241
242OMAP FB allocates the framebuffer memory using the OMAP VRAM allocator.
243
244Using DSI DPLL to generate pixel clock it is possible produce the pixel clock
245of 86.5MHz (max possible), and with that you get 1280x1024@57 output from DVI.
246
247Rotation and mirroring currently only supports RGB565 and RGB8888 modes. VRFB
248does not support mirroring.
249
250VRFB rotation requires much more memory than non-rotated framebuffer, so you
251probably need to increase your vram setting before using VRFB rotation. Also,
252many applications may not work with VRFB if they do not pay attention to all
253framebuffer parameters.
254
255Kernel boot arguments
256---------------------
257
258vram=<size>
259 - Amount of total VRAM to preallocate. For example, "10M". omapfb
260 allocates memory for framebuffers from VRAM.
261
262omapfb.mode=<display>:<mode>[,...]
263 - Default video mode for specified displays. For example,
264 "dvi:800x400MR-24@60". See drivers/video/modedb.c.
265 There are also two special modes: "pal" and "ntsc" that
266 can be used to tv out.
267
268omapfb.vram=<fbnum>:<size>[@<physaddr>][,...]
269 - VRAM allocated for a framebuffer. Normally omapfb allocates vram
270 depending on the display size. With this you can manually allocate
271 more or define the physical address of each framebuffer. For example,
272 "1:4M" to allocate 4M for fb1.
273
274omapfb.debug=<y|n>
275 - Enable debug printing. You have to have OMAPFB debug support enabled
276 in kernel config.
277
278omapfb.test=<y|n>
279 - Draw test pattern to framebuffer whenever framebuffer settings change.
280 You need to have OMAPFB debug support enabled in kernel config.
281
282omapfb.vrfb=<y|n>
283 - Use VRFB rotation for all framebuffers.
284
285omapfb.rotate=<angle>
286 - Default rotation applied to all framebuffers.
287 0 - 0 degree rotation
288 1 - 90 degree rotation
289 2 - 180 degree rotation
290 3 - 270 degree rotation
291
292omapfb.mirror=<y|n>
293 - Default mirror for all framebuffers. Only works with DMA rotation.
294
295omapdss.def_disp=<display>
296 - Name of default display, to which all overlays will be connected.
297 Common examples are "lcd" or "tv".
298
299omapdss.debug=<y|n>
300 - Enable debug printing. You have to have DSS debug support enabled in
301 kernel config.
302
303TODO
304----
305
306DSS locking
307
308Error checking
309- Lots of checks are missing or implemented just as BUG()
310
311System DMA update for DSI
312- Can be used for RGB16 and RGB24P modes. Probably not for RGB24U (how
313 to skip the empty byte?)
314
315OMAP1 support
316- Not sure if needed
317
diff --git a/MAINTAINERS b/MAINTAINERS
index d7f8668b7a72..98d5ca10ac04 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3903,6 +3903,23 @@ L: linux-omap@vger.kernel.org
3903S: Maintained 3903S: Maintained
3904F: drivers/video/omap/ 3904F: drivers/video/omap/
3905 3905
3906OMAP DISPLAY SUBSYSTEM SUPPORT (DSS2)
3907M: Tomi Valkeinen <tomi.valkeinen@nokia.com>
3908L: linux-omap@vger.kernel.org
3909L: linux-fbdev@vger.kernel.org (moderated for non-subscribers)
3910S: Maintained
3911F: drivers/video/omap2/dss/
3912F: drivers/video/omap2/vrfb.c
3913F: drivers/video/omap2/vram.c
3914F: Documentation/arm/OMAP/DSS
3915
3916OMAP FRAMEBUFFER SUPPORT (FOR DSS2)
3917M: Tomi Valkeinen <tomi.valkeinen@nokia.com>
3918L: linux-omap@vger.kernel.org
3919L: linux-fbdev@vger.kernel.org (moderated for non-subscribers)
3920S: Maintained
3921F: drivers/video/omap2/omapfb/
3922
3906OMAP MMC SUPPORT 3923OMAP MMC SUPPORT
3907M: Jarkko Lavinen <jarkko.lavinen@nokia.com> 3924M: Jarkko Lavinen <jarkko.lavinen@nokia.com>
3908L: linux-omap@vger.kernel.org 3925L: linux-omap@vger.kernel.org
diff --git a/arch/arm/configs/omap_3430sdp_defconfig b/arch/arm/configs/omap_3430sdp_defconfig
index 84829587d55a..592457cfbbe5 100644
--- a/arch/arm/configs/omap_3430sdp_defconfig
+++ b/arch/arm/configs/omap_3430sdp_defconfig
@@ -963,10 +963,32 @@ CONFIG_FB_CFB_IMAGEBLIT=y
963# 963#
964# CONFIG_FB_S1D13XXX is not set 964# CONFIG_FB_S1D13XXX is not set
965# CONFIG_FB_VIRTUAL is not set 965# CONFIG_FB_VIRTUAL is not set
966CONFIG_FB_OMAP=y 966# CONFIG_FB_METRONOME is not set
967# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set 967# CONFIG_FB_MB862XX is not set
968# CONFIG_FB_BROADSHEET is not set
969# CONFIG_FB_OMAP_LCD_VGA is not set
968# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set 970# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
969CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2 971CONFIG_OMAP2_VRAM=y
972CONFIG_OMAP2_VRFB=y
973CONFIG_OMAP2_DSS=y
974CONFIG_OMAP2_VRAM_SIZE=4
975CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y
976# CONFIG_OMAP2_DSS_RFBI is not set
977CONFIG_OMAP2_DSS_VENC=y
978# CONFIG_OMAP2_DSS_SDI is not set
979# CONFIG_OMAP2_DSS_DSI is not set
980# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
981CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0
982CONFIG_FB_OMAP2=y
983CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
984# CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set
985CONFIG_FB_OMAP2_NUM_FBS=3
986
987#
988# OMAP2/3 Display Device Drivers
989#
990CONFIG_PANEL_GENERIC=y
991CONFIG_PANEL_SHARP_LS037V7DW01=y
970# CONFIG_BACKLIGHT_LCD_SUPPORT is not set 992# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
971 993
972# 994#
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index 5a275bab2dfe..71e1a3fad0ea 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -14,6 +14,7 @@
14#include <linux/platform_device.h> 14#include <linux/platform_device.h>
15#include <linux/input.h> 15#include <linux/input.h>
16#include <linux/clk.h> 16#include <linux/clk.h>
17#include <linux/omapfb.h>
17 18
18#include <linux/spi/spi.h> 19#include <linux/spi/spi.h>
19#include <linux/spi/ads7846.h> 20#include <linux/spi/ads7846.h>
@@ -32,7 +33,6 @@
32#include <plat/keypad.h> 33#include <plat/keypad.h>
33#include <plat/common.h> 34#include <plat/common.h>
34#include <plat/dsp_common.h> 35#include <plat/dsp_common.h>
35#include <plat/omapfb.h>
36#include <plat/hwa742.h> 36#include <plat/hwa742.h>
37#include <plat/lcd_mipid.h> 37#include <plat/lcd_mipid.h>
38#include <plat/mmc.h> 38#include <plat/mmc.h>
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 491364e44c7d..5bda9fdbee9e 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -37,6 +37,7 @@
37#include <plat/common.h> 37#include <plat/common.h>
38#include <plat/dma.h> 38#include <plat/dma.h>
39#include <plat/gpmc.h> 39#include <plat/gpmc.h>
40#include <plat/display.h>
40 41
41#include <plat/control.h> 42#include <plat/control.h>
42#include <plat/gpmc-smc91x.h> 43#include <plat/gpmc-smc91x.h>
@@ -152,31 +153,152 @@ static struct spi_board_info sdp3430_spi_board_info[] __initdata = {
152 }, 153 },
153}; 154};
154 155
155static struct platform_device sdp3430_lcd_device = { 156
156 .name = "sdp2430_lcd", 157#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 8
157 .id = -1, 158#define SDP3430_LCD_PANEL_ENABLE_GPIO 5
159
160static unsigned backlight_gpio;
161static unsigned enable_gpio;
162static int lcd_enabled;
163static int dvi_enabled;
164
165static void __init sdp3430_display_init(void)
166{
167 int r;
168
169 enable_gpio = SDP3430_LCD_PANEL_ENABLE_GPIO;
170 backlight_gpio = SDP3430_LCD_PANEL_BACKLIGHT_GPIO;
171
172 r = gpio_request(enable_gpio, "LCD reset");
173 if (r) {
174 printk(KERN_ERR "failed to get LCD reset GPIO\n");
175 goto err0;
176 }
177
178 r = gpio_request(backlight_gpio, "LCD Backlight");
179 if (r) {
180 printk(KERN_ERR "failed to get LCD backlight GPIO\n");
181 goto err1;
182 }
183
184 gpio_direction_output(enable_gpio, 0);
185 gpio_direction_output(backlight_gpio, 0);
186
187 return;
188err1:
189 gpio_free(enable_gpio);
190err0:
191 return;
192}
193
194static int sdp3430_panel_enable_lcd(struct omap_dss_device *dssdev)
195{
196 if (dvi_enabled) {
197 printk(KERN_ERR "cannot enable LCD, DVI is enabled\n");
198 return -EINVAL;
199 }
200
201 gpio_direction_output(enable_gpio, 1);
202 gpio_direction_output(backlight_gpio, 1);
203
204 lcd_enabled = 1;
205
206 return 0;
207}
208
209static void sdp3430_panel_disable_lcd(struct omap_dss_device *dssdev)
210{
211 lcd_enabled = 0;
212
213 gpio_direction_output(enable_gpio, 0);
214 gpio_direction_output(backlight_gpio, 0);
215}
216
217static int sdp3430_panel_enable_dvi(struct omap_dss_device *dssdev)
218{
219 if (lcd_enabled) {
220 printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
221 return -EINVAL;
222 }
223
224 dvi_enabled = 1;
225
226 return 0;
227}
228
229static void sdp3430_panel_disable_dvi(struct omap_dss_device *dssdev)
230{
231 dvi_enabled = 0;
232}
233
234static int sdp3430_panel_enable_tv(struct omap_dss_device *dssdev)
235{
236 return 0;
237}
238
239static void sdp3430_panel_disable_tv(struct omap_dss_device *dssdev)
240{
241}
242
243
244static struct omap_dss_device sdp3430_lcd_device = {
245 .name = "lcd",
246 .driver_name = "sharp_ls_panel",
247 .type = OMAP_DISPLAY_TYPE_DPI,
248 .phy.dpi.data_lines = 16,
249 .platform_enable = sdp3430_panel_enable_lcd,
250 .platform_disable = sdp3430_panel_disable_lcd,
158}; 251};
159 252
160static struct regulator_consumer_supply sdp3430_vdac_supply = { 253static struct omap_dss_device sdp3430_dvi_device = {
161 .supply = "vdac", 254 .name = "dvi",
162 .dev = &sdp3430_lcd_device.dev, 255 .driver_name = "generic_panel",
256 .type = OMAP_DISPLAY_TYPE_DPI,
257 .phy.dpi.data_lines = 24,
258 .platform_enable = sdp3430_panel_enable_dvi,
259 .platform_disable = sdp3430_panel_disable_dvi,
163}; 260};
164 261
165static struct regulator_consumer_supply sdp3430_vdvi_supply = { 262static struct omap_dss_device sdp3430_tv_device = {
166 .supply = "vdvi", 263 .name = "tv",
167 .dev = &sdp3430_lcd_device.dev, 264 .driver_name = "venc",
265 .type = OMAP_DISPLAY_TYPE_VENC,
266 .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO,
267 .platform_enable = sdp3430_panel_enable_tv,
268 .platform_disable = sdp3430_panel_disable_tv,
168}; 269};
169 270
170static struct platform_device *sdp3430_devices[] __initdata = { 271
272static struct omap_dss_device *sdp3430_dss_devices[] = {
171 &sdp3430_lcd_device, 273 &sdp3430_lcd_device,
274 &sdp3430_dvi_device,
275 &sdp3430_tv_device,
172}; 276};
173 277
174static struct omap_lcd_config sdp3430_lcd_config __initdata = { 278static struct omap_dss_board_info sdp3430_dss_data = {
175 .ctrl_name = "internal", 279 .num_devices = ARRAY_SIZE(sdp3430_dss_devices),
280 .devices = sdp3430_dss_devices,
281 .default_device = &sdp3430_lcd_device,
282};
283
284static struct platform_device sdp3430_dss_device = {
285 .name = "omapdss",
286 .id = -1,
287 .dev = {
288 .platform_data = &sdp3430_dss_data,
289 },
290};
291
292static struct regulator_consumer_supply sdp3430_vdda_dac_supply = {
293 .supply = "vdda_dac",
294 .dev = &sdp3430_dss_device.dev,
295};
296
297static struct platform_device *sdp3430_devices[] __initdata = {
298 &sdp3430_dss_device,
176}; 299};
177 300
178static struct omap_board_config_kernel sdp3430_config[] __initdata = { 301static struct omap_board_config_kernel sdp3430_config[] __initdata = {
179 { OMAP_TAG_LCD, &sdp3430_lcd_config },
180}; 302};
181 303
182static void __init omap_3430sdp_init_irq(void) 304static void __init omap_3430sdp_init_irq(void)
@@ -392,22 +514,34 @@ static struct regulator_init_data sdp3430_vdac = {
392 | REGULATOR_CHANGE_STATUS, 514 | REGULATOR_CHANGE_STATUS,
393 }, 515 },
394 .num_consumer_supplies = 1, 516 .num_consumer_supplies = 1,
395 .consumer_supplies = &sdp3430_vdac_supply, 517 .consumer_supplies = &sdp3430_vdda_dac_supply,
396}; 518};
397 519
398/* VPLL2 for digital video outputs */ 520/* VPLL2 for digital video outputs */
521static struct regulator_consumer_supply sdp3430_vpll2_supplies[] = {
522 {
523 .supply = "vdvi",
524 .dev = &sdp3430_lcd_device.dev,
525 },
526 {
527 .supply = "vdds_dsi",
528 .dev = &sdp3430_dss_device.dev,
529 }
530};
531
399static struct regulator_init_data sdp3430_vpll2 = { 532static struct regulator_init_data sdp3430_vpll2 = {
400 .constraints = { 533 .constraints = {
401 .name = "VDVI", 534 .name = "VDVI",
402 .min_uV = 1800000, 535 .min_uV = 1800000,
403 .max_uV = 1800000, 536 .max_uV = 1800000,
537 .apply_uV = true,
404 .valid_modes_mask = REGULATOR_MODE_NORMAL 538 .valid_modes_mask = REGULATOR_MODE_NORMAL
405 | REGULATOR_MODE_STANDBY, 539 | REGULATOR_MODE_STANDBY,
406 .valid_ops_mask = REGULATOR_CHANGE_MODE 540 .valid_ops_mask = REGULATOR_CHANGE_MODE
407 | REGULATOR_CHANGE_STATUS, 541 | REGULATOR_CHANGE_STATUS,
408 }, 542 },
409 .num_consumer_supplies = 1, 543 .num_consumer_supplies = ARRAY_SIZE(sdp3430_vpll2_supplies),
410 .consumer_supplies = &sdp3430_vdvi_supply, 544 .consumer_supplies = sdp3430_vpll2_supplies,
411}; 545};
412 546
413static struct twl4030_codec_audio_data sdp3430_audio = { 547static struct twl4030_codec_audio_data sdp3430_audio = {
@@ -521,6 +655,7 @@ static void __init omap_3430sdp_init(void)
521 omap_serial_init(); 655 omap_serial_init();
522 usb_musb_init(); 656 usb_musb_init();
523 board_smc91x_init(); 657 board_smc91x_init();
658 sdp3430_display_init();
524 enable_board_wakeup_source(); 659 enable_board_wakeup_source();
525 usb_ehci_init(&ehci_pdata); 660 usb_ehci_init(&ehci_pdata);
526} 661}
diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c
index e70e7e000eaa..845b478ebeee 100644
--- a/arch/arm/mach-omap2/clock24xx.c
+++ b/arch/arm/mach-omap2/clock24xx.c
@@ -116,10 +116,10 @@ static struct omap_clk omap24xx_clks[] = {
116 CLK(NULL, "mdm_ick", &mdm_ick, CK_243X), 116 CLK(NULL, "mdm_ick", &mdm_ick, CK_243X),
117 CLK(NULL, "mdm_osc_ck", &mdm_osc_ck, CK_243X), 117 CLK(NULL, "mdm_osc_ck", &mdm_osc_ck, CK_243X),
118 /* DSS domain clocks */ 118 /* DSS domain clocks */
119 CLK("omapfb", "ick", &dss_ick, CK_243X | CK_242X), 119 CLK("omapdss", "ick", &dss_ick, CK_243X | CK_242X),
120 CLK("omapfb", "dss1_fck", &dss1_fck, CK_243X | CK_242X), 120 CLK("omapdss", "dss1_fck", &dss1_fck, CK_243X | CK_242X),
121 CLK("omapfb", "dss2_fck", &dss2_fck, CK_243X | CK_242X), 121 CLK("omapdss", "dss2_fck", &dss2_fck, CK_243X | CK_242X),
122 CLK("omapfb", "tv_fck", &dss_54m_fck, CK_243X | CK_242X), 122 CLK("omapdss", "tv_fck", &dss_54m_fck, CK_243X | CK_242X),
123 /* L3 domain clocks */ 123 /* L3 domain clocks */
124 CLK(NULL, "core_l3_ck", &core_l3_ck, CK_243X | CK_242X), 124 CLK(NULL, "core_l3_ck", &core_l3_ck, CK_243X | CK_242X),
125 CLK(NULL, "ssi_fck", &ssi_ssr_sst_fck, CK_243X | CK_242X), 125 CLK(NULL, "ssi_fck", &ssi_ssr_sst_fck, CK_243X | CK_242X),
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index 9f2feaf79865..ecbb5cd8eec8 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -236,13 +236,13 @@ static struct omap_clk omap34xx_clks[] = {
236 CLK("omap_rng", "ick", &rng_ick, CK_343X), 236 CLK("omap_rng", "ick", &rng_ick, CK_343X),
237 CLK(NULL, "sha11_ick", &sha11_ick, CK_343X), 237 CLK(NULL, "sha11_ick", &sha11_ick, CK_343X),
238 CLK(NULL, "des1_ick", &des1_ick, CK_343X), 238 CLK(NULL, "des1_ick", &des1_ick, CK_343X),
239 CLK("omapfb", "dss1_fck", &dss1_alwon_fck_3430es1, CK_3430ES1), 239 CLK("omapdss", "dss1_fck", &dss1_alwon_fck_3430es1, CK_3430ES1),
240 CLK("omapfb", "dss1_fck", &dss1_alwon_fck_3430es2, CK_3430ES2), 240 CLK("omapdss", "dss1_fck", &dss1_alwon_fck_3430es2, CK_3430ES2),
241 CLK("omapfb", "tv_fck", &dss_tv_fck, CK_343X), 241 CLK("omapdss", "tv_fck", &dss_tv_fck, CK_343X),
242 CLK("omapfb", "video_fck", &dss_96m_fck, CK_343X), 242 CLK("omapdss", "video_fck", &dss_96m_fck, CK_343X),
243 CLK("omapfb", "dss2_fck", &dss2_alwon_fck, CK_343X), 243 CLK("omapdss", "dss2_fck", &dss2_alwon_fck, CK_343X),
244 CLK("omapfb", "ick", &dss_ick_3430es1, CK_3430ES1), 244 CLK("omapdss", "ick", &dss_ick_3430es1, CK_3430ES1),
245 CLK("omapfb", "ick", &dss_ick_3430es2, CK_3430ES2), 245 CLK("omapdss", "ick", &dss_ick_3430es2, CK_3430ES2),
246 CLK(NULL, "cam_mclk", &cam_mclk, CK_343X), 246 CLK(NULL, "cam_mclk", &cam_mclk, CK_343X),
247 CLK(NULL, "cam_ick", &cam_ick, CK_343X), 247 CLK(NULL, "cam_ick", &cam_ick, CK_343X),
248 CLK(NULL, "csi2_96m_fck", &csi2_96m_fck, CK_343X), 248 CLK(NULL, "csi2_96m_fck", &csi2_96m_fck, CK_343X),
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 59d28b2fd8c5..6a4d8e468703 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -22,17 +22,18 @@
22#include <linux/init.h> 22#include <linux/init.h>
23#include <linux/io.h> 23#include <linux/io.h>
24#include <linux/clk.h> 24#include <linux/clk.h>
25#include <linux/omapfb.h>
25 26
26#include <asm/tlb.h> 27#include <asm/tlb.h>
27 28
28#include <asm/mach/map.h> 29#include <asm/mach/map.h>
29 30
30#include <plat/mux.h> 31#include <plat/mux.h>
31#include <plat/omapfb.h>
32#include <plat/sram.h> 32#include <plat/sram.h>
33#include <plat/sdrc.h> 33#include <plat/sdrc.h>
34#include <plat/gpmc.h> 34#include <plat/gpmc.h>
35#include <plat/serial.h> 35#include <plat/serial.h>
36#include <plat/vram.h>
36 37
37#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdev is ready */ 38#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdev is ready */
38#include "clock.h" 39#include "clock.h"
@@ -264,6 +265,7 @@ void __init omap2_map_common_io(void)
264 omap2_check_revision(); 265 omap2_check_revision();
265 omap_sram_init(); 266 omap_sram_init();
266 omapfb_reserve_sdram(); 267 omapfb_reserve_sdram();
268 omap_vram_reserve_sdram();
267} 269}
268 270
269/* 271/*
diff --git a/arch/arm/mach-omap2/sdrc.c b/arch/arm/mach-omap2/sdrc.c
index 9a592199321c..cbfbd142e946 100644
--- a/arch/arm/mach-omap2/sdrc.c
+++ b/arch/arm/mach-omap2/sdrc.c
@@ -160,3 +160,19 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
160 sdrc_write_reg(l, SDRC_POWER); 160 sdrc_write_reg(l, SDRC_POWER);
161 omap2_sms_save_context(); 161 omap2_sms_save_context();
162} 162}
163
164void omap2_sms_write_rot_control(u32 val, unsigned ctx)
165{
166 sms_write_reg(val, SMS_ROT_CONTROL(ctx));
167}
168
169void omap2_sms_write_rot_size(u32 val, unsigned ctx)
170{
171 sms_write_reg(val, SMS_ROT_SIZE(ctx));
172}
173
174void omap2_sms_write_rot_physical_ba(u32 val, unsigned ctx)
175{
176 sms_write_reg(val, SMS_ROT_PHYSICAL_BA(ctx));
177}
178
diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c
index 78a4ce538dbd..d3eea4f47533 100644
--- a/arch/arm/plat-omap/fb.c
+++ b/arch/arm/plat-omap/fb.c
@@ -28,13 +28,13 @@
28#include <linux/platform_device.h> 28#include <linux/platform_device.h>
29#include <linux/bootmem.h> 29#include <linux/bootmem.h>
30#include <linux/io.h> 30#include <linux/io.h>
31#include <linux/omapfb.h>
31 32
32#include <mach/hardware.h> 33#include <mach/hardware.h>
33#include <asm/mach/map.h> 34#include <asm/mach/map.h>
34 35
35#include <plat/board.h> 36#include <plat/board.h>
36#include <plat/sram.h> 37#include <plat/sram.h>
37#include <plat/omapfb.h>
38 38
39#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE) 39#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
40 40
@@ -55,6 +55,10 @@ static struct platform_device omap_fb_device = {
55 .num_resources = 0, 55 .num_resources = 0,
56}; 56};
57 57
58void omapfb_set_platform_data(struct omapfb_platform_data *data)
59{
60}
61
58static inline int ranges_overlap(unsigned long start1, unsigned long size1, 62static inline int ranges_overlap(unsigned long start1, unsigned long size1,
59 unsigned long start2, unsigned long size2) 63 unsigned long start2, unsigned long size2)
60{ 64{
@@ -327,7 +331,33 @@ static inline int omap_init_fb(void)
327 331
328arch_initcall(omap_init_fb); 332arch_initcall(omap_init_fb);
329 333
330#else 334#elif defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
335
336static u64 omap_fb_dma_mask = ~(u32)0;
337static struct omapfb_platform_data omapfb_config;
338
339static struct platform_device omap_fb_device = {
340 .name = "omapfb",
341 .id = -1,
342 .dev = {
343 .dma_mask = &omap_fb_dma_mask,
344 .coherent_dma_mask = ~(u32)0,
345 .platform_data = &omapfb_config,
346 },
347 .num_resources = 0,
348};
349
350void omapfb_set_platform_data(struct omapfb_platform_data *data)
351{
352 omapfb_config = *data;
353}
354
355static inline int omap_init_fb(void)
356{
357 return platform_device_register(&omap_fb_device);
358}
359
360arch_initcall(omap_init_fb);
331 361
332void omapfb_reserve_sdram(void) {} 362void omapfb_reserve_sdram(void) {}
333unsigned long omapfb_reserve_sram(unsigned long sram_pstart, 363unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
@@ -339,5 +369,20 @@ unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
339 return 0; 369 return 0;
340} 370}
341 371
372#else
373
374void omapfb_set_platform_data(struct omapfb_platform_data *data)
375{
376}
377
378void omapfb_reserve_sdram(void) {}
379unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
380 unsigned long sram_vstart,
381 unsigned long sram_size,
382 unsigned long start_avail,
383 unsigned long size_avail)
384{
385 return 0;
386}
342 387
343#endif 388#endif
diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h
new file mode 100644
index 000000000000..c66e464732df
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/display.h
@@ -0,0 +1,575 @@
1/*
2 * linux/include/asm-arm/arch-omap/display.h
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#ifndef __ASM_ARCH_OMAP_DISPLAY_H
21#define __ASM_ARCH_OMAP_DISPLAY_H
22
23#include <linux/list.h>
24#include <linux/kobject.h>
25#include <linux/device.h>
26#include <asm/atomic.h>
27
28#define DISPC_IRQ_FRAMEDONE (1 << 0)
29#define DISPC_IRQ_VSYNC (1 << 1)
30#define DISPC_IRQ_EVSYNC_EVEN (1 << 2)
31#define DISPC_IRQ_EVSYNC_ODD (1 << 3)
32#define DISPC_IRQ_ACBIAS_COUNT_STAT (1 << 4)
33#define DISPC_IRQ_PROG_LINE_NUM (1 << 5)
34#define DISPC_IRQ_GFX_FIFO_UNDERFLOW (1 << 6)
35#define DISPC_IRQ_GFX_END_WIN (1 << 7)
36#define DISPC_IRQ_PAL_GAMMA_MASK (1 << 8)
37#define DISPC_IRQ_OCP_ERR (1 << 9)
38#define DISPC_IRQ_VID1_FIFO_UNDERFLOW (1 << 10)
39#define DISPC_IRQ_VID1_END_WIN (1 << 11)
40#define DISPC_IRQ_VID2_FIFO_UNDERFLOW (1 << 12)
41#define DISPC_IRQ_VID2_END_WIN (1 << 13)
42#define DISPC_IRQ_SYNC_LOST (1 << 14)
43#define DISPC_IRQ_SYNC_LOST_DIGIT (1 << 15)
44#define DISPC_IRQ_WAKEUP (1 << 16)
45
46struct omap_dss_device;
47struct omap_overlay_manager;
48
49enum omap_display_type {
50 OMAP_DISPLAY_TYPE_NONE = 0,
51 OMAP_DISPLAY_TYPE_DPI = 1 << 0,
52 OMAP_DISPLAY_TYPE_DBI = 1 << 1,
53 OMAP_DISPLAY_TYPE_SDI = 1 << 2,
54 OMAP_DISPLAY_TYPE_DSI = 1 << 3,
55 OMAP_DISPLAY_TYPE_VENC = 1 << 4,
56};
57
58enum omap_plane {
59 OMAP_DSS_GFX = 0,
60 OMAP_DSS_VIDEO1 = 1,
61 OMAP_DSS_VIDEO2 = 2
62};
63
64enum omap_channel {
65 OMAP_DSS_CHANNEL_LCD = 0,
66 OMAP_DSS_CHANNEL_DIGIT = 1,
67};
68
69enum omap_color_mode {
70 OMAP_DSS_COLOR_CLUT1 = 1 << 0, /* BITMAP 1 */
71 OMAP_DSS_COLOR_CLUT2 = 1 << 1, /* BITMAP 2 */
72 OMAP_DSS_COLOR_CLUT4 = 1 << 2, /* BITMAP 4 */
73 OMAP_DSS_COLOR_CLUT8 = 1 << 3, /* BITMAP 8 */
74 OMAP_DSS_COLOR_RGB12U = 1 << 4, /* RGB12, 16-bit container */
75 OMAP_DSS_COLOR_ARGB16 = 1 << 5, /* ARGB16 */
76 OMAP_DSS_COLOR_RGB16 = 1 << 6, /* RGB16 */
77 OMAP_DSS_COLOR_RGB24U = 1 << 7, /* RGB24, 32-bit container */
78 OMAP_DSS_COLOR_RGB24P = 1 << 8, /* RGB24, 24-bit container */
79 OMAP_DSS_COLOR_YUV2 = 1 << 9, /* YUV2 4:2:2 co-sited */
80 OMAP_DSS_COLOR_UYVY = 1 << 10, /* UYVY 4:2:2 co-sited */
81 OMAP_DSS_COLOR_ARGB32 = 1 << 11, /* ARGB32 */
82 OMAP_DSS_COLOR_RGBA32 = 1 << 12, /* RGBA32 */
83 OMAP_DSS_COLOR_RGBX32 = 1 << 13, /* RGBx32 */
84
85 OMAP_DSS_COLOR_GFX_OMAP2 =
86 OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
87 OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
88 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
89 OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P,
90
91 OMAP_DSS_COLOR_VID_OMAP2 =
92 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
93 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
94 OMAP_DSS_COLOR_UYVY,
95
96 OMAP_DSS_COLOR_GFX_OMAP3 =
97 OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
98 OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
99 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
100 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
101 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
102 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
103
104 OMAP_DSS_COLOR_VID1_OMAP3 =
105 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
106 OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
107 OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
108
109 OMAP_DSS_COLOR_VID2_OMAP3 =
110 OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
111 OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
112 OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
113 OMAP_DSS_COLOR_UYVY | OMAP_DSS_COLOR_ARGB32 |
114 OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
115};
116
117enum omap_lcd_display_type {
118 OMAP_DSS_LCD_DISPLAY_STN,
119 OMAP_DSS_LCD_DISPLAY_TFT,
120};
121
122enum omap_dss_load_mode {
123 OMAP_DSS_LOAD_CLUT_AND_FRAME = 0,
124 OMAP_DSS_LOAD_CLUT_ONLY = 1,
125 OMAP_DSS_LOAD_FRAME_ONLY = 2,
126 OMAP_DSS_LOAD_CLUT_ONCE_FRAME = 3,
127};
128
129enum omap_dss_trans_key_type {
130 OMAP_DSS_COLOR_KEY_GFX_DST = 0,
131 OMAP_DSS_COLOR_KEY_VID_SRC = 1,
132};
133
134enum omap_rfbi_te_mode {
135 OMAP_DSS_RFBI_TE_MODE_1 = 1,
136 OMAP_DSS_RFBI_TE_MODE_2 = 2,
137};
138
139enum omap_panel_config {
140 OMAP_DSS_LCD_IVS = 1<<0,
141 OMAP_DSS_LCD_IHS = 1<<1,
142 OMAP_DSS_LCD_IPC = 1<<2,
143 OMAP_DSS_LCD_IEO = 1<<3,
144 OMAP_DSS_LCD_RF = 1<<4,
145 OMAP_DSS_LCD_ONOFF = 1<<5,
146
147 OMAP_DSS_LCD_TFT = 1<<20,
148};
149
150enum omap_dss_venc_type {
151 OMAP_DSS_VENC_TYPE_COMPOSITE,
152 OMAP_DSS_VENC_TYPE_SVIDEO,
153};
154
155enum omap_display_caps {
156 OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE = 1 << 0,
157 OMAP_DSS_DISPLAY_CAP_TEAR_ELIM = 1 << 1,
158};
159
160enum omap_dss_update_mode {
161 OMAP_DSS_UPDATE_DISABLED = 0,
162 OMAP_DSS_UPDATE_AUTO,
163 OMAP_DSS_UPDATE_MANUAL,
164};
165
166enum omap_dss_display_state {
167 OMAP_DSS_DISPLAY_DISABLED = 0,
168 OMAP_DSS_DISPLAY_ACTIVE,
169 OMAP_DSS_DISPLAY_SUSPENDED,
170};
171
172/* XXX perhaps this should be removed */
173enum omap_dss_overlay_managers {
174 OMAP_DSS_OVL_MGR_LCD,
175 OMAP_DSS_OVL_MGR_TV,
176};
177
178enum omap_dss_rotation_type {
179 OMAP_DSS_ROT_DMA = 0,
180 OMAP_DSS_ROT_VRFB = 1,
181};
182
183/* clockwise rotation angle */
184enum omap_dss_rotation_angle {
185 OMAP_DSS_ROT_0 = 0,
186 OMAP_DSS_ROT_90 = 1,
187 OMAP_DSS_ROT_180 = 2,
188 OMAP_DSS_ROT_270 = 3,
189};
190
191enum omap_overlay_caps {
192 OMAP_DSS_OVL_CAP_SCALE = 1 << 0,
193 OMAP_DSS_OVL_CAP_DISPC = 1 << 1,
194};
195
196enum omap_overlay_manager_caps {
197 OMAP_DSS_OVL_MGR_CAP_DISPC = 1 << 0,
198};
199
200/* RFBI */
201
202struct rfbi_timings {
203 int cs_on_time;
204 int cs_off_time;
205 int we_on_time;
206 int we_off_time;
207 int re_on_time;
208 int re_off_time;
209 int we_cycle_time;
210 int re_cycle_time;
211 int cs_pulse_width;
212 int access_time;
213
214 int clk_div;
215
216 u32 tim[5]; /* set by rfbi_convert_timings() */
217
218 int converted;
219};
220
221void omap_rfbi_write_command(const void *buf, u32 len);
222void omap_rfbi_read_data(void *buf, u32 len);
223void omap_rfbi_write_data(const void *buf, u32 len);
224void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
225 u16 x, u16 y,
226 u16 w, u16 h);
227int omap_rfbi_enable_te(bool enable, unsigned line);
228int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
229 unsigned hs_pulse_time, unsigned vs_pulse_time,
230 int hs_pol_inv, int vs_pol_inv, int extif_div);
231
232/* DSI */
233void dsi_bus_lock(void);
234void dsi_bus_unlock(void);
235int dsi_vc_dcs_write(int channel, u8 *data, int len);
236int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len);
237int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen);
238int dsi_vc_set_max_rx_packet_size(int channel, u16 len);
239int dsi_vc_send_null(int channel);
240int dsi_vc_send_bta_sync(int channel);
241
242/* Board specific data */
243struct omap_dss_board_info {
244 int (*get_last_off_on_transaction_id)(struct device *dev);
245 int num_devices;
246 struct omap_dss_device **devices;
247 struct omap_dss_device *default_device;
248};
249
250struct omap_video_timings {
251 /* Unit: pixels */
252 u16 x_res;
253 /* Unit: pixels */
254 u16 y_res;
255 /* Unit: KHz */
256 u32 pixel_clock;
257 /* Unit: pixel clocks */
258 u16 hsw; /* Horizontal synchronization pulse width */
259 /* Unit: pixel clocks */
260 u16 hfp; /* Horizontal front porch */
261 /* Unit: pixel clocks */
262 u16 hbp; /* Horizontal back porch */
263 /* Unit: line clocks */
264 u16 vsw; /* Vertical synchronization pulse width */
265 /* Unit: line clocks */
266 u16 vfp; /* Vertical front porch */
267 /* Unit: line clocks */
268 u16 vbp; /* Vertical back porch */
269};
270
271#ifdef CONFIG_OMAP2_DSS_VENC
272/* Hardcoded timings for tv modes. Venc only uses these to
273 * identify the mode, and does not actually use the configs
274 * itself. However, the configs should be something that
275 * a normal monitor can also show */
276const extern struct omap_video_timings omap_dss_pal_timings;
277const extern struct omap_video_timings omap_dss_ntsc_timings;
278#endif
279
280struct omap_overlay_info {
281 bool enabled;
282
283 u32 paddr;
284 void __iomem *vaddr;
285 u16 screen_width;
286 u16 width;
287 u16 height;
288 enum omap_color_mode color_mode;
289 u8 rotation;
290 enum omap_dss_rotation_type rotation_type;
291 bool mirror;
292
293 u16 pos_x;
294 u16 pos_y;
295 u16 out_width; /* if 0, out_width == width */
296 u16 out_height; /* if 0, out_height == height */
297 u8 global_alpha;
298};
299
300struct omap_overlay {
301 struct kobject kobj;
302 struct list_head list;
303
304 /* static fields */
305 const char *name;
306 int id;
307 enum omap_color_mode supported_modes;
308 enum omap_overlay_caps caps;
309
310 /* dynamic fields */
311 struct omap_overlay_manager *manager;
312 struct omap_overlay_info info;
313
314 /* if true, info has been changed, but not applied() yet */
315 bool info_dirty;
316
317 int (*set_manager)(struct omap_overlay *ovl,
318 struct omap_overlay_manager *mgr);
319 int (*unset_manager)(struct omap_overlay *ovl);
320
321 int (*set_overlay_info)(struct omap_overlay *ovl,
322 struct omap_overlay_info *info);
323 void (*get_overlay_info)(struct omap_overlay *ovl,
324 struct omap_overlay_info *info);
325
326 int (*wait_for_go)(struct omap_overlay *ovl);
327};
328
329struct omap_overlay_manager_info {
330 u32 default_color;
331
332 enum omap_dss_trans_key_type trans_key_type;
333 u32 trans_key;
334 bool trans_enabled;
335
336 bool alpha_enabled;
337};
338
339struct omap_overlay_manager {
340 struct kobject kobj;
341 struct list_head list;
342
343 /* static fields */
344 const char *name;
345 int id;
346 enum omap_overlay_manager_caps caps;
347 int num_overlays;
348 struct omap_overlay **overlays;
349 enum omap_display_type supported_displays;
350
351 /* dynamic fields */
352 struct omap_dss_device *device;
353 struct omap_overlay_manager_info info;
354
355 bool device_changed;
356 /* if true, info has been changed but not applied() yet */
357 bool info_dirty;
358
359 int (*set_device)(struct omap_overlay_manager *mgr,
360 struct omap_dss_device *dssdev);
361 int (*unset_device)(struct omap_overlay_manager *mgr);
362
363 int (*set_manager_info)(struct omap_overlay_manager *mgr,
364 struct omap_overlay_manager_info *info);
365 void (*get_manager_info)(struct omap_overlay_manager *mgr,
366 struct omap_overlay_manager_info *info);
367
368 int (*apply)(struct omap_overlay_manager *mgr);
369 int (*wait_for_go)(struct omap_overlay_manager *mgr);
370};
371
372struct omap_dss_device {
373 struct device dev;
374
375 enum omap_display_type type;
376
377 union {
378 struct {
379 u8 data_lines;
380 } dpi;
381
382 struct {
383 u8 channel;
384 u8 data_lines;
385 } rfbi;
386
387 struct {
388 u8 datapairs;
389 } sdi;
390
391 struct {
392 u8 clk_lane;
393 u8 clk_pol;
394 u8 data1_lane;
395 u8 data1_pol;
396 u8 data2_lane;
397 u8 data2_pol;
398
399 struct {
400 u16 regn;
401 u16 regm;
402 u16 regm3;
403 u16 regm4;
404
405 u16 lp_clk_div;
406
407 u16 lck_div;
408 u16 pck_div;
409 } div;
410
411 bool ext_te;
412 u8 ext_te_gpio;
413 } dsi;
414
415 struct {
416 enum omap_dss_venc_type type;
417 bool invert_polarity;
418 } venc;
419 } phy;
420
421 struct {
422 struct omap_video_timings timings;
423
424 int acbi; /* ac-bias pin transitions per interrupt */
425 /* Unit: line clocks */
426 int acb; /* ac-bias pin frequency */
427
428 enum omap_panel_config config;
429
430 u8 recommended_bpp;
431
432 struct omap_dss_device *ctrl;
433 } panel;
434
435 struct {
436 u8 pixel_size;
437 struct rfbi_timings rfbi_timings;
438 struct omap_dss_device *panel;
439 } ctrl;
440
441 int reset_gpio;
442
443 int max_backlight_level;
444
445 const char *name;
446
447 /* used to match device to driver */
448 const char *driver_name;
449
450 void *data;
451
452 struct omap_dss_driver *driver;
453
454 /* helper variable for driver suspend/resume */
455 bool activate_after_resume;
456
457 enum omap_display_caps caps;
458
459 struct omap_overlay_manager *manager;
460
461 enum omap_dss_display_state state;
462
463 int (*enable)(struct omap_dss_device *dssdev);
464 void (*disable)(struct omap_dss_device *dssdev);
465
466 int (*suspend)(struct omap_dss_device *dssdev);
467 int (*resume)(struct omap_dss_device *dssdev);
468
469 void (*get_resolution)(struct omap_dss_device *dssdev,
470 u16 *xres, u16 *yres);
471 int (*get_recommended_bpp)(struct omap_dss_device *dssdev);
472
473 int (*check_timings)(struct omap_dss_device *dssdev,
474 struct omap_video_timings *timings);
475 void (*set_timings)(struct omap_dss_device *dssdev,
476 struct omap_video_timings *timings);
477 void (*get_timings)(struct omap_dss_device *dssdev,
478 struct omap_video_timings *timings);
479 int (*update)(struct omap_dss_device *dssdev,
480 u16 x, u16 y, u16 w, u16 h);
481 int (*sync)(struct omap_dss_device *dssdev);
482 int (*wait_vsync)(struct omap_dss_device *dssdev);
483
484 int (*set_update_mode)(struct omap_dss_device *dssdev,
485 enum omap_dss_update_mode);
486 enum omap_dss_update_mode (*get_update_mode)
487 (struct omap_dss_device *dssdev);
488
489 int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
490 int (*get_te)(struct omap_dss_device *dssdev);
491
492 u8 (*get_rotate)(struct omap_dss_device *dssdev);
493 int (*set_rotate)(struct omap_dss_device *dssdev, u8 rotate);
494
495 bool (*get_mirror)(struct omap_dss_device *dssdev);
496 int (*set_mirror)(struct omap_dss_device *dssdev, bool enable);
497
498 int (*run_test)(struct omap_dss_device *dssdev, int test);
499 int (*memory_read)(struct omap_dss_device *dssdev,
500 void *buf, size_t size,
501 u16 x, u16 y, u16 w, u16 h);
502
503 int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
504 u32 (*get_wss)(struct omap_dss_device *dssdev);
505
506 /* platform specific */
507 int (*platform_enable)(struct omap_dss_device *dssdev);
508 void (*platform_disable)(struct omap_dss_device *dssdev);
509 int (*set_backlight)(struct omap_dss_device *dssdev, int level);
510 int (*get_backlight)(struct omap_dss_device *dssdev);
511};
512
513struct omap_dss_driver {
514 struct device_driver driver;
515
516 int (*probe)(struct omap_dss_device *);
517 void (*remove)(struct omap_dss_device *);
518
519 int (*enable)(struct omap_dss_device *display);
520 void (*disable)(struct omap_dss_device *display);
521 int (*suspend)(struct omap_dss_device *display);
522 int (*resume)(struct omap_dss_device *display);
523 int (*run_test)(struct omap_dss_device *display, int test);
524
525 void (*setup_update)(struct omap_dss_device *dssdev,
526 u16 x, u16 y, u16 w, u16 h);
527
528 int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
529 int (*wait_for_te)(struct omap_dss_device *dssdev);
530
531 u8 (*get_rotate)(struct omap_dss_device *dssdev);
532 int (*set_rotate)(struct omap_dss_device *dssdev, u8 rotate);
533
534 bool (*get_mirror)(struct omap_dss_device *dssdev);
535 int (*set_mirror)(struct omap_dss_device *dssdev, bool enable);
536
537 int (*memory_read)(struct omap_dss_device *dssdev,
538 void *buf, size_t size,
539 u16 x, u16 y, u16 w, u16 h);
540};
541
542int omap_dss_register_driver(struct omap_dss_driver *);
543void omap_dss_unregister_driver(struct omap_dss_driver *);
544
545int omap_dss_register_device(struct omap_dss_device *);
546void omap_dss_unregister_device(struct omap_dss_device *);
547
548void omap_dss_get_device(struct omap_dss_device *dssdev);
549void omap_dss_put_device(struct omap_dss_device *dssdev);
550#define for_each_dss_dev(d) while ((d = omap_dss_get_next_device(d)) != NULL)
551struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from);
552struct omap_dss_device *omap_dss_find_device(void *data,
553 int (*match)(struct omap_dss_device *dssdev, void *data));
554
555int omap_dss_start_device(struct omap_dss_device *dssdev);
556void omap_dss_stop_device(struct omap_dss_device *dssdev);
557
558int omap_dss_get_num_overlay_managers(void);
559struct omap_overlay_manager *omap_dss_get_overlay_manager(int num);
560
561int omap_dss_get_num_overlays(void);
562struct omap_overlay *omap_dss_get_overlay(int num);
563
564typedef void (*omap_dispc_isr_t) (void *arg, u32 mask);
565int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
566int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
567
568int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout);
569int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
570 unsigned long timeout);
571
572#define to_dss_driver(x) container_of((x), struct omap_dss_driver, driver)
573#define to_dss_device(x) container_of((x), struct omap_dss_device, dev)
574
575#endif
diff --git a/arch/arm/plat-omap/include/plat/sdrc.h b/arch/arm/plat-omap/include/plat/sdrc.h
index f704030d2a70..7b76f50564ba 100644
--- a/arch/arm/plat-omap/include/plat/sdrc.h
+++ b/arch/arm/plat-omap/include/plat/sdrc.h
@@ -94,7 +94,10 @@
94 94
95/* SMS register offsets - read/write with sms_{read,write}_reg() */ 95/* SMS register offsets - read/write with sms_{read,write}_reg() */
96 96
97#define SMS_SYSCONFIG 0x010 97#define SMS_SYSCONFIG 0x010
98#define SMS_ROT_CONTROL(context) (0x180 + 0x10 * context)
99#define SMS_ROT_SIZE(context) (0x184 + 0x10 * context)
100#define SMS_ROT_PHYSICAL_BA(context) (0x188 + 0x10 * context)
98/* REVISIT: fill in other SMS registers here */ 101/* REVISIT: fill in other SMS registers here */
99 102
100 103
@@ -129,6 +132,10 @@ int omap2_sdrc_get_params(unsigned long r,
129void omap2_sms_save_context(void); 132void omap2_sms_save_context(void);
130void omap2_sms_restore_context(void); 133void omap2_sms_restore_context(void);
131 134
135void omap2_sms_write_rot_control(u32 val, unsigned ctx);
136void omap2_sms_write_rot_size(u32 val, unsigned ctx);
137void omap2_sms_write_rot_physical_ba(u32 val, unsigned ctx);
138
132#ifdef CONFIG_ARCH_OMAP2 139#ifdef CONFIG_ARCH_OMAP2
133 140
134struct memory_timings { 141struct memory_timings {
diff --git a/arch/arm/plat-omap/include/plat/vram.h b/arch/arm/plat-omap/include/plat/vram.h
new file mode 100644
index 000000000000..edd4987758a6
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/vram.h
@@ -0,0 +1,62 @@
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#ifndef __OMAP_VRAM_H__
22#define __OMAP_VRAM_H__
23
24#include <linux/types.h>
25
26#define OMAP_VRAM_MEMTYPE_SDRAM 0
27#define OMAP_VRAM_MEMTYPE_SRAM 1
28#define OMAP_VRAM_MEMTYPE_MAX 1
29
30extern int omap_vram_add_region(unsigned long paddr, size_t size);
31extern int omap_vram_free(unsigned long paddr, size_t size);
32extern int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr);
33extern int omap_vram_reserve(unsigned long paddr, size_t size);
34extern void omap_vram_get_info(unsigned long *vram, unsigned long *free_vram,
35 unsigned long *largest_free_block);
36
37#ifdef CONFIG_OMAP2_VRAM
38extern void omap_vram_set_sdram_vram(u32 size, u32 start);
39extern void omap_vram_set_sram_vram(u32 size, u32 start);
40
41extern void omap_vram_reserve_sdram(void);
42extern unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
43 unsigned long sram_vstart,
44 unsigned long sram_size,
45 unsigned long pstart_avail,
46 unsigned long size_avail);
47#else
48static inline void omap_vram_set_sdram_vram(u32 size, u32 start) { }
49static inline void omap_vram_set_sram_vram(u32 size, u32 start) { }
50
51static inline void omap_vram_reserve_sdram(void) { }
52static inline unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
53 unsigned long sram_vstart,
54 unsigned long sram_size,
55 unsigned long pstart_avail,
56 unsigned long size_avail)
57{
58 return 0;
59}
60#endif
61
62#endif
diff --git a/arch/arm/plat-omap/include/plat/vrfb.h b/arch/arm/plat-omap/include/plat/vrfb.h
new file mode 100644
index 000000000000..d8a03ced3b10
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/vrfb.h
@@ -0,0 +1,50 @@
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#ifndef __OMAP_VRFB_H__
22#define __OMAP_VRFB_H__
23
24#define OMAP_VRFB_LINE_LEN 2048
25
26struct vrfb {
27 u8 context;
28 void __iomem *vaddr[4];
29 unsigned long paddr[4];
30 u16 xres;
31 u16 yres;
32 u16 xoffset;
33 u16 yoffset;
34 u8 bytespp;
35 bool yuv_mode;
36};
37
38extern int omap_vrfb_request_ctx(struct vrfb *vrfb);
39extern void omap_vrfb_release_ctx(struct vrfb *vrfb);
40extern void omap_vrfb_adjust_size(u16 *width, u16 *height,
41 u8 bytespp);
42extern u32 omap_vrfb_min_phys_size(u16 width, u16 height, u8 bytespp);
43extern u16 omap_vrfb_max_height(u32 phys_size, u16 width, u8 bytespp);
44extern void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
45 u16 width, u16 height,
46 unsigned bytespp, bool yuv_mode);
47extern int omap_vrfb_map_angle(struct vrfb *vrfb, u16 height, u8 rot);
48extern void omap_vrfb_restore_context(void);
49
50#endif /* __VRFB_H */
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 3e923668778d..ad2bf07d30b5 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -28,6 +28,7 @@
28#include <plat/sram.h> 28#include <plat/sram.h>
29#include <plat/board.h> 29#include <plat/board.h>
30#include <plat/cpu.h> 30#include <plat/cpu.h>
31#include <plat/vram.h>
31 32
32#include <plat/control.h> 33#include <plat/control.h>
33 34
@@ -185,6 +186,13 @@ void __init omap_detect_sram(void)
185 omap_sram_start + SRAM_BOOTLOADER_SZ, 186 omap_sram_start + SRAM_BOOTLOADER_SZ,
186 omap_sram_size - SRAM_BOOTLOADER_SZ); 187 omap_sram_size - SRAM_BOOTLOADER_SZ);
187 omap_sram_size -= reserved; 188 omap_sram_size -= reserved;
189
190 reserved = omap_vram_reserve_sram(omap_sram_start, omap_sram_base,
191 omap_sram_size,
192 omap_sram_start + SRAM_BOOTLOADER_SZ,
193 omap_sram_size - SRAM_BOOTLOADER_SZ);
194 omap_sram_size -= reserved;
195
188 omap_sram_ceil = omap_sram_base + omap_sram_size; 196 omap_sram_ceil = omap_sram_base + omap_sram_size;
189} 197}
190 198
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e9f193e6b27e..bb5fbed89e7f 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2165,6 +2165,7 @@ config FB_BROADSHEET
2165 a bridge adapter. 2165 a bridge adapter.
2166 2166
2167source "drivers/video/omap/Kconfig" 2167source "drivers/video/omap/Kconfig"
2168source "drivers/video/omap2/Kconfig"
2168 2169
2169source "drivers/video/backlight/Kconfig" 2170source "drivers/video/backlight/Kconfig"
2170source "drivers/video/display/Kconfig" 2171source "drivers/video/display/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 80232e124889..0f8da331ba0f 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -124,6 +124,7 @@ obj-$(CONFIG_FB_SM501) += sm501fb.o
124obj-$(CONFIG_FB_XILINX) += xilinxfb.o 124obj-$(CONFIG_FB_XILINX) += xilinxfb.o
125obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o 125obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
126obj-$(CONFIG_FB_OMAP) += omap/ 126obj-$(CONFIG_FB_OMAP) += omap/
127obj-y += omap2/
127obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o 128obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
128obj-$(CONFIG_FB_CARMINE) += carminefb.o 129obj-$(CONFIG_FB_CARMINE) += carminefb.o
129obj-$(CONFIG_FB_MB862XX) += mb862xx/ 130obj-$(CONFIG_FB_MB862XX) += mb862xx/
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
index 551e3e9c4cbe..455c6055325d 100644
--- a/drivers/video/omap/Kconfig
+++ b/drivers/video/omap/Kconfig
@@ -1,6 +1,7 @@
1config FB_OMAP 1config FB_OMAP
2 tristate "OMAP frame buffer support (EXPERIMENTAL)" 2 tristate "OMAP frame buffer support (EXPERIMENTAL)"
3 depends on FB && ARCH_OMAP 3 depends on FB && ARCH_OMAP && (OMAP2_DSS = "n")
4
4 select FB_CFB_FILLRECT 5 select FB_CFB_FILLRECT
5 select FB_CFB_COPYAREA 6 select FB_CFB_COPYAREA
6 select FB_CFB_IMAGEBLIT 7 select FB_CFB_IMAGEBLIT
@@ -72,7 +73,7 @@ config FB_OMAP_LCD_MIPID
72 73
73config FB_OMAP_BOOTLOADER_INIT 74config FB_OMAP_BOOTLOADER_INIT
74 bool "Check bootloader initialization" 75 bool "Check bootloader initialization"
75 depends on FB_OMAP 76 depends on FB_OMAP || FB_OMAP2
76 help 77 help
77 Say Y here if you want to enable checking if the bootloader has 78 Say Y here if you want to enable checking if the bootloader has
78 already initialized the display controller. In this case the 79 already initialized the display controller. In this case the
diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c
index f5d75f22cef9..2ffb34af4c59 100644
--- a/drivers/video/omap/blizzard.c
+++ b/drivers/video/omap/blizzard.c
@@ -27,9 +27,9 @@
27#include <linux/clk.h> 27#include <linux/clk.h>
28 28
29#include <plat/dma.h> 29#include <plat/dma.h>
30#include <plat/omapfb.h>
31#include <plat/blizzard.h> 30#include <plat/blizzard.h>
32 31
32#include "omapfb.h"
33#include "dispc.h" 33#include "dispc.h"
34 34
35#define MODULE_NAME "blizzard" 35#define MODULE_NAME "blizzard"
diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c
index 7c833db4f9b7..c7c6455f1fa8 100644
--- a/drivers/video/omap/dispc.c
+++ b/drivers/video/omap/dispc.c
@@ -24,11 +24,12 @@
24#include <linux/vmalloc.h> 24#include <linux/vmalloc.h>
25#include <linux/clk.h> 25#include <linux/clk.h>
26#include <linux/io.h> 26#include <linux/io.h>
27#include <linux/platform_device.h>
27 28
28#include <plat/sram.h> 29#include <plat/sram.h>
29#include <plat/omapfb.h>
30#include <plat/board.h> 30#include <plat/board.h>
31 31
32#include "omapfb.h"
32#include "dispc.h" 33#include "dispc.h"
33 34
34#define MODULE_NAME "dispc" 35#define MODULE_NAME "dispc"
@@ -188,6 +189,11 @@ static struct {
188 struct omapfb_color_key color_key; 189 struct omapfb_color_key color_key;
189} dispc; 190} dispc;
190 191
192static struct platform_device omapdss_device = {
193 .name = "omapdss",
194 .id = -1,
195};
196
191static void enable_lcd_clocks(int enable); 197static void enable_lcd_clocks(int enable);
192 198
193static void inline dispc_write_reg(int idx, u32 val) 199static void inline dispc_write_reg(int idx, u32 val)
@@ -914,20 +920,20 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
914 920
915static int get_dss_clocks(void) 921static int get_dss_clocks(void)
916{ 922{
917 dispc.dss_ick = clk_get(dispc.fbdev->dev, "ick"); 923 dispc.dss_ick = clk_get(&omapdss_device.dev, "ick");
918 if (IS_ERR(dispc.dss_ick)) { 924 if (IS_ERR(dispc.dss_ick)) {
919 dev_err(dispc.fbdev->dev, "can't get ick\n"); 925 dev_err(dispc.fbdev->dev, "can't get ick\n");
920 return PTR_ERR(dispc.dss_ick); 926 return PTR_ERR(dispc.dss_ick);
921 } 927 }
922 928
923 dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck"); 929 dispc.dss1_fck = clk_get(&omapdss_device.dev, "dss1_fck");
924 if (IS_ERR(dispc.dss1_fck)) { 930 if (IS_ERR(dispc.dss1_fck)) {
925 dev_err(dispc.fbdev->dev, "can't get dss1_fck\n"); 931 dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
926 clk_put(dispc.dss_ick); 932 clk_put(dispc.dss_ick);
927 return PTR_ERR(dispc.dss1_fck); 933 return PTR_ERR(dispc.dss1_fck);
928 } 934 }
929 935
930 dispc.dss_54m_fck = clk_get(dispc.fbdev->dev, "tv_fck"); 936 dispc.dss_54m_fck = clk_get(&omapdss_device.dev, "tv_fck");
931 if (IS_ERR(dispc.dss_54m_fck)) { 937 if (IS_ERR(dispc.dss_54m_fck)) {
932 dev_err(dispc.fbdev->dev, "can't get tv_fck\n"); 938 dev_err(dispc.fbdev->dev, "can't get tv_fck\n");
933 clk_put(dispc.dss_ick); 939 clk_put(dispc.dss_ick);
@@ -1379,6 +1385,12 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
1379 int skip_init = 0; 1385 int skip_init = 0;
1380 int i; 1386 int i;
1381 1387
1388 r = platform_device_register(&omapdss_device);
1389 if (r) {
1390 dev_err(fbdev->dev, "can't register omapdss device\n");
1391 return r;
1392 }
1393
1382 memset(&dispc, 0, sizeof(dispc)); 1394 memset(&dispc, 0, sizeof(dispc));
1383 1395
1384 dispc.base = ioremap(DISPC_BASE, SZ_1K); 1396 dispc.base = ioremap(DISPC_BASE, SZ_1K);
@@ -1522,6 +1534,7 @@ static void omap_dispc_cleanup(void)
1522 free_irq(INT_24XX_DSS_IRQ, dispc.fbdev); 1534 free_irq(INT_24XX_DSS_IRQ, dispc.fbdev);
1523 put_dss_clocks(); 1535 put_dss_clocks();
1524 iounmap(dispc.base); 1536 iounmap(dispc.base);
1537 platform_device_unregister(&omapdss_device);
1525} 1538}
1526 1539
1527const struct lcd_ctrl omap2_int_ctrl = { 1540const struct lcd_ctrl omap2_int_ctrl = {
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c
index 17a975e4c9c9..0016f77cd13f 100644
--- a/drivers/video/omap/hwa742.c
+++ b/drivers/video/omap/hwa742.c
@@ -25,10 +25,11 @@
25#include <linux/fb.h> 25#include <linux/fb.h>
26#include <linux/delay.h> 26#include <linux/delay.h>
27#include <linux/clk.h> 27#include <linux/clk.h>
28#include <linux/interrupt.h>
28 29
29#include <plat/dma.h> 30#include <plat/dma.h>
30#include <plat/omapfb.h>
31#include <plat/hwa742.h> 31#include <plat/hwa742.h>
32#include "omapfb.h"
32 33
33#define HWA742_REV_CODE_REG 0x0 34#define HWA742_REV_CODE_REG 0x0
34#define HWA742_CONFIG_REG 0x2 35#define HWA742_CONFIG_REG 0x2
diff --git a/drivers/video/omap/lcd_2430sdp.c b/drivers/video/omap/lcd_2430sdp.c
index fea7feee0b77..760645d9dbb6 100644
--- a/drivers/video/omap/lcd_2430sdp.c
+++ b/drivers/video/omap/lcd_2430sdp.c
@@ -28,9 +28,10 @@
28#include <linux/i2c/twl4030.h> 28#include <linux/i2c/twl4030.h>
29 29
30#include <plat/mux.h> 30#include <plat/mux.h>
31#include <plat/omapfb.h>
32#include <asm/mach-types.h> 31#include <asm/mach-types.h>
33 32
33#include "omapfb.h"
34
34#define SDP2430_LCD_PANEL_BACKLIGHT_GPIO 91 35#define SDP2430_LCD_PANEL_BACKLIGHT_GPIO 91
35#define SDP2430_LCD_PANEL_ENABLE_GPIO 154 36#define SDP2430_LCD_PANEL_ENABLE_GPIO 154
36#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 24 37#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 24
diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c
index b3973ebd1b0f..567db6ac32c8 100644
--- a/drivers/video/omap/lcd_ams_delta.c
+++ b/drivers/video/omap/lcd_ams_delta.c
@@ -27,7 +27,8 @@
27 27
28#include <plat/board-ams-delta.h> 28#include <plat/board-ams-delta.h>
29#include <mach/hardware.h> 29#include <mach/hardware.h>
30#include <plat/omapfb.h> 30
31#include "omapfb.h"
31 32
32#define AMS_DELTA_DEFAULT_CONTRAST 112 33#define AMS_DELTA_DEFAULT_CONTRAST 112
33 34
diff --git a/drivers/video/omap/lcd_apollon.c b/drivers/video/omap/lcd_apollon.c
index 4c5cefc5153b..2be94eb3bbf5 100644
--- a/drivers/video/omap/lcd_apollon.c
+++ b/drivers/video/omap/lcd_apollon.c
@@ -26,7 +26,8 @@
26 26
27#include <mach/gpio.h> 27#include <mach/gpio.h>
28#include <plat/mux.h> 28#include <plat/mux.h>
29#include <plat/omapfb.h> 29
30#include "omapfb.h"
30 31
31/* #define USE_35INCH_LCD 1 */ 32/* #define USE_35INCH_LCD 1 */
32 33
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c
index 240b4fb10741..8df688748b5a 100644
--- a/drivers/video/omap/lcd_h3.c
+++ b/drivers/video/omap/lcd_h3.c
@@ -24,7 +24,7 @@
24#include <linux/i2c/tps65010.h> 24#include <linux/i2c/tps65010.h>
25 25
26#include <mach/gpio.h> 26#include <mach/gpio.h>
27#include <plat/omapfb.h> 27#include "omapfb.h"
28 28
29#define MODULE_NAME "omapfb-lcd_h3" 29#define MODULE_NAME "omapfb-lcd_h3"
30 30
diff --git a/drivers/video/omap/lcd_h4.c b/drivers/video/omap/lcd_h4.c
index 720625da1f4e..03a06a982750 100644
--- a/drivers/video/omap/lcd_h4.c
+++ b/drivers/video/omap/lcd_h4.c
@@ -22,7 +22,7 @@
22#include <linux/module.h> 22#include <linux/module.h>
23#include <linux/platform_device.h> 23#include <linux/platform_device.h>
24 24
25#include <plat/omapfb.h> 25#include "omapfb.h"
26 26
27static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) 27static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
28{ 28{
diff --git a/drivers/video/omap/lcd_htcherald.c b/drivers/video/omap/lcd_htcherald.c
index 2e0c81ea7483..a9007c5d1fad 100644
--- a/drivers/video/omap/lcd_htcherald.c
+++ b/drivers/video/omap/lcd_htcherald.c
@@ -29,7 +29,7 @@
29#include <linux/module.h> 29#include <linux/module.h>
30#include <linux/platform_device.h> 30#include <linux/platform_device.h>
31 31
32#include <plat/omapfb.h> 32#include "omapfb.h"
33 33
34static int htcherald_panel_init(struct lcd_panel *panel, 34static int htcherald_panel_init(struct lcd_panel *panel,
35 struct omapfb_device *fbdev) 35 struct omapfb_device *fbdev)
diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c
index aafe9b497e2d..3271f1643b26 100644
--- a/drivers/video/omap/lcd_inn1510.c
+++ b/drivers/video/omap/lcd_inn1510.c
@@ -24,7 +24,7 @@
24#include <linux/io.h> 24#include <linux/io.h>
25 25
26#include <plat/fpga.h> 26#include <plat/fpga.h>
27#include <plat/omapfb.h> 27#include "omapfb.h"
28 28
29static int innovator1510_panel_init(struct lcd_panel *panel, 29static int innovator1510_panel_init(struct lcd_panel *panel,
30 struct omapfb_device *fbdev) 30 struct omapfb_device *fbdev)
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c
index 0de338264a8a..9fff86f67bde 100644
--- a/drivers/video/omap/lcd_inn1610.c
+++ b/drivers/video/omap/lcd_inn1610.c
@@ -23,7 +23,7 @@
23#include <linux/platform_device.h> 23#include <linux/platform_device.h>
24 24
25#include <mach/gpio.h> 25#include <mach/gpio.h>
26#include <plat/omapfb.h> 26#include "omapfb.h"
27 27
28#define MODULE_NAME "omapfb-lcd_h3" 28#define MODULE_NAME "omapfb-lcd_h3"
29 29
diff --git a/drivers/video/omap/lcd_ldp.c b/drivers/video/omap/lcd_ldp.c
index 6a260dfdadc5..5bb7f6f14601 100644
--- a/drivers/video/omap/lcd_ldp.c
+++ b/drivers/video/omap/lcd_ldp.c
@@ -28,9 +28,10 @@
28 28
29#include <mach/gpio.h> 29#include <mach/gpio.h>
30#include <plat/mux.h> 30#include <plat/mux.h>
31#include <plat/omapfb.h>
32#include <asm/mach-types.h> 31#include <asm/mach-types.h>
33 32
33#include "omapfb.h"
34
34#define LCD_PANEL_BACKLIGHT_GPIO (15 + OMAP_MAX_GPIO_LINES) 35#define LCD_PANEL_BACKLIGHT_GPIO (15 + OMAP_MAX_GPIO_LINES)
35#define LCD_PANEL_ENABLE_GPIO (7 + OMAP_MAX_GPIO_LINES) 36#define LCD_PANEL_ENABLE_GPIO (7 + OMAP_MAX_GPIO_LINES)
36 37
diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c
index 8f3e2b4bb4f3..abe1c76a3257 100644
--- a/drivers/video/omap/lcd_mipid.c
+++ b/drivers/video/omap/lcd_mipid.c
@@ -23,9 +23,10 @@
23#include <linux/workqueue.h> 23#include <linux/workqueue.h>
24#include <linux/spi/spi.h> 24#include <linux/spi/spi.h>
25 25
26#include <plat/omapfb.h>
27#include <plat/lcd_mipid.h> 26#include <plat/lcd_mipid.h>
28 27
28#include "omapfb.h"
29
29#define MIPID_MODULE_NAME "lcd_mipid" 30#define MIPID_MODULE_NAME "lcd_mipid"
30 31
31#define MIPID_CMD_READ_DISP_ID 0x04 32#define MIPID_CMD_READ_DISP_ID 0x04
diff --git a/drivers/video/omap/lcd_omap2evm.c b/drivers/video/omap/lcd_omap2evm.c
index e1a38abca3e7..006c2fe7360e 100644
--- a/drivers/video/omap/lcd_omap2evm.c
+++ b/drivers/video/omap/lcd_omap2evm.c
@@ -27,9 +27,10 @@
27#include <linux/i2c/twl4030.h> 27#include <linux/i2c/twl4030.h>
28 28
29#include <plat/mux.h> 29#include <plat/mux.h>
30#include <plat/omapfb.h>
31#include <asm/mach-types.h> 30#include <asm/mach-types.h>
32 31
32#include "omapfb.h"
33
33#define LCD_PANEL_ENABLE_GPIO 154 34#define LCD_PANEL_ENABLE_GPIO 154
34#define LCD_PANEL_LR 128 35#define LCD_PANEL_LR 128
35#define LCD_PANEL_UD 129 36#define LCD_PANEL_UD 129
diff --git a/drivers/video/omap/lcd_omap3beagle.c b/drivers/video/omap/lcd_omap3beagle.c
index ccec084ed647..fc503d8f3c24 100644
--- a/drivers/video/omap/lcd_omap3beagle.c
+++ b/drivers/video/omap/lcd_omap3beagle.c
@@ -26,9 +26,11 @@
26#include <linux/i2c/twl4030.h> 26#include <linux/i2c/twl4030.h>
27 27
28#include <plat/mux.h> 28#include <plat/mux.h>
29#include <plat/omapfb.h> 29#include <plat/mux.h>
30#include <asm/mach-types.h> 30#include <asm/mach-types.h>
31 31
32#include "omapfb.h"
33
32#define LCD_PANEL_ENABLE_GPIO 170 34#define LCD_PANEL_ENABLE_GPIO 170
33 35
34static int omap3beagle_panel_init(struct lcd_panel *panel, 36static int omap3beagle_panel_init(struct lcd_panel *panel,
diff --git a/drivers/video/omap/lcd_omap3evm.c b/drivers/video/omap/lcd_omap3evm.c
index 556eb31db24c..ae2edc4081a8 100644
--- a/drivers/video/omap/lcd_omap3evm.c
+++ b/drivers/video/omap/lcd_omap3evm.c
@@ -26,9 +26,10 @@
26#include <linux/i2c/twl4030.h> 26#include <linux/i2c/twl4030.h>
27 27
28#include <plat/mux.h> 28#include <plat/mux.h>
29#include <plat/omapfb.h>
30#include <asm/mach-types.h> 29#include <asm/mach-types.h>
31 30
31#include "omapfb.h"
32
32#define LCD_PANEL_ENABLE_GPIO 153 33#define LCD_PANEL_ENABLE_GPIO 153
33#define LCD_PANEL_LR 2 34#define LCD_PANEL_LR 2
34#define LCD_PANEL_UD 3 35#define LCD_PANEL_UD 3
diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c
index bb21d7dca39e..b87e8b83f29c 100644
--- a/drivers/video/omap/lcd_osk.c
+++ b/drivers/video/omap/lcd_osk.c
@@ -25,7 +25,7 @@
25 25
26#include <mach/gpio.h> 26#include <mach/gpio.h>
27#include <plat/mux.h> 27#include <plat/mux.h>
28#include <plat/omapfb.h> 28#include "omapfb.h"
29 29
30static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) 30static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
31{ 31{
diff --git a/drivers/video/omap/lcd_overo.c b/drivers/video/omap/lcd_overo.c
index b0f86e514cde..56ee192e9ee2 100644
--- a/drivers/video/omap/lcd_overo.c
+++ b/drivers/video/omap/lcd_overo.c
@@ -25,9 +25,10 @@
25 25
26#include <mach/gpio.h> 26#include <mach/gpio.h>
27#include <plat/mux.h> 27#include <plat/mux.h>
28#include <plat/omapfb.h>
29#include <asm/mach-types.h> 28#include <asm/mach-types.h>
30 29
30#include "omapfb.h"
31
31#define LCD_ENABLE 144 32#define LCD_ENABLE 144
32 33
33static int overo_panel_init(struct lcd_panel *panel, 34static int overo_panel_init(struct lcd_panel *panel,
diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c
index d30289603ce8..4cb301750d02 100644
--- a/drivers/video/omap/lcd_palmte.c
+++ b/drivers/video/omap/lcd_palmte.c
@@ -24,7 +24,7 @@
24#include <linux/io.h> 24#include <linux/io.h>
25 25
26#include <plat/fpga.h> 26#include <plat/fpga.h>
27#include <plat/omapfb.h> 27#include "omapfb.h"
28 28
29static int palmte_panel_init(struct lcd_panel *panel, 29static int palmte_panel_init(struct lcd_panel *panel,
30 struct omapfb_device *fbdev) 30 struct omapfb_device *fbdev)
diff --git a/drivers/video/omap/lcd_palmtt.c b/drivers/video/omap/lcd_palmtt.c
index 557424fb6df1..ff0e6d7ab3a2 100644
--- a/drivers/video/omap/lcd_palmtt.c
+++ b/drivers/video/omap/lcd_palmtt.c
@@ -30,7 +30,7 @@ GPIO13 - screen blanking
30#include <linux/io.h> 30#include <linux/io.h>
31 31
32#include <mach/gpio.h> 32#include <mach/gpio.h>
33#include <plat/omapfb.h> 33#include "omapfb.h"
34 34
35static int palmtt_panel_init(struct lcd_panel *panel, 35static int palmtt_panel_init(struct lcd_panel *panel,
36 struct omapfb_device *fbdev) 36 struct omapfb_device *fbdev)
diff --git a/drivers/video/omap/lcd_palmz71.c b/drivers/video/omap/lcd_palmz71.c
index 5f4b5b2c1f41..2334e56536bc 100644
--- a/drivers/video/omap/lcd_palmz71.c
+++ b/drivers/video/omap/lcd_palmz71.c
@@ -24,7 +24,7 @@
24#include <linux/platform_device.h> 24#include <linux/platform_device.h>
25#include <linux/io.h> 25#include <linux/io.h>
26 26
27#include <plat/omapfb.h> 27#include "omapfb.h"
28 28
29static int palmz71_panel_init(struct lcd_panel *panel, 29static int palmz71_panel_init(struct lcd_panel *panel,
30 struct omapfb_device *fbdev) 30 struct omapfb_device *fbdev)
diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c
index 5f32cafbf74c..b831e1df629e 100644
--- a/drivers/video/omap/lcdc.c
+++ b/drivers/video/omap/lcdc.c
@@ -30,10 +30,11 @@
30#include <linux/clk.h> 30#include <linux/clk.h>
31 31
32#include <plat/dma.h> 32#include <plat/dma.h>
33#include <plat/omapfb.h>
34 33
35#include <asm/mach-types.h> 34#include <asm/mach-types.h>
36 35
36#include "omapfb.h"
37
37#include "lcdc.h" 38#include "lcdc.h"
38 39
39#define MODULE_NAME "lcdc" 40#define MODULE_NAME "lcdc"
diff --git a/arch/arm/plat-omap/include/plat/omapfb.h b/drivers/video/omap/omapfb.h
index bfef7ab95f17..46e4714014e8 100644
--- a/arch/arm/plat-omap/include/plat/omapfb.h
+++ b/drivers/video/omap/omapfb.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * File: arch/arm/plat-omap/include/mach/omapfb.h 2 * File: drivers/video/omap/omapfb.h
3 * 3 *
4 * Framebuffer driver for TI OMAP boards 4 * Framebuffer driver for TI OMAP boards
5 * 5 *
@@ -24,151 +24,12 @@
24#ifndef __OMAPFB_H 24#ifndef __OMAPFB_H
25#define __OMAPFB_H 25#define __OMAPFB_H
26 26
27#include <asm/ioctl.h>
28#include <asm/types.h>
29
30/* IOCTL commands. */
31
32#define OMAP_IOW(num, dtype) _IOW('O', num, dtype)
33#define OMAP_IOR(num, dtype) _IOR('O', num, dtype)
34#define OMAP_IOWR(num, dtype) _IOWR('O', num, dtype)
35#define OMAP_IO(num) _IO('O', num)
36
37#define OMAPFB_MIRROR OMAP_IOW(31, int)
38#define OMAPFB_SYNC_GFX OMAP_IO(37)
39#define OMAPFB_VSYNC OMAP_IO(38)
40#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int)
41#define OMAPFB_GET_CAPS OMAP_IOR(42, struct omapfb_caps)
42#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int)
43#define OMAPFB_LCD_TEST OMAP_IOW(45, int)
44#define OMAPFB_CTRL_TEST OMAP_IOW(46, int)
45#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(47, struct omapfb_update_window_old)
46#define OMAPFB_SET_COLOR_KEY OMAP_IOW(50, struct omapfb_color_key)
47#define OMAPFB_GET_COLOR_KEY OMAP_IOW(51, struct omapfb_color_key)
48#define OMAPFB_SETUP_PLANE OMAP_IOW(52, struct omapfb_plane_info)
49#define OMAPFB_QUERY_PLANE OMAP_IOW(53, struct omapfb_plane_info)
50#define OMAPFB_UPDATE_WINDOW OMAP_IOW(54, struct omapfb_update_window)
51#define OMAPFB_SETUP_MEM OMAP_IOW(55, struct omapfb_mem_info)
52#define OMAPFB_QUERY_MEM OMAP_IOW(56, struct omapfb_mem_info)
53
54#define OMAPFB_CAPS_GENERIC_MASK 0x00000fff
55#define OMAPFB_CAPS_LCDC_MASK 0x00fff000
56#define OMAPFB_CAPS_PANEL_MASK 0xff000000
57
58#define OMAPFB_CAPS_MANUAL_UPDATE 0x00001000
59#define OMAPFB_CAPS_TEARSYNC 0x00002000
60#define OMAPFB_CAPS_PLANE_RELOCATE_MEM 0x00004000
61#define OMAPFB_CAPS_PLANE_SCALE 0x00008000
62#define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE 0x00010000
63#define OMAPFB_CAPS_WINDOW_SCALE 0x00020000
64#define OMAPFB_CAPS_WINDOW_OVERLAY 0x00040000
65#define OMAPFB_CAPS_WINDOW_ROTATE 0x00080000
66#define OMAPFB_CAPS_SET_BACKLIGHT 0x01000000
67
68/* Values from DSP must map to lower 16-bits */
69#define OMAPFB_FORMAT_MASK 0x00ff
70#define OMAPFB_FORMAT_FLAG_DOUBLE 0x0100
71#define OMAPFB_FORMAT_FLAG_TEARSYNC 0x0200
72#define OMAPFB_FORMAT_FLAG_FORCE_VSYNC 0x0400
73#define OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY 0x0800
74#define OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY 0x1000
75
76#define OMAPFB_EVENT_READY 1
77#define OMAPFB_EVENT_DISABLED 2
78
79#define OMAPFB_MEMTYPE_SDRAM 0
80#define OMAPFB_MEMTYPE_SRAM 1
81#define OMAPFB_MEMTYPE_MAX 1
82
83enum omapfb_color_format {
84 OMAPFB_COLOR_RGB565 = 0,
85 OMAPFB_COLOR_YUV422,
86 OMAPFB_COLOR_YUV420,
87 OMAPFB_COLOR_CLUT_8BPP,
88 OMAPFB_COLOR_CLUT_4BPP,
89 OMAPFB_COLOR_CLUT_2BPP,
90 OMAPFB_COLOR_CLUT_1BPP,
91 OMAPFB_COLOR_RGB444,
92 OMAPFB_COLOR_YUY422,
93};
94
95struct omapfb_update_window {
96 __u32 x, y;
97 __u32 width, height;
98 __u32 format;
99 __u32 out_x, out_y;
100 __u32 out_width, out_height;
101 __u32 reserved[8];
102};
103
104struct omapfb_update_window_old {
105 __u32 x, y;
106 __u32 width, height;
107 __u32 format;
108};
109
110enum omapfb_plane {
111 OMAPFB_PLANE_GFX = 0,
112 OMAPFB_PLANE_VID1,
113 OMAPFB_PLANE_VID2,
114};
115
116enum omapfb_channel_out {
117 OMAPFB_CHANNEL_OUT_LCD = 0,
118 OMAPFB_CHANNEL_OUT_DIGIT,
119};
120
121struct omapfb_plane_info {
122 __u32 pos_x;
123 __u32 pos_y;
124 __u8 enabled;
125 __u8 channel_out;
126 __u8 mirror;
127 __u8 reserved1;
128 __u32 out_width;
129 __u32 out_height;
130 __u32 reserved2[12];
131};
132
133struct omapfb_mem_info {
134 __u32 size;
135 __u8 type;
136 __u8 reserved[3];
137};
138
139struct omapfb_caps {
140 __u32 ctrl;
141 __u32 plane_color;
142 __u32 wnd_color;
143};
144
145enum omapfb_color_key_type {
146 OMAPFB_COLOR_KEY_DISABLED = 0,
147 OMAPFB_COLOR_KEY_GFX_DST,
148 OMAPFB_COLOR_KEY_VID_SRC,
149};
150
151struct omapfb_color_key {
152 __u8 channel_out;
153 __u32 background;
154 __u32 trans_key;
155 __u8 key_type;
156};
157
158enum omapfb_update_mode {
159 OMAPFB_UPDATE_DISABLED = 0,
160 OMAPFB_AUTO_UPDATE,
161 OMAPFB_MANUAL_UPDATE
162};
163
164#ifdef __KERNEL__
165
166#include <linux/completion.h>
167#include <linux/interrupt.h>
168#include <linux/fb.h> 27#include <linux/fb.h>
169#include <linux/mutex.h> 28#include <linux/mutex.h>
29#include <linux/omapfb.h>
170 30
171#include <plat/board.h> 31#define OMAPFB_EVENT_READY 1
32#define OMAPFB_EVENT_DISABLED 2
172 33
173#define OMAP_LCDC_INV_VSYNC 0x0001 34#define OMAP_LCDC_INV_VSYNC 0x0001
174#define OMAP_LCDC_INV_HSYNC 0x0002 35#define OMAP_LCDC_INV_HSYNC 0x0002
@@ -184,12 +45,6 @@ enum omapfb_update_mode {
184#define OMAPFB_PLANE_XRES_MIN 8 45#define OMAPFB_PLANE_XRES_MIN 8
185#define OMAPFB_PLANE_YRES_MIN 8 46#define OMAPFB_PLANE_YRES_MIN 8
186 47
187#ifdef CONFIG_ARCH_OMAP1
188#define OMAPFB_PLANE_NUM 1
189#else
190#define OMAPFB_PLANE_NUM 3
191#endif
192
193struct omapfb_device; 48struct omapfb_device;
194 49
195struct lcd_panel { 50struct lcd_panel {
@@ -256,7 +111,7 @@ struct lcd_ctrl_extif {
256 void (*read_data) (void *buf, unsigned int len); 111 void (*read_data) (void *buf, unsigned int len);
257 void (*write_data) (const void *buf, unsigned int len); 112 void (*write_data) (const void *buf, unsigned int len);
258 void (*transfer_area) (int width, int height, 113 void (*transfer_area) (int width, int height,
259 void (callback)(void * data), void *data); 114 void (callback)(void *data), void *data);
260 int (*setup_tearsync) (unsigned pin_cnt, 115 int (*setup_tearsync) (unsigned pin_cnt,
261 unsigned hs_pulse_time, unsigned vs_pulse_time, 116 unsigned hs_pulse_time, unsigned vs_pulse_time,
262 int hs_pol_inv, int vs_pol_inv, int div); 117 int hs_pol_inv, int vs_pol_inv, int div);
@@ -275,20 +130,6 @@ typedef int (*omapfb_notifier_callback_t)(struct notifier_block *,
275 unsigned long event, 130 unsigned long event,
276 void *fbi); 131 void *fbi);
277 132
278struct omapfb_mem_region {
279 u32 paddr;
280 void __iomem *vaddr;
281 unsigned long size;
282 u8 type; /* OMAPFB_PLANE_MEM_* */
283 unsigned alloc:1; /* allocated by the driver */
284 unsigned map:1; /* kernel mapped by the driver */
285};
286
287struct omapfb_mem_desc {
288 int region_cnt;
289 struct omapfb_mem_region region[OMAPFB_PLANE_NUM];
290};
291
292struct lcd_ctrl { 133struct lcd_ctrl {
293 const char *name; 134 const char *name;
294 void *data; 135 void *data;
@@ -331,9 +172,9 @@ struct lcd_ctrl {
331}; 172};
332 173
333enum omapfb_state { 174enum omapfb_state {
334 OMAPFB_DISABLED = 0, 175 OMAPFB_DISABLED = 0,
335 OMAPFB_SUSPENDED= 99, 176 OMAPFB_SUSPENDED = 99,
336 OMAPFB_ACTIVE = 100 177 OMAPFB_ACTIVE = 100
337}; 178};
338 179
339struct omapfb_plane_struct { 180struct omapfb_plane_struct {
@@ -345,8 +186,8 @@ struct omapfb_plane_struct {
345 186
346struct omapfb_device { 187struct omapfb_device {
347 int state; 188 int state;
348 int ext_lcdc; /* Using external 189 int ext_lcdc; /* Using external
349 LCD controller */ 190 LCD controller */
350 struct mutex rqueue_mutex; 191 struct mutex rqueue_mutex;
351 192
352 int palette_size; 193 int palette_size;
@@ -364,19 +205,12 @@ struct omapfb_device {
364 struct fb_info *fb_info[OMAPFB_PLANE_NUM]; 205 struct fb_info *fb_info[OMAPFB_PLANE_NUM];
365}; 206};
366 207
367struct omapfb_platform_data {
368 struct omap_lcd_config lcd;
369 struct omapfb_mem_desc mem_desc;
370 void *ctrl_platform_data;
371};
372
373#ifdef CONFIG_ARCH_OMAP1 208#ifdef CONFIG_ARCH_OMAP1
374extern struct lcd_ctrl omap1_lcd_ctrl; 209extern struct lcd_ctrl omap1_lcd_ctrl;
375#else 210#else
376extern struct lcd_ctrl omap2_disp_ctrl; 211extern struct lcd_ctrl omap2_disp_ctrl;
377#endif 212#endif
378 213
379extern void omapfb_reserve_sdram(void);
380extern void omapfb_register_panel(struct lcd_panel *panel); 214extern void omapfb_register_panel(struct lcd_panel *panel);
381extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval); 215extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
382extern void omapfb_notify_clients(struct omapfb_device *fbdev, 216extern void omapfb_notify_clients(struct omapfb_device *fbdev,
@@ -390,9 +224,4 @@ extern int omapfb_update_window_async(struct fb_info *fbi,
390 void (*callback)(void *), 224 void (*callback)(void *),
391 void *callback_data); 225 void *callback_data);
392 226
393/* in arch/arm/plat-omap/fb.c */
394extern void omapfb_set_ctrl_platform_data(void *pdata);
395
396#endif /* __KERNEL__ */
397
398#endif /* __OMAPFB_H */ 227#endif /* __OMAPFB_H */
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
index f900a43db8d7..c7f59a5ccdbc 100644
--- a/drivers/video/omap/omapfb_main.c
+++ b/drivers/video/omap/omapfb_main.c
@@ -29,8 +29,8 @@
29#include <linux/uaccess.h> 29#include <linux/uaccess.h>
30 30
31#include <plat/dma.h> 31#include <plat/dma.h>
32#include <plat/omapfb.h>
33 32
33#include "omapfb.h"
34#include "lcdc.h" 34#include "lcdc.h"
35#include "dispc.h" 35#include "dispc.h"
36 36
diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c
index c90fa39486b4..fed7b1bda19c 100644
--- a/drivers/video/omap/rfbi.c
+++ b/drivers/video/omap/rfbi.c
@@ -27,8 +27,7 @@
27#include <linux/clk.h> 27#include <linux/clk.h>
28#include <linux/io.h> 28#include <linux/io.h>
29 29
30#include <plat/omapfb.h> 30#include "omapfb.h"
31
32#include "dispc.h" 31#include "dispc.h"
33 32
34/* To work around an RFBI transfer rate limitation */ 33/* To work around an RFBI transfer rate limitation */
diff --git a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c
index 79dc84f09713..8fb7c708f563 100644
--- a/drivers/video/omap/sossi.c
+++ b/drivers/video/omap/sossi.c
@@ -23,10 +23,11 @@
23#include <linux/clk.h> 23#include <linux/clk.h>
24#include <linux/irq.h> 24#include <linux/irq.h>
25#include <linux/io.h> 25#include <linux/io.h>
26#include <linux/interrupt.h>
26 27
27#include <plat/dma.h> 28#include <plat/dma.h>
28#include <plat/omapfb.h>
29 29
30#include "omapfb.h"
30#include "lcdc.h" 31#include "lcdc.h"
31 32
32#define MODULE_NAME "omapfb-sossi" 33#define MODULE_NAME "omapfb-sossi"
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..b12a59c9c50a
--- /dev/null
+++ b/drivers/video/omap2/displays/Kconfig
@@ -0,0 +1,22 @@
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_TAAL
17 tristate "Taal DSI Panel"
18 depends on OMAP2_DSS_DSI
19 help
20 Taal DSI command mode panel from TPO.
21
22endmenu
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
new file mode 100644
index 000000000000..955646440b3a
--- /dev/null
+++ b/drivers/video/omap2/displays/Makefile
@@ -0,0 +1,4 @@
1obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
2obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
3
4obj-$(CONFIG_PANEL_TAAL) += panel-taal.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..eb48d1afd800
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-generic.c
@@ -0,0 +1,104 @@
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_probe(struct omap_dss_device *dssdev)
39{
40 dssdev->panel.config = OMAP_DSS_LCD_TFT;
41 dssdev->panel.timings = generic_panel_timings;
42
43 return 0;
44}
45
46static void generic_panel_remove(struct omap_dss_device *dssdev)
47{
48}
49
50static int generic_panel_enable(struct omap_dss_device *dssdev)
51{
52 int r = 0;
53
54 if (dssdev->platform_enable)
55 r = dssdev->platform_enable(dssdev);
56
57 return r;
58}
59
60static void generic_panel_disable(struct omap_dss_device *dssdev)
61{
62 if (dssdev->platform_disable)
63 dssdev->platform_disable(dssdev);
64}
65
66static int generic_panel_suspend(struct omap_dss_device *dssdev)
67{
68 generic_panel_disable(dssdev);
69 return 0;
70}
71
72static int generic_panel_resume(struct omap_dss_device *dssdev)
73{
74 return generic_panel_enable(dssdev);
75}
76
77static struct omap_dss_driver generic_driver = {
78 .probe = generic_panel_probe,
79 .remove = generic_panel_remove,
80
81 .enable = generic_panel_enable,
82 .disable = generic_panel_disable,
83 .suspend = generic_panel_suspend,
84 .resume = generic_panel_resume,
85
86 .driver = {
87 .name = "generic_panel",
88 .owner = THIS_MODULE,
89 },
90};
91
92static int __init generic_panel_drv_init(void)
93{
94 return omap_dss_register_driver(&generic_driver);
95}
96
97static void __exit generic_panel_drv_exit(void)
98{
99 omap_dss_unregister_driver(&generic_driver);
100}
101
102module_init(generic_panel_drv_init);
103module_exit(generic_panel_drv_exit);
104MODULE_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..bbe880bbe795
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
@@ -0,0 +1,153 @@
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/regulator/consumer.h>
24#include <linux/err.h>
25
26#include <plat/display.h>
27
28struct sharp_data {
29 /* XXX This regulator should actually be in SDP board file, not here,
30 * as it doesn't actually power the LCD, but something else that
31 * affects the output to LCD (I think. Somebody clarify). It doesn't do
32 * harm here, as SDP is the only board using this currently */
33 struct regulator *vdvi_reg;
34};
35
36static struct omap_video_timings sharp_ls_timings = {
37 .x_res = 480,
38 .y_res = 640,
39
40 .pixel_clock = 19200,
41
42 .hsw = 2,
43 .hfp = 1,
44 .hbp = 28,
45
46 .vsw = 1,
47 .vfp = 1,
48 .vbp = 1,
49};
50
51static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
52{
53 struct sharp_data *sd;
54
55 dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
56 OMAP_DSS_LCD_IHS;
57 dssdev->panel.acb = 0x28;
58 dssdev->panel.timings = sharp_ls_timings;
59
60 sd = kzalloc(sizeof(*sd), GFP_KERNEL);
61 if (!sd)
62 return -ENOMEM;
63
64 dev_set_drvdata(&dssdev->dev, sd);
65
66 sd->vdvi_reg = regulator_get(&dssdev->dev, "vdvi");
67 if (IS_ERR(sd->vdvi_reg)) {
68 kfree(sd);
69 pr_err("failed to get VDVI regulator\n");
70 return PTR_ERR(sd->vdvi_reg);
71 }
72
73 return 0;
74}
75
76static void sharp_ls_panel_remove(struct omap_dss_device *dssdev)
77{
78 struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
79
80 regulator_put(sd->vdvi_reg);
81
82 kfree(sd);
83}
84
85static int sharp_ls_panel_enable(struct omap_dss_device *dssdev)
86{
87 struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
88 int r = 0;
89
90 /* wait couple of vsyncs until enabling the LCD */
91 msleep(50);
92
93 regulator_enable(sd->vdvi_reg);
94
95 if (dssdev->platform_enable)
96 r = dssdev->platform_enable(dssdev);
97
98 return r;
99}
100
101static void sharp_ls_panel_disable(struct omap_dss_device *dssdev)
102{
103 struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
104
105 if (dssdev->platform_disable)
106 dssdev->platform_disable(dssdev);
107
108 regulator_disable(sd->vdvi_reg);
109
110 /* wait at least 5 vsyncs after disabling the LCD */
111
112 msleep(100);
113}
114
115static int sharp_ls_panel_suspend(struct omap_dss_device *dssdev)
116{
117 sharp_ls_panel_disable(dssdev);
118 return 0;
119}
120
121static int sharp_ls_panel_resume(struct omap_dss_device *dssdev)
122{
123 return sharp_ls_panel_enable(dssdev);
124}
125
126static struct omap_dss_driver sharp_ls_driver = {
127 .probe = sharp_ls_panel_probe,
128 .remove = sharp_ls_panel_remove,
129
130 .enable = sharp_ls_panel_enable,
131 .disable = sharp_ls_panel_disable,
132 .suspend = sharp_ls_panel_suspend,
133 .resume = sharp_ls_panel_resume,
134
135 .driver = {
136 .name = "sharp_ls_panel",
137 .owner = THIS_MODULE,
138 },
139};
140
141static int __init sharp_ls_panel_drv_init(void)
142{
143 return omap_dss_register_driver(&sharp_ls_driver);
144}
145
146static void __exit sharp_ls_panel_drv_exit(void)
147{
148 omap_dss_unregister_driver(&sharp_ls_driver);
149}
150
151module_init(sharp_ls_panel_drv_init);
152module_exit(sharp_ls_panel_drv_exit);
153MODULE_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..1f01dfc5e52e
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -0,0 +1,1003 @@
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
34#include <plat/display.h>
35
36/* DSI Virtual channel. Hardcoded for now. */
37#define TCH 0
38
39#define DCS_READ_NUM_ERRORS 0x05
40#define DCS_READ_POWER_MODE 0x0a
41#define DCS_READ_MADCTL 0x0b
42#define DCS_READ_PIXEL_FORMAT 0x0c
43#define DCS_RDDSDR 0x0f
44#define DCS_SLEEP_IN 0x10
45#define DCS_SLEEP_OUT 0x11
46#define DCS_DISPLAY_OFF 0x28
47#define DCS_DISPLAY_ON 0x29
48#define DCS_COLUMN_ADDR 0x2a
49#define DCS_PAGE_ADDR 0x2b
50#define DCS_MEMORY_WRITE 0x2c
51#define DCS_TEAR_OFF 0x34
52#define DCS_TEAR_ON 0x35
53#define DCS_MEM_ACC_CTRL 0x36
54#define DCS_PIXEL_FORMAT 0x3a
55#define DCS_BRIGHTNESS 0x51
56#define DCS_CTRL_DISPLAY 0x53
57#define DCS_WRITE_CABC 0x55
58#define DCS_READ_CABC 0x56
59#define DCS_GET_ID1 0xda
60#define DCS_GET_ID2 0xdb
61#define DCS_GET_ID3 0xdc
62
63/* #define TAAL_USE_ESD_CHECK */
64#define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000)
65
66struct taal_data {
67 struct backlight_device *bldev;
68
69 unsigned long hw_guard_end; /* next value of jiffies when we can
70 * issue the next sleep in/out command
71 */
72 unsigned long hw_guard_wait; /* max guard time in jiffies */
73
74 struct omap_dss_device *dssdev;
75
76 bool enabled;
77 u8 rotate;
78 bool mirror;
79
80 bool te_enabled;
81 bool use_ext_te;
82 struct completion te_completion;
83
84 bool use_dsi_bl;
85
86 bool cabc_broken;
87 unsigned cabc_mode;
88
89 bool intro_printed;
90
91 struct workqueue_struct *esd_wq;
92 struct delayed_work esd_work;
93};
94
95static void taal_esd_work(struct work_struct *work);
96
97static void hw_guard_start(struct taal_data *td, int guard_msec)
98{
99 td->hw_guard_wait = msecs_to_jiffies(guard_msec);
100 td->hw_guard_end = jiffies + td->hw_guard_wait;
101}
102
103static void hw_guard_wait(struct taal_data *td)
104{
105 unsigned long wait = td->hw_guard_end - jiffies;
106
107 if ((long)wait > 0 && wait <= td->hw_guard_wait) {
108 set_current_state(TASK_UNINTERRUPTIBLE);
109 schedule_timeout(wait);
110 }
111}
112
113static int taal_dcs_read_1(u8 dcs_cmd, u8 *data)
114{
115 int r;
116 u8 buf[1];
117
118 r = dsi_vc_dcs_read(TCH, dcs_cmd, buf, 1);
119
120 if (r < 0)
121 return r;
122
123 *data = buf[0];
124
125 return 0;
126}
127
128static int taal_dcs_write_0(u8 dcs_cmd)
129{
130 return dsi_vc_dcs_write(TCH, &dcs_cmd, 1);
131}
132
133static int taal_dcs_write_1(u8 dcs_cmd, u8 param)
134{
135 u8 buf[2];
136 buf[0] = dcs_cmd;
137 buf[1] = param;
138 return dsi_vc_dcs_write(TCH, buf, 2);
139}
140
141static int taal_sleep_in(struct taal_data *td)
142
143{
144 u8 cmd;
145 int r;
146
147 hw_guard_wait(td);
148
149 cmd = DCS_SLEEP_IN;
150 r = dsi_vc_dcs_write_nosync(TCH, &cmd, 1);
151 if (r)
152 return r;
153
154 hw_guard_start(td, 120);
155
156 msleep(5);
157
158 return 0;
159}
160
161static int taal_sleep_out(struct taal_data *td)
162{
163 int r;
164
165 hw_guard_wait(td);
166
167 r = taal_dcs_write_0(DCS_SLEEP_OUT);
168 if (r)
169 return r;
170
171 hw_guard_start(td, 120);
172
173 msleep(5);
174
175 return 0;
176}
177
178static int taal_get_id(u8 *id1, u8 *id2, u8 *id3)
179{
180 int r;
181
182 r = taal_dcs_read_1(DCS_GET_ID1, id1);
183 if (r)
184 return r;
185 r = taal_dcs_read_1(DCS_GET_ID2, id2);
186 if (r)
187 return r;
188 r = taal_dcs_read_1(DCS_GET_ID3, id3);
189 if (r)
190 return r;
191
192 return 0;
193}
194
195static int taal_set_addr_mode(u8 rotate, bool mirror)
196{
197 int r;
198 u8 mode;
199 int b5, b6, b7;
200
201 r = taal_dcs_read_1(DCS_READ_MADCTL, &mode);
202 if (r)
203 return r;
204
205 switch (rotate) {
206 default:
207 case 0:
208 b7 = 0;
209 b6 = 0;
210 b5 = 0;
211 break;
212 case 1:
213 b7 = 0;
214 b6 = 1;
215 b5 = 1;
216 break;
217 case 2:
218 b7 = 1;
219 b6 = 1;
220 b5 = 0;
221 break;
222 case 3:
223 b7 = 1;
224 b6 = 0;
225 b5 = 1;
226 break;
227 }
228
229 if (mirror)
230 b6 = !b6;
231
232 mode &= ~((1<<7) | (1<<6) | (1<<5));
233 mode |= (b7 << 7) | (b6 << 6) | (b5 << 5);
234
235 return taal_dcs_write_1(DCS_MEM_ACC_CTRL, mode);
236}
237
238static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h)
239{
240 int r;
241 u16 x1 = x;
242 u16 x2 = x + w - 1;
243 u16 y1 = y;
244 u16 y2 = y + h - 1;
245
246 u8 buf[5];
247 buf[0] = DCS_COLUMN_ADDR;
248 buf[1] = (x1 >> 8) & 0xff;
249 buf[2] = (x1 >> 0) & 0xff;
250 buf[3] = (x2 >> 8) & 0xff;
251 buf[4] = (x2 >> 0) & 0xff;
252
253 r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
254 if (r)
255 return r;
256
257 buf[0] = DCS_PAGE_ADDR;
258 buf[1] = (y1 >> 8) & 0xff;
259 buf[2] = (y1 >> 0) & 0xff;
260 buf[3] = (y2 >> 8) & 0xff;
261 buf[4] = (y2 >> 0) & 0xff;
262
263 r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
264 if (r)
265 return r;
266
267 dsi_vc_send_bta_sync(TCH);
268
269 return r;
270}
271
272static int taal_bl_update_status(struct backlight_device *dev)
273{
274 struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
275 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
276 int r;
277 int level;
278
279 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
280 dev->props.power == FB_BLANK_UNBLANK)
281 level = dev->props.brightness;
282 else
283 level = 0;
284
285 dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
286
287 if (td->use_dsi_bl) {
288 if (td->enabled) {
289 dsi_bus_lock();
290 r = taal_dcs_write_1(DCS_BRIGHTNESS, level);
291 dsi_bus_unlock();
292 if (r)
293 return r;
294 }
295 } else {
296 if (!dssdev->set_backlight)
297 return -EINVAL;
298
299 r = dssdev->set_backlight(dssdev, level);
300 if (r)
301 return r;
302 }
303
304 return 0;
305}
306
307static int taal_bl_get_intensity(struct backlight_device *dev)
308{
309 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
310 dev->props.power == FB_BLANK_UNBLANK)
311 return dev->props.brightness;
312
313 return 0;
314}
315
316static struct backlight_ops taal_bl_ops = {
317 .get_brightness = taal_bl_get_intensity,
318 .update_status = taal_bl_update_status,
319};
320
321static void taal_get_timings(struct omap_dss_device *dssdev,
322 struct omap_video_timings *timings)
323{
324 *timings = dssdev->panel.timings;
325}
326
327static void taal_get_resolution(struct omap_dss_device *dssdev,
328 u16 *xres, u16 *yres)
329{
330 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
331
332 if (td->rotate == 0 || td->rotate == 2) {
333 *xres = dssdev->panel.timings.x_res;
334 *yres = dssdev->panel.timings.y_res;
335 } else {
336 *yres = dssdev->panel.timings.x_res;
337 *xres = dssdev->panel.timings.y_res;
338 }
339}
340
341static irqreturn_t taal_te_isr(int irq, void *data)
342{
343 struct omap_dss_device *dssdev = data;
344 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
345
346 complete_all(&td->te_completion);
347
348 return IRQ_HANDLED;
349}
350
351static ssize_t taal_num_errors_show(struct device *dev,
352 struct device_attribute *attr, char *buf)
353{
354 struct omap_dss_device *dssdev = to_dss_device(dev);
355 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
356 u8 errors;
357 int r;
358
359 if (td->enabled) {
360 dsi_bus_lock();
361 r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors);
362 dsi_bus_unlock();
363 } else {
364 r = -ENODEV;
365 }
366
367 if (r)
368 return r;
369
370 return snprintf(buf, PAGE_SIZE, "%d\n", errors);
371}
372
373static ssize_t taal_hw_revision_show(struct device *dev,
374 struct device_attribute *attr, char *buf)
375{
376 struct omap_dss_device *dssdev = to_dss_device(dev);
377 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
378 u8 id1, id2, id3;
379 int r;
380
381 if (td->enabled) {
382 dsi_bus_lock();
383 r = taal_get_id(&id1, &id2, &id3);
384 dsi_bus_unlock();
385 } else {
386 r = -ENODEV;
387 }
388
389 if (r)
390 return r;
391
392 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3);
393}
394
395static const char *cabc_modes[] = {
396 "off", /* used also always when CABC is not supported */
397 "ui",
398 "still-image",
399 "moving-image",
400};
401
402static ssize_t show_cabc_mode(struct device *dev,
403 struct device_attribute *attr,
404 char *buf)
405{
406 struct omap_dss_device *dssdev = to_dss_device(dev);
407 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
408 const char *mode_str;
409 int mode;
410 int len;
411
412 mode = td->cabc_mode;
413
414 mode_str = "unknown";
415 if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
416 mode_str = cabc_modes[mode];
417 len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
418
419 return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
420}
421
422static ssize_t store_cabc_mode(struct device *dev,
423 struct device_attribute *attr,
424 const char *buf, size_t count)
425{
426 struct omap_dss_device *dssdev = to_dss_device(dev);
427 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
428 int i;
429
430 for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
431 if (sysfs_streq(cabc_modes[i], buf))
432 break;
433 }
434
435 if (i == ARRAY_SIZE(cabc_modes))
436 return -EINVAL;
437
438 if (td->enabled) {
439 dsi_bus_lock();
440 if (!td->cabc_broken)
441 taal_dcs_write_1(DCS_WRITE_CABC, i);
442 dsi_bus_unlock();
443 }
444
445 td->cabc_mode = i;
446
447 return count;
448}
449
450static ssize_t show_cabc_available_modes(struct device *dev,
451 struct device_attribute *attr,
452 char *buf)
453{
454 int len;
455 int i;
456
457 for (i = 0, len = 0;
458 len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
459 len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
460 i ? " " : "", cabc_modes[i],
461 i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
462
463 return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
464}
465
466static DEVICE_ATTR(num_dsi_errors, S_IRUGO, taal_num_errors_show, NULL);
467static DEVICE_ATTR(hw_revision, S_IRUGO, taal_hw_revision_show, NULL);
468static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
469 show_cabc_mode, store_cabc_mode);
470static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
471 show_cabc_available_modes, NULL);
472
473static struct attribute *taal_attrs[] = {
474 &dev_attr_num_dsi_errors.attr,
475 &dev_attr_hw_revision.attr,
476 &dev_attr_cabc_mode.attr,
477 &dev_attr_cabc_available_modes.attr,
478 NULL,
479};
480
481static struct attribute_group taal_attr_group = {
482 .attrs = taal_attrs,
483};
484
485static int taal_probe(struct omap_dss_device *dssdev)
486{
487 struct taal_data *td;
488 struct backlight_device *bldev;
489 int r;
490
491 const struct omap_video_timings taal_panel_timings = {
492 .x_res = 864,
493 .y_res = 480,
494 };
495
496 dev_dbg(&dssdev->dev, "probe\n");
497
498 dssdev->panel.config = OMAP_DSS_LCD_TFT;
499 dssdev->panel.timings = taal_panel_timings;
500 dssdev->ctrl.pixel_size = 24;
501
502 td = kzalloc(sizeof(*td), GFP_KERNEL);
503 if (!td) {
504 r = -ENOMEM;
505 goto err0;
506 }
507 td->dssdev = dssdev;
508
509 td->esd_wq = create_singlethread_workqueue("taal_esd");
510 if (td->esd_wq == NULL) {
511 dev_err(&dssdev->dev, "can't create ESD workqueue\n");
512 r = -ENOMEM;
513 goto err2;
514 }
515 INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
516
517 dev_set_drvdata(&dssdev->dev, td);
518
519 dssdev->get_timings = taal_get_timings;
520 dssdev->get_resolution = taal_get_resolution;
521
522 /* if no platform set_backlight() defined, presume DSI backlight
523 * control */
524 if (!dssdev->set_backlight)
525 td->use_dsi_bl = true;
526
527 bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
528 &taal_bl_ops);
529 if (IS_ERR(bldev)) {
530 r = PTR_ERR(bldev);
531 goto err1;
532 }
533
534 td->bldev = bldev;
535
536 bldev->props.fb_blank = FB_BLANK_UNBLANK;
537 bldev->props.power = FB_BLANK_UNBLANK;
538 if (td->use_dsi_bl) {
539 bldev->props.max_brightness = 255;
540 bldev->props.brightness = 255;
541 } else {
542 bldev->props.max_brightness = 127;
543 bldev->props.brightness = 127;
544 }
545
546 taal_bl_update_status(bldev);
547
548 if (dssdev->phy.dsi.ext_te) {
549 int gpio = dssdev->phy.dsi.ext_te_gpio;
550
551 r = gpio_request(gpio, "taal irq");
552 if (r) {
553 dev_err(&dssdev->dev, "GPIO request failed\n");
554 goto err3;
555 }
556
557 gpio_direction_input(gpio);
558
559 r = request_irq(gpio_to_irq(gpio), taal_te_isr,
560 IRQF_DISABLED | IRQF_TRIGGER_RISING,
561 "taal vsync", dssdev);
562
563 if (r) {
564 dev_err(&dssdev->dev, "IRQ request failed\n");
565 gpio_free(gpio);
566 goto err3;
567 }
568
569 init_completion(&td->te_completion);
570
571 td->use_ext_te = true;
572 }
573
574 r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group);
575 if (r) {
576 dev_err(&dssdev->dev, "failed to create sysfs files\n");
577 goto err4;
578 }
579
580 return 0;
581err4:
582 if (td->use_ext_te) {
583 int gpio = dssdev->phy.dsi.ext_te_gpio;
584 free_irq(gpio_to_irq(gpio), dssdev);
585 gpio_free(gpio);
586 }
587err3:
588 backlight_device_unregister(bldev);
589err2:
590 cancel_delayed_work_sync(&td->esd_work);
591 destroy_workqueue(td->esd_wq);
592err1:
593 kfree(td);
594err0:
595 return r;
596}
597
598static void taal_remove(struct omap_dss_device *dssdev)
599{
600 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
601 struct backlight_device *bldev;
602
603 dev_dbg(&dssdev->dev, "remove\n");
604
605 sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group);
606
607 if (td->use_ext_te) {
608 int gpio = dssdev->phy.dsi.ext_te_gpio;
609 free_irq(gpio_to_irq(gpio), dssdev);
610 gpio_free(gpio);
611 }
612
613 bldev = td->bldev;
614 bldev->props.power = FB_BLANK_POWERDOWN;
615 taal_bl_update_status(bldev);
616 backlight_device_unregister(bldev);
617
618 cancel_delayed_work_sync(&td->esd_work);
619 destroy_workqueue(td->esd_wq);
620
621 kfree(td);
622}
623
624static int taal_enable(struct omap_dss_device *dssdev)
625{
626 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
627 u8 id1, id2, id3;
628 int r;
629
630 dev_dbg(&dssdev->dev, "enable\n");
631
632 if (dssdev->platform_enable) {
633 r = dssdev->platform_enable(dssdev);
634 if (r)
635 return r;
636 }
637
638 /* it seems we have to wait a bit until taal is ready */
639 msleep(5);
640
641 r = taal_sleep_out(td);
642 if (r)
643 goto err;
644
645 r = taal_get_id(&id1, &id2, &id3);
646 if (r)
647 goto err;
648
649 /* on early revisions CABC is broken */
650 if (id2 == 0x00 || id2 == 0xff || id2 == 0x81)
651 td->cabc_broken = true;
652
653 taal_dcs_write_1(DCS_BRIGHTNESS, 0xff);
654 taal_dcs_write_1(DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */
655
656 taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
657
658 taal_set_addr_mode(td->rotate, td->mirror);
659 if (!td->cabc_broken)
660 taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode);
661
662 taal_dcs_write_0(DCS_DISPLAY_ON);
663
664#ifdef TAAL_USE_ESD_CHECK
665 queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
666#endif
667
668 td->enabled = 1;
669
670 if (!td->intro_printed) {
671 dev_info(&dssdev->dev, "revision %02x.%02x.%02x\n",
672 id1, id2, id3);
673 if (td->cabc_broken)
674 dev_info(&dssdev->dev,
675 "old Taal version, CABC disabled\n");
676 td->intro_printed = true;
677 }
678
679 return 0;
680err:
681 if (dssdev->platform_disable)
682 dssdev->platform_disable(dssdev);
683
684 return r;
685}
686
687static void taal_disable(struct omap_dss_device *dssdev)
688{
689 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
690
691 dev_dbg(&dssdev->dev, "disable\n");
692
693 cancel_delayed_work(&td->esd_work);
694
695 taal_dcs_write_0(DCS_DISPLAY_OFF);
696 taal_sleep_in(td);
697
698 /* wait a bit so that the message goes through */
699 msleep(10);
700
701 if (dssdev->platform_disable)
702 dssdev->platform_disable(dssdev);
703
704 td->enabled = 0;
705}
706
707static int taal_suspend(struct omap_dss_device *dssdev)
708{
709 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
710 struct backlight_device *bldev = td->bldev;
711
712 bldev->props.power = FB_BLANK_POWERDOWN;
713 taal_bl_update_status(bldev);
714
715 return 0;
716}
717
718static int taal_resume(struct omap_dss_device *dssdev)
719{
720 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
721 struct backlight_device *bldev = td->bldev;
722
723 bldev->props.power = FB_BLANK_UNBLANK;
724 taal_bl_update_status(bldev);
725
726 return 0;
727}
728
729static void taal_setup_update(struct omap_dss_device *dssdev,
730 u16 x, u16 y, u16 w, u16 h)
731{
732 taal_set_update_window(x, y, w, h);
733}
734
735static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
736{
737 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
738 int r;
739
740 td->te_enabled = enable;
741
742 if (enable)
743 r = taal_dcs_write_1(DCS_TEAR_ON, 0);
744 else
745 r = taal_dcs_write_0(DCS_TEAR_OFF);
746
747 return r;
748}
749
750static int taal_wait_te(struct omap_dss_device *dssdev)
751{
752 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
753 long wait = msecs_to_jiffies(500);
754
755 if (!td->use_ext_te || !td->te_enabled)
756 return 0;
757
758 INIT_COMPLETION(td->te_completion);
759 wait = wait_for_completion_timeout(&td->te_completion, wait);
760 if (wait == 0) {
761 dev_err(&dssdev->dev, "timeout waiting TE\n");
762 return -ETIME;
763 }
764
765 return 0;
766}
767
768static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
769{
770 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
771 int r;
772
773 dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
774
775 if (td->enabled) {
776 r = taal_set_addr_mode(rotate, td->mirror);
777
778 if (r)
779 return r;
780 }
781
782 td->rotate = rotate;
783
784 return 0;
785}
786
787static u8 taal_get_rotate(struct omap_dss_device *dssdev)
788{
789 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
790 return td->rotate;
791}
792
793static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
794{
795 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
796 int r;
797
798 dev_dbg(&dssdev->dev, "mirror %d\n", enable);
799
800 if (td->enabled) {
801 r = taal_set_addr_mode(td->rotate, enable);
802
803 if (r)
804 return r;
805 }
806
807 td->mirror = enable;
808
809 return 0;
810}
811
812static bool taal_get_mirror(struct omap_dss_device *dssdev)
813{
814 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
815 return td->mirror;
816}
817
818static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
819{
820 u8 id1, id2, id3;
821 int r;
822
823 r = taal_dcs_read_1(DCS_GET_ID1, &id1);
824 if (r)
825 return r;
826 r = taal_dcs_read_1(DCS_GET_ID2, &id2);
827 if (r)
828 return r;
829 r = taal_dcs_read_1(DCS_GET_ID3, &id3);
830 if (r)
831 return r;
832
833 return 0;
834}
835
836static int taal_memory_read(struct omap_dss_device *dssdev,
837 void *buf, size_t size,
838 u16 x, u16 y, u16 w, u16 h)
839{
840 int r;
841 int first = 1;
842 int plen;
843 unsigned buf_used = 0;
844
845 if (size < w * h * 3)
846 return -ENOMEM;
847
848 size = min(w * h * 3,
849 dssdev->panel.timings.x_res *
850 dssdev->panel.timings.y_res * 3);
851
852 /* plen 1 or 2 goes into short packet. until checksum error is fixed,
853 * use short packets. plen 32 works, but bigger packets seem to cause
854 * an error. */
855 if (size % 2)
856 plen = 1;
857 else
858 plen = 2;
859
860 taal_setup_update(dssdev, x, y, w, h);
861
862 r = dsi_vc_set_max_rx_packet_size(TCH, plen);
863 if (r)
864 return r;
865
866 while (buf_used < size) {
867 u8 dcs_cmd = first ? 0x2e : 0x3e;
868 first = 0;
869
870 r = dsi_vc_dcs_read(TCH, dcs_cmd,
871 buf + buf_used, size - buf_used);
872
873 if (r < 0) {
874 dev_err(&dssdev->dev, "read error\n");
875 goto err;
876 }
877
878 buf_used += r;
879
880 if (r < plen) {
881 dev_err(&dssdev->dev, "short read\n");
882 break;
883 }
884
885 if (signal_pending(current)) {
886 dev_err(&dssdev->dev, "signal pending, "
887 "aborting memory read\n");
888 r = -ERESTARTSYS;
889 goto err;
890 }
891 }
892
893 r = buf_used;
894
895err:
896 dsi_vc_set_max_rx_packet_size(TCH, 1);
897
898 return r;
899}
900
901static void taal_esd_work(struct work_struct *work)
902{
903 struct taal_data *td = container_of(work, struct taal_data,
904 esd_work.work);
905 struct omap_dss_device *dssdev = td->dssdev;
906 u8 state1, state2;
907 int r;
908
909 if (!td->enabled)
910 return;
911
912 dsi_bus_lock();
913
914 r = taal_dcs_read_1(DCS_RDDSDR, &state1);
915 if (r) {
916 dev_err(&dssdev->dev, "failed to read Taal status\n");
917 goto err;
918 }
919
920 /* Run self diagnostics */
921 r = taal_sleep_out(td);
922 if (r) {
923 dev_err(&dssdev->dev, "failed to run Taal self-diagnostics\n");
924 goto err;
925 }
926
927 r = taal_dcs_read_1(DCS_RDDSDR, &state2);
928 if (r) {
929 dev_err(&dssdev->dev, "failed to read Taal status\n");
930 goto err;
931 }
932
933 /* Each sleep out command will trigger a self diagnostic and flip
934 * Bit6 if the test passes.
935 */
936 if (!((state1 ^ state2) & (1 << 6))) {
937 dev_err(&dssdev->dev, "LCD self diagnostics failed\n");
938 goto err;
939 }
940 /* Self-diagnostics result is also shown on TE GPIO line. We need
941 * to re-enable TE after self diagnostics */
942 if (td->use_ext_te && td->te_enabled)
943 taal_enable_te(dssdev, true);
944
945 dsi_bus_unlock();
946
947 queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
948
949 return;
950err:
951 dev_err(&dssdev->dev, "performing LCD reset\n");
952
953 taal_disable(dssdev);
954 taal_enable(dssdev);
955
956 dsi_bus_unlock();
957
958 queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
959}
960
961static struct omap_dss_driver taal_driver = {
962 .probe = taal_probe,
963 .remove = taal_remove,
964
965 .enable = taal_enable,
966 .disable = taal_disable,
967 .suspend = taal_suspend,
968 .resume = taal_resume,
969
970 .setup_update = taal_setup_update,
971 .enable_te = taal_enable_te,
972 .wait_for_te = taal_wait_te,
973 .set_rotate = taal_rotate,
974 .get_rotate = taal_get_rotate,
975 .set_mirror = taal_mirror,
976 .get_mirror = taal_get_mirror,
977 .run_test = taal_run_test,
978 .memory_read = taal_memory_read,
979
980 .driver = {
981 .name = "taal",
982 .owner = THIS_MODULE,
983 },
984};
985
986static int __init taal_init(void)
987{
988 omap_dss_register_driver(&taal_driver);
989
990 return 0;
991}
992
993static void __exit taal_exit(void)
994{
995 omap_dss_unregister_driver(&taal_driver);
996}
997
998module_init(taal_init);
999module_exit(taal_exit);
1000
1001MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
1002MODULE_DESCRIPTION("Taal Driver");
1003MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
new file mode 100644
index 000000000000..71d8dec30635
--- /dev/null
+++ b/drivers/video/omap2/dss/Kconfig
@@ -0,0 +1,89 @@
1menuconfig OMAP2_DSS
2 tristate "OMAP2/3 Display Subsystem support (EXPERIMENTAL)"
3 depends on ARCH_OMAP2 || ARCH_OMAP3
4 help
5 OMAP2/3 Display Subsystem support.
6
7if OMAP2_DSS
8
9config OMAP2_VRAM_SIZE
10 int "VRAM size (MB)"
11 range 0 32
12 default 0
13 help
14 The amount of SDRAM to reserve at boot time for video RAM use.
15 This VRAM will be used by omapfb and other drivers that need
16 large continuous RAM area for video use.
17
18 You can also set this with "vram=<bytes>" kernel argument, or
19 in the board file.
20
21config OMAP2_DSS_DEBUG_SUPPORT
22 bool "Debug support"
23 default y
24 help
25 This enables debug messages. You need to enable printing
26 with 'debug' module parameter.
27
28config OMAP2_DSS_RFBI
29 bool "RFBI support"
30 default n
31 help
32 MIPI DBI, or RFBI (Remote Framebuffer Interface), support.
33
34config OMAP2_DSS_VENC
35 bool "VENC support"
36 default y
37 help
38 OMAP Video Encoder support.
39
40config OMAP2_DSS_SDI
41 bool "SDI support"
42 depends on ARCH_OMAP3
43 default n
44 help
45 SDI (Serial Display Interface) support.
46
47config OMAP2_DSS_DSI
48 bool "DSI support"
49 depends on ARCH_OMAP3
50 default n
51 help
52 MIPI DSI support.
53
54config OMAP2_DSS_USE_DSI_PLL
55 bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
56 default n
57 depends on OMAP2_DSS_DSI
58 help
59 Use DSI PLL to generate pixel clock. Currently only for DPI output.
60 DSI PLL can be used to generate higher and more precise pixel clocks.
61
62config OMAP2_DSS_FAKE_VSYNC
63 bool "Fake VSYNC irq from manual update displays"
64 default n
65 help
66 If this is selected, DSI will generate a fake DISPC VSYNC interrupt
67 when DSI has sent a frame. This is only needed with DSI or RFBI
68 displays using manual mode, and you want VSYNC to, for example,
69 time animation.
70
71config OMAP2_DSS_MIN_FCK_PER_PCK
72 int "Minimum FCK/PCK ratio (for scaling)"
73 range 0 32
74 default 0
75 help
76 This can be used to adjust the minimum FCK/PCK ratio.
77
78 With this you can make sure that DISPC FCK is at least
79 n x PCK. Video plane scaling requires higher FCK than
80 normally.
81
82 If this is set to 0, there's no extra constraint on the
83 DISPC FCK. However, the FCK will at minimum be
84 2xPCK (if active matrix) or 3xPCK (if passive matrix).
85
86 Max FCK is 173MHz, so this doesn't work if your PCK
87 is very high.
88
89endif
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
new file mode 100644
index 000000000000..980c72c2db98
--- /dev/null
+++ b/drivers/video/omap2/dss/Makefile
@@ -0,0 +1,6 @@
1obj-$(CONFIG_OMAP2_DSS) += omapdss.o
2omapdss-y := core.o dss.o dispc.o dpi.o display.o manager.o overlay.o
3omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
4omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
5omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
6omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
new file mode 100644
index 000000000000..29497a0c9a91
--- /dev/null
+++ b/drivers/video/omap2/dss/core.c
@@ -0,0 +1,919 @@
1/*
2 * linux/drivers/video/omap2/dss/core.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "CORE"
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/clk.h>
28#include <linux/err.h>
29#include <linux/platform_device.h>
30#include <linux/seq_file.h>
31#include <linux/debugfs.h>
32#include <linux/io.h>
33#include <linux/device.h>
34
35#include <plat/display.h>
36#include <plat/clock.h>
37
38#include "dss.h"
39
40static struct {
41 struct platform_device *pdev;
42 int ctx_id;
43
44 struct clk *dss_ick;
45 struct clk *dss1_fck;
46 struct clk *dss2_fck;
47 struct clk *dss_54m_fck;
48 struct clk *dss_96m_fck;
49 unsigned num_clks_enabled;
50} core;
51
52static void dss_clk_enable_all_no_ctx(void);
53static void dss_clk_disable_all_no_ctx(void);
54static void dss_clk_enable_no_ctx(enum dss_clock clks);
55static void dss_clk_disable_no_ctx(enum dss_clock clks);
56
57static char *def_disp_name;
58module_param_named(def_disp, def_disp_name, charp, 0);
59MODULE_PARM_DESC(def_disp_name, "default display name");
60
61#ifdef DEBUG
62unsigned int dss_debug;
63module_param_named(debug, dss_debug, bool, 0644);
64#endif
65
66/* CONTEXT */
67static int dss_get_ctx_id(void)
68{
69 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
70 int r;
71
72 if (!pdata->get_last_off_on_transaction_id)
73 return 0;
74 r = pdata->get_last_off_on_transaction_id(&core.pdev->dev);
75 if (r < 0) {
76 dev_err(&core.pdev->dev, "getting transaction ID failed, "
77 "will force context restore\n");
78 r = -1;
79 }
80 return r;
81}
82
83int dss_need_ctx_restore(void)
84{
85 int id = dss_get_ctx_id();
86
87 if (id < 0 || id != core.ctx_id) {
88 DSSDBG("ctx id %d -> id %d\n",
89 core.ctx_id, id);
90 core.ctx_id = id;
91 return 1;
92 } else {
93 return 0;
94 }
95}
96
97static void save_all_ctx(void)
98{
99 DSSDBG("save context\n");
100
101 dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
102
103 dss_save_context();
104 dispc_save_context();
105#ifdef CONFIG_OMAP2_DSS_DSI
106 dsi_save_context();
107#endif
108
109 dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
110}
111
112static void restore_all_ctx(void)
113{
114 DSSDBG("restore context\n");
115
116 dss_clk_enable_all_no_ctx();
117
118 dss_restore_context();
119 dispc_restore_context();
120#ifdef CONFIG_OMAP2_DSS_DSI
121 dsi_restore_context();
122#endif
123
124 dss_clk_disable_all_no_ctx();
125}
126
127/* CLOCKS */
128static void core_dump_clocks(struct seq_file *s)
129{
130 int i;
131 struct clk *clocks[5] = {
132 core.dss_ick,
133 core.dss1_fck,
134 core.dss2_fck,
135 core.dss_54m_fck,
136 core.dss_96m_fck
137 };
138
139 seq_printf(s, "- CORE -\n");
140
141 seq_printf(s, "internal clk count\t\t%u\n", core.num_clks_enabled);
142
143 for (i = 0; i < 5; i++) {
144 if (!clocks[i])
145 continue;
146 seq_printf(s, "%-15s\t%lu\t%d\n",
147 clocks[i]->name,
148 clk_get_rate(clocks[i]),
149 clocks[i]->usecount);
150 }
151}
152
153static int dss_get_clock(struct clk **clock, const char *clk_name)
154{
155 struct clk *clk;
156
157 clk = clk_get(&core.pdev->dev, clk_name);
158
159 if (IS_ERR(clk)) {
160 DSSERR("can't get clock %s", clk_name);
161 return PTR_ERR(clk);
162 }
163
164 *clock = clk;
165
166 DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
167
168 return 0;
169}
170
171static int dss_get_clocks(void)
172{
173 int r;
174
175 core.dss_ick = NULL;
176 core.dss1_fck = NULL;
177 core.dss2_fck = NULL;
178 core.dss_54m_fck = NULL;
179 core.dss_96m_fck = NULL;
180
181 r = dss_get_clock(&core.dss_ick, "ick");
182 if (r)
183 goto err;
184
185 r = dss_get_clock(&core.dss1_fck, "dss1_fck");
186 if (r)
187 goto err;
188
189 r = dss_get_clock(&core.dss2_fck, "dss2_fck");
190 if (r)
191 goto err;
192
193 r = dss_get_clock(&core.dss_54m_fck, "tv_fck");
194 if (r)
195 goto err;
196
197 r = dss_get_clock(&core.dss_96m_fck, "video_fck");
198 if (r)
199 goto err;
200
201 return 0;
202
203err:
204 if (core.dss_ick)
205 clk_put(core.dss_ick);
206 if (core.dss1_fck)
207 clk_put(core.dss1_fck);
208 if (core.dss2_fck)
209 clk_put(core.dss2_fck);
210 if (core.dss_54m_fck)
211 clk_put(core.dss_54m_fck);
212 if (core.dss_96m_fck)
213 clk_put(core.dss_96m_fck);
214
215 return r;
216}
217
218static void dss_put_clocks(void)
219{
220 if (core.dss_96m_fck)
221 clk_put(core.dss_96m_fck);
222 clk_put(core.dss_54m_fck);
223 clk_put(core.dss1_fck);
224 clk_put(core.dss2_fck);
225 clk_put(core.dss_ick);
226}
227
228unsigned long dss_clk_get_rate(enum dss_clock clk)
229{
230 switch (clk) {
231 case DSS_CLK_ICK:
232 return clk_get_rate(core.dss_ick);
233 case DSS_CLK_FCK1:
234 return clk_get_rate(core.dss1_fck);
235 case DSS_CLK_FCK2:
236 return clk_get_rate(core.dss2_fck);
237 case DSS_CLK_54M:
238 return clk_get_rate(core.dss_54m_fck);
239 case DSS_CLK_96M:
240 return clk_get_rate(core.dss_96m_fck);
241 }
242
243 BUG();
244 return 0;
245}
246
247static unsigned count_clk_bits(enum dss_clock clks)
248{
249 unsigned num_clks = 0;
250
251 if (clks & DSS_CLK_ICK)
252 ++num_clks;
253 if (clks & DSS_CLK_FCK1)
254 ++num_clks;
255 if (clks & DSS_CLK_FCK2)
256 ++num_clks;
257 if (clks & DSS_CLK_54M)
258 ++num_clks;
259 if (clks & DSS_CLK_96M)
260 ++num_clks;
261
262 return num_clks;
263}
264
265static void dss_clk_enable_no_ctx(enum dss_clock clks)
266{
267 unsigned num_clks = count_clk_bits(clks);
268
269 if (clks & DSS_CLK_ICK)
270 clk_enable(core.dss_ick);
271 if (clks & DSS_CLK_FCK1)
272 clk_enable(core.dss1_fck);
273 if (clks & DSS_CLK_FCK2)
274 clk_enable(core.dss2_fck);
275 if (clks & DSS_CLK_54M)
276 clk_enable(core.dss_54m_fck);
277 if (clks & DSS_CLK_96M)
278 clk_enable(core.dss_96m_fck);
279
280 core.num_clks_enabled += num_clks;
281}
282
283void dss_clk_enable(enum dss_clock clks)
284{
285 dss_clk_enable_no_ctx(clks);
286
287 if (cpu_is_omap34xx() && dss_need_ctx_restore())
288 restore_all_ctx();
289}
290
291static void dss_clk_disable_no_ctx(enum dss_clock clks)
292{
293 unsigned num_clks = count_clk_bits(clks);
294
295 if (clks & DSS_CLK_ICK)
296 clk_disable(core.dss_ick);
297 if (clks & DSS_CLK_FCK1)
298 clk_disable(core.dss1_fck);
299 if (clks & DSS_CLK_FCK2)
300 clk_disable(core.dss2_fck);
301 if (clks & DSS_CLK_54M)
302 clk_disable(core.dss_54m_fck);
303 if (clks & DSS_CLK_96M)
304 clk_disable(core.dss_96m_fck);
305
306 core.num_clks_enabled -= num_clks;
307}
308
309void dss_clk_disable(enum dss_clock clks)
310{
311 if (cpu_is_omap34xx()) {
312 unsigned num_clks = count_clk_bits(clks);
313
314 BUG_ON(core.num_clks_enabled < num_clks);
315
316 if (core.num_clks_enabled == num_clks)
317 save_all_ctx();
318 }
319
320 dss_clk_disable_no_ctx(clks);
321}
322
323static void dss_clk_enable_all_no_ctx(void)
324{
325 enum dss_clock clks;
326
327 clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
328 if (cpu_is_omap34xx())
329 clks |= DSS_CLK_96M;
330 dss_clk_enable_no_ctx(clks);
331}
332
333static void dss_clk_disable_all_no_ctx(void)
334{
335 enum dss_clock clks;
336
337 clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
338 if (cpu_is_omap34xx())
339 clks |= DSS_CLK_96M;
340 dss_clk_disable_no_ctx(clks);
341}
342
343static void dss_clk_disable_all(void)
344{
345 enum dss_clock clks;
346
347 clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
348 if (cpu_is_omap34xx())
349 clks |= DSS_CLK_96M;
350 dss_clk_disable(clks);
351}
352
353/* DEBUGFS */
354#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
355static void dss_debug_dump_clocks(struct seq_file *s)
356{
357 core_dump_clocks(s);
358 dss_dump_clocks(s);
359 dispc_dump_clocks(s);
360#ifdef CONFIG_OMAP2_DSS_DSI
361 dsi_dump_clocks(s);
362#endif
363}
364
365static int dss_debug_show(struct seq_file *s, void *unused)
366{
367 void (*func)(struct seq_file *) = s->private;
368 func(s);
369 return 0;
370}
371
372static int dss_debug_open(struct inode *inode, struct file *file)
373{
374 return single_open(file, dss_debug_show, inode->i_private);
375}
376
377static const struct file_operations dss_debug_fops = {
378 .open = dss_debug_open,
379 .read = seq_read,
380 .llseek = seq_lseek,
381 .release = single_release,
382};
383
384static struct dentry *dss_debugfs_dir;
385
386static int dss_initialize_debugfs(void)
387{
388 dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
389 if (IS_ERR(dss_debugfs_dir)) {
390 int err = PTR_ERR(dss_debugfs_dir);
391 dss_debugfs_dir = NULL;
392 return err;
393 }
394
395 debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
396 &dss_debug_dump_clocks, &dss_debug_fops);
397
398 debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir,
399 &dss_dump_regs, &dss_debug_fops);
400 debugfs_create_file("dispc", S_IRUGO, dss_debugfs_dir,
401 &dispc_dump_regs, &dss_debug_fops);
402#ifdef CONFIG_OMAP2_DSS_RFBI
403 debugfs_create_file("rfbi", S_IRUGO, dss_debugfs_dir,
404 &rfbi_dump_regs, &dss_debug_fops);
405#endif
406#ifdef CONFIG_OMAP2_DSS_DSI
407 debugfs_create_file("dsi", S_IRUGO, dss_debugfs_dir,
408 &dsi_dump_regs, &dss_debug_fops);
409#endif
410#ifdef CONFIG_OMAP2_DSS_VENC
411 debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
412 &venc_dump_regs, &dss_debug_fops);
413#endif
414 return 0;
415}
416
417static void dss_uninitialize_debugfs(void)
418{
419 if (dss_debugfs_dir)
420 debugfs_remove_recursive(dss_debugfs_dir);
421}
422#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
423
424/* PLATFORM DEVICE */
425static int omap_dss_probe(struct platform_device *pdev)
426{
427 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
428 int skip_init = 0;
429 int r;
430 int i;
431
432 core.pdev = pdev;
433
434 dss_init_overlay_managers(pdev);
435 dss_init_overlays(pdev);
436
437 r = dss_get_clocks();
438 if (r)
439 goto fail0;
440
441 dss_clk_enable_all_no_ctx();
442
443 core.ctx_id = dss_get_ctx_id();
444 DSSDBG("initial ctx id %u\n", core.ctx_id);
445
446#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
447 /* DISPC_CONTROL */
448 if (omap_readl(0x48050440) & 1) /* LCD enabled? */
449 skip_init = 1;
450#endif
451
452 r = dss_init(skip_init);
453 if (r) {
454 DSSERR("Failed to initialize DSS\n");
455 goto fail0;
456 }
457
458#ifdef CONFIG_OMAP2_DSS_RFBI
459 r = rfbi_init();
460 if (r) {
461 DSSERR("Failed to initialize rfbi\n");
462 goto fail0;
463 }
464#endif
465
466 r = dpi_init();
467 if (r) {
468 DSSERR("Failed to initialize dpi\n");
469 goto fail0;
470 }
471
472 r = dispc_init();
473 if (r) {
474 DSSERR("Failed to initialize dispc\n");
475 goto fail0;
476 }
477#ifdef CONFIG_OMAP2_DSS_VENC
478 r = venc_init(pdev);
479 if (r) {
480 DSSERR("Failed to initialize venc\n");
481 goto fail0;
482 }
483#endif
484 if (cpu_is_omap34xx()) {
485#ifdef CONFIG_OMAP2_DSS_SDI
486 r = sdi_init(skip_init);
487 if (r) {
488 DSSERR("Failed to initialize SDI\n");
489 goto fail0;
490 }
491#endif
492#ifdef CONFIG_OMAP2_DSS_DSI
493 r = dsi_init(pdev);
494 if (r) {
495 DSSERR("Failed to initialize DSI\n");
496 goto fail0;
497 }
498#endif
499 }
500
501#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
502 r = dss_initialize_debugfs();
503 if (r)
504 goto fail0;
505#endif
506
507 for (i = 0; i < pdata->num_devices; ++i) {
508 struct omap_dss_device *dssdev = pdata->devices[i];
509
510 r = omap_dss_register_device(dssdev);
511 if (r)
512 DSSERR("device reg failed %d\n", i);
513
514 if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0)
515 pdata->default_device = dssdev;
516 }
517
518 dss_clk_disable_all();
519
520 return 0;
521
522 /* XXX fail correctly */
523fail0:
524 return r;
525}
526
527static int omap_dss_remove(struct platform_device *pdev)
528{
529 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
530 int i;
531 int c;
532
533#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
534 dss_uninitialize_debugfs();
535#endif
536
537#ifdef CONFIG_OMAP2_DSS_VENC
538 venc_exit();
539#endif
540 dispc_exit();
541 dpi_exit();
542#ifdef CONFIG_OMAP2_DSS_RFBI
543 rfbi_exit();
544#endif
545 if (cpu_is_omap34xx()) {
546#ifdef CONFIG_OMAP2_DSS_DSI
547 dsi_exit();
548#endif
549#ifdef CONFIG_OMAP2_DSS_SDI
550 sdi_exit();
551#endif
552 }
553
554 dss_exit();
555
556 /* these should be removed at some point */
557 c = core.dss_ick->usecount;
558 if (c > 0) {
559 DSSERR("warning: dss_ick usecount %d, disabling\n", c);
560 while (c-- > 0)
561 clk_disable(core.dss_ick);
562 }
563
564 c = core.dss1_fck->usecount;
565 if (c > 0) {
566 DSSERR("warning: dss1_fck usecount %d, disabling\n", c);
567 while (c-- > 0)
568 clk_disable(core.dss1_fck);
569 }
570
571 c = core.dss2_fck->usecount;
572 if (c > 0) {
573 DSSERR("warning: dss2_fck usecount %d, disabling\n", c);
574 while (c-- > 0)
575 clk_disable(core.dss2_fck);
576 }
577
578 c = core.dss_54m_fck->usecount;
579 if (c > 0) {
580 DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c);
581 while (c-- > 0)
582 clk_disable(core.dss_54m_fck);
583 }
584
585 if (core.dss_96m_fck) {
586 c = core.dss_96m_fck->usecount;
587 if (c > 0) {
588 DSSERR("warning: dss_96m_fck usecount %d, disabling\n",
589 c);
590 while (c-- > 0)
591 clk_disable(core.dss_96m_fck);
592 }
593 }
594
595 dss_put_clocks();
596
597 dss_uninit_overlays(pdev);
598 dss_uninit_overlay_managers(pdev);
599
600 for (i = 0; i < pdata->num_devices; ++i)
601 omap_dss_unregister_device(pdata->devices[i]);
602
603 return 0;
604}
605
606static void omap_dss_shutdown(struct platform_device *pdev)
607{
608 DSSDBG("shutdown\n");
609 dss_disable_all_devices();
610}
611
612static int omap_dss_suspend(struct platform_device *pdev, pm_message_t state)
613{
614 DSSDBG("suspend %d\n", state.event);
615
616 return dss_suspend_all_devices();
617}
618
619static int omap_dss_resume(struct platform_device *pdev)
620{
621 DSSDBG("resume\n");
622
623 return dss_resume_all_devices();
624}
625
626static struct platform_driver omap_dss_driver = {
627 .probe = omap_dss_probe,
628 .remove = omap_dss_remove,
629 .shutdown = omap_dss_shutdown,
630 .suspend = omap_dss_suspend,
631 .resume = omap_dss_resume,
632 .driver = {
633 .name = "omapdss",
634 .owner = THIS_MODULE,
635 },
636};
637
638/* BUS */
639static int dss_bus_match(struct device *dev, struct device_driver *driver)
640{
641 struct omap_dss_device *dssdev = to_dss_device(dev);
642
643 DSSDBG("bus_match. dev %s/%s, drv %s\n",
644 dev_name(dev), dssdev->driver_name, driver->name);
645
646 return strcmp(dssdev->driver_name, driver->name) == 0;
647}
648
649static ssize_t device_name_show(struct device *dev,
650 struct device_attribute *attr, char *buf)
651{
652 struct omap_dss_device *dssdev = to_dss_device(dev);
653 return snprintf(buf, PAGE_SIZE, "%s\n",
654 dssdev->name ?
655 dssdev->name : "");
656}
657
658static struct device_attribute default_dev_attrs[] = {
659 __ATTR(name, S_IRUGO, device_name_show, NULL),
660 __ATTR_NULL,
661};
662
663static ssize_t driver_name_show(struct device_driver *drv, char *buf)
664{
665 struct omap_dss_driver *dssdrv = to_dss_driver(drv);
666 return snprintf(buf, PAGE_SIZE, "%s\n",
667 dssdrv->driver.name ?
668 dssdrv->driver.name : "");
669}
670static struct driver_attribute default_drv_attrs[] = {
671 __ATTR(name, S_IRUGO, driver_name_show, NULL),
672 __ATTR_NULL,
673};
674
675static struct bus_type dss_bus_type = {
676 .name = "omapdss",
677 .match = dss_bus_match,
678 .dev_attrs = default_dev_attrs,
679 .drv_attrs = default_drv_attrs,
680};
681
682static void dss_bus_release(struct device *dev)
683{
684 DSSDBG("bus_release\n");
685}
686
687static struct device dss_bus = {
688 .release = dss_bus_release,
689};
690
691struct bus_type *dss_get_bus(void)
692{
693 return &dss_bus_type;
694}
695
696/* DRIVER */
697static int dss_driver_probe(struct device *dev)
698{
699 int r;
700 struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
701 struct omap_dss_device *dssdev = to_dss_device(dev);
702 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
703 bool force;
704
705 DSSDBG("driver_probe: dev %s/%s, drv %s\n",
706 dev_name(dev), dssdev->driver_name,
707 dssdrv->driver.name);
708
709 dss_init_device(core.pdev, dssdev);
710
711 /* skip this if the device is behind a ctrl */
712 if (!dssdev->panel.ctrl) {
713 force = pdata->default_device == dssdev;
714 dss_recheck_connections(dssdev, force);
715 }
716
717 r = dssdrv->probe(dssdev);
718
719 if (r) {
720 DSSERR("driver probe failed: %d\n", r);
721 return r;
722 }
723
724 DSSDBG("probe done for device %s\n", dev_name(dev));
725
726 dssdev->driver = dssdrv;
727
728 return 0;
729}
730
731static int dss_driver_remove(struct device *dev)
732{
733 struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
734 struct omap_dss_device *dssdev = to_dss_device(dev);
735
736 DSSDBG("driver_remove: dev %s/%s\n", dev_name(dev),
737 dssdev->driver_name);
738
739 dssdrv->remove(dssdev);
740
741 dss_uninit_device(core.pdev, dssdev);
742
743 dssdev->driver = NULL;
744
745 return 0;
746}
747
748int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
749{
750 dssdriver->driver.bus = &dss_bus_type;
751 dssdriver->driver.probe = dss_driver_probe;
752 dssdriver->driver.remove = dss_driver_remove;
753 return driver_register(&dssdriver->driver);
754}
755EXPORT_SYMBOL(omap_dss_register_driver);
756
757void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver)
758{
759 driver_unregister(&dssdriver->driver);
760}
761EXPORT_SYMBOL(omap_dss_unregister_driver);
762
763/* DEVICE */
764static void reset_device(struct device *dev, int check)
765{
766 u8 *dev_p = (u8 *)dev;
767 u8 *dev_end = dev_p + sizeof(*dev);
768 void *saved_pdata;
769
770 saved_pdata = dev->platform_data;
771 if (check) {
772 /*
773 * Check if there is any other setting than platform_data
774 * in struct device; warn that these will be reset by our
775 * init.
776 */
777 dev->platform_data = NULL;
778 while (dev_p < dev_end) {
779 if (*dev_p) {
780 WARN("%s: struct device fields will be "
781 "discarded\n",
782 __func__);
783 break;
784 }
785 dev_p++;
786 }
787 }
788 memset(dev, 0, sizeof(*dev));
789 dev->platform_data = saved_pdata;
790}
791
792
793static void omap_dss_dev_release(struct device *dev)
794{
795 reset_device(dev, 0);
796}
797
798int omap_dss_register_device(struct omap_dss_device *dssdev)
799{
800 static int dev_num;
801 static int panel_num;
802 int r;
803
804 WARN_ON(!dssdev->driver_name);
805
806 reset_device(&dssdev->dev, 1);
807 dssdev->dev.bus = &dss_bus_type;
808 dssdev->dev.parent = &dss_bus;
809 dssdev->dev.release = omap_dss_dev_release;
810 dev_set_name(&dssdev->dev, "display%d", dev_num++);
811 r = device_register(&dssdev->dev);
812 if (r)
813 return r;
814
815 if (dssdev->ctrl.panel) {
816 struct omap_dss_device *panel = dssdev->ctrl.panel;
817
818 panel->panel.ctrl = dssdev;
819
820 reset_device(&panel->dev, 1);
821 panel->dev.bus = &dss_bus_type;
822 panel->dev.parent = &dssdev->dev;
823 panel->dev.release = omap_dss_dev_release;
824 dev_set_name(&panel->dev, "panel%d", panel_num++);
825 r = device_register(&panel->dev);
826 if (r)
827 return r;
828 }
829
830 return 0;
831}
832
833void omap_dss_unregister_device(struct omap_dss_device *dssdev)
834{
835 device_unregister(&dssdev->dev);
836
837 if (dssdev->ctrl.panel) {
838 struct omap_dss_device *panel = dssdev->ctrl.panel;
839 device_unregister(&panel->dev);
840 }
841}
842
843/* BUS */
844static int omap_dss_bus_register(void)
845{
846 int r;
847
848 r = bus_register(&dss_bus_type);
849 if (r) {
850 DSSERR("bus register failed\n");
851 return r;
852 }
853
854 dev_set_name(&dss_bus, "omapdss");
855 r = device_register(&dss_bus);
856 if (r) {
857 DSSERR("bus driver register failed\n");
858 bus_unregister(&dss_bus_type);
859 return r;
860 }
861
862 return 0;
863}
864
865/* INIT */
866
867#ifdef CONFIG_OMAP2_DSS_MODULE
868static void omap_dss_bus_unregister(void)
869{
870 device_unregister(&dss_bus);
871
872 bus_unregister(&dss_bus_type);
873}
874
875static int __init omap_dss_init(void)
876{
877 int r;
878
879 r = omap_dss_bus_register();
880 if (r)
881 return r;
882
883 r = platform_driver_register(&omap_dss_driver);
884 if (r) {
885 omap_dss_bus_unregister();
886 return r;
887 }
888
889 return 0;
890}
891
892static void __exit omap_dss_exit(void)
893{
894 platform_driver_unregister(&omap_dss_driver);
895
896 omap_dss_bus_unregister();
897}
898
899module_init(omap_dss_init);
900module_exit(omap_dss_exit);
901#else
902static int __init omap_dss_init(void)
903{
904 return omap_dss_bus_register();
905}
906
907static int __init omap_dss_init2(void)
908{
909 return platform_driver_register(&omap_dss_driver);
910}
911
912core_initcall(omap_dss_init);
913device_initcall(omap_dss_init2);
914#endif
915
916MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
917MODULE_DESCRIPTION("OMAP2/3 Display Subsystem");
918MODULE_LICENSE("GPL v2");
919
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
new file mode 100644
index 000000000000..6dabf4b2f005
--- /dev/null
+++ b/drivers/video/omap2/dss/dispc.c
@@ -0,0 +1,3091 @@
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
151static struct {
152 void __iomem *base;
153
154 u32 fifo_size[3];
155
156 spinlock_t irq_lock;
157 u32 irq_error_mask;
158 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
159 u32 error_irqs;
160 struct work_struct error_work;
161
162 u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
163} dispc;
164
165static void _omap_dispc_set_irqs(void);
166
167static inline void dispc_write_reg(const struct dispc_reg idx, u32 val)
168{
169 __raw_writel(val, dispc.base + idx.idx);
170}
171
172static inline u32 dispc_read_reg(const struct dispc_reg idx)
173{
174 return __raw_readl(dispc.base + idx.idx);
175}
176
177#define SR(reg) \
178 dispc.ctx[(DISPC_##reg).idx / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
179#define RR(reg) \
180 dispc_write_reg(DISPC_##reg, dispc.ctx[(DISPC_##reg).idx / sizeof(u32)])
181
182void dispc_save_context(void)
183{
184 if (cpu_is_omap24xx())
185 return;
186
187 SR(SYSCONFIG);
188 SR(IRQENABLE);
189 SR(CONTROL);
190 SR(CONFIG);
191 SR(DEFAULT_COLOR0);
192 SR(DEFAULT_COLOR1);
193 SR(TRANS_COLOR0);
194 SR(TRANS_COLOR1);
195 SR(LINE_NUMBER);
196 SR(TIMING_H);
197 SR(TIMING_V);
198 SR(POL_FREQ);
199 SR(DIVISOR);
200 SR(GLOBAL_ALPHA);
201 SR(SIZE_DIG);
202 SR(SIZE_LCD);
203
204 SR(GFX_BA0);
205 SR(GFX_BA1);
206 SR(GFX_POSITION);
207 SR(GFX_SIZE);
208 SR(GFX_ATTRIBUTES);
209 SR(GFX_FIFO_THRESHOLD);
210 SR(GFX_ROW_INC);
211 SR(GFX_PIXEL_INC);
212 SR(GFX_WINDOW_SKIP);
213 SR(GFX_TABLE_BA);
214
215 SR(DATA_CYCLE1);
216 SR(DATA_CYCLE2);
217 SR(DATA_CYCLE3);
218
219 SR(CPR_COEF_R);
220 SR(CPR_COEF_G);
221 SR(CPR_COEF_B);
222
223 SR(GFX_PRELOAD);
224
225 /* VID1 */
226 SR(VID_BA0(0));
227 SR(VID_BA1(0));
228 SR(VID_POSITION(0));
229 SR(VID_SIZE(0));
230 SR(VID_ATTRIBUTES(0));
231 SR(VID_FIFO_THRESHOLD(0));
232 SR(VID_ROW_INC(0));
233 SR(VID_PIXEL_INC(0));
234 SR(VID_FIR(0));
235 SR(VID_PICTURE_SIZE(0));
236 SR(VID_ACCU0(0));
237 SR(VID_ACCU1(0));
238
239 SR(VID_FIR_COEF_H(0, 0));
240 SR(VID_FIR_COEF_H(0, 1));
241 SR(VID_FIR_COEF_H(0, 2));
242 SR(VID_FIR_COEF_H(0, 3));
243 SR(VID_FIR_COEF_H(0, 4));
244 SR(VID_FIR_COEF_H(0, 5));
245 SR(VID_FIR_COEF_H(0, 6));
246 SR(VID_FIR_COEF_H(0, 7));
247
248 SR(VID_FIR_COEF_HV(0, 0));
249 SR(VID_FIR_COEF_HV(0, 1));
250 SR(VID_FIR_COEF_HV(0, 2));
251 SR(VID_FIR_COEF_HV(0, 3));
252 SR(VID_FIR_COEF_HV(0, 4));
253 SR(VID_FIR_COEF_HV(0, 5));
254 SR(VID_FIR_COEF_HV(0, 6));
255 SR(VID_FIR_COEF_HV(0, 7));
256
257 SR(VID_CONV_COEF(0, 0));
258 SR(VID_CONV_COEF(0, 1));
259 SR(VID_CONV_COEF(0, 2));
260 SR(VID_CONV_COEF(0, 3));
261 SR(VID_CONV_COEF(0, 4));
262
263 SR(VID_FIR_COEF_V(0, 0));
264 SR(VID_FIR_COEF_V(0, 1));
265 SR(VID_FIR_COEF_V(0, 2));
266 SR(VID_FIR_COEF_V(0, 3));
267 SR(VID_FIR_COEF_V(0, 4));
268 SR(VID_FIR_COEF_V(0, 5));
269 SR(VID_FIR_COEF_V(0, 6));
270 SR(VID_FIR_COEF_V(0, 7));
271
272 SR(VID_PRELOAD(0));
273
274 /* VID2 */
275 SR(VID_BA0(1));
276 SR(VID_BA1(1));
277 SR(VID_POSITION(1));
278 SR(VID_SIZE(1));
279 SR(VID_ATTRIBUTES(1));
280 SR(VID_FIFO_THRESHOLD(1));
281 SR(VID_ROW_INC(1));
282 SR(VID_PIXEL_INC(1));
283 SR(VID_FIR(1));
284 SR(VID_PICTURE_SIZE(1));
285 SR(VID_ACCU0(1));
286 SR(VID_ACCU1(1));
287
288 SR(VID_FIR_COEF_H(1, 0));
289 SR(VID_FIR_COEF_H(1, 1));
290 SR(VID_FIR_COEF_H(1, 2));
291 SR(VID_FIR_COEF_H(1, 3));
292 SR(VID_FIR_COEF_H(1, 4));
293 SR(VID_FIR_COEF_H(1, 5));
294 SR(VID_FIR_COEF_H(1, 6));
295 SR(VID_FIR_COEF_H(1, 7));
296
297 SR(VID_FIR_COEF_HV(1, 0));
298 SR(VID_FIR_COEF_HV(1, 1));
299 SR(VID_FIR_COEF_HV(1, 2));
300 SR(VID_FIR_COEF_HV(1, 3));
301 SR(VID_FIR_COEF_HV(1, 4));
302 SR(VID_FIR_COEF_HV(1, 5));
303 SR(VID_FIR_COEF_HV(1, 6));
304 SR(VID_FIR_COEF_HV(1, 7));
305
306 SR(VID_CONV_COEF(1, 0));
307 SR(VID_CONV_COEF(1, 1));
308 SR(VID_CONV_COEF(1, 2));
309 SR(VID_CONV_COEF(1, 3));
310 SR(VID_CONV_COEF(1, 4));
311
312 SR(VID_FIR_COEF_V(1, 0));
313 SR(VID_FIR_COEF_V(1, 1));
314 SR(VID_FIR_COEF_V(1, 2));
315 SR(VID_FIR_COEF_V(1, 3));
316 SR(VID_FIR_COEF_V(1, 4));
317 SR(VID_FIR_COEF_V(1, 5));
318 SR(VID_FIR_COEF_V(1, 6));
319 SR(VID_FIR_COEF_V(1, 7));
320
321 SR(VID_PRELOAD(1));
322}
323
324void dispc_restore_context(void)
325{
326 RR(SYSCONFIG);
327 RR(IRQENABLE);
328 /*RR(CONTROL);*/
329 RR(CONFIG);
330 RR(DEFAULT_COLOR0);
331 RR(DEFAULT_COLOR1);
332 RR(TRANS_COLOR0);
333 RR(TRANS_COLOR1);
334 RR(LINE_NUMBER);
335 RR(TIMING_H);
336 RR(TIMING_V);
337 RR(POL_FREQ);
338 RR(DIVISOR);
339 RR(GLOBAL_ALPHA);
340 RR(SIZE_DIG);
341 RR(SIZE_LCD);
342
343 RR(GFX_BA0);
344 RR(GFX_BA1);
345 RR(GFX_POSITION);
346 RR(GFX_SIZE);
347 RR(GFX_ATTRIBUTES);
348 RR(GFX_FIFO_THRESHOLD);
349 RR(GFX_ROW_INC);
350 RR(GFX_PIXEL_INC);
351 RR(GFX_WINDOW_SKIP);
352 RR(GFX_TABLE_BA);
353
354 RR(DATA_CYCLE1);
355 RR(DATA_CYCLE2);
356 RR(DATA_CYCLE3);
357
358 RR(CPR_COEF_R);
359 RR(CPR_COEF_G);
360 RR(CPR_COEF_B);
361
362 RR(GFX_PRELOAD);
363
364 /* VID1 */
365 RR(VID_BA0(0));
366 RR(VID_BA1(0));
367 RR(VID_POSITION(0));
368 RR(VID_SIZE(0));
369 RR(VID_ATTRIBUTES(0));
370 RR(VID_FIFO_THRESHOLD(0));
371 RR(VID_ROW_INC(0));
372 RR(VID_PIXEL_INC(0));
373 RR(VID_FIR(0));
374 RR(VID_PICTURE_SIZE(0));
375 RR(VID_ACCU0(0));
376 RR(VID_ACCU1(0));
377
378 RR(VID_FIR_COEF_H(0, 0));
379 RR(VID_FIR_COEF_H(0, 1));
380 RR(VID_FIR_COEF_H(0, 2));
381 RR(VID_FIR_COEF_H(0, 3));
382 RR(VID_FIR_COEF_H(0, 4));
383 RR(VID_FIR_COEF_H(0, 5));
384 RR(VID_FIR_COEF_H(0, 6));
385 RR(VID_FIR_COEF_H(0, 7));
386
387 RR(VID_FIR_COEF_HV(0, 0));
388 RR(VID_FIR_COEF_HV(0, 1));
389 RR(VID_FIR_COEF_HV(0, 2));
390 RR(VID_FIR_COEF_HV(0, 3));
391 RR(VID_FIR_COEF_HV(0, 4));
392 RR(VID_FIR_COEF_HV(0, 5));
393 RR(VID_FIR_COEF_HV(0, 6));
394 RR(VID_FIR_COEF_HV(0, 7));
395
396 RR(VID_CONV_COEF(0, 0));
397 RR(VID_CONV_COEF(0, 1));
398 RR(VID_CONV_COEF(0, 2));
399 RR(VID_CONV_COEF(0, 3));
400 RR(VID_CONV_COEF(0, 4));
401
402 RR(VID_FIR_COEF_V(0, 0));
403 RR(VID_FIR_COEF_V(0, 1));
404 RR(VID_FIR_COEF_V(0, 2));
405 RR(VID_FIR_COEF_V(0, 3));
406 RR(VID_FIR_COEF_V(0, 4));
407 RR(VID_FIR_COEF_V(0, 5));
408 RR(VID_FIR_COEF_V(0, 6));
409 RR(VID_FIR_COEF_V(0, 7));
410
411 RR(VID_PRELOAD(0));
412
413 /* VID2 */
414 RR(VID_BA0(1));
415 RR(VID_BA1(1));
416 RR(VID_POSITION(1));
417 RR(VID_SIZE(1));
418 RR(VID_ATTRIBUTES(1));
419 RR(VID_FIFO_THRESHOLD(1));
420 RR(VID_ROW_INC(1));
421 RR(VID_PIXEL_INC(1));
422 RR(VID_FIR(1));
423 RR(VID_PICTURE_SIZE(1));
424 RR(VID_ACCU0(1));
425 RR(VID_ACCU1(1));
426
427 RR(VID_FIR_COEF_H(1, 0));
428 RR(VID_FIR_COEF_H(1, 1));
429 RR(VID_FIR_COEF_H(1, 2));
430 RR(VID_FIR_COEF_H(1, 3));
431 RR(VID_FIR_COEF_H(1, 4));
432 RR(VID_FIR_COEF_H(1, 5));
433 RR(VID_FIR_COEF_H(1, 6));
434 RR(VID_FIR_COEF_H(1, 7));
435
436 RR(VID_FIR_COEF_HV(1, 0));
437 RR(VID_FIR_COEF_HV(1, 1));
438 RR(VID_FIR_COEF_HV(1, 2));
439 RR(VID_FIR_COEF_HV(1, 3));
440 RR(VID_FIR_COEF_HV(1, 4));
441 RR(VID_FIR_COEF_HV(1, 5));
442 RR(VID_FIR_COEF_HV(1, 6));
443 RR(VID_FIR_COEF_HV(1, 7));
444
445 RR(VID_CONV_COEF(1, 0));
446 RR(VID_CONV_COEF(1, 1));
447 RR(VID_CONV_COEF(1, 2));
448 RR(VID_CONV_COEF(1, 3));
449 RR(VID_CONV_COEF(1, 4));
450
451 RR(VID_FIR_COEF_V(1, 0));
452 RR(VID_FIR_COEF_V(1, 1));
453 RR(VID_FIR_COEF_V(1, 2));
454 RR(VID_FIR_COEF_V(1, 3));
455 RR(VID_FIR_COEF_V(1, 4));
456 RR(VID_FIR_COEF_V(1, 5));
457 RR(VID_FIR_COEF_V(1, 6));
458 RR(VID_FIR_COEF_V(1, 7));
459
460 RR(VID_PRELOAD(1));
461
462 /* enable last, because LCD & DIGIT enable are here */
463 RR(CONTROL);
464}
465
466#undef SR
467#undef RR
468
469static inline void enable_clocks(bool enable)
470{
471 if (enable)
472 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
473 else
474 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
475}
476
477bool dispc_go_busy(enum omap_channel channel)
478{
479 int bit;
480
481 if (channel == OMAP_DSS_CHANNEL_LCD)
482 bit = 5; /* GOLCD */
483 else
484 bit = 6; /* GODIGIT */
485
486 return REG_GET(DISPC_CONTROL, bit, bit) == 1;
487}
488
489void dispc_go(enum omap_channel channel)
490{
491 int bit;
492
493 enable_clocks(1);
494
495 if (channel == OMAP_DSS_CHANNEL_LCD)
496 bit = 0; /* LCDENABLE */
497 else
498 bit = 1; /* DIGITALENABLE */
499
500 /* if the channel is not enabled, we don't need GO */
501 if (REG_GET(DISPC_CONTROL, bit, bit) == 0)
502 goto end;
503
504 if (channel == OMAP_DSS_CHANNEL_LCD)
505 bit = 5; /* GOLCD */
506 else
507 bit = 6; /* GODIGIT */
508
509 if (REG_GET(DISPC_CONTROL, bit, bit) == 1) {
510 DSSERR("GO bit not down for channel %d\n", channel);
511 goto end;
512 }
513
514 DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT");
515
516 REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
517end:
518 enable_clocks(0);
519}
520
521static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
522{
523 BUG_ON(plane == OMAP_DSS_GFX);
524
525 dispc_write_reg(DISPC_VID_FIR_COEF_H(plane-1, reg), value);
526}
527
528static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
529{
530 BUG_ON(plane == OMAP_DSS_GFX);
531
532 dispc_write_reg(DISPC_VID_FIR_COEF_HV(plane-1, reg), value);
533}
534
535static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
536{
537 BUG_ON(plane == OMAP_DSS_GFX);
538
539 dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
540}
541
542static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
543 int vscaleup, int five_taps)
544{
545 /* Coefficients for horizontal up-sampling */
546 static const u32 coef_hup[8] = {
547 0x00800000,
548 0x0D7CF800,
549 0x1E70F5FF,
550 0x335FF5FE,
551 0xF74949F7,
552 0xF55F33FB,
553 0xF5701EFE,
554 0xF87C0DFF,
555 };
556
557 /* Coefficients for horizontal down-sampling */
558 static const u32 coef_hdown[8] = {
559 0x24382400,
560 0x28371FFE,
561 0x2C361BFB,
562 0x303516F9,
563 0x11343311,
564 0x1635300C,
565 0x1B362C08,
566 0x1F372804,
567 };
568
569 /* Coefficients for horizontal and vertical up-sampling */
570 static const u32 coef_hvup[2][8] = {
571 {
572 0x00800000,
573 0x037B02FF,
574 0x0C6F05FE,
575 0x205907FB,
576 0x00404000,
577 0x075920FE,
578 0x056F0CFF,
579 0x027B0300,
580 },
581 {
582 0x00800000,
583 0x0D7CF8FF,
584 0x1E70F5FE,
585 0x335FF5FB,
586 0xF7404000,
587 0xF55F33FE,
588 0xF5701EFF,
589 0xF87C0D00,
590 },
591 };
592
593 /* Coefficients for horizontal and vertical down-sampling */
594 static const u32 coef_hvdown[2][8] = {
595 {
596 0x24382400,
597 0x28391F04,
598 0x2D381B08,
599 0x3237170C,
600 0x123737F7,
601 0x173732F9,
602 0x1B382DFB,
603 0x1F3928FE,
604 },
605 {
606 0x24382400,
607 0x28371F04,
608 0x2C361B08,
609 0x3035160C,
610 0x113433F7,
611 0x163530F9,
612 0x1B362CFB,
613 0x1F3728FE,
614 },
615 };
616
617 /* Coefficients for vertical up-sampling */
618 static const u32 coef_vup[8] = {
619 0x00000000,
620 0x0000FF00,
621 0x0000FEFF,
622 0x0000FBFE,
623 0x000000F7,
624 0x0000FEFB,
625 0x0000FFFE,
626 0x000000FF,
627 };
628
629
630 /* Coefficients for vertical down-sampling */
631 static const u32 coef_vdown[8] = {
632 0x00000000,
633 0x000004FE,
634 0x000008FB,
635 0x00000CF9,
636 0x0000F711,
637 0x0000F90C,
638 0x0000FB08,
639 0x0000FE04,
640 };
641
642 const u32 *h_coef;
643 const u32 *hv_coef;
644 const u32 *hv_coef_mod;
645 const u32 *v_coef;
646 int i;
647
648 if (hscaleup)
649 h_coef = coef_hup;
650 else
651 h_coef = coef_hdown;
652
653 if (vscaleup) {
654 hv_coef = coef_hvup[five_taps];
655 v_coef = coef_vup;
656
657 if (hscaleup)
658 hv_coef_mod = NULL;
659 else
660 hv_coef_mod = coef_hvdown[five_taps];
661 } else {
662 hv_coef = coef_hvdown[five_taps];
663 v_coef = coef_vdown;
664
665 if (hscaleup)
666 hv_coef_mod = coef_hvup[five_taps];
667 else
668 hv_coef_mod = NULL;
669 }
670
671 for (i = 0; i < 8; i++) {
672 u32 h, hv;
673
674 h = h_coef[i];
675
676 hv = hv_coef[i];
677
678 if (hv_coef_mod) {
679 hv &= 0xffffff00;
680 hv |= (hv_coef_mod[i] & 0xff);
681 }
682
683 _dispc_write_firh_reg(plane, i, h);
684 _dispc_write_firhv_reg(plane, i, hv);
685 }
686
687 if (!five_taps)
688 return;
689
690 for (i = 0; i < 8; i++) {
691 u32 v;
692 v = v_coef[i];
693 _dispc_write_firv_reg(plane, i, v);
694 }
695}
696
697static void _dispc_setup_color_conv_coef(void)
698{
699 const struct color_conv_coef {
700 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
701 int full_range;
702 } ctbl_bt601_5 = {
703 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
704 };
705
706 const struct color_conv_coef *ct;
707
708#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
709
710 ct = &ctbl_bt601_5;
711
712 dispc_write_reg(DISPC_VID_CONV_COEF(0, 0), CVAL(ct->rcr, ct->ry));
713 dispc_write_reg(DISPC_VID_CONV_COEF(0, 1), CVAL(ct->gy, ct->rcb));
714 dispc_write_reg(DISPC_VID_CONV_COEF(0, 2), CVAL(ct->gcb, ct->gcr));
715 dispc_write_reg(DISPC_VID_CONV_COEF(0, 3), CVAL(ct->bcr, ct->by));
716 dispc_write_reg(DISPC_VID_CONV_COEF(0, 4), CVAL(0, ct->bcb));
717
718 dispc_write_reg(DISPC_VID_CONV_COEF(1, 0), CVAL(ct->rcr, ct->ry));
719 dispc_write_reg(DISPC_VID_CONV_COEF(1, 1), CVAL(ct->gy, ct->rcb));
720 dispc_write_reg(DISPC_VID_CONV_COEF(1, 2), CVAL(ct->gcb, ct->gcr));
721 dispc_write_reg(DISPC_VID_CONV_COEF(1, 3), CVAL(ct->bcr, ct->by));
722 dispc_write_reg(DISPC_VID_CONV_COEF(1, 4), CVAL(0, ct->bcb));
723
724#undef CVAL
725
726 REG_FLD_MOD(DISPC_VID_ATTRIBUTES(0), ct->full_range, 11, 11);
727 REG_FLD_MOD(DISPC_VID_ATTRIBUTES(1), ct->full_range, 11, 11);
728}
729
730
731static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
732{
733 const struct dispc_reg ba0_reg[] = { DISPC_GFX_BA0,
734 DISPC_VID_BA0(0),
735 DISPC_VID_BA0(1) };
736
737 dispc_write_reg(ba0_reg[plane], paddr);
738}
739
740static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr)
741{
742 const struct dispc_reg ba1_reg[] = { DISPC_GFX_BA1,
743 DISPC_VID_BA1(0),
744 DISPC_VID_BA1(1) };
745
746 dispc_write_reg(ba1_reg[plane], paddr);
747}
748
749static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
750{
751 const struct dispc_reg pos_reg[] = { DISPC_GFX_POSITION,
752 DISPC_VID_POSITION(0),
753 DISPC_VID_POSITION(1) };
754
755 u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
756 dispc_write_reg(pos_reg[plane], val);
757}
758
759static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
760{
761 const struct dispc_reg siz_reg[] = { DISPC_GFX_SIZE,
762 DISPC_VID_PICTURE_SIZE(0),
763 DISPC_VID_PICTURE_SIZE(1) };
764 u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
765 dispc_write_reg(siz_reg[plane], val);
766}
767
768static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
769{
770 u32 val;
771 const struct dispc_reg vsi_reg[] = { DISPC_VID_SIZE(0),
772 DISPC_VID_SIZE(1) };
773
774 BUG_ON(plane == OMAP_DSS_GFX);
775
776 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
777 dispc_write_reg(vsi_reg[plane-1], val);
778}
779
780static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
781{
782
783 BUG_ON(plane == OMAP_DSS_VIDEO1);
784
785 if (cpu_is_omap24xx())
786 return;
787
788 if (plane == OMAP_DSS_GFX)
789 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
790 else if (plane == OMAP_DSS_VIDEO2)
791 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16);
792}
793
794static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
795{
796 const struct dispc_reg ri_reg[] = { DISPC_GFX_PIXEL_INC,
797 DISPC_VID_PIXEL_INC(0),
798 DISPC_VID_PIXEL_INC(1) };
799
800 dispc_write_reg(ri_reg[plane], inc);
801}
802
803static void _dispc_set_row_inc(enum omap_plane plane, s32 inc)
804{
805 const struct dispc_reg ri_reg[] = { DISPC_GFX_ROW_INC,
806 DISPC_VID_ROW_INC(0),
807 DISPC_VID_ROW_INC(1) };
808
809 dispc_write_reg(ri_reg[plane], inc);
810}
811
812static void _dispc_set_color_mode(enum omap_plane plane,
813 enum omap_color_mode color_mode)
814{
815 u32 m = 0;
816
817 switch (color_mode) {
818 case OMAP_DSS_COLOR_CLUT1:
819 m = 0x0; break;
820 case OMAP_DSS_COLOR_CLUT2:
821 m = 0x1; break;
822 case OMAP_DSS_COLOR_CLUT4:
823 m = 0x2; break;
824 case OMAP_DSS_COLOR_CLUT8:
825 m = 0x3; break;
826 case OMAP_DSS_COLOR_RGB12U:
827 m = 0x4; break;
828 case OMAP_DSS_COLOR_ARGB16:
829 m = 0x5; break;
830 case OMAP_DSS_COLOR_RGB16:
831 m = 0x6; break;
832 case OMAP_DSS_COLOR_RGB24U:
833 m = 0x8; break;
834 case OMAP_DSS_COLOR_RGB24P:
835 m = 0x9; break;
836 case OMAP_DSS_COLOR_YUV2:
837 m = 0xa; break;
838 case OMAP_DSS_COLOR_UYVY:
839 m = 0xb; break;
840 case OMAP_DSS_COLOR_ARGB32:
841 m = 0xc; break;
842 case OMAP_DSS_COLOR_RGBA32:
843 m = 0xd; break;
844 case OMAP_DSS_COLOR_RGBX32:
845 m = 0xe; break;
846 default:
847 BUG(); break;
848 }
849
850 REG_FLD_MOD(dispc_reg_att[plane], m, 4, 1);
851}
852
853static void _dispc_set_channel_out(enum omap_plane plane,
854 enum omap_channel channel)
855{
856 int shift;
857 u32 val;
858
859 switch (plane) {
860 case OMAP_DSS_GFX:
861 shift = 8;
862 break;
863 case OMAP_DSS_VIDEO1:
864 case OMAP_DSS_VIDEO2:
865 shift = 16;
866 break;
867 default:
868 BUG();
869 return;
870 }
871
872 val = dispc_read_reg(dispc_reg_att[plane]);
873 val = FLD_MOD(val, channel, shift, shift);
874 dispc_write_reg(dispc_reg_att[plane], val);
875}
876
877void dispc_set_burst_size(enum omap_plane plane,
878 enum omap_burst_size burst_size)
879{
880 int shift;
881 u32 val;
882
883 enable_clocks(1);
884
885 switch (plane) {
886 case OMAP_DSS_GFX:
887 shift = 6;
888 break;
889 case OMAP_DSS_VIDEO1:
890 case OMAP_DSS_VIDEO2:
891 shift = 14;
892 break;
893 default:
894 BUG();
895 return;
896 }
897
898 val = dispc_read_reg(dispc_reg_att[plane]);
899 val = FLD_MOD(val, burst_size, shift+1, shift);
900 dispc_write_reg(dispc_reg_att[plane], val);
901
902 enable_clocks(0);
903}
904
905static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
906{
907 u32 val;
908
909 BUG_ON(plane == OMAP_DSS_GFX);
910
911 val = dispc_read_reg(dispc_reg_att[plane]);
912 val = FLD_MOD(val, enable, 9, 9);
913 dispc_write_reg(dispc_reg_att[plane], val);
914}
915
916void dispc_enable_replication(enum omap_plane plane, bool enable)
917{
918 int bit;
919
920 if (plane == OMAP_DSS_GFX)
921 bit = 5;
922 else
923 bit = 10;
924
925 enable_clocks(1);
926 REG_FLD_MOD(dispc_reg_att[plane], enable, bit, bit);
927 enable_clocks(0);
928}
929
930void dispc_set_lcd_size(u16 width, u16 height)
931{
932 u32 val;
933 BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
934 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
935 enable_clocks(1);
936 dispc_write_reg(DISPC_SIZE_LCD, val);
937 enable_clocks(0);
938}
939
940void dispc_set_digit_size(u16 width, u16 height)
941{
942 u32 val;
943 BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
944 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
945 enable_clocks(1);
946 dispc_write_reg(DISPC_SIZE_DIG, val);
947 enable_clocks(0);
948}
949
950static void dispc_read_plane_fifo_sizes(void)
951{
952 const struct dispc_reg fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
953 DISPC_VID_FIFO_SIZE_STATUS(0),
954 DISPC_VID_FIFO_SIZE_STATUS(1) };
955 u32 size;
956 int plane;
957
958 enable_clocks(1);
959
960 for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
961 if (cpu_is_omap24xx())
962 size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 8, 0);
963 else if (cpu_is_omap34xx())
964 size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 10, 0);
965 else
966 BUG();
967
968 dispc.fifo_size[plane] = size;
969 }
970
971 enable_clocks(0);
972}
973
974u32 dispc_get_plane_fifo_size(enum omap_plane plane)
975{
976 return dispc.fifo_size[plane];
977}
978
979void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
980{
981 const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
982 DISPC_VID_FIFO_THRESHOLD(0),
983 DISPC_VID_FIFO_THRESHOLD(1) };
984 enable_clocks(1);
985
986 DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
987 plane,
988 REG_GET(ftrs_reg[plane], 11, 0),
989 REG_GET(ftrs_reg[plane], 27, 16),
990 low, high);
991
992 if (cpu_is_omap24xx())
993 dispc_write_reg(ftrs_reg[plane],
994 FLD_VAL(high, 24, 16) | FLD_VAL(low, 8, 0));
995 else
996 dispc_write_reg(ftrs_reg[plane],
997 FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0));
998
999 enable_clocks(0);
1000}
1001
1002void dispc_enable_fifomerge(bool enable)
1003{
1004 enable_clocks(1);
1005
1006 DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1007 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
1008
1009 enable_clocks(0);
1010}
1011
1012static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
1013{
1014 u32 val;
1015 const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0),
1016 DISPC_VID_FIR(1) };
1017
1018 BUG_ON(plane == OMAP_DSS_GFX);
1019
1020 if (cpu_is_omap24xx())
1021 val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0);
1022 else
1023 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1024 dispc_write_reg(fir_reg[plane-1], val);
1025}
1026
1027static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
1028{
1029 u32 val;
1030 const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
1031 DISPC_VID_ACCU0(1) };
1032
1033 BUG_ON(plane == OMAP_DSS_GFX);
1034
1035 val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
1036 dispc_write_reg(ac0_reg[plane-1], val);
1037}
1038
1039static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
1040{
1041 u32 val;
1042 const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
1043 DISPC_VID_ACCU1(1) };
1044
1045 BUG_ON(plane == OMAP_DSS_GFX);
1046
1047 val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
1048 dispc_write_reg(ac1_reg[plane-1], val);
1049}
1050
1051
1052static void _dispc_set_scaling(enum omap_plane plane,
1053 u16 orig_width, u16 orig_height,
1054 u16 out_width, u16 out_height,
1055 bool ilace, bool five_taps,
1056 bool fieldmode)
1057{
1058 int fir_hinc;
1059 int fir_vinc;
1060 int hscaleup, vscaleup;
1061 int accu0 = 0;
1062 int accu1 = 0;
1063 u32 l;
1064
1065 BUG_ON(plane == OMAP_DSS_GFX);
1066
1067 hscaleup = orig_width <= out_width;
1068 vscaleup = orig_height <= out_height;
1069
1070 _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps);
1071
1072 if (!orig_width || orig_width == out_width)
1073 fir_hinc = 0;
1074 else
1075 fir_hinc = 1024 * orig_width / out_width;
1076
1077 if (!orig_height || orig_height == out_height)
1078 fir_vinc = 0;
1079 else
1080 fir_vinc = 1024 * orig_height / out_height;
1081
1082 _dispc_set_fir(plane, fir_hinc, fir_vinc);
1083
1084 l = dispc_read_reg(dispc_reg_att[plane]);
1085 l &= ~((0x0f << 5) | (0x3 << 21));
1086
1087 l |= fir_hinc ? (1 << 5) : 0;
1088 l |= fir_vinc ? (1 << 6) : 0;
1089
1090 l |= hscaleup ? 0 : (1 << 7);
1091 l |= vscaleup ? 0 : (1 << 8);
1092
1093 l |= five_taps ? (1 << 21) : 0;
1094 l |= five_taps ? (1 << 22) : 0;
1095
1096 dispc_write_reg(dispc_reg_att[plane], l);
1097
1098 /*
1099 * field 0 = even field = bottom field
1100 * field 1 = odd field = top field
1101 */
1102 if (ilace && !fieldmode) {
1103 accu1 = 0;
1104 accu0 = (fir_vinc / 2) & 0x3ff;
1105 if (accu0 >= 1024/2) {
1106 accu1 = 1024/2;
1107 accu0 -= accu1;
1108 }
1109 }
1110
1111 _dispc_set_vid_accu0(plane, 0, accu0);
1112 _dispc_set_vid_accu1(plane, 0, accu1);
1113}
1114
1115static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
1116 bool mirroring, enum omap_color_mode color_mode)
1117{
1118 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1119 color_mode == OMAP_DSS_COLOR_UYVY) {
1120 int vidrot = 0;
1121
1122 if (mirroring) {
1123 switch (rotation) {
1124 case OMAP_DSS_ROT_0:
1125 vidrot = 2;
1126 break;
1127 case OMAP_DSS_ROT_90:
1128 vidrot = 1;
1129 break;
1130 case OMAP_DSS_ROT_180:
1131 vidrot = 0;
1132 break;
1133 case OMAP_DSS_ROT_270:
1134 vidrot = 3;
1135 break;
1136 }
1137 } else {
1138 switch (rotation) {
1139 case OMAP_DSS_ROT_0:
1140 vidrot = 0;
1141 break;
1142 case OMAP_DSS_ROT_90:
1143 vidrot = 1;
1144 break;
1145 case OMAP_DSS_ROT_180:
1146 vidrot = 2;
1147 break;
1148 case OMAP_DSS_ROT_270:
1149 vidrot = 3;
1150 break;
1151 }
1152 }
1153
1154 REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
1155
1156 if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
1157 REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
1158 else
1159 REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
1160 } else {
1161 REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
1162 REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
1163 }
1164}
1165
1166static int color_mode_to_bpp(enum omap_color_mode color_mode)
1167{
1168 switch (color_mode) {
1169 case OMAP_DSS_COLOR_CLUT1:
1170 return 1;
1171 case OMAP_DSS_COLOR_CLUT2:
1172 return 2;
1173 case OMAP_DSS_COLOR_CLUT4:
1174 return 4;
1175 case OMAP_DSS_COLOR_CLUT8:
1176 return 8;
1177 case OMAP_DSS_COLOR_RGB12U:
1178 case OMAP_DSS_COLOR_RGB16:
1179 case OMAP_DSS_COLOR_ARGB16:
1180 case OMAP_DSS_COLOR_YUV2:
1181 case OMAP_DSS_COLOR_UYVY:
1182 return 16;
1183 case OMAP_DSS_COLOR_RGB24P:
1184 return 24;
1185 case OMAP_DSS_COLOR_RGB24U:
1186 case OMAP_DSS_COLOR_ARGB32:
1187 case OMAP_DSS_COLOR_RGBA32:
1188 case OMAP_DSS_COLOR_RGBX32:
1189 return 32;
1190 default:
1191 BUG();
1192 }
1193}
1194
1195static s32 pixinc(int pixels, u8 ps)
1196{
1197 if (pixels == 1)
1198 return 1;
1199 else if (pixels > 1)
1200 return 1 + (pixels - 1) * ps;
1201 else if (pixels < 0)
1202 return 1 - (-pixels + 1) * ps;
1203 else
1204 BUG();
1205}
1206
1207static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
1208 u16 screen_width,
1209 u16 width, u16 height,
1210 enum omap_color_mode color_mode, bool fieldmode,
1211 unsigned int field_offset,
1212 unsigned *offset0, unsigned *offset1,
1213 s32 *row_inc, s32 *pix_inc)
1214{
1215 u8 ps;
1216
1217 /* FIXME CLUT formats */
1218 switch (color_mode) {
1219 case OMAP_DSS_COLOR_CLUT1:
1220 case OMAP_DSS_COLOR_CLUT2:
1221 case OMAP_DSS_COLOR_CLUT4:
1222 case OMAP_DSS_COLOR_CLUT8:
1223 BUG();
1224 return;
1225 case OMAP_DSS_COLOR_YUV2:
1226 case OMAP_DSS_COLOR_UYVY:
1227 ps = 4;
1228 break;
1229 default:
1230 ps = color_mode_to_bpp(color_mode) / 8;
1231 break;
1232 }
1233
1234 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1235 width, height);
1236
1237 /*
1238 * field 0 = even field = bottom field
1239 * field 1 = odd field = top field
1240 */
1241 switch (rotation + mirror * 4) {
1242 case OMAP_DSS_ROT_0:
1243 case OMAP_DSS_ROT_180:
1244 /*
1245 * If the pixel format is YUV or UYVY divide the width
1246 * of the image by 2 for 0 and 180 degree rotation.
1247 */
1248 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1249 color_mode == OMAP_DSS_COLOR_UYVY)
1250 width = width >> 1;
1251 case OMAP_DSS_ROT_90:
1252 case OMAP_DSS_ROT_270:
1253 *offset1 = 0;
1254 if (field_offset)
1255 *offset0 = field_offset * screen_width * ps;
1256 else
1257 *offset0 = 0;
1258
1259 *row_inc = pixinc(1 + (screen_width - width) +
1260 (fieldmode ? screen_width : 0),
1261 ps);
1262 *pix_inc = pixinc(1, ps);
1263 break;
1264
1265 case OMAP_DSS_ROT_0 + 4:
1266 case OMAP_DSS_ROT_180 + 4:
1267 /* If the pixel format is YUV or UYVY divide the width
1268 * of the image by 2 for 0 degree and 180 degree
1269 */
1270 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1271 color_mode == OMAP_DSS_COLOR_UYVY)
1272 width = width >> 1;
1273 case OMAP_DSS_ROT_90 + 4:
1274 case OMAP_DSS_ROT_270 + 4:
1275 *offset1 = 0;
1276 if (field_offset)
1277 *offset0 = field_offset * screen_width * ps;
1278 else
1279 *offset0 = 0;
1280 *row_inc = pixinc(1 - (screen_width + width) -
1281 (fieldmode ? screen_width : 0),
1282 ps);
1283 *pix_inc = pixinc(1, ps);
1284 break;
1285
1286 default:
1287 BUG();
1288 }
1289}
1290
1291static void calc_dma_rotation_offset(u8 rotation, bool mirror,
1292 u16 screen_width,
1293 u16 width, u16 height,
1294 enum omap_color_mode color_mode, bool fieldmode,
1295 unsigned int field_offset,
1296 unsigned *offset0, unsigned *offset1,
1297 s32 *row_inc, s32 *pix_inc)
1298{
1299 u8 ps;
1300 u16 fbw, fbh;
1301
1302 /* FIXME CLUT formats */
1303 switch (color_mode) {
1304 case OMAP_DSS_COLOR_CLUT1:
1305 case OMAP_DSS_COLOR_CLUT2:
1306 case OMAP_DSS_COLOR_CLUT4:
1307 case OMAP_DSS_COLOR_CLUT8:
1308 BUG();
1309 return;
1310 default:
1311 ps = color_mode_to_bpp(color_mode) / 8;
1312 break;
1313 }
1314
1315 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1316 width, height);
1317
1318 /* width & height are overlay sizes, convert to fb sizes */
1319
1320 if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) {
1321 fbw = width;
1322 fbh = height;
1323 } else {
1324 fbw = height;
1325 fbh = width;
1326 }
1327
1328 /*
1329 * field 0 = even field = bottom field
1330 * field 1 = odd field = top field
1331 */
1332 switch (rotation + mirror * 4) {
1333 case OMAP_DSS_ROT_0:
1334 *offset1 = 0;
1335 if (field_offset)
1336 *offset0 = *offset1 + field_offset * screen_width * ps;
1337 else
1338 *offset0 = *offset1;
1339 *row_inc = pixinc(1 + (screen_width - fbw) +
1340 (fieldmode ? screen_width : 0),
1341 ps);
1342 *pix_inc = pixinc(1, ps);
1343 break;
1344 case OMAP_DSS_ROT_90:
1345 *offset1 = screen_width * (fbh - 1) * ps;
1346 if (field_offset)
1347 *offset0 = *offset1 + field_offset * ps;
1348 else
1349 *offset0 = *offset1;
1350 *row_inc = pixinc(screen_width * (fbh - 1) + 1 +
1351 (fieldmode ? 1 : 0), ps);
1352 *pix_inc = pixinc(-screen_width, ps);
1353 break;
1354 case OMAP_DSS_ROT_180:
1355 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1356 if (field_offset)
1357 *offset0 = *offset1 - field_offset * screen_width * ps;
1358 else
1359 *offset0 = *offset1;
1360 *row_inc = pixinc(-1 -
1361 (screen_width - fbw) -
1362 (fieldmode ? screen_width : 0),
1363 ps);
1364 *pix_inc = pixinc(-1, ps);
1365 break;
1366 case OMAP_DSS_ROT_270:
1367 *offset1 = (fbw - 1) * ps;
1368 if (field_offset)
1369 *offset0 = *offset1 - field_offset * ps;
1370 else
1371 *offset0 = *offset1;
1372 *row_inc = pixinc(-screen_width * (fbh - 1) - 1 -
1373 (fieldmode ? 1 : 0), ps);
1374 *pix_inc = pixinc(screen_width, ps);
1375 break;
1376
1377 /* mirroring */
1378 case OMAP_DSS_ROT_0 + 4:
1379 *offset1 = (fbw - 1) * ps;
1380 if (field_offset)
1381 *offset0 = *offset1 + field_offset * screen_width * ps;
1382 else
1383 *offset0 = *offset1;
1384 *row_inc = pixinc(screen_width * 2 - 1 +
1385 (fieldmode ? screen_width : 0),
1386 ps);
1387 *pix_inc = pixinc(-1, ps);
1388 break;
1389
1390 case OMAP_DSS_ROT_90 + 4:
1391 *offset1 = 0;
1392 if (field_offset)
1393 *offset0 = *offset1 + field_offset * ps;
1394 else
1395 *offset0 = *offset1;
1396 *row_inc = pixinc(-screen_width * (fbh - 1) + 1 +
1397 (fieldmode ? 1 : 0),
1398 ps);
1399 *pix_inc = pixinc(screen_width, ps);
1400 break;
1401
1402 case OMAP_DSS_ROT_180 + 4:
1403 *offset1 = screen_width * (fbh - 1) * ps;
1404 if (field_offset)
1405 *offset0 = *offset1 - field_offset * screen_width * ps;
1406 else
1407 *offset0 = *offset1;
1408 *row_inc = pixinc(1 - screen_width * 2 -
1409 (fieldmode ? screen_width : 0),
1410 ps);
1411 *pix_inc = pixinc(1, ps);
1412 break;
1413
1414 case OMAP_DSS_ROT_270 + 4:
1415 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1416 if (field_offset)
1417 *offset0 = *offset1 - field_offset * ps;
1418 else
1419 *offset0 = *offset1;
1420 *row_inc = pixinc(screen_width * (fbh - 1) - 1 -
1421 (fieldmode ? 1 : 0),
1422 ps);
1423 *pix_inc = pixinc(-screen_width, ps);
1424 break;
1425
1426 default:
1427 BUG();
1428 }
1429}
1430
1431static unsigned long calc_fclk_five_taps(u16 width, u16 height,
1432 u16 out_width, u16 out_height, enum omap_color_mode color_mode)
1433{
1434 u32 fclk = 0;
1435 /* FIXME venc pclk? */
1436 u64 tmp, pclk = dispc_pclk_rate();
1437
1438 if (height > out_height) {
1439 /* FIXME get real display PPL */
1440 unsigned int ppl = 800;
1441
1442 tmp = pclk * height * out_width;
1443 do_div(tmp, 2 * out_height * ppl);
1444 fclk = tmp;
1445
1446 if (height > 2 * out_height && ppl != out_width) {
1447 tmp = pclk * (height - 2 * out_height) * out_width;
1448 do_div(tmp, 2 * out_height * (ppl - out_width));
1449 fclk = max(fclk, (u32) tmp);
1450 }
1451 }
1452
1453 if (width > out_width) {
1454 tmp = pclk * width;
1455 do_div(tmp, out_width);
1456 fclk = max(fclk, (u32) tmp);
1457
1458 if (color_mode == OMAP_DSS_COLOR_RGB24U)
1459 fclk <<= 1;
1460 }
1461
1462 return fclk;
1463}
1464
1465static unsigned long calc_fclk(u16 width, u16 height,
1466 u16 out_width, u16 out_height)
1467{
1468 unsigned int hf, vf;
1469
1470 /*
1471 * FIXME how to determine the 'A' factor
1472 * for the no downscaling case ?
1473 */
1474
1475 if (width > 3 * out_width)
1476 hf = 4;
1477 else if (width > 2 * out_width)
1478 hf = 3;
1479 else if (width > out_width)
1480 hf = 2;
1481 else
1482 hf = 1;
1483
1484 if (height > out_height)
1485 vf = 2;
1486 else
1487 vf = 1;
1488
1489 /* FIXME venc pclk? */
1490 return dispc_pclk_rate() * vf * hf;
1491}
1492
1493void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
1494{
1495 enable_clocks(1);
1496 _dispc_set_channel_out(plane, channel_out);
1497 enable_clocks(0);
1498}
1499
1500static int _dispc_setup_plane(enum omap_plane plane,
1501 u32 paddr, u16 screen_width,
1502 u16 pos_x, u16 pos_y,
1503 u16 width, u16 height,
1504 u16 out_width, u16 out_height,
1505 enum omap_color_mode color_mode,
1506 bool ilace,
1507 enum omap_dss_rotation_type rotation_type,
1508 u8 rotation, int mirror,
1509 u8 global_alpha)
1510{
1511 const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
1512 bool five_taps = 0;
1513 bool fieldmode = 0;
1514 int cconv = 0;
1515 unsigned offset0, offset1;
1516 s32 row_inc;
1517 s32 pix_inc;
1518 u16 frame_height = height;
1519 unsigned int field_offset = 0;
1520
1521 if (paddr == 0)
1522 return -EINVAL;
1523
1524 if (ilace && height == out_height)
1525 fieldmode = 1;
1526
1527 if (ilace) {
1528 if (fieldmode)
1529 height /= 2;
1530 pos_y /= 2;
1531 out_height /= 2;
1532
1533 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
1534 "out_height %d\n",
1535 height, pos_y, out_height);
1536 }
1537
1538 if (plane == OMAP_DSS_GFX) {
1539 if (width != out_width || height != out_height)
1540 return -EINVAL;
1541
1542 switch (color_mode) {
1543 case OMAP_DSS_COLOR_ARGB16:
1544 case OMAP_DSS_COLOR_ARGB32:
1545 case OMAP_DSS_COLOR_RGBA32:
1546 case OMAP_DSS_COLOR_RGBX32:
1547 if (cpu_is_omap24xx())
1548 return -EINVAL;
1549 /* fall through */
1550 case OMAP_DSS_COLOR_RGB12U:
1551 case OMAP_DSS_COLOR_RGB16:
1552 case OMAP_DSS_COLOR_RGB24P:
1553 case OMAP_DSS_COLOR_RGB24U:
1554 break;
1555
1556 default:
1557 return -EINVAL;
1558 }
1559 } else {
1560 /* video plane */
1561
1562 unsigned long fclk = 0;
1563
1564 if (out_width < width / maxdownscale ||
1565 out_width > width * 8)
1566 return -EINVAL;
1567
1568 if (out_height < height / maxdownscale ||
1569 out_height > height * 8)
1570 return -EINVAL;
1571
1572 switch (color_mode) {
1573 case OMAP_DSS_COLOR_RGBX32:
1574 case OMAP_DSS_COLOR_RGB12U:
1575 if (cpu_is_omap24xx())
1576 return -EINVAL;
1577 /* fall through */
1578 case OMAP_DSS_COLOR_RGB16:
1579 case OMAP_DSS_COLOR_RGB24P:
1580 case OMAP_DSS_COLOR_RGB24U:
1581 break;
1582
1583 case OMAP_DSS_COLOR_ARGB16:
1584 case OMAP_DSS_COLOR_ARGB32:
1585 case OMAP_DSS_COLOR_RGBA32:
1586 if (cpu_is_omap24xx())
1587 return -EINVAL;
1588 if (plane == OMAP_DSS_VIDEO1)
1589 return -EINVAL;
1590 break;
1591
1592 case OMAP_DSS_COLOR_YUV2:
1593 case OMAP_DSS_COLOR_UYVY:
1594 cconv = 1;
1595 break;
1596
1597 default:
1598 return -EINVAL;
1599 }
1600
1601 /* Must use 5-tap filter? */
1602 five_taps = height > out_height * 2;
1603
1604 if (!five_taps) {
1605 fclk = calc_fclk(width, height,
1606 out_width, out_height);
1607
1608 /* Try 5-tap filter if 3-tap fclk is too high */
1609 if (cpu_is_omap34xx() && height > out_height &&
1610 fclk > dispc_fclk_rate())
1611 five_taps = true;
1612 }
1613
1614 if (width > (2048 >> five_taps)) {
1615 DSSERR("failed to set up scaling, fclk too low\n");
1616 return -EINVAL;
1617 }
1618
1619 if (five_taps)
1620 fclk = calc_fclk_five_taps(width, height,
1621 out_width, out_height, color_mode);
1622
1623 DSSDBG("required fclk rate = %lu Hz\n", fclk);
1624 DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
1625
1626 if (fclk > dispc_fclk_rate()) {
1627 DSSERR("failed to set up scaling, "
1628 "required fclk rate = %lu Hz, "
1629 "current fclk rate = %lu Hz\n",
1630 fclk, dispc_fclk_rate());
1631 return -EINVAL;
1632 }
1633 }
1634
1635 if (ilace && !fieldmode) {
1636 /*
1637 * when downscaling the bottom field may have to start several
1638 * source lines below the top field. Unfortunately ACCUI
1639 * registers will only hold the fractional part of the offset
1640 * so the integer part must be added to the base address of the
1641 * bottom field.
1642 */
1643 if (!height || height == out_height)
1644 field_offset = 0;
1645 else
1646 field_offset = height / out_height / 2;
1647 }
1648
1649 /* Fields are independent but interleaved in memory. */
1650 if (fieldmode)
1651 field_offset = 1;
1652
1653 if (rotation_type == OMAP_DSS_ROT_DMA)
1654 calc_dma_rotation_offset(rotation, mirror,
1655 screen_width, width, frame_height, color_mode,
1656 fieldmode, field_offset,
1657 &offset0, &offset1, &row_inc, &pix_inc);
1658 else
1659 calc_vrfb_rotation_offset(rotation, mirror,
1660 screen_width, width, frame_height, color_mode,
1661 fieldmode, field_offset,
1662 &offset0, &offset1, &row_inc, &pix_inc);
1663
1664 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
1665 offset0, offset1, row_inc, pix_inc);
1666
1667 _dispc_set_color_mode(plane, color_mode);
1668
1669 _dispc_set_plane_ba0(plane, paddr + offset0);
1670 _dispc_set_plane_ba1(plane, paddr + offset1);
1671
1672 _dispc_set_row_inc(plane, row_inc);
1673 _dispc_set_pix_inc(plane, pix_inc);
1674
1675 DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height,
1676 out_width, out_height);
1677
1678 _dispc_set_plane_pos(plane, pos_x, pos_y);
1679
1680 _dispc_set_pic_size(plane, width, height);
1681
1682 if (plane != OMAP_DSS_GFX) {
1683 _dispc_set_scaling(plane, width, height,
1684 out_width, out_height,
1685 ilace, five_taps, fieldmode);
1686 _dispc_set_vid_size(plane, out_width, out_height);
1687 _dispc_set_vid_color_conv(plane, cconv);
1688 }
1689
1690 _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
1691
1692 if (plane != OMAP_DSS_VIDEO1)
1693 _dispc_setup_global_alpha(plane, global_alpha);
1694
1695 return 0;
1696}
1697
1698static void _dispc_enable_plane(enum omap_plane plane, bool enable)
1699{
1700 REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 0, 0);
1701}
1702
1703static void dispc_disable_isr(void *data, u32 mask)
1704{
1705 struct completion *compl = data;
1706 complete(compl);
1707}
1708
1709static void _enable_lcd_out(bool enable)
1710{
1711 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
1712}
1713
1714void dispc_enable_lcd_out(bool enable)
1715{
1716 struct completion frame_done_completion;
1717 bool is_on;
1718 int r;
1719
1720 enable_clocks(1);
1721
1722 /* When we disable LCD output, we need to wait until frame is done.
1723 * Otherwise the DSS is still working, and turning off the clocks
1724 * prevents DSS from going to OFF mode */
1725 is_on = REG_GET(DISPC_CONTROL, 0, 0);
1726
1727 if (!enable && is_on) {
1728 init_completion(&frame_done_completion);
1729
1730 r = omap_dispc_register_isr(dispc_disable_isr,
1731 &frame_done_completion,
1732 DISPC_IRQ_FRAMEDONE);
1733
1734 if (r)
1735 DSSERR("failed to register FRAMEDONE isr\n");
1736 }
1737
1738 _enable_lcd_out(enable);
1739
1740 if (!enable && is_on) {
1741 if (!wait_for_completion_timeout(&frame_done_completion,
1742 msecs_to_jiffies(100)))
1743 DSSERR("timeout waiting for FRAME DONE\n");
1744
1745 r = omap_dispc_unregister_isr(dispc_disable_isr,
1746 &frame_done_completion,
1747 DISPC_IRQ_FRAMEDONE);
1748
1749 if (r)
1750 DSSERR("failed to unregister FRAMEDONE isr\n");
1751 }
1752
1753 enable_clocks(0);
1754}
1755
1756static void _enable_digit_out(bool enable)
1757{
1758 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
1759}
1760
1761void dispc_enable_digit_out(bool enable)
1762{
1763 struct completion frame_done_completion;
1764 int r;
1765
1766 enable_clocks(1);
1767
1768 if (REG_GET(DISPC_CONTROL, 1, 1) == enable) {
1769 enable_clocks(0);
1770 return;
1771 }
1772
1773 if (enable) {
1774 unsigned long flags;
1775 /* When we enable digit output, we'll get an extra digit
1776 * sync lost interrupt, that we need to ignore */
1777 spin_lock_irqsave(&dispc.irq_lock, flags);
1778 dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
1779 _omap_dispc_set_irqs();
1780 spin_unlock_irqrestore(&dispc.irq_lock, flags);
1781 }
1782
1783 /* When we disable digit output, we need to wait until fields are done.
1784 * Otherwise the DSS is still working, and turning off the clocks
1785 * prevents DSS from going to OFF mode. And when enabling, we need to
1786 * wait for the extra sync losts */
1787 init_completion(&frame_done_completion);
1788
1789 r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion,
1790 DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
1791 if (r)
1792 DSSERR("failed to register EVSYNC isr\n");
1793
1794 _enable_digit_out(enable);
1795
1796 /* XXX I understand from TRM that we should only wait for the
1797 * current field to complete. But it seems we have to wait
1798 * for both fields */
1799 if (!wait_for_completion_timeout(&frame_done_completion,
1800 msecs_to_jiffies(100)))
1801 DSSERR("timeout waiting for EVSYNC\n");
1802
1803 if (!wait_for_completion_timeout(&frame_done_completion,
1804 msecs_to_jiffies(100)))
1805 DSSERR("timeout waiting for EVSYNC\n");
1806
1807 r = omap_dispc_unregister_isr(dispc_disable_isr,
1808 &frame_done_completion,
1809 DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
1810 if (r)
1811 DSSERR("failed to unregister EVSYNC isr\n");
1812
1813 if (enable) {
1814 unsigned long flags;
1815 spin_lock_irqsave(&dispc.irq_lock, flags);
1816 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
1817 dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
1818 _omap_dispc_set_irqs();
1819 spin_unlock_irqrestore(&dispc.irq_lock, flags);
1820 }
1821
1822 enable_clocks(0);
1823}
1824
1825void dispc_lcd_enable_signal_polarity(bool act_high)
1826{
1827 enable_clocks(1);
1828 REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
1829 enable_clocks(0);
1830}
1831
1832void dispc_lcd_enable_signal(bool enable)
1833{
1834 enable_clocks(1);
1835 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
1836 enable_clocks(0);
1837}
1838
1839void dispc_pck_free_enable(bool enable)
1840{
1841 enable_clocks(1);
1842 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
1843 enable_clocks(0);
1844}
1845
1846void dispc_enable_fifohandcheck(bool enable)
1847{
1848 enable_clocks(1);
1849 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
1850 enable_clocks(0);
1851}
1852
1853
1854void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
1855{
1856 int mode;
1857
1858 switch (type) {
1859 case OMAP_DSS_LCD_DISPLAY_STN:
1860 mode = 0;
1861 break;
1862
1863 case OMAP_DSS_LCD_DISPLAY_TFT:
1864 mode = 1;
1865 break;
1866
1867 default:
1868 BUG();
1869 return;
1870 }
1871
1872 enable_clocks(1);
1873 REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
1874 enable_clocks(0);
1875}
1876
1877void dispc_set_loadmode(enum omap_dss_load_mode mode)
1878{
1879 enable_clocks(1);
1880 REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
1881 enable_clocks(0);
1882}
1883
1884
1885void dispc_set_default_color(enum omap_channel channel, u32 color)
1886{
1887 const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1888 DISPC_DEFAULT_COLOR1 };
1889
1890 enable_clocks(1);
1891 dispc_write_reg(def_reg[channel], color);
1892 enable_clocks(0);
1893}
1894
1895u32 dispc_get_default_color(enum omap_channel channel)
1896{
1897 const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1898 DISPC_DEFAULT_COLOR1 };
1899 u32 l;
1900
1901 BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
1902 channel != OMAP_DSS_CHANNEL_LCD);
1903
1904 enable_clocks(1);
1905 l = dispc_read_reg(def_reg[channel]);
1906 enable_clocks(0);
1907
1908 return l;
1909}
1910
1911void dispc_set_trans_key(enum omap_channel ch,
1912 enum omap_dss_trans_key_type type,
1913 u32 trans_key)
1914{
1915 const struct dispc_reg tr_reg[] = {
1916 DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1917
1918 enable_clocks(1);
1919 if (ch == OMAP_DSS_CHANNEL_LCD)
1920 REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
1921 else /* OMAP_DSS_CHANNEL_DIGIT */
1922 REG_FLD_MOD(DISPC_CONFIG, type, 13, 13);
1923
1924 dispc_write_reg(tr_reg[ch], trans_key);
1925 enable_clocks(0);
1926}
1927
1928void dispc_get_trans_key(enum omap_channel ch,
1929 enum omap_dss_trans_key_type *type,
1930 u32 *trans_key)
1931{
1932 const struct dispc_reg tr_reg[] = {
1933 DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1934
1935 enable_clocks(1);
1936 if (type) {
1937 if (ch == OMAP_DSS_CHANNEL_LCD)
1938 *type = REG_GET(DISPC_CONFIG, 11, 11);
1939 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
1940 *type = REG_GET(DISPC_CONFIG, 13, 13);
1941 else
1942 BUG();
1943 }
1944
1945 if (trans_key)
1946 *trans_key = dispc_read_reg(tr_reg[ch]);
1947 enable_clocks(0);
1948}
1949
1950void dispc_enable_trans_key(enum omap_channel ch, bool enable)
1951{
1952 enable_clocks(1);
1953 if (ch == OMAP_DSS_CHANNEL_LCD)
1954 REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
1955 else /* OMAP_DSS_CHANNEL_DIGIT */
1956 REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
1957 enable_clocks(0);
1958}
1959void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
1960{
1961 if (cpu_is_omap24xx())
1962 return;
1963
1964 enable_clocks(1);
1965 if (ch == OMAP_DSS_CHANNEL_LCD)
1966 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
1967 else /* OMAP_DSS_CHANNEL_DIGIT */
1968 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
1969 enable_clocks(0);
1970}
1971bool dispc_alpha_blending_enabled(enum omap_channel ch)
1972{
1973 bool enabled;
1974
1975 if (cpu_is_omap24xx())
1976 return false;
1977
1978 enable_clocks(1);
1979 if (ch == OMAP_DSS_CHANNEL_LCD)
1980 enabled = REG_GET(DISPC_CONFIG, 18, 18);
1981 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
1982 enabled = REG_GET(DISPC_CONFIG, 18, 18);
1983 else
1984 BUG();
1985 enable_clocks(0);
1986
1987 return enabled;
1988
1989}
1990
1991
1992bool dispc_trans_key_enabled(enum omap_channel ch)
1993{
1994 bool enabled;
1995
1996 enable_clocks(1);
1997 if (ch == OMAP_DSS_CHANNEL_LCD)
1998 enabled = REG_GET(DISPC_CONFIG, 10, 10);
1999 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2000 enabled = REG_GET(DISPC_CONFIG, 12, 12);
2001 else
2002 BUG();
2003 enable_clocks(0);
2004
2005 return enabled;
2006}
2007
2008
2009void dispc_set_tft_data_lines(u8 data_lines)
2010{
2011 int code;
2012
2013 switch (data_lines) {
2014 case 12:
2015 code = 0;
2016 break;
2017 case 16:
2018 code = 1;
2019 break;
2020 case 18:
2021 code = 2;
2022 break;
2023 case 24:
2024 code = 3;
2025 break;
2026 default:
2027 BUG();
2028 return;
2029 }
2030
2031 enable_clocks(1);
2032 REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
2033 enable_clocks(0);
2034}
2035
2036void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
2037{
2038 u32 l;
2039 int stallmode;
2040 int gpout0 = 1;
2041 int gpout1;
2042
2043 switch (mode) {
2044 case OMAP_DSS_PARALLELMODE_BYPASS:
2045 stallmode = 0;
2046 gpout1 = 1;
2047 break;
2048
2049 case OMAP_DSS_PARALLELMODE_RFBI:
2050 stallmode = 1;
2051 gpout1 = 0;
2052 break;
2053
2054 case OMAP_DSS_PARALLELMODE_DSI:
2055 stallmode = 1;
2056 gpout1 = 1;
2057 break;
2058
2059 default:
2060 BUG();
2061 return;
2062 }
2063
2064 enable_clocks(1);
2065
2066 l = dispc_read_reg(DISPC_CONTROL);
2067
2068 l = FLD_MOD(l, stallmode, 11, 11);
2069 l = FLD_MOD(l, gpout0, 15, 15);
2070 l = FLD_MOD(l, gpout1, 16, 16);
2071
2072 dispc_write_reg(DISPC_CONTROL, l);
2073
2074 enable_clocks(0);
2075}
2076
2077static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
2078 int vsw, int vfp, int vbp)
2079{
2080 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2081 if (hsw < 1 || hsw > 64 ||
2082 hfp < 1 || hfp > 256 ||
2083 hbp < 1 || hbp > 256 ||
2084 vsw < 1 || vsw > 64 ||
2085 vfp < 0 || vfp > 255 ||
2086 vbp < 0 || vbp > 255)
2087 return false;
2088 } else {
2089 if (hsw < 1 || hsw > 256 ||
2090 hfp < 1 || hfp > 4096 ||
2091 hbp < 1 || hbp > 4096 ||
2092 vsw < 1 || vsw > 256 ||
2093 vfp < 0 || vfp > 4095 ||
2094 vbp < 0 || vbp > 4095)
2095 return false;
2096 }
2097
2098 return true;
2099}
2100
2101bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
2102{
2103 return _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2104 timings->hbp, timings->vsw,
2105 timings->vfp, timings->vbp);
2106}
2107
2108static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
2109 int vsw, int vfp, int vbp)
2110{
2111 u32 timing_h, timing_v;
2112
2113 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2114 timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
2115 FLD_VAL(hbp-1, 27, 20);
2116
2117 timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
2118 FLD_VAL(vbp, 27, 20);
2119 } else {
2120 timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
2121 FLD_VAL(hbp-1, 31, 20);
2122
2123 timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
2124 FLD_VAL(vbp, 31, 20);
2125 }
2126
2127 enable_clocks(1);
2128 dispc_write_reg(DISPC_TIMING_H, timing_h);
2129 dispc_write_reg(DISPC_TIMING_V, timing_v);
2130 enable_clocks(0);
2131}
2132
2133/* change name to mode? */
2134void dispc_set_lcd_timings(struct omap_video_timings *timings)
2135{
2136 unsigned xtot, ytot;
2137 unsigned long ht, vt;
2138
2139 if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2140 timings->hbp, timings->vsw,
2141 timings->vfp, timings->vbp))
2142 BUG();
2143
2144 _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp,
2145 timings->vsw, timings->vfp, timings->vbp);
2146
2147 dispc_set_lcd_size(timings->x_res, timings->y_res);
2148
2149 xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
2150 ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
2151
2152 ht = (timings->pixel_clock * 1000) / xtot;
2153 vt = (timings->pixel_clock * 1000) / xtot / ytot;
2154
2155 DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res);
2156 DSSDBG("pck %u\n", timings->pixel_clock);
2157 DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
2158 timings->hsw, timings->hfp, timings->hbp,
2159 timings->vsw, timings->vfp, timings->vbp);
2160
2161 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
2162}
2163
2164static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div)
2165{
2166 BUG_ON(lck_div < 1);
2167 BUG_ON(pck_div < 2);
2168
2169 enable_clocks(1);
2170 dispc_write_reg(DISPC_DIVISOR,
2171 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
2172 enable_clocks(0);
2173}
2174
2175static void dispc_get_lcd_divisor(int *lck_div, int *pck_div)
2176{
2177 u32 l;
2178 l = dispc_read_reg(DISPC_DIVISOR);
2179 *lck_div = FLD_GET(l, 23, 16);
2180 *pck_div = FLD_GET(l, 7, 0);
2181}
2182
2183unsigned long dispc_fclk_rate(void)
2184{
2185 unsigned long r = 0;
2186
2187 if (dss_get_dispc_clk_source() == 0)
2188 r = dss_clk_get_rate(DSS_CLK_FCK1);
2189 else
2190#ifdef CONFIG_OMAP2_DSS_DSI
2191 r = dsi_get_dsi1_pll_rate();
2192#else
2193 BUG();
2194#endif
2195 return r;
2196}
2197
2198unsigned long dispc_lclk_rate(void)
2199{
2200 int lcd;
2201 unsigned long r;
2202 u32 l;
2203
2204 l = dispc_read_reg(DISPC_DIVISOR);
2205
2206 lcd = FLD_GET(l, 23, 16);
2207
2208 r = dispc_fclk_rate();
2209
2210 return r / lcd;
2211}
2212
2213unsigned long dispc_pclk_rate(void)
2214{
2215 int lcd, pcd;
2216 unsigned long r;
2217 u32 l;
2218
2219 l = dispc_read_reg(DISPC_DIVISOR);
2220
2221 lcd = FLD_GET(l, 23, 16);
2222 pcd = FLD_GET(l, 7, 0);
2223
2224 r = dispc_fclk_rate();
2225
2226 return r / lcd / pcd;
2227}
2228
2229void dispc_dump_clocks(struct seq_file *s)
2230{
2231 int lcd, pcd;
2232
2233 enable_clocks(1);
2234
2235 dispc_get_lcd_divisor(&lcd, &pcd);
2236
2237 seq_printf(s, "- DISPC -\n");
2238
2239 seq_printf(s, "dispc fclk source = %s\n",
2240 dss_get_dispc_clk_source() == 0 ?
2241 "dss1_alwon_fclk" : "dsi1_pll_fclk");
2242
2243 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
2244 seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd);
2245 seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd);
2246
2247 enable_clocks(0);
2248}
2249
2250void dispc_dump_regs(struct seq_file *s)
2251{
2252#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
2253
2254 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
2255
2256 DUMPREG(DISPC_REVISION);
2257 DUMPREG(DISPC_SYSCONFIG);
2258 DUMPREG(DISPC_SYSSTATUS);
2259 DUMPREG(DISPC_IRQSTATUS);
2260 DUMPREG(DISPC_IRQENABLE);
2261 DUMPREG(DISPC_CONTROL);
2262 DUMPREG(DISPC_CONFIG);
2263 DUMPREG(DISPC_CAPABLE);
2264 DUMPREG(DISPC_DEFAULT_COLOR0);
2265 DUMPREG(DISPC_DEFAULT_COLOR1);
2266 DUMPREG(DISPC_TRANS_COLOR0);
2267 DUMPREG(DISPC_TRANS_COLOR1);
2268 DUMPREG(DISPC_LINE_STATUS);
2269 DUMPREG(DISPC_LINE_NUMBER);
2270 DUMPREG(DISPC_TIMING_H);
2271 DUMPREG(DISPC_TIMING_V);
2272 DUMPREG(DISPC_POL_FREQ);
2273 DUMPREG(DISPC_DIVISOR);
2274 DUMPREG(DISPC_GLOBAL_ALPHA);
2275 DUMPREG(DISPC_SIZE_DIG);
2276 DUMPREG(DISPC_SIZE_LCD);
2277
2278 DUMPREG(DISPC_GFX_BA0);
2279 DUMPREG(DISPC_GFX_BA1);
2280 DUMPREG(DISPC_GFX_POSITION);
2281 DUMPREG(DISPC_GFX_SIZE);
2282 DUMPREG(DISPC_GFX_ATTRIBUTES);
2283 DUMPREG(DISPC_GFX_FIFO_THRESHOLD);
2284 DUMPREG(DISPC_GFX_FIFO_SIZE_STATUS);
2285 DUMPREG(DISPC_GFX_ROW_INC);
2286 DUMPREG(DISPC_GFX_PIXEL_INC);
2287 DUMPREG(DISPC_GFX_WINDOW_SKIP);
2288 DUMPREG(DISPC_GFX_TABLE_BA);
2289
2290 DUMPREG(DISPC_DATA_CYCLE1);
2291 DUMPREG(DISPC_DATA_CYCLE2);
2292 DUMPREG(DISPC_DATA_CYCLE3);
2293
2294 DUMPREG(DISPC_CPR_COEF_R);
2295 DUMPREG(DISPC_CPR_COEF_G);
2296 DUMPREG(DISPC_CPR_COEF_B);
2297
2298 DUMPREG(DISPC_GFX_PRELOAD);
2299
2300 DUMPREG(DISPC_VID_BA0(0));
2301 DUMPREG(DISPC_VID_BA1(0));
2302 DUMPREG(DISPC_VID_POSITION(0));
2303 DUMPREG(DISPC_VID_SIZE(0));
2304 DUMPREG(DISPC_VID_ATTRIBUTES(0));
2305 DUMPREG(DISPC_VID_FIFO_THRESHOLD(0));
2306 DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(0));
2307 DUMPREG(DISPC_VID_ROW_INC(0));
2308 DUMPREG(DISPC_VID_PIXEL_INC(0));
2309 DUMPREG(DISPC_VID_FIR(0));
2310 DUMPREG(DISPC_VID_PICTURE_SIZE(0));
2311 DUMPREG(DISPC_VID_ACCU0(0));
2312 DUMPREG(DISPC_VID_ACCU1(0));
2313
2314 DUMPREG(DISPC_VID_BA0(1));
2315 DUMPREG(DISPC_VID_BA1(1));
2316 DUMPREG(DISPC_VID_POSITION(1));
2317 DUMPREG(DISPC_VID_SIZE(1));
2318 DUMPREG(DISPC_VID_ATTRIBUTES(1));
2319 DUMPREG(DISPC_VID_FIFO_THRESHOLD(1));
2320 DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(1));
2321 DUMPREG(DISPC_VID_ROW_INC(1));
2322 DUMPREG(DISPC_VID_PIXEL_INC(1));
2323 DUMPREG(DISPC_VID_FIR(1));
2324 DUMPREG(DISPC_VID_PICTURE_SIZE(1));
2325 DUMPREG(DISPC_VID_ACCU0(1));
2326 DUMPREG(DISPC_VID_ACCU1(1));
2327
2328 DUMPREG(DISPC_VID_FIR_COEF_H(0, 0));
2329 DUMPREG(DISPC_VID_FIR_COEF_H(0, 1));
2330 DUMPREG(DISPC_VID_FIR_COEF_H(0, 2));
2331 DUMPREG(DISPC_VID_FIR_COEF_H(0, 3));
2332 DUMPREG(DISPC_VID_FIR_COEF_H(0, 4));
2333 DUMPREG(DISPC_VID_FIR_COEF_H(0, 5));
2334 DUMPREG(DISPC_VID_FIR_COEF_H(0, 6));
2335 DUMPREG(DISPC_VID_FIR_COEF_H(0, 7));
2336 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 0));
2337 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 1));
2338 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 2));
2339 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 3));
2340 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 4));
2341 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 5));
2342 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 6));
2343 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 7));
2344 DUMPREG(DISPC_VID_CONV_COEF(0, 0));
2345 DUMPREG(DISPC_VID_CONV_COEF(0, 1));
2346 DUMPREG(DISPC_VID_CONV_COEF(0, 2));
2347 DUMPREG(DISPC_VID_CONV_COEF(0, 3));
2348 DUMPREG(DISPC_VID_CONV_COEF(0, 4));
2349 DUMPREG(DISPC_VID_FIR_COEF_V(0, 0));
2350 DUMPREG(DISPC_VID_FIR_COEF_V(0, 1));
2351 DUMPREG(DISPC_VID_FIR_COEF_V(0, 2));
2352 DUMPREG(DISPC_VID_FIR_COEF_V(0, 3));
2353 DUMPREG(DISPC_VID_FIR_COEF_V(0, 4));
2354 DUMPREG(DISPC_VID_FIR_COEF_V(0, 5));
2355 DUMPREG(DISPC_VID_FIR_COEF_V(0, 6));
2356 DUMPREG(DISPC_VID_FIR_COEF_V(0, 7));
2357
2358 DUMPREG(DISPC_VID_FIR_COEF_H(1, 0));
2359 DUMPREG(DISPC_VID_FIR_COEF_H(1, 1));
2360 DUMPREG(DISPC_VID_FIR_COEF_H(1, 2));
2361 DUMPREG(DISPC_VID_FIR_COEF_H(1, 3));
2362 DUMPREG(DISPC_VID_FIR_COEF_H(1, 4));
2363 DUMPREG(DISPC_VID_FIR_COEF_H(1, 5));
2364 DUMPREG(DISPC_VID_FIR_COEF_H(1, 6));
2365 DUMPREG(DISPC_VID_FIR_COEF_H(1, 7));
2366 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 0));
2367 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 1));
2368 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 2));
2369 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 3));
2370 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 4));
2371 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 5));
2372 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 6));
2373 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 7));
2374 DUMPREG(DISPC_VID_CONV_COEF(1, 0));
2375 DUMPREG(DISPC_VID_CONV_COEF(1, 1));
2376 DUMPREG(DISPC_VID_CONV_COEF(1, 2));
2377 DUMPREG(DISPC_VID_CONV_COEF(1, 3));
2378 DUMPREG(DISPC_VID_CONV_COEF(1, 4));
2379 DUMPREG(DISPC_VID_FIR_COEF_V(1, 0));
2380 DUMPREG(DISPC_VID_FIR_COEF_V(1, 1));
2381 DUMPREG(DISPC_VID_FIR_COEF_V(1, 2));
2382 DUMPREG(DISPC_VID_FIR_COEF_V(1, 3));
2383 DUMPREG(DISPC_VID_FIR_COEF_V(1, 4));
2384 DUMPREG(DISPC_VID_FIR_COEF_V(1, 5));
2385 DUMPREG(DISPC_VID_FIR_COEF_V(1, 6));
2386 DUMPREG(DISPC_VID_FIR_COEF_V(1, 7));
2387
2388 DUMPREG(DISPC_VID_PRELOAD(0));
2389 DUMPREG(DISPC_VID_PRELOAD(1));
2390
2391 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
2392#undef DUMPREG
2393}
2394
2395static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
2396 bool ihs, bool ivs, u8 acbi, u8 acb)
2397{
2398 u32 l = 0;
2399
2400 DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n",
2401 onoff, rf, ieo, ipc, ihs, ivs, acbi, acb);
2402
2403 l |= FLD_VAL(onoff, 17, 17);
2404 l |= FLD_VAL(rf, 16, 16);
2405 l |= FLD_VAL(ieo, 15, 15);
2406 l |= FLD_VAL(ipc, 14, 14);
2407 l |= FLD_VAL(ihs, 13, 13);
2408 l |= FLD_VAL(ivs, 12, 12);
2409 l |= FLD_VAL(acbi, 11, 8);
2410 l |= FLD_VAL(acb, 7, 0);
2411
2412 enable_clocks(1);
2413 dispc_write_reg(DISPC_POL_FREQ, l);
2414 enable_clocks(0);
2415}
2416
2417void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb)
2418{
2419 _dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0,
2420 (config & OMAP_DSS_LCD_RF) != 0,
2421 (config & OMAP_DSS_LCD_IEO) != 0,
2422 (config & OMAP_DSS_LCD_IPC) != 0,
2423 (config & OMAP_DSS_LCD_IHS) != 0,
2424 (config & OMAP_DSS_LCD_IVS) != 0,
2425 acbi, acb);
2426}
2427
2428/* with fck as input clock rate, find dispc dividers that produce req_pck */
2429void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
2430 struct dispc_clock_info *cinfo)
2431{
2432 u16 pcd_min = is_tft ? 2 : 3;
2433 unsigned long best_pck;
2434 u16 best_ld, cur_ld;
2435 u16 best_pd, cur_pd;
2436
2437 best_pck = 0;
2438 best_ld = 0;
2439 best_pd = 0;
2440
2441 for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
2442 unsigned long lck = fck / cur_ld;
2443
2444 for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) {
2445 unsigned long pck = lck / cur_pd;
2446 long old_delta = abs(best_pck - req_pck);
2447 long new_delta = abs(pck - req_pck);
2448
2449 if (best_pck == 0 || new_delta < old_delta) {
2450 best_pck = pck;
2451 best_ld = cur_ld;
2452 best_pd = cur_pd;
2453
2454 if (pck == req_pck)
2455 goto found;
2456 }
2457
2458 if (pck < req_pck)
2459 break;
2460 }
2461
2462 if (lck / pcd_min < req_pck)
2463 break;
2464 }
2465
2466found:
2467 cinfo->lck_div = best_ld;
2468 cinfo->pck_div = best_pd;
2469 cinfo->lck = fck / cinfo->lck_div;
2470 cinfo->pck = cinfo->lck / cinfo->pck_div;
2471}
2472
2473/* calculate clock rates using dividers in cinfo */
2474int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
2475 struct dispc_clock_info *cinfo)
2476{
2477 if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
2478 return -EINVAL;
2479 if (cinfo->pck_div < 2 || cinfo->pck_div > 255)
2480 return -EINVAL;
2481
2482 cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
2483 cinfo->pck = cinfo->lck / cinfo->pck_div;
2484
2485 return 0;
2486}
2487
2488int dispc_set_clock_div(struct dispc_clock_info *cinfo)
2489{
2490 DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
2491 DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
2492
2493 dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div);
2494
2495 return 0;
2496}
2497
2498int dispc_get_clock_div(struct dispc_clock_info *cinfo)
2499{
2500 unsigned long fck;
2501
2502 fck = dispc_fclk_rate();
2503
2504 cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
2505 cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
2506
2507 cinfo->lck = fck / cinfo->lck_div;
2508 cinfo->pck = cinfo->lck / cinfo->pck_div;
2509
2510 return 0;
2511}
2512
2513/* dispc.irq_lock has to be locked by the caller */
2514static void _omap_dispc_set_irqs(void)
2515{
2516 u32 mask;
2517 u32 old_mask;
2518 int i;
2519 struct omap_dispc_isr_data *isr_data;
2520
2521 mask = dispc.irq_error_mask;
2522
2523 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2524 isr_data = &dispc.registered_isr[i];
2525
2526 if (isr_data->isr == NULL)
2527 continue;
2528
2529 mask |= isr_data->mask;
2530 }
2531
2532 enable_clocks(1);
2533
2534 old_mask = dispc_read_reg(DISPC_IRQENABLE);
2535 /* clear the irqstatus for newly enabled irqs */
2536 dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
2537
2538 dispc_write_reg(DISPC_IRQENABLE, mask);
2539
2540 enable_clocks(0);
2541}
2542
2543int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2544{
2545 int i;
2546 int ret;
2547 unsigned long flags;
2548 struct omap_dispc_isr_data *isr_data;
2549
2550 if (isr == NULL)
2551 return -EINVAL;
2552
2553 spin_lock_irqsave(&dispc.irq_lock, flags);
2554
2555 /* check for duplicate entry */
2556 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2557 isr_data = &dispc.registered_isr[i];
2558 if (isr_data->isr == isr && isr_data->arg == arg &&
2559 isr_data->mask == mask) {
2560 ret = -EINVAL;
2561 goto err;
2562 }
2563 }
2564
2565 isr_data = NULL;
2566 ret = -EBUSY;
2567
2568 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2569 isr_data = &dispc.registered_isr[i];
2570
2571 if (isr_data->isr != NULL)
2572 continue;
2573
2574 isr_data->isr = isr;
2575 isr_data->arg = arg;
2576 isr_data->mask = mask;
2577 ret = 0;
2578
2579 break;
2580 }
2581
2582 _omap_dispc_set_irqs();
2583
2584 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2585
2586 return 0;
2587err:
2588 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2589
2590 return ret;
2591}
2592EXPORT_SYMBOL(omap_dispc_register_isr);
2593
2594int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2595{
2596 int i;
2597 unsigned long flags;
2598 int ret = -EINVAL;
2599 struct omap_dispc_isr_data *isr_data;
2600
2601 spin_lock_irqsave(&dispc.irq_lock, flags);
2602
2603 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2604 isr_data = &dispc.registered_isr[i];
2605 if (isr_data->isr != isr || isr_data->arg != arg ||
2606 isr_data->mask != mask)
2607 continue;
2608
2609 /* found the correct isr */
2610
2611 isr_data->isr = NULL;
2612 isr_data->arg = NULL;
2613 isr_data->mask = 0;
2614
2615 ret = 0;
2616 break;
2617 }
2618
2619 if (ret == 0)
2620 _omap_dispc_set_irqs();
2621
2622 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2623
2624 return ret;
2625}
2626EXPORT_SYMBOL(omap_dispc_unregister_isr);
2627
2628#ifdef DEBUG
2629static void print_irq_status(u32 status)
2630{
2631 if ((status & dispc.irq_error_mask) == 0)
2632 return;
2633
2634 printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status);
2635
2636#define PIS(x) \
2637 if (status & DISPC_IRQ_##x) \
2638 printk(#x " ");
2639 PIS(GFX_FIFO_UNDERFLOW);
2640 PIS(OCP_ERR);
2641 PIS(VID1_FIFO_UNDERFLOW);
2642 PIS(VID2_FIFO_UNDERFLOW);
2643 PIS(SYNC_LOST);
2644 PIS(SYNC_LOST_DIGIT);
2645#undef PIS
2646
2647 printk("\n");
2648}
2649#endif
2650
2651/* Called from dss.c. Note that we don't touch clocks here,
2652 * but we presume they are on because we got an IRQ. However,
2653 * an irq handler may turn the clocks off, so we may not have
2654 * clock later in the function. */
2655void dispc_irq_handler(void)
2656{
2657 int i;
2658 u32 irqstatus;
2659 u32 handledirqs = 0;
2660 u32 unhandled_errors;
2661 struct omap_dispc_isr_data *isr_data;
2662 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
2663
2664 spin_lock(&dispc.irq_lock);
2665
2666 irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
2667
2668#ifdef DEBUG
2669 if (dss_debug)
2670 print_irq_status(irqstatus);
2671#endif
2672 /* Ack the interrupt. Do it here before clocks are possibly turned
2673 * off */
2674 dispc_write_reg(DISPC_IRQSTATUS, irqstatus);
2675 /* flush posted write */
2676 dispc_read_reg(DISPC_IRQSTATUS);
2677
2678 /* make a copy and unlock, so that isrs can unregister
2679 * themselves */
2680 memcpy(registered_isr, dispc.registered_isr,
2681 sizeof(registered_isr));
2682
2683 spin_unlock(&dispc.irq_lock);
2684
2685 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2686 isr_data = &registered_isr[i];
2687
2688 if (!isr_data->isr)
2689 continue;
2690
2691 if (isr_data->mask & irqstatus) {
2692 isr_data->isr(isr_data->arg, irqstatus);
2693 handledirqs |= isr_data->mask;
2694 }
2695 }
2696
2697 spin_lock(&dispc.irq_lock);
2698
2699 unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
2700
2701 if (unhandled_errors) {
2702 dispc.error_irqs |= unhandled_errors;
2703
2704 dispc.irq_error_mask &= ~unhandled_errors;
2705 _omap_dispc_set_irqs();
2706
2707 schedule_work(&dispc.error_work);
2708 }
2709
2710 spin_unlock(&dispc.irq_lock);
2711}
2712
2713static void dispc_error_worker(struct work_struct *work)
2714{
2715 int i;
2716 u32 errors;
2717 unsigned long flags;
2718
2719 spin_lock_irqsave(&dispc.irq_lock, flags);
2720 errors = dispc.error_irqs;
2721 dispc.error_irqs = 0;
2722 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2723
2724 if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) {
2725 DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n");
2726 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2727 struct omap_overlay *ovl;
2728 ovl = omap_dss_get_overlay(i);
2729
2730 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2731 continue;
2732
2733 if (ovl->id == 0) {
2734 dispc_enable_plane(ovl->id, 0);
2735 dispc_go(ovl->manager->id);
2736 mdelay(50);
2737 break;
2738 }
2739 }
2740 }
2741
2742 if (errors & DISPC_IRQ_VID1_FIFO_UNDERFLOW) {
2743 DSSERR("VID1_FIFO_UNDERFLOW, disabling VID1\n");
2744 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2745 struct omap_overlay *ovl;
2746 ovl = omap_dss_get_overlay(i);
2747
2748 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2749 continue;
2750
2751 if (ovl->id == 1) {
2752 dispc_enable_plane(ovl->id, 0);
2753 dispc_go(ovl->manager->id);
2754 mdelay(50);
2755 break;
2756 }
2757 }
2758 }
2759
2760 if (errors & DISPC_IRQ_VID2_FIFO_UNDERFLOW) {
2761 DSSERR("VID2_FIFO_UNDERFLOW, disabling VID2\n");
2762 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2763 struct omap_overlay *ovl;
2764 ovl = omap_dss_get_overlay(i);
2765
2766 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2767 continue;
2768
2769 if (ovl->id == 2) {
2770 dispc_enable_plane(ovl->id, 0);
2771 dispc_go(ovl->manager->id);
2772 mdelay(50);
2773 break;
2774 }
2775 }
2776 }
2777
2778 if (errors & DISPC_IRQ_SYNC_LOST) {
2779 struct omap_overlay_manager *manager = NULL;
2780 bool enable = false;
2781
2782 DSSERR("SYNC_LOST, disabling LCD\n");
2783
2784 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2785 struct omap_overlay_manager *mgr;
2786 mgr = omap_dss_get_overlay_manager(i);
2787
2788 if (mgr->id == OMAP_DSS_CHANNEL_LCD) {
2789 manager = mgr;
2790 enable = mgr->device->state ==
2791 OMAP_DSS_DISPLAY_ACTIVE;
2792 mgr->device->disable(mgr->device);
2793 break;
2794 }
2795 }
2796
2797 if (manager) {
2798 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2799 struct omap_overlay *ovl;
2800 ovl = omap_dss_get_overlay(i);
2801
2802 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2803 continue;
2804
2805 if (ovl->id != 0 && ovl->manager == manager)
2806 dispc_enable_plane(ovl->id, 0);
2807 }
2808
2809 dispc_go(manager->id);
2810 mdelay(50);
2811 if (enable)
2812 manager->device->enable(manager->device);
2813 }
2814 }
2815
2816 if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) {
2817 struct omap_overlay_manager *manager = NULL;
2818 bool enable = false;
2819
2820 DSSERR("SYNC_LOST_DIGIT, disabling TV\n");
2821
2822 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2823 struct omap_overlay_manager *mgr;
2824 mgr = omap_dss_get_overlay_manager(i);
2825
2826 if (mgr->id == OMAP_DSS_CHANNEL_DIGIT) {
2827 manager = mgr;
2828 enable = mgr->device->state ==
2829 OMAP_DSS_DISPLAY_ACTIVE;
2830 mgr->device->disable(mgr->device);
2831 break;
2832 }
2833 }
2834
2835 if (manager) {
2836 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2837 struct omap_overlay *ovl;
2838 ovl = omap_dss_get_overlay(i);
2839
2840 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2841 continue;
2842
2843 if (ovl->id != 0 && ovl->manager == manager)
2844 dispc_enable_plane(ovl->id, 0);
2845 }
2846
2847 dispc_go(manager->id);
2848 mdelay(50);
2849 if (enable)
2850 manager->device->enable(manager->device);
2851 }
2852 }
2853
2854 if (errors & DISPC_IRQ_OCP_ERR) {
2855 DSSERR("OCP_ERR\n");
2856 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2857 struct omap_overlay_manager *mgr;
2858 mgr = omap_dss_get_overlay_manager(i);
2859
2860 if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC)
2861 mgr->device->disable(mgr->device);
2862 }
2863 }
2864
2865 spin_lock_irqsave(&dispc.irq_lock, flags);
2866 dispc.irq_error_mask |= errors;
2867 _omap_dispc_set_irqs();
2868 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2869}
2870
2871int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
2872{
2873 void dispc_irq_wait_handler(void *data, u32 mask)
2874 {
2875 complete((struct completion *)data);
2876 }
2877
2878 int r;
2879 DECLARE_COMPLETION_ONSTACK(completion);
2880
2881 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2882 irqmask);
2883
2884 if (r)
2885 return r;
2886
2887 timeout = wait_for_completion_timeout(&completion, timeout);
2888
2889 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
2890
2891 if (timeout == 0)
2892 return -ETIMEDOUT;
2893
2894 if (timeout == -ERESTARTSYS)
2895 return -ERESTARTSYS;
2896
2897 return 0;
2898}
2899
2900int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
2901 unsigned long timeout)
2902{
2903 void dispc_irq_wait_handler(void *data, u32 mask)
2904 {
2905 complete((struct completion *)data);
2906 }
2907
2908 int r;
2909 DECLARE_COMPLETION_ONSTACK(completion);
2910
2911 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2912 irqmask);
2913
2914 if (r)
2915 return r;
2916
2917 timeout = wait_for_completion_interruptible_timeout(&completion,
2918 timeout);
2919
2920 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
2921
2922 if (timeout == 0)
2923 return -ETIMEDOUT;
2924
2925 if (timeout == -ERESTARTSYS)
2926 return -ERESTARTSYS;
2927
2928 return 0;
2929}
2930
2931#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
2932void dispc_fake_vsync_irq(void)
2933{
2934 u32 irqstatus = DISPC_IRQ_VSYNC;
2935 int i;
2936
2937 local_irq_disable();
2938
2939 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2940 struct omap_dispc_isr_data *isr_data;
2941 isr_data = &dispc.registered_isr[i];
2942
2943 if (!isr_data->isr)
2944 continue;
2945
2946 if (isr_data->mask & irqstatus)
2947 isr_data->isr(isr_data->arg, irqstatus);
2948 }
2949
2950 local_irq_enable();
2951}
2952#endif
2953
2954static void _omap_dispc_initialize_irq(void)
2955{
2956 unsigned long flags;
2957
2958 spin_lock_irqsave(&dispc.irq_lock, flags);
2959
2960 memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
2961
2962 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
2963
2964 /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
2965 * so clear it */
2966 dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS));
2967
2968 _omap_dispc_set_irqs();
2969
2970 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2971}
2972
2973void dispc_enable_sidle(void)
2974{
2975 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
2976}
2977
2978void dispc_disable_sidle(void)
2979{
2980 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
2981}
2982
2983static void _omap_dispc_initial_config(void)
2984{
2985 u32 l;
2986
2987 l = dispc_read_reg(DISPC_SYSCONFIG);
2988 l = FLD_MOD(l, 2, 13, 12); /* MIDLEMODE: smart standby */
2989 l = FLD_MOD(l, 2, 4, 3); /* SIDLEMODE: smart idle */
2990 l = FLD_MOD(l, 1, 2, 2); /* ENWAKEUP */
2991 l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */
2992 dispc_write_reg(DISPC_SYSCONFIG, l);
2993
2994 /* FUNCGATED */
2995 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
2996
2997 /* L3 firewall setting: enable access to OCM RAM */
2998 /* XXX this should be somewhere in plat-omap */
2999 if (cpu_is_omap24xx())
3000 __raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0));
3001
3002 _dispc_setup_color_conv_coef();
3003
3004 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3005
3006 dispc_read_plane_fifo_sizes();
3007}
3008
3009int dispc_init(void)
3010{
3011 u32 rev;
3012
3013 spin_lock_init(&dispc.irq_lock);
3014
3015 INIT_WORK(&dispc.error_work, dispc_error_worker);
3016
3017 dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
3018 if (!dispc.base) {
3019 DSSERR("can't ioremap DISPC\n");
3020 return -ENOMEM;
3021 }
3022
3023 enable_clocks(1);
3024
3025 _omap_dispc_initial_config();
3026
3027 _omap_dispc_initialize_irq();
3028
3029 dispc_save_context();
3030
3031 rev = dispc_read_reg(DISPC_REVISION);
3032 printk(KERN_INFO "OMAP DISPC rev %d.%d\n",
3033 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
3034
3035 enable_clocks(0);
3036
3037 return 0;
3038}
3039
3040void dispc_exit(void)
3041{
3042 iounmap(dispc.base);
3043}
3044
3045int dispc_enable_plane(enum omap_plane plane, bool enable)
3046{
3047 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
3048
3049 enable_clocks(1);
3050 _dispc_enable_plane(plane, enable);
3051 enable_clocks(0);
3052
3053 return 0;
3054}
3055
3056int dispc_setup_plane(enum omap_plane plane,
3057 u32 paddr, u16 screen_width,
3058 u16 pos_x, u16 pos_y,
3059 u16 width, u16 height,
3060 u16 out_width, u16 out_height,
3061 enum omap_color_mode color_mode,
3062 bool ilace,
3063 enum omap_dss_rotation_type rotation_type,
3064 u8 rotation, bool mirror, u8 global_alpha)
3065{
3066 int r = 0;
3067
3068 DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
3069 "%dx%d, ilace %d, cmode %x, rot %d, mir %d\n",
3070 plane, paddr, screen_width, pos_x, pos_y,
3071 width, height,
3072 out_width, out_height,
3073 ilace, color_mode,
3074 rotation, mirror);
3075
3076 enable_clocks(1);
3077
3078 r = _dispc_setup_plane(plane,
3079 paddr, screen_width,
3080 pos_x, pos_y,
3081 width, height,
3082 out_width, out_height,
3083 color_mode, ilace,
3084 rotation_type,
3085 rotation, mirror,
3086 global_alpha);
3087
3088 enable_clocks(0);
3089
3090 return r;
3091}
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
new file mode 100644
index 000000000000..3b92b84b9560
--- /dev/null
+++ b/drivers/video/omap2/dss/display.c
@@ -0,0 +1,671 @@
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->enable(dssdev);
57 if (r)
58 return r;
59 } else {
60 dssdev->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->get_update_mode)
73 mode = dssdev->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->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->get_te ? dssdev->get_te(dssdev) : 0);
110}
111
112static ssize_t display_tear_store(struct device *dev,
113 struct device_attribute *attr, const char *buf, size_t size)
114{
115 struct omap_dss_device *dssdev = to_dss_device(dev);
116 unsigned long te;
117 int r;
118
119 if (!dssdev->enable_te || !dssdev->get_te)
120 return -ENOENT;
121
122 te = simple_strtoul(buf, NULL, 0);
123
124 r = dssdev->enable_te(dssdev, te);
125 if (r)
126 return r;
127
128 return size;
129}
130
131static ssize_t display_timings_show(struct device *dev,
132 struct device_attribute *attr, char *buf)
133{
134 struct omap_dss_device *dssdev = to_dss_device(dev);
135 struct omap_video_timings t;
136
137 if (!dssdev->get_timings)
138 return -ENOENT;
139
140 dssdev->get_timings(dssdev, &t);
141
142 return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
143 t.pixel_clock,
144 t.x_res, t.hfp, t.hbp, t.hsw,
145 t.y_res, t.vfp, t.vbp, t.vsw);
146}
147
148static ssize_t display_timings_store(struct device *dev,
149 struct device_attribute *attr, const char *buf, size_t size)
150{
151 struct omap_dss_device *dssdev = to_dss_device(dev);
152 struct omap_video_timings t;
153 int r, found;
154
155 if (!dssdev->set_timings || !dssdev->check_timings)
156 return -ENOENT;
157
158 found = 0;
159#ifdef CONFIG_OMAP2_DSS_VENC
160 if (strncmp("pal", buf, 3) == 0) {
161 t = omap_dss_pal_timings;
162 found = 1;
163 } else if (strncmp("ntsc", buf, 4) == 0) {
164 t = omap_dss_ntsc_timings;
165 found = 1;
166 }
167#endif
168 if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
169 &t.pixel_clock,
170 &t.x_res, &t.hfp, &t.hbp, &t.hsw,
171 &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
172 return -EINVAL;
173
174 r = dssdev->check_timings(dssdev, &t);
175 if (r)
176 return r;
177
178 dssdev->set_timings(dssdev, &t);
179
180 return size;
181}
182
183static ssize_t display_rotate_show(struct device *dev,
184 struct device_attribute *attr, char *buf)
185{
186 struct omap_dss_device *dssdev = to_dss_device(dev);
187 int rotate;
188 if (!dssdev->get_rotate)
189 return -ENOENT;
190 rotate = dssdev->get_rotate(dssdev);
191 return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
192}
193
194static ssize_t display_rotate_store(struct device *dev,
195 struct device_attribute *attr, const char *buf, size_t size)
196{
197 struct omap_dss_device *dssdev = to_dss_device(dev);
198 unsigned long rot;
199 int r;
200
201 if (!dssdev->set_rotate || !dssdev->get_rotate)
202 return -ENOENT;
203
204 rot = simple_strtoul(buf, NULL, 0);
205
206 r = dssdev->set_rotate(dssdev, rot);
207 if (r)
208 return r;
209
210 return size;
211}
212
213static ssize_t display_mirror_show(struct device *dev,
214 struct device_attribute *attr, char *buf)
215{
216 struct omap_dss_device *dssdev = to_dss_device(dev);
217 int mirror;
218 if (!dssdev->get_mirror)
219 return -ENOENT;
220 mirror = dssdev->get_mirror(dssdev);
221 return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
222}
223
224static ssize_t display_mirror_store(struct device *dev,
225 struct device_attribute *attr, const char *buf, size_t size)
226{
227 struct omap_dss_device *dssdev = to_dss_device(dev);
228 unsigned long mirror;
229 int r;
230
231 if (!dssdev->set_mirror || !dssdev->get_mirror)
232 return -ENOENT;
233
234 mirror = simple_strtoul(buf, NULL, 0);
235
236 r = dssdev->set_mirror(dssdev, mirror);
237 if (r)
238 return r;
239
240 return size;
241}
242
243static ssize_t display_wss_show(struct device *dev,
244 struct device_attribute *attr, char *buf)
245{
246 struct omap_dss_device *dssdev = to_dss_device(dev);
247 unsigned int wss;
248
249 if (!dssdev->get_wss)
250 return -ENOENT;
251
252 wss = dssdev->get_wss(dssdev);
253
254 return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
255}
256
257static ssize_t display_wss_store(struct device *dev,
258 struct device_attribute *attr, const char *buf, size_t size)
259{
260 struct omap_dss_device *dssdev = to_dss_device(dev);
261 unsigned long wss;
262 int r;
263
264 if (!dssdev->get_wss || !dssdev->set_wss)
265 return -ENOENT;
266
267 if (strict_strtoul(buf, 0, &wss))
268 return -EINVAL;
269
270 if (wss > 0xfffff)
271 return -EINVAL;
272
273 r = dssdev->set_wss(dssdev, wss);
274 if (r)
275 return r;
276
277 return size;
278}
279
280static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
281 display_enabled_show, display_enabled_store);
282static DEVICE_ATTR(update_mode, S_IRUGO|S_IWUSR,
283 display_upd_mode_show, display_upd_mode_store);
284static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
285 display_tear_show, display_tear_store);
286static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
287 display_timings_show, display_timings_store);
288static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
289 display_rotate_show, display_rotate_store);
290static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
291 display_mirror_show, display_mirror_store);
292static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
293 display_wss_show, display_wss_store);
294
295static struct device_attribute *display_sysfs_attrs[] = {
296 &dev_attr_enabled,
297 &dev_attr_update_mode,
298 &dev_attr_tear_elim,
299 &dev_attr_timings,
300 &dev_attr_rotate,
301 &dev_attr_mirror,
302 &dev_attr_wss,
303 NULL
304};
305
306static void default_get_resolution(struct omap_dss_device *dssdev,
307 u16 *xres, u16 *yres)
308{
309 *xres = dssdev->panel.timings.x_res;
310 *yres = dssdev->panel.timings.y_res;
311}
312
313void default_get_overlay_fifo_thresholds(enum omap_plane plane,
314 u32 fifo_size, enum omap_burst_size *burst_size,
315 u32 *fifo_low, u32 *fifo_high)
316{
317 unsigned burst_size_bytes;
318
319 *burst_size = OMAP_DSS_BURST_16x32;
320 burst_size_bytes = 16 * 32 / 8;
321
322 *fifo_high = fifo_size - 1;
323 *fifo_low = fifo_size - burst_size_bytes;
324}
325
326static int default_wait_vsync(struct omap_dss_device *dssdev)
327{
328 unsigned long timeout = msecs_to_jiffies(500);
329 u32 irq;
330
331 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
332 irq = DISPC_IRQ_EVSYNC_ODD;
333 else
334 irq = DISPC_IRQ_VSYNC;
335
336 return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
337}
338
339static int default_get_recommended_bpp(struct omap_dss_device *dssdev)
340{
341 if (dssdev->panel.recommended_bpp)
342 return dssdev->panel.recommended_bpp;
343
344 switch (dssdev->type) {
345 case OMAP_DISPLAY_TYPE_DPI:
346 if (dssdev->phy.dpi.data_lines == 24)
347 return 24;
348 else
349 return 16;
350
351 case OMAP_DISPLAY_TYPE_DBI:
352 case OMAP_DISPLAY_TYPE_DSI:
353 if (dssdev->ctrl.pixel_size == 24)
354 return 24;
355 else
356 return 16;
357 case OMAP_DISPLAY_TYPE_VENC:
358 case OMAP_DISPLAY_TYPE_SDI:
359 return 24;
360 return 24;
361 default:
362 BUG();
363 }
364}
365
366/* Checks if replication logic should be used. Only use for active matrix,
367 * when overlay is in RGB12U or RGB16 mode, and LCD interface is
368 * 18bpp or 24bpp */
369bool dss_use_replication(struct omap_dss_device *dssdev,
370 enum omap_color_mode mode)
371{
372 int bpp;
373
374 if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
375 return false;
376
377 if (dssdev->type == OMAP_DISPLAY_TYPE_DPI &&
378 (dssdev->panel.config & OMAP_DSS_LCD_TFT) == 0)
379 return false;
380
381 switch (dssdev->type) {
382 case OMAP_DISPLAY_TYPE_DPI:
383 bpp = dssdev->phy.dpi.data_lines;
384 break;
385 case OMAP_DISPLAY_TYPE_VENC:
386 case OMAP_DISPLAY_TYPE_SDI:
387 bpp = 24;
388 break;
389 case OMAP_DISPLAY_TYPE_DBI:
390 case OMAP_DISPLAY_TYPE_DSI:
391 bpp = dssdev->ctrl.pixel_size;
392 break;
393 default:
394 BUG();
395 }
396
397 return bpp > 16;
398}
399
400void dss_init_device(struct platform_device *pdev,
401 struct omap_dss_device *dssdev)
402{
403 struct device_attribute *attr;
404 int i;
405 int r;
406
407 switch (dssdev->type) {
408 case OMAP_DISPLAY_TYPE_DPI:
409#ifdef CONFIG_OMAP2_DSS_RFBI
410 case OMAP_DISPLAY_TYPE_DBI:
411#endif
412#ifdef CONFIG_OMAP2_DSS_SDI
413 case OMAP_DISPLAY_TYPE_SDI:
414#endif
415#ifdef CONFIG_OMAP2_DSS_DSI
416 case OMAP_DISPLAY_TYPE_DSI:
417#endif
418#ifdef CONFIG_OMAP2_DSS_VENC
419 case OMAP_DISPLAY_TYPE_VENC:
420#endif
421 break;
422 default:
423 DSSERR("Support for display '%s' not compiled in.\n",
424 dssdev->name);
425 return;
426 }
427
428 dssdev->get_resolution = default_get_resolution;
429 dssdev->get_recommended_bpp = default_get_recommended_bpp;
430 dssdev->wait_vsync = default_wait_vsync;
431
432 switch (dssdev->type) {
433 case OMAP_DISPLAY_TYPE_DPI:
434 r = dpi_init_display(dssdev);
435 break;
436#ifdef CONFIG_OMAP2_DSS_RFBI
437 case OMAP_DISPLAY_TYPE_DBI:
438 r = rfbi_init_display(dssdev);
439 break;
440#endif
441#ifdef CONFIG_OMAP2_DSS_VENC
442 case OMAP_DISPLAY_TYPE_VENC:
443 r = venc_init_display(dssdev);
444 break;
445#endif
446#ifdef CONFIG_OMAP2_DSS_SDI
447 case OMAP_DISPLAY_TYPE_SDI:
448 r = sdi_init_display(dssdev);
449 break;
450#endif
451#ifdef CONFIG_OMAP2_DSS_DSI
452 case OMAP_DISPLAY_TYPE_DSI:
453 r = dsi_init_display(dssdev);
454 break;
455#endif
456 default:
457 BUG();
458 }
459
460 if (r) {
461 DSSERR("failed to init display %s\n", dssdev->name);
462 return;
463 }
464
465 /* create device sysfs files */
466 i = 0;
467 while ((attr = display_sysfs_attrs[i++]) != NULL) {
468 r = device_create_file(&dssdev->dev, attr);
469 if (r)
470 DSSERR("failed to create sysfs file\n");
471 }
472
473 /* create display? sysfs links */
474 r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
475 dev_name(&dssdev->dev));
476 if (r)
477 DSSERR("failed to create sysfs display link\n");
478}
479
480void dss_uninit_device(struct platform_device *pdev,
481 struct omap_dss_device *dssdev)
482{
483 struct device_attribute *attr;
484 int i = 0;
485
486 sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev));
487
488 while ((attr = display_sysfs_attrs[i++]) != NULL)
489 device_remove_file(&dssdev->dev, attr);
490
491 if (dssdev->manager)
492 dssdev->manager->unset_device(dssdev->manager);
493}
494
495static int dss_suspend_device(struct device *dev, void *data)
496{
497 int r;
498 struct omap_dss_device *dssdev = to_dss_device(dev);
499
500 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
501 dssdev->activate_after_resume = false;
502 return 0;
503 }
504
505 if (!dssdev->suspend) {
506 DSSERR("display '%s' doesn't implement suspend\n",
507 dssdev->name);
508 return -ENOSYS;
509 }
510
511 r = dssdev->suspend(dssdev);
512 if (r)
513 return r;
514
515 dssdev->activate_after_resume = true;
516
517 return 0;
518}
519
520int dss_suspend_all_devices(void)
521{
522 int r;
523 struct bus_type *bus = dss_get_bus();
524
525 r = bus_for_each_dev(bus, NULL, NULL, dss_suspend_device);
526 if (r) {
527 /* resume all displays that were suspended */
528 dss_resume_all_devices();
529 return r;
530 }
531
532 return 0;
533}
534
535static int dss_resume_device(struct device *dev, void *data)
536{
537 int r;
538 struct omap_dss_device *dssdev = to_dss_device(dev);
539
540 if (dssdev->activate_after_resume && dssdev->resume) {
541 r = dssdev->resume(dssdev);
542 if (r)
543 return r;
544 }
545
546 dssdev->activate_after_resume = false;
547
548 return 0;
549}
550
551int dss_resume_all_devices(void)
552{
553 struct bus_type *bus = dss_get_bus();
554
555 return bus_for_each_dev(bus, NULL, NULL, dss_resume_device);
556}
557
558static int dss_disable_device(struct device *dev, void *data)
559{
560 struct omap_dss_device *dssdev = to_dss_device(dev);
561 dssdev->disable(dssdev);
562 return 0;
563}
564
565void dss_disable_all_devices(void)
566{
567 struct bus_type *bus = dss_get_bus();
568 bus_for_each_dev(bus, NULL, NULL, dss_disable_device);
569}
570
571
572void omap_dss_get_device(struct omap_dss_device *dssdev)
573{
574 get_device(&dssdev->dev);
575}
576EXPORT_SYMBOL(omap_dss_get_device);
577
578void omap_dss_put_device(struct omap_dss_device *dssdev)
579{
580 put_device(&dssdev->dev);
581}
582EXPORT_SYMBOL(omap_dss_put_device);
583
584/* ref count of the found device is incremented. ref count
585 * of from-device is decremented. */
586struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
587{
588 struct device *dev;
589 struct device *dev_start = NULL;
590 struct omap_dss_device *dssdev = NULL;
591
592 int match(struct device *dev, void *data)
593 {
594 /* skip panels connected to controllers */
595 if (to_dss_device(dev)->panel.ctrl)
596 return 0;
597
598 return 1;
599 }
600
601 if (from)
602 dev_start = &from->dev;
603 dev = bus_find_device(dss_get_bus(), dev_start, NULL, match);
604 if (dev)
605 dssdev = to_dss_device(dev);
606 if (from)
607 put_device(&from->dev);
608
609 return dssdev;
610}
611EXPORT_SYMBOL(omap_dss_get_next_device);
612
613struct omap_dss_device *omap_dss_find_device(void *data,
614 int (*match)(struct omap_dss_device *dssdev, void *data))
615{
616 struct omap_dss_device *dssdev = NULL;
617
618 while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
619 if (match(dssdev, data))
620 return dssdev;
621 }
622
623 return NULL;
624}
625EXPORT_SYMBOL(omap_dss_find_device);
626
627int omap_dss_start_device(struct omap_dss_device *dssdev)
628{
629 int r;
630
631 if (!dssdev->driver) {
632 DSSDBG("no driver\n");
633 r = -ENODEV;
634 goto err0;
635 }
636
637 if (dssdev->ctrl.panel && !dssdev->ctrl.panel->driver) {
638 DSSDBG("no panel driver\n");
639 r = -ENODEV;
640 goto err0;
641 }
642
643 if (!try_module_get(dssdev->dev.driver->owner)) {
644 r = -ENODEV;
645 goto err0;
646 }
647
648 if (dssdev->ctrl.panel) {
649 if (!try_module_get(dssdev->ctrl.panel->dev.driver->owner)) {
650 r = -ENODEV;
651 goto err1;
652 }
653 }
654
655 return 0;
656err1:
657 module_put(dssdev->dev.driver->owner);
658err0:
659 return r;
660}
661EXPORT_SYMBOL(omap_dss_start_device);
662
663void omap_dss_stop_device(struct omap_dss_device *dssdev)
664{
665 if (dssdev->ctrl.panel)
666 module_put(dssdev->ctrl.panel->dev.driver->owner);
667
668 module_put(dssdev->dev.driver->owner);
669}
670EXPORT_SYMBOL(omap_dss_stop_device);
671
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
new file mode 100644
index 000000000000..2d71031baa25
--- /dev/null
+++ b/drivers/video/omap2/dss/dpi.c
@@ -0,0 +1,399 @@
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/errno.h>
29
30#include <plat/display.h>
31#include <plat/cpu.h>
32
33#include "dss.h"
34
35static struct {
36 int update_enabled;
37} dpi;
38
39#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
40static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
41 unsigned long *fck, int *lck_div, int *pck_div)
42{
43 struct dsi_clock_info dsi_cinfo;
44 struct dispc_clock_info dispc_cinfo;
45 int r;
46
47 r = dsi_pll_calc_clock_div_pck(is_tft, pck_req, &dsi_cinfo,
48 &dispc_cinfo);
49 if (r)
50 return r;
51
52 r = dsi_pll_set_clock_div(&dsi_cinfo);
53 if (r)
54 return r;
55
56 dss_select_clk_source(0, 1);
57
58 r = dispc_set_clock_div(&dispc_cinfo);
59 if (r)
60 return r;
61
62 *fck = dsi_cinfo.dsi1_pll_fclk;
63 *lck_div = dispc_cinfo.lck_div;
64 *pck_div = dispc_cinfo.pck_div;
65
66 return 0;
67}
68#else
69static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
70 unsigned long *fck, int *lck_div, int *pck_div)
71{
72 struct dss_clock_info dss_cinfo;
73 struct dispc_clock_info dispc_cinfo;
74 int r;
75
76 r = dss_calc_clock_div(is_tft, pck_req, &dss_cinfo, &dispc_cinfo);
77 if (r)
78 return r;
79
80 r = dss_set_clock_div(&dss_cinfo);
81 if (r)
82 return r;
83
84 r = dispc_set_clock_div(&dispc_cinfo);
85 if (r)
86 return r;
87
88 *fck = dss_cinfo.fck;
89 *lck_div = dispc_cinfo.lck_div;
90 *pck_div = dispc_cinfo.pck_div;
91
92 return 0;
93}
94#endif
95
96static int dpi_set_mode(struct omap_dss_device *dssdev)
97{
98 struct omap_video_timings *t = &dssdev->panel.timings;
99 int lck_div, pck_div;
100 unsigned long fck;
101 unsigned long pck;
102 bool is_tft;
103 int r = 0;
104
105 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
106
107 dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
108 dssdev->panel.acb);
109
110 is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
111
112#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
113 r = dpi_set_dsi_clk(is_tft, t->pixel_clock * 1000,
114 &fck, &lck_div, &pck_div);
115#else
116 r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000,
117 &fck, &lck_div, &pck_div);
118#endif
119 if (r)
120 goto err0;
121
122 pck = fck / lck_div / pck_div / 1000;
123
124 if (pck != t->pixel_clock) {
125 DSSWARN("Could not find exact pixel clock. "
126 "Requested %d kHz, got %lu kHz\n",
127 t->pixel_clock, pck);
128
129 t->pixel_clock = pck;
130 }
131
132 dispc_set_lcd_timings(t);
133
134err0:
135 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
136 return r;
137}
138
139static int dpi_basic_init(struct omap_dss_device *dssdev)
140{
141 bool is_tft;
142
143 is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
144
145 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
146 dispc_set_lcd_display_type(is_tft ? OMAP_DSS_LCD_DISPLAY_TFT :
147 OMAP_DSS_LCD_DISPLAY_STN);
148 dispc_set_tft_data_lines(dssdev->phy.dpi.data_lines);
149
150 return 0;
151}
152
153static int dpi_display_enable(struct omap_dss_device *dssdev)
154{
155 int r;
156
157 r = omap_dss_start_device(dssdev);
158 if (r) {
159 DSSERR("failed to start device\n");
160 goto err0;
161 }
162
163 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
164 DSSERR("display already enabled\n");
165 r = -EINVAL;
166 goto err1;
167 }
168
169 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
170
171 r = dpi_basic_init(dssdev);
172 if (r)
173 goto err2;
174
175#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
176 dss_clk_enable(DSS_CLK_FCK2);
177 r = dsi_pll_init(dssdev, 0, 1);
178 if (r)
179 goto err3;
180#endif
181 r = dpi_set_mode(dssdev);
182 if (r)
183 goto err4;
184
185 mdelay(2);
186
187 dispc_enable_lcd_out(1);
188
189 r = dssdev->driver->enable(dssdev);
190 if (r)
191 goto err5;
192
193 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
194
195 return 0;
196
197err5:
198 dispc_enable_lcd_out(0);
199err4:
200#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
201 dsi_pll_uninit();
202err3:
203 dss_clk_disable(DSS_CLK_FCK2);
204#endif
205err2:
206 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
207err1:
208 omap_dss_stop_device(dssdev);
209err0:
210 return r;
211}
212
213static int dpi_display_resume(struct omap_dss_device *dssdev);
214
215static void dpi_display_disable(struct omap_dss_device *dssdev)
216{
217 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
218 return;
219
220 if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
221 dpi_display_resume(dssdev);
222
223 dssdev->driver->disable(dssdev);
224
225 dispc_enable_lcd_out(0);
226
227#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
228 dss_select_clk_source(0, 0);
229 dsi_pll_uninit();
230 dss_clk_disable(DSS_CLK_FCK2);
231#endif
232
233 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
234
235 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
236
237 omap_dss_stop_device(dssdev);
238}
239
240static int dpi_display_suspend(struct omap_dss_device *dssdev)
241{
242 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
243 return -EINVAL;
244
245 DSSDBG("dpi_display_suspend\n");
246
247 if (dssdev->driver->suspend)
248 dssdev->driver->suspend(dssdev);
249
250 dispc_enable_lcd_out(0);
251
252 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
253
254 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
255
256 return 0;
257}
258
259static int dpi_display_resume(struct omap_dss_device *dssdev)
260{
261 if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
262 return -EINVAL;
263
264 DSSDBG("dpi_display_resume\n");
265
266 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
267
268 dispc_enable_lcd_out(1);
269
270 if (dssdev->driver->resume)
271 dssdev->driver->resume(dssdev);
272
273 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
274
275 return 0;
276}
277
278static void dpi_set_timings(struct omap_dss_device *dssdev,
279 struct omap_video_timings *timings)
280{
281 DSSDBG("dpi_set_timings\n");
282 dssdev->panel.timings = *timings;
283 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
284 dpi_set_mode(dssdev);
285 dispc_go(OMAP_DSS_CHANNEL_LCD);
286 }
287}
288
289static int dpi_check_timings(struct omap_dss_device *dssdev,
290 struct omap_video_timings *timings)
291{
292 bool is_tft;
293 int r;
294 int lck_div, pck_div;
295 unsigned long fck;
296 unsigned long pck;
297
298 if (!dispc_lcd_timings_ok(timings))
299 return -EINVAL;
300
301 if (timings->pixel_clock == 0)
302 return -EINVAL;
303
304 is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
305
306#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
307 {
308 struct dsi_clock_info dsi_cinfo;
309 struct dispc_clock_info dispc_cinfo;
310 r = dsi_pll_calc_clock_div_pck(is_tft,
311 timings->pixel_clock * 1000,
312 &dsi_cinfo, &dispc_cinfo);
313
314 if (r)
315 return r;
316
317 fck = dsi_cinfo.dsi1_pll_fclk;
318 lck_div = dispc_cinfo.lck_div;
319 pck_div = dispc_cinfo.pck_div;
320 }
321#else
322 {
323 struct dss_clock_info dss_cinfo;
324 struct dispc_clock_info dispc_cinfo;
325 r = dss_calc_clock_div(is_tft, timings->pixel_clock * 1000,
326 &dss_cinfo, &dispc_cinfo);
327
328 if (r)
329 return r;
330
331 fck = dss_cinfo.fck;
332 lck_div = dispc_cinfo.lck_div;
333 pck_div = dispc_cinfo.pck_div;
334 }
335#endif
336
337 pck = fck / lck_div / pck_div / 1000;
338
339 timings->pixel_clock = pck;
340
341 return 0;
342}
343
344static void dpi_get_timings(struct omap_dss_device *dssdev,
345 struct omap_video_timings *timings)
346{
347 *timings = dssdev->panel.timings;
348}
349
350static int dpi_display_set_update_mode(struct omap_dss_device *dssdev,
351 enum omap_dss_update_mode mode)
352{
353 if (mode == OMAP_DSS_UPDATE_MANUAL)
354 return -EINVAL;
355
356 if (mode == OMAP_DSS_UPDATE_DISABLED) {
357 dispc_enable_lcd_out(0);
358 dpi.update_enabled = 0;
359 } else {
360 dispc_enable_lcd_out(1);
361 dpi.update_enabled = 1;
362 }
363
364 return 0;
365}
366
367static enum omap_dss_update_mode dpi_display_get_update_mode(
368 struct omap_dss_device *dssdev)
369{
370 return dpi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
371 OMAP_DSS_UPDATE_DISABLED;
372}
373
374int dpi_init_display(struct omap_dss_device *dssdev)
375{
376 DSSDBG("init_display\n");
377
378 dssdev->enable = dpi_display_enable;
379 dssdev->disable = dpi_display_disable;
380 dssdev->suspend = dpi_display_suspend;
381 dssdev->resume = dpi_display_resume;
382 dssdev->set_timings = dpi_set_timings;
383 dssdev->check_timings = dpi_check_timings;
384 dssdev->get_timings = dpi_get_timings;
385 dssdev->set_update_mode = dpi_display_set_update_mode;
386 dssdev->get_update_mode = dpi_display_get_update_mode;
387
388 return 0;
389}
390
391int dpi_init(void)
392{
393 return 0;
394}
395
396void dpi_exit(void)
397{
398}
399
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
new file mode 100644
index 000000000000..5936487b5def
--- /dev/null
+++ b/drivers/video/omap2/dss/dsi.c
@@ -0,0 +1,3710 @@
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/seq_file.h>
31#include <linux/platform_device.h>
32#include <linux/regulator/consumer.h>
33#include <linux/kthread.h>
34#include <linux/wait.h>
35
36#include <plat/display.h>
37#include <plat/clock.h>
38
39#include "dss.h"
40
41/*#define VERBOSE_IRQ*/
42#define DSI_CATCH_MISSING_TE
43
44#define DSI_BASE 0x4804FC00
45
46struct dsi_reg { u16 idx; };
47
48#define DSI_REG(idx) ((const struct dsi_reg) { idx })
49
50#define DSI_SZ_REGS SZ_1K
51/* DSI Protocol Engine */
52
53#define DSI_REVISION DSI_REG(0x0000)
54#define DSI_SYSCONFIG DSI_REG(0x0010)
55#define DSI_SYSSTATUS DSI_REG(0x0014)
56#define DSI_IRQSTATUS DSI_REG(0x0018)
57#define DSI_IRQENABLE DSI_REG(0x001C)
58#define DSI_CTRL DSI_REG(0x0040)
59#define DSI_COMPLEXIO_CFG1 DSI_REG(0x0048)
60#define DSI_COMPLEXIO_IRQ_STATUS DSI_REG(0x004C)
61#define DSI_COMPLEXIO_IRQ_ENABLE DSI_REG(0x0050)
62#define DSI_CLK_CTRL DSI_REG(0x0054)
63#define DSI_TIMING1 DSI_REG(0x0058)
64#define DSI_TIMING2 DSI_REG(0x005C)
65#define DSI_VM_TIMING1 DSI_REG(0x0060)
66#define DSI_VM_TIMING2 DSI_REG(0x0064)
67#define DSI_VM_TIMING3 DSI_REG(0x0068)
68#define DSI_CLK_TIMING DSI_REG(0x006C)
69#define DSI_TX_FIFO_VC_SIZE DSI_REG(0x0070)
70#define DSI_RX_FIFO_VC_SIZE DSI_REG(0x0074)
71#define DSI_COMPLEXIO_CFG2 DSI_REG(0x0078)
72#define DSI_RX_FIFO_VC_FULLNESS DSI_REG(0x007C)
73#define DSI_VM_TIMING4 DSI_REG(0x0080)
74#define DSI_TX_FIFO_VC_EMPTINESS DSI_REG(0x0084)
75#define DSI_VM_TIMING5 DSI_REG(0x0088)
76#define DSI_VM_TIMING6 DSI_REG(0x008C)
77#define DSI_VM_TIMING7 DSI_REG(0x0090)
78#define DSI_STOPCLK_TIMING DSI_REG(0x0094)
79#define DSI_VC_CTRL(n) DSI_REG(0x0100 + (n * 0x20))
80#define DSI_VC_TE(n) DSI_REG(0x0104 + (n * 0x20))
81#define DSI_VC_LONG_PACKET_HEADER(n) DSI_REG(0x0108 + (n * 0x20))
82#define DSI_VC_LONG_PACKET_PAYLOAD(n) DSI_REG(0x010C + (n * 0x20))
83#define DSI_VC_SHORT_PACKET_HEADER(n) DSI_REG(0x0110 + (n * 0x20))
84#define DSI_VC_IRQSTATUS(n) DSI_REG(0x0118 + (n * 0x20))
85#define DSI_VC_IRQENABLE(n) DSI_REG(0x011C + (n * 0x20))
86
87/* DSIPHY_SCP */
88
89#define DSI_DSIPHY_CFG0 DSI_REG(0x200 + 0x0000)
90#define DSI_DSIPHY_CFG1 DSI_REG(0x200 + 0x0004)
91#define DSI_DSIPHY_CFG2 DSI_REG(0x200 + 0x0008)
92#define DSI_DSIPHY_CFG5 DSI_REG(0x200 + 0x0014)
93
94/* DSI_PLL_CTRL_SCP */
95
96#define DSI_PLL_CONTROL DSI_REG(0x300 + 0x0000)
97#define DSI_PLL_STATUS DSI_REG(0x300 + 0x0004)
98#define DSI_PLL_GO DSI_REG(0x300 + 0x0008)
99#define DSI_PLL_CONFIGURATION1 DSI_REG(0x300 + 0x000C)
100#define DSI_PLL_CONFIGURATION2 DSI_REG(0x300 + 0x0010)
101
102#define REG_GET(idx, start, end) \
103 FLD_GET(dsi_read_reg(idx), start, end)
104
105#define REG_FLD_MOD(idx, val, start, end) \
106 dsi_write_reg(idx, FLD_MOD(dsi_read_reg(idx), val, start, end))
107
108/* Global interrupts */
109#define DSI_IRQ_VC0 (1 << 0)
110#define DSI_IRQ_VC1 (1 << 1)
111#define DSI_IRQ_VC2 (1 << 2)
112#define DSI_IRQ_VC3 (1 << 3)
113#define DSI_IRQ_WAKEUP (1 << 4)
114#define DSI_IRQ_RESYNC (1 << 5)
115#define DSI_IRQ_PLL_LOCK (1 << 7)
116#define DSI_IRQ_PLL_UNLOCK (1 << 8)
117#define DSI_IRQ_PLL_RECALL (1 << 9)
118#define DSI_IRQ_COMPLEXIO_ERR (1 << 10)
119#define DSI_IRQ_HS_TX_TIMEOUT (1 << 14)
120#define DSI_IRQ_LP_RX_TIMEOUT (1 << 15)
121#define DSI_IRQ_TE_TRIGGER (1 << 16)
122#define DSI_IRQ_ACK_TRIGGER (1 << 17)
123#define DSI_IRQ_SYNC_LOST (1 << 18)
124#define DSI_IRQ_LDO_POWER_GOOD (1 << 19)
125#define DSI_IRQ_TA_TIMEOUT (1 << 20)
126#define DSI_IRQ_ERROR_MASK \
127 (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \
128 DSI_IRQ_TA_TIMEOUT)
129#define DSI_IRQ_CHANNEL_MASK 0xf
130
131/* Virtual channel interrupts */
132#define DSI_VC_IRQ_CS (1 << 0)
133#define DSI_VC_IRQ_ECC_CORR (1 << 1)
134#define DSI_VC_IRQ_PACKET_SENT (1 << 2)
135#define DSI_VC_IRQ_FIFO_TX_OVF (1 << 3)
136#define DSI_VC_IRQ_FIFO_RX_OVF (1 << 4)
137#define DSI_VC_IRQ_BTA (1 << 5)
138#define DSI_VC_IRQ_ECC_NO_CORR (1 << 6)
139#define DSI_VC_IRQ_FIFO_TX_UDF (1 << 7)
140#define DSI_VC_IRQ_PP_BUSY_CHANGE (1 << 8)
141#define DSI_VC_IRQ_ERROR_MASK \
142 (DSI_VC_IRQ_CS | DSI_VC_IRQ_ECC_CORR | DSI_VC_IRQ_FIFO_TX_OVF | \
143 DSI_VC_IRQ_FIFO_RX_OVF | DSI_VC_IRQ_ECC_NO_CORR | \
144 DSI_VC_IRQ_FIFO_TX_UDF)
145
146/* ComplexIO interrupts */
147#define DSI_CIO_IRQ_ERRSYNCESC1 (1 << 0)
148#define DSI_CIO_IRQ_ERRSYNCESC2 (1 << 1)
149#define DSI_CIO_IRQ_ERRSYNCESC3 (1 << 2)
150#define DSI_CIO_IRQ_ERRESC1 (1 << 5)
151#define DSI_CIO_IRQ_ERRESC2 (1 << 6)
152#define DSI_CIO_IRQ_ERRESC3 (1 << 7)
153#define DSI_CIO_IRQ_ERRCONTROL1 (1 << 10)
154#define DSI_CIO_IRQ_ERRCONTROL2 (1 << 11)
155#define DSI_CIO_IRQ_ERRCONTROL3 (1 << 12)
156#define DSI_CIO_IRQ_STATEULPS1 (1 << 15)
157#define DSI_CIO_IRQ_STATEULPS2 (1 << 16)
158#define DSI_CIO_IRQ_STATEULPS3 (1 << 17)
159#define DSI_CIO_IRQ_ERRCONTENTIONLP0_1 (1 << 20)
160#define DSI_CIO_IRQ_ERRCONTENTIONLP1_1 (1 << 21)
161#define DSI_CIO_IRQ_ERRCONTENTIONLP0_2 (1 << 22)
162#define DSI_CIO_IRQ_ERRCONTENTIONLP1_2 (1 << 23)
163#define DSI_CIO_IRQ_ERRCONTENTIONLP0_3 (1 << 24)
164#define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25)
165#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30)
166#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31)
167
168#define DSI_DT_DCS_SHORT_WRITE_0 0x05
169#define DSI_DT_DCS_SHORT_WRITE_1 0x15
170#define DSI_DT_DCS_READ 0x06
171#define DSI_DT_SET_MAX_RET_PKG_SIZE 0x37
172#define DSI_DT_NULL_PACKET 0x09
173#define DSI_DT_DCS_LONG_WRITE 0x39
174
175#define DSI_DT_RX_ACK_WITH_ERR 0x02
176#define DSI_DT_RX_DCS_LONG_READ 0x1c
177#define DSI_DT_RX_SHORT_READ_1 0x21
178#define DSI_DT_RX_SHORT_READ_2 0x22
179
180#define FINT_MAX 2100000
181#define FINT_MIN 750000
182#define REGN_MAX (1 << 7)
183#define REGM_MAX ((1 << 11) - 1)
184#define REGM3_MAX (1 << 4)
185#define REGM4_MAX (1 << 4)
186#define LP_DIV_MAX ((1 << 13) - 1)
187
188enum fifo_size {
189 DSI_FIFO_SIZE_0 = 0,
190 DSI_FIFO_SIZE_32 = 1,
191 DSI_FIFO_SIZE_64 = 2,
192 DSI_FIFO_SIZE_96 = 3,
193 DSI_FIFO_SIZE_128 = 4,
194};
195
196enum dsi_vc_mode {
197 DSI_VC_MODE_L4 = 0,
198 DSI_VC_MODE_VP,
199};
200
201struct dsi_update_region {
202 bool dirty;
203 u16 x, y, w, h;
204 struct omap_dss_device *device;
205};
206
207static struct
208{
209 void __iomem *base;
210
211 struct dsi_clock_info current_cinfo;
212
213 struct regulator *vdds_dsi_reg;
214
215 struct {
216 enum dsi_vc_mode mode;
217 struct omap_dss_device *dssdev;
218 enum fifo_size fifo_size;
219 int dest_per; /* destination peripheral 0-3 */
220 } vc[4];
221
222 struct mutex lock;
223 struct mutex bus_lock;
224
225 unsigned pll_locked;
226
227 struct completion bta_completion;
228
229 struct task_struct *thread;
230 wait_queue_head_t waitqueue;
231
232 spinlock_t update_lock;
233 bool framedone_received;
234 struct dsi_update_region update_region;
235 struct dsi_update_region active_update_region;
236 struct completion update_completion;
237
238 enum omap_dss_update_mode user_update_mode;
239 enum omap_dss_update_mode update_mode;
240 bool te_enabled;
241 bool use_ext_te;
242
243#ifdef DSI_CATCH_MISSING_TE
244 struct timer_list te_timer;
245#endif
246
247 unsigned long cache_req_pck;
248 unsigned long cache_clk_freq;
249 struct dsi_clock_info cache_cinfo;
250
251 u32 errors;
252 spinlock_t errors_lock;
253#ifdef DEBUG
254 ktime_t perf_setup_time;
255 ktime_t perf_start_time;
256 ktime_t perf_start_time_auto;
257 int perf_measure_frames;
258#endif
259 int debug_read;
260 int debug_write;
261} dsi;
262
263#ifdef DEBUG
264static unsigned int dsi_perf;
265module_param_named(dsi_perf, dsi_perf, bool, 0644);
266#endif
267
268static inline void dsi_write_reg(const struct dsi_reg idx, u32 val)
269{
270 __raw_writel(val, dsi.base + idx.idx);
271}
272
273static inline u32 dsi_read_reg(const struct dsi_reg idx)
274{
275 return __raw_readl(dsi.base + idx.idx);
276}
277
278
279void dsi_save_context(void)
280{
281}
282
283void dsi_restore_context(void)
284{
285}
286
287void dsi_bus_lock(void)
288{
289 mutex_lock(&dsi.bus_lock);
290}
291EXPORT_SYMBOL(dsi_bus_lock);
292
293void dsi_bus_unlock(void)
294{
295 mutex_unlock(&dsi.bus_lock);
296}
297EXPORT_SYMBOL(dsi_bus_unlock);
298
299static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
300 int value)
301{
302 int t = 100000;
303
304 while (REG_GET(idx, bitnum, bitnum) != value) {
305 if (--t == 0)
306 return !value;
307 }
308
309 return value;
310}
311
312#ifdef DEBUG
313static void dsi_perf_mark_setup(void)
314{
315 dsi.perf_setup_time = ktime_get();
316}
317
318static void dsi_perf_mark_start(void)
319{
320 dsi.perf_start_time = ktime_get();
321}
322
323static void dsi_perf_mark_start_auto(void)
324{
325 dsi.perf_measure_frames = 0;
326 dsi.perf_start_time_auto = ktime_get();
327}
328
329static void dsi_perf_show(const char *name)
330{
331 ktime_t t, setup_time, trans_time;
332 u32 total_bytes;
333 u32 setup_us, trans_us, total_us;
334
335 if (!dsi_perf)
336 return;
337
338 if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED)
339 return;
340
341 t = ktime_get();
342
343 setup_time = ktime_sub(dsi.perf_start_time, dsi.perf_setup_time);
344 setup_us = (u32)ktime_to_us(setup_time);
345 if (setup_us == 0)
346 setup_us = 1;
347
348 trans_time = ktime_sub(t, dsi.perf_start_time);
349 trans_us = (u32)ktime_to_us(trans_time);
350 if (trans_us == 0)
351 trans_us = 1;
352
353 total_us = setup_us + trans_us;
354
355 total_bytes = dsi.active_update_region.w *
356 dsi.active_update_region.h *
357 dsi.active_update_region.device->ctrl.pixel_size / 8;
358
359 if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) {
360 static u32 s_total_trans_us, s_total_setup_us;
361 static u32 s_min_trans_us = 0xffffffff, s_min_setup_us;
362 static u32 s_max_trans_us, s_max_setup_us;
363 const int numframes = 100;
364 ktime_t total_time_auto;
365 u32 total_time_auto_us;
366
367 dsi.perf_measure_frames++;
368
369 if (setup_us < s_min_setup_us)
370 s_min_setup_us = setup_us;
371
372 if (setup_us > s_max_setup_us)
373 s_max_setup_us = setup_us;
374
375 s_total_setup_us += setup_us;
376
377 if (trans_us < s_min_trans_us)
378 s_min_trans_us = trans_us;
379
380 if (trans_us > s_max_trans_us)
381 s_max_trans_us = trans_us;
382
383 s_total_trans_us += trans_us;
384
385 if (dsi.perf_measure_frames < numframes)
386 return;
387
388 total_time_auto = ktime_sub(t, dsi.perf_start_time_auto);
389 total_time_auto_us = (u32)ktime_to_us(total_time_auto);
390
391 printk(KERN_INFO "DSI(%s): %u fps, setup %u/%u/%u, "
392 "trans %u/%u/%u\n",
393 name,
394 1000 * 1000 * numframes / total_time_auto_us,
395 s_min_setup_us,
396 s_max_setup_us,
397 s_total_setup_us / numframes,
398 s_min_trans_us,
399 s_max_trans_us,
400 s_total_trans_us / numframes);
401
402 s_total_setup_us = 0;
403 s_min_setup_us = 0xffffffff;
404 s_max_setup_us = 0;
405 s_total_trans_us = 0;
406 s_min_trans_us = 0xffffffff;
407 s_max_trans_us = 0;
408 dsi_perf_mark_start_auto();
409 } else {
410 printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
411 "%u bytes, %u kbytes/sec\n",
412 name,
413 setup_us,
414 trans_us,
415 total_us,
416 1000*1000 / total_us,
417 total_bytes,
418 total_bytes * 1000 / total_us);
419 }
420}
421#else
422#define dsi_perf_mark_setup()
423#define dsi_perf_mark_start()
424#define dsi_perf_mark_start_auto()
425#define dsi_perf_show(x)
426#endif
427
428static void print_irq_status(u32 status)
429{
430#ifndef VERBOSE_IRQ
431 if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0)
432 return;
433#endif
434 printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status);
435
436#define PIS(x) \
437 if (status & DSI_IRQ_##x) \
438 printk(#x " ");
439#ifdef VERBOSE_IRQ
440 PIS(VC0);
441 PIS(VC1);
442 PIS(VC2);
443 PIS(VC3);
444#endif
445 PIS(WAKEUP);
446 PIS(RESYNC);
447 PIS(PLL_LOCK);
448 PIS(PLL_UNLOCK);
449 PIS(PLL_RECALL);
450 PIS(COMPLEXIO_ERR);
451 PIS(HS_TX_TIMEOUT);
452 PIS(LP_RX_TIMEOUT);
453 PIS(TE_TRIGGER);
454 PIS(ACK_TRIGGER);
455 PIS(SYNC_LOST);
456 PIS(LDO_POWER_GOOD);
457 PIS(TA_TIMEOUT);
458#undef PIS
459
460 printk("\n");
461}
462
463static void print_irq_status_vc(int channel, u32 status)
464{
465#ifndef VERBOSE_IRQ
466 if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
467 return;
468#endif
469 printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status);
470
471#define PIS(x) \
472 if (status & DSI_VC_IRQ_##x) \
473 printk(#x " ");
474 PIS(CS);
475 PIS(ECC_CORR);
476#ifdef VERBOSE_IRQ
477 PIS(PACKET_SENT);
478#endif
479 PIS(FIFO_TX_OVF);
480 PIS(FIFO_RX_OVF);
481 PIS(BTA);
482 PIS(ECC_NO_CORR);
483 PIS(FIFO_TX_UDF);
484 PIS(PP_BUSY_CHANGE);
485#undef PIS
486 printk("\n");
487}
488
489static void print_irq_status_cio(u32 status)
490{
491 printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status);
492
493#define PIS(x) \
494 if (status & DSI_CIO_IRQ_##x) \
495 printk(#x " ");
496 PIS(ERRSYNCESC1);
497 PIS(ERRSYNCESC2);
498 PIS(ERRSYNCESC3);
499 PIS(ERRESC1);
500 PIS(ERRESC2);
501 PIS(ERRESC3);
502 PIS(ERRCONTROL1);
503 PIS(ERRCONTROL2);
504 PIS(ERRCONTROL3);
505 PIS(STATEULPS1);
506 PIS(STATEULPS2);
507 PIS(STATEULPS3);
508 PIS(ERRCONTENTIONLP0_1);
509 PIS(ERRCONTENTIONLP1_1);
510 PIS(ERRCONTENTIONLP0_2);
511 PIS(ERRCONTENTIONLP1_2);
512 PIS(ERRCONTENTIONLP0_3);
513 PIS(ERRCONTENTIONLP1_3);
514 PIS(ULPSACTIVENOT_ALL0);
515 PIS(ULPSACTIVENOT_ALL1);
516#undef PIS
517
518 printk("\n");
519}
520
521static int debug_irq;
522
523/* called from dss */
524void dsi_irq_handler(void)
525{
526 u32 irqstatus, vcstatus, ciostatus;
527 int i;
528
529 irqstatus = dsi_read_reg(DSI_IRQSTATUS);
530
531 if (irqstatus & DSI_IRQ_ERROR_MASK) {
532 DSSERR("DSI error, irqstatus %x\n", irqstatus);
533 print_irq_status(irqstatus);
534 spin_lock(&dsi.errors_lock);
535 dsi.errors |= irqstatus & DSI_IRQ_ERROR_MASK;
536 spin_unlock(&dsi.errors_lock);
537 } else if (debug_irq) {
538 print_irq_status(irqstatus);
539 }
540
541#ifdef DSI_CATCH_MISSING_TE
542 if (irqstatus & DSI_IRQ_TE_TRIGGER)
543 del_timer(&dsi.te_timer);
544#endif
545
546 for (i = 0; i < 4; ++i) {
547 if ((irqstatus & (1<<i)) == 0)
548 continue;
549
550 vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i));
551
552 if (vcstatus & DSI_VC_IRQ_BTA)
553 complete(&dsi.bta_completion);
554
555 if (vcstatus & DSI_VC_IRQ_ERROR_MASK) {
556 DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
557 i, vcstatus);
558 print_irq_status_vc(i, vcstatus);
559 } else if (debug_irq) {
560 print_irq_status_vc(i, vcstatus);
561 }
562
563 dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus);
564 /* flush posted write */
565 dsi_read_reg(DSI_VC_IRQSTATUS(i));
566 }
567
568 if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
569 ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
570
571 dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
572 /* flush posted write */
573 dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
574
575 DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
576 print_irq_status_cio(ciostatus);
577 }
578
579 dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
580 /* flush posted write */
581 dsi_read_reg(DSI_IRQSTATUS);
582}
583
584
585static void _dsi_initialize_irq(void)
586{
587 u32 l;
588 int i;
589
590 /* disable all interrupts */
591 dsi_write_reg(DSI_IRQENABLE, 0);
592 for (i = 0; i < 4; ++i)
593 dsi_write_reg(DSI_VC_IRQENABLE(i), 0);
594 dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0);
595
596 /* clear interrupt status */
597 l = dsi_read_reg(DSI_IRQSTATUS);
598 dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK);
599
600 for (i = 0; i < 4; ++i) {
601 l = dsi_read_reg(DSI_VC_IRQSTATUS(i));
602 dsi_write_reg(DSI_VC_IRQSTATUS(i), l);
603 }
604
605 l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
606 dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l);
607
608 /* enable error irqs */
609 l = DSI_IRQ_ERROR_MASK;
610#ifdef DSI_CATCH_MISSING_TE
611 l |= DSI_IRQ_TE_TRIGGER;
612#endif
613 dsi_write_reg(DSI_IRQENABLE, l);
614
615 l = DSI_VC_IRQ_ERROR_MASK;
616 for (i = 0; i < 4; ++i)
617 dsi_write_reg(DSI_VC_IRQENABLE(i), l);
618
619 /* XXX zonda responds incorrectly, causing control error:
620 Exit from LP-ESC mode to LP11 uses wrong transition states on the
621 data lines LP0 and LN0. */
622 dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE,
623 -1 & (~DSI_CIO_IRQ_ERRCONTROL2));
624}
625
626static u32 dsi_get_errors(void)
627{
628 unsigned long flags;
629 u32 e;
630 spin_lock_irqsave(&dsi.errors_lock, flags);
631 e = dsi.errors;
632 dsi.errors = 0;
633 spin_unlock_irqrestore(&dsi.errors_lock, flags);
634 return e;
635}
636
637static void dsi_vc_enable_bta_irq(int channel)
638{
639 u32 l;
640
641 dsi_write_reg(DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA);
642
643 l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
644 l |= DSI_VC_IRQ_BTA;
645 dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
646}
647
648static void dsi_vc_disable_bta_irq(int channel)
649{
650 u32 l;
651
652 l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
653 l &= ~DSI_VC_IRQ_BTA;
654 dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
655}
656
657/* DSI func clock. this could also be DSI2_PLL_FCLK */
658static inline void enable_clocks(bool enable)
659{
660 if (enable)
661 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
662 else
663 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
664}
665
666/* source clock for DSI PLL. this could also be PCLKFREE */
667static inline void dsi_enable_pll_clock(bool enable)
668{
669 if (enable)
670 dss_clk_enable(DSS_CLK_FCK2);
671 else
672 dss_clk_disable(DSS_CLK_FCK2);
673
674 if (enable && dsi.pll_locked) {
675 if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1)
676 DSSERR("cannot lock PLL when enabling clocks\n");
677 }
678}
679
680#ifdef DEBUG
681static void _dsi_print_reset_status(void)
682{
683 u32 l;
684
685 if (!dss_debug)
686 return;
687
688 /* A dummy read using the SCP interface to any DSIPHY register is
689 * required after DSIPHY reset to complete the reset of the DSI complex
690 * I/O. */
691 l = dsi_read_reg(DSI_DSIPHY_CFG5);
692
693 printk(KERN_DEBUG "DSI resets: ");
694
695 l = dsi_read_reg(DSI_PLL_STATUS);
696 printk("PLL (%d) ", FLD_GET(l, 0, 0));
697
698 l = dsi_read_reg(DSI_COMPLEXIO_CFG1);
699 printk("CIO (%d) ", FLD_GET(l, 29, 29));
700
701 l = dsi_read_reg(DSI_DSIPHY_CFG5);
702 printk("PHY (%x, %d, %d, %d)\n",
703 FLD_GET(l, 28, 26),
704 FLD_GET(l, 29, 29),
705 FLD_GET(l, 30, 30),
706 FLD_GET(l, 31, 31));
707}
708#else
709#define _dsi_print_reset_status()
710#endif
711
712static inline int dsi_if_enable(bool enable)
713{
714 DSSDBG("dsi_if_enable(%d)\n", enable);
715
716 enable = enable ? 1 : 0;
717 REG_FLD_MOD(DSI_CTRL, enable, 0, 0); /* IF_EN */
718
719 if (wait_for_bit_change(DSI_CTRL, 0, enable) != enable) {
720 DSSERR("Failed to set dsi_if_enable to %d\n", enable);
721 return -EIO;
722 }
723
724 return 0;
725}
726
727unsigned long dsi_get_dsi1_pll_rate(void)
728{
729 return dsi.current_cinfo.dsi1_pll_fclk;
730}
731
732static unsigned long dsi_get_dsi2_pll_rate(void)
733{
734 return dsi.current_cinfo.dsi2_pll_fclk;
735}
736
737static unsigned long dsi_get_txbyteclkhs(void)
738{
739 return dsi.current_cinfo.clkin4ddr / 16;
740}
741
742static unsigned long dsi_fclk_rate(void)
743{
744 unsigned long r;
745
746 if (dss_get_dsi_clk_source() == 0) {
747 /* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */
748 r = dss_clk_get_rate(DSS_CLK_FCK1);
749 } else {
750 /* DSI FCLK source is DSI2_PLL_FCLK */
751 r = dsi_get_dsi2_pll_rate();
752 }
753
754 return r;
755}
756
757static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
758{
759 unsigned long dsi_fclk;
760 unsigned lp_clk_div;
761 unsigned long lp_clk;
762
763 lp_clk_div = dssdev->phy.dsi.div.lp_clk_div;
764
765 if (lp_clk_div == 0 || lp_clk_div > LP_DIV_MAX)
766 return -EINVAL;
767
768 dsi_fclk = dsi_fclk_rate();
769
770 lp_clk = dsi_fclk / 2 / lp_clk_div;
771
772 DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
773 dsi.current_cinfo.lp_clk = lp_clk;
774 dsi.current_cinfo.lp_clk_div = lp_clk_div;
775
776 REG_FLD_MOD(DSI_CLK_CTRL, lp_clk_div, 12, 0); /* LP_CLK_DIVISOR */
777
778 REG_FLD_MOD(DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0,
779 21, 21); /* LP_RX_SYNCHRO_ENABLE */
780
781 return 0;
782}
783
784
785enum dsi_pll_power_state {
786 DSI_PLL_POWER_OFF = 0x0,
787 DSI_PLL_POWER_ON_HSCLK = 0x1,
788 DSI_PLL_POWER_ON_ALL = 0x2,
789 DSI_PLL_POWER_ON_DIV = 0x3,
790};
791
792static int dsi_pll_power(enum dsi_pll_power_state state)
793{
794 int t = 0;
795
796 REG_FLD_MOD(DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_CMD */
797
798 /* PLL_PWR_STATUS */
799 while (FLD_GET(dsi_read_reg(DSI_CLK_CTRL), 29, 28) != state) {
800 udelay(1);
801 if (t++ > 1000) {
802 DSSERR("Failed to set DSI PLL power mode to %d\n",
803 state);
804 return -ENODEV;
805 }
806 }
807
808 return 0;
809}
810
811/* calculate clock rates using dividers in cinfo */
812static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo)
813{
814 if (cinfo->regn == 0 || cinfo->regn > REGN_MAX)
815 return -EINVAL;
816
817 if (cinfo->regm == 0 || cinfo->regm > REGM_MAX)
818 return -EINVAL;
819
820 if (cinfo->regm3 > REGM3_MAX)
821 return -EINVAL;
822
823 if (cinfo->regm4 > REGM4_MAX)
824 return -EINVAL;
825
826 if (cinfo->use_dss2_fck) {
827 cinfo->clkin = dss_clk_get_rate(DSS_CLK_FCK2);
828 /* XXX it is unclear if highfreq should be used
829 * with DSS2_FCK source also */
830 cinfo->highfreq = 0;
831 } else {
832 cinfo->clkin = dispc_pclk_rate();
833
834 if (cinfo->clkin < 32000000)
835 cinfo->highfreq = 0;
836 else
837 cinfo->highfreq = 1;
838 }
839
840 cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1));
841
842 if (cinfo->fint > FINT_MAX || cinfo->fint < FINT_MIN)
843 return -EINVAL;
844
845 cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
846
847 if (cinfo->clkin4ddr > 1800 * 1000 * 1000)
848 return -EINVAL;
849
850 if (cinfo->regm3 > 0)
851 cinfo->dsi1_pll_fclk = cinfo->clkin4ddr / cinfo->regm3;
852 else
853 cinfo->dsi1_pll_fclk = 0;
854
855 if (cinfo->regm4 > 0)
856 cinfo->dsi2_pll_fclk = cinfo->clkin4ddr / cinfo->regm4;
857 else
858 cinfo->dsi2_pll_fclk = 0;
859
860 return 0;
861}
862
863int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
864 struct dsi_clock_info *dsi_cinfo,
865 struct dispc_clock_info *dispc_cinfo)
866{
867 struct dsi_clock_info cur, best;
868 struct dispc_clock_info best_dispc;
869 int min_fck_per_pck;
870 int match = 0;
871 unsigned long dss_clk_fck2;
872
873 dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_FCK2);
874
875 if (req_pck == dsi.cache_req_pck &&
876 dsi.cache_cinfo.clkin == dss_clk_fck2) {
877 DSSDBG("DSI clock info found from cache\n");
878 *dsi_cinfo = dsi.cache_cinfo;
879 dispc_find_clk_divs(is_tft, req_pck, dsi_cinfo->dsi1_pll_fclk,
880 dispc_cinfo);
881 return 0;
882 }
883
884 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
885
886 if (min_fck_per_pck &&
887 req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
888 DSSERR("Requested pixel clock not possible with the current "
889 "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
890 "the constraint off.\n");
891 min_fck_per_pck = 0;
892 }
893
894 DSSDBG("dsi_pll_calc\n");
895
896retry:
897 memset(&best, 0, sizeof(best));
898 memset(&best_dispc, 0, sizeof(best_dispc));
899
900 memset(&cur, 0, sizeof(cur));
901 cur.clkin = dss_clk_fck2;
902 cur.use_dss2_fck = 1;
903 cur.highfreq = 0;
904
905 /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
906 /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
907 /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
908 for (cur.regn = 1; cur.regn < REGN_MAX; ++cur.regn) {
909 if (cur.highfreq == 0)
910 cur.fint = cur.clkin / cur.regn;
911 else
912 cur.fint = cur.clkin / (2 * cur.regn);
913
914 if (cur.fint > FINT_MAX || cur.fint < FINT_MIN)
915 continue;
916
917 /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
918 for (cur.regm = 1; cur.regm < REGM_MAX; ++cur.regm) {
919 unsigned long a, b;
920
921 a = 2 * cur.regm * (cur.clkin/1000);
922 b = cur.regn * (cur.highfreq + 1);
923 cur.clkin4ddr = a / b * 1000;
924
925 if (cur.clkin4ddr > 1800 * 1000 * 1000)
926 break;
927
928 /* DSI1_PLL_FCLK(MHz) = DSIPHY(MHz) / regm3 < 173MHz */
929 for (cur.regm3 = 1; cur.regm3 < REGM3_MAX;
930 ++cur.regm3) {
931 struct dispc_clock_info cur_dispc;
932 cur.dsi1_pll_fclk = cur.clkin4ddr / cur.regm3;
933
934 /* this will narrow down the search a bit,
935 * but still give pixclocks below what was
936 * requested */
937 if (cur.dsi1_pll_fclk < req_pck)
938 break;
939
940 if (cur.dsi1_pll_fclk > DISPC_MAX_FCK)
941 continue;
942
943 if (min_fck_per_pck &&
944 cur.dsi1_pll_fclk <
945 req_pck * min_fck_per_pck)
946 continue;
947
948 match = 1;
949
950 dispc_find_clk_divs(is_tft, req_pck,
951 cur.dsi1_pll_fclk,
952 &cur_dispc);
953
954 if (abs(cur_dispc.pck - req_pck) <
955 abs(best_dispc.pck - req_pck)) {
956 best = cur;
957 best_dispc = cur_dispc;
958
959 if (cur_dispc.pck == req_pck)
960 goto found;
961 }
962 }
963 }
964 }
965found:
966 if (!match) {
967 if (min_fck_per_pck) {
968 DSSERR("Could not find suitable clock settings.\n"
969 "Turning FCK/PCK constraint off and"
970 "trying again.\n");
971 min_fck_per_pck = 0;
972 goto retry;
973 }
974
975 DSSERR("Could not find suitable clock settings.\n");
976
977 return -EINVAL;
978 }
979
980 /* DSI2_PLL_FCLK (regm4) is not used */
981 best.regm4 = 0;
982 best.dsi2_pll_fclk = 0;
983
984 if (dsi_cinfo)
985 *dsi_cinfo = best;
986 if (dispc_cinfo)
987 *dispc_cinfo = best_dispc;
988
989 dsi.cache_req_pck = req_pck;
990 dsi.cache_clk_freq = 0;
991 dsi.cache_cinfo = best;
992
993 return 0;
994}
995
996int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
997{
998 int r = 0;
999 u32 l;
1000 int f;
1001
1002 DSSDBGF();
1003
1004 dsi.current_cinfo.fint = cinfo->fint;
1005 dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr;
1006 dsi.current_cinfo.dsi1_pll_fclk = cinfo->dsi1_pll_fclk;
1007 dsi.current_cinfo.dsi2_pll_fclk = cinfo->dsi2_pll_fclk;
1008
1009 dsi.current_cinfo.regn = cinfo->regn;
1010 dsi.current_cinfo.regm = cinfo->regm;
1011 dsi.current_cinfo.regm3 = cinfo->regm3;
1012 dsi.current_cinfo.regm4 = cinfo->regm4;
1013
1014 DSSDBG("DSI Fint %ld\n", cinfo->fint);
1015
1016 DSSDBG("clkin (%s) rate %ld, highfreq %d\n",
1017 cinfo->use_dss2_fck ? "dss2_fck" : "pclkfree",
1018 cinfo->clkin,
1019 cinfo->highfreq);
1020
1021 /* DSIPHY == CLKIN4DDR */
1022 DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu / %d = %lu\n",
1023 cinfo->regm,
1024 cinfo->regn,
1025 cinfo->clkin,
1026 cinfo->highfreq + 1,
1027 cinfo->clkin4ddr);
1028
1029 DSSDBG("Data rate on 1 DSI lane %ld Mbps\n",
1030 cinfo->clkin4ddr / 1000 / 1000 / 2);
1031
1032 DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);
1033
1034 DSSDBG("regm3 = %d, dsi1_pll_fclk = %lu\n",
1035 cinfo->regm3, cinfo->dsi1_pll_fclk);
1036 DSSDBG("regm4 = %d, dsi2_pll_fclk = %lu\n",
1037 cinfo->regm4, cinfo->dsi2_pll_fclk);
1038
1039 REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */
1040
1041 l = dsi_read_reg(DSI_PLL_CONFIGURATION1);
1042 l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */
1043 l = FLD_MOD(l, cinfo->regn - 1, 7, 1); /* DSI_PLL_REGN */
1044 l = FLD_MOD(l, cinfo->regm, 18, 8); /* DSI_PLL_REGM */
1045 l = FLD_MOD(l, cinfo->regm3 > 0 ? cinfo->regm3 - 1 : 0,
1046 22, 19); /* DSI_CLOCK_DIV */
1047 l = FLD_MOD(l, cinfo->regm4 > 0 ? cinfo->regm4 - 1 : 0,
1048 26, 23); /* DSIPROTO_CLOCK_DIV */
1049 dsi_write_reg(DSI_PLL_CONFIGURATION1, l);
1050
1051 BUG_ON(cinfo->fint < 750000 || cinfo->fint > 2100000);
1052 if (cinfo->fint < 1000000)
1053 f = 0x3;
1054 else if (cinfo->fint < 1250000)
1055 f = 0x4;
1056 else if (cinfo->fint < 1500000)
1057 f = 0x5;
1058 else if (cinfo->fint < 1750000)
1059 f = 0x6;
1060 else
1061 f = 0x7;
1062
1063 l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
1064 l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
1065 l = FLD_MOD(l, cinfo->use_dss2_fck ? 0 : 1,
1066 11, 11); /* DSI_PLL_CLKSEL */
1067 l = FLD_MOD(l, cinfo->highfreq,
1068 12, 12); /* DSI_PLL_HIGHFREQ */
1069 l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
1070 l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */
1071 l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */
1072 dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
1073
1074 REG_FLD_MOD(DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
1075
1076 if (wait_for_bit_change(DSI_PLL_GO, 0, 0) != 0) {
1077 DSSERR("dsi pll go bit not going down.\n");
1078 r = -EIO;
1079 goto err;
1080 }
1081
1082 if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1) {
1083 DSSERR("cannot lock PLL\n");
1084 r = -EIO;
1085 goto err;
1086 }
1087
1088 dsi.pll_locked = 1;
1089
1090 l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
1091 l = FLD_MOD(l, 0, 0, 0); /* DSI_PLL_IDLE */
1092 l = FLD_MOD(l, 0, 5, 5); /* DSI_PLL_PLLLPMODE */
1093 l = FLD_MOD(l, 0, 6, 6); /* DSI_PLL_LOWCURRSTBY */
1094 l = FLD_MOD(l, 0, 7, 7); /* DSI_PLL_TIGHTPHASELOCK */
1095 l = FLD_MOD(l, 0, 8, 8); /* DSI_PLL_DRIFTGUARDEN */
1096 l = FLD_MOD(l, 0, 10, 9); /* DSI_PLL_LOCKSEL */
1097 l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
1098 l = FLD_MOD(l, 1, 14, 14); /* DSIPHY_CLKINEN */
1099 l = FLD_MOD(l, 0, 15, 15); /* DSI_BYPASSEN */
1100 l = FLD_MOD(l, 1, 16, 16); /* DSS_CLOCK_EN */
1101 l = FLD_MOD(l, 0, 17, 17); /* DSS_CLOCK_PWDN */
1102 l = FLD_MOD(l, 1, 18, 18); /* DSI_PROTO_CLOCK_EN */
1103 l = FLD_MOD(l, 0, 19, 19); /* DSI_PROTO_CLOCK_PWDN */
1104 l = FLD_MOD(l, 0, 20, 20); /* DSI_HSDIVBYPASS */
1105 dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
1106
1107 DSSDBG("PLL config done\n");
1108err:
1109 return r;
1110}
1111
1112int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
1113 bool enable_hsdiv)
1114{
1115 int r = 0;
1116 enum dsi_pll_power_state pwstate;
1117
1118 DSSDBG("PLL init\n");
1119
1120 enable_clocks(1);
1121 dsi_enable_pll_clock(1);
1122
1123 r = regulator_enable(dsi.vdds_dsi_reg);
1124 if (r)
1125 goto err0;
1126
1127 /* XXX PLL does not come out of reset without this... */
1128 dispc_pck_free_enable(1);
1129
1130 if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) {
1131 DSSERR("PLL not coming out of reset.\n");
1132 r = -ENODEV;
1133 goto err1;
1134 }
1135
1136 /* XXX ... but if left on, we get problems when planes do not
1137 * fill the whole display. No idea about this */
1138 dispc_pck_free_enable(0);
1139
1140 if (enable_hsclk && enable_hsdiv)
1141 pwstate = DSI_PLL_POWER_ON_ALL;
1142 else if (enable_hsclk)
1143 pwstate = DSI_PLL_POWER_ON_HSCLK;
1144 else if (enable_hsdiv)
1145 pwstate = DSI_PLL_POWER_ON_DIV;
1146 else
1147 pwstate = DSI_PLL_POWER_OFF;
1148
1149 r = dsi_pll_power(pwstate);
1150
1151 if (r)
1152 goto err1;
1153
1154 DSSDBG("PLL init done\n");
1155
1156 return 0;
1157err1:
1158 regulator_disable(dsi.vdds_dsi_reg);
1159err0:
1160 enable_clocks(0);
1161 dsi_enable_pll_clock(0);
1162 return r;
1163}
1164
1165void dsi_pll_uninit(void)
1166{
1167 enable_clocks(0);
1168 dsi_enable_pll_clock(0);
1169
1170 dsi.pll_locked = 0;
1171 dsi_pll_power(DSI_PLL_POWER_OFF);
1172 regulator_disable(dsi.vdds_dsi_reg);
1173 DSSDBG("PLL uninit done\n");
1174}
1175
1176void dsi_dump_clocks(struct seq_file *s)
1177{
1178 int clksel;
1179 struct dsi_clock_info *cinfo = &dsi.current_cinfo;
1180
1181 enable_clocks(1);
1182
1183 clksel = REG_GET(DSI_PLL_CONFIGURATION2, 11, 11);
1184
1185 seq_printf(s, "- DSI PLL -\n");
1186
1187 seq_printf(s, "dsi pll source = %s\n",
1188 clksel == 0 ?
1189 "dss2_alwon_fclk" : "pclkfree");
1190
1191 seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
1192
1193 seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n",
1194 cinfo->clkin4ddr, cinfo->regm);
1195
1196 seq_printf(s, "dsi1_pll_fck\t%-16luregm3 %u\t(%s)\n",
1197 cinfo->dsi1_pll_fclk,
1198 cinfo->regm3,
1199 dss_get_dispc_clk_source() == 0 ? "off" : "on");
1200
1201 seq_printf(s, "dsi2_pll_fck\t%-16luregm4 %u\t(%s)\n",
1202 cinfo->dsi2_pll_fclk,
1203 cinfo->regm4,
1204 dss_get_dsi_clk_source() == 0 ? "off" : "on");
1205
1206 seq_printf(s, "- DSI -\n");
1207
1208 seq_printf(s, "dsi fclk source = %s\n",
1209 dss_get_dsi_clk_source() == 0 ?
1210 "dss1_alwon_fclk" : "dsi2_pll_fclk");
1211
1212 seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate());
1213
1214 seq_printf(s, "DDR_CLK\t\t%lu\n",
1215 cinfo->clkin4ddr / 4);
1216
1217 seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs());
1218
1219 seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk);
1220
1221 seq_printf(s, "VP_CLK\t\t%lu\n"
1222 "VP_PCLK\t\t%lu\n",
1223 dispc_lclk_rate(),
1224 dispc_pclk_rate());
1225
1226 enable_clocks(0);
1227}
1228
1229void dsi_dump_regs(struct seq_file *s)
1230{
1231#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r))
1232
1233 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
1234
1235 DUMPREG(DSI_REVISION);
1236 DUMPREG(DSI_SYSCONFIG);
1237 DUMPREG(DSI_SYSSTATUS);
1238 DUMPREG(DSI_IRQSTATUS);
1239 DUMPREG(DSI_IRQENABLE);
1240 DUMPREG(DSI_CTRL);
1241 DUMPREG(DSI_COMPLEXIO_CFG1);
1242 DUMPREG(DSI_COMPLEXIO_IRQ_STATUS);
1243 DUMPREG(DSI_COMPLEXIO_IRQ_ENABLE);
1244 DUMPREG(DSI_CLK_CTRL);
1245 DUMPREG(DSI_TIMING1);
1246 DUMPREG(DSI_TIMING2);
1247 DUMPREG(DSI_VM_TIMING1);
1248 DUMPREG(DSI_VM_TIMING2);
1249 DUMPREG(DSI_VM_TIMING3);
1250 DUMPREG(DSI_CLK_TIMING);
1251 DUMPREG(DSI_TX_FIFO_VC_SIZE);
1252 DUMPREG(DSI_RX_FIFO_VC_SIZE);
1253 DUMPREG(DSI_COMPLEXIO_CFG2);
1254 DUMPREG(DSI_RX_FIFO_VC_FULLNESS);
1255 DUMPREG(DSI_VM_TIMING4);
1256 DUMPREG(DSI_TX_FIFO_VC_EMPTINESS);
1257 DUMPREG(DSI_VM_TIMING5);
1258 DUMPREG(DSI_VM_TIMING6);
1259 DUMPREG(DSI_VM_TIMING7);
1260 DUMPREG(DSI_STOPCLK_TIMING);
1261
1262 DUMPREG(DSI_VC_CTRL(0));
1263 DUMPREG(DSI_VC_TE(0));
1264 DUMPREG(DSI_VC_LONG_PACKET_HEADER(0));
1265 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(0));
1266 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(0));
1267 DUMPREG(DSI_VC_IRQSTATUS(0));
1268 DUMPREG(DSI_VC_IRQENABLE(0));
1269
1270 DUMPREG(DSI_VC_CTRL(1));
1271 DUMPREG(DSI_VC_TE(1));
1272 DUMPREG(DSI_VC_LONG_PACKET_HEADER(1));
1273 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(1));
1274 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(1));
1275 DUMPREG(DSI_VC_IRQSTATUS(1));
1276 DUMPREG(DSI_VC_IRQENABLE(1));
1277
1278 DUMPREG(DSI_VC_CTRL(2));
1279 DUMPREG(DSI_VC_TE(2));
1280 DUMPREG(DSI_VC_LONG_PACKET_HEADER(2));
1281 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(2));
1282 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(2));
1283 DUMPREG(DSI_VC_IRQSTATUS(2));
1284 DUMPREG(DSI_VC_IRQENABLE(2));
1285
1286 DUMPREG(DSI_VC_CTRL(3));
1287 DUMPREG(DSI_VC_TE(3));
1288 DUMPREG(DSI_VC_LONG_PACKET_HEADER(3));
1289 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(3));
1290 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(3));
1291 DUMPREG(DSI_VC_IRQSTATUS(3));
1292 DUMPREG(DSI_VC_IRQENABLE(3));
1293
1294 DUMPREG(DSI_DSIPHY_CFG0);
1295 DUMPREG(DSI_DSIPHY_CFG1);
1296 DUMPREG(DSI_DSIPHY_CFG2);
1297 DUMPREG(DSI_DSIPHY_CFG5);
1298
1299 DUMPREG(DSI_PLL_CONTROL);
1300 DUMPREG(DSI_PLL_STATUS);
1301 DUMPREG(DSI_PLL_GO);
1302 DUMPREG(DSI_PLL_CONFIGURATION1);
1303 DUMPREG(DSI_PLL_CONFIGURATION2);
1304
1305 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
1306#undef DUMPREG
1307}
1308
1309enum dsi_complexio_power_state {
1310 DSI_COMPLEXIO_POWER_OFF = 0x0,
1311 DSI_COMPLEXIO_POWER_ON = 0x1,
1312 DSI_COMPLEXIO_POWER_ULPS = 0x2,
1313};
1314
1315static int dsi_complexio_power(enum dsi_complexio_power_state state)
1316{
1317 int t = 0;
1318
1319 /* PWR_CMD */
1320 REG_FLD_MOD(DSI_COMPLEXIO_CFG1, state, 28, 27);
1321
1322 /* PWR_STATUS */
1323 while (FLD_GET(dsi_read_reg(DSI_COMPLEXIO_CFG1), 26, 25) != state) {
1324 udelay(1);
1325 if (t++ > 1000) {
1326 DSSERR("failed to set complexio power state to "
1327 "%d\n", state);
1328 return -ENODEV;
1329 }
1330 }
1331
1332 return 0;
1333}
1334
1335static void dsi_complexio_config(struct omap_dss_device *dssdev)
1336{
1337 u32 r;
1338
1339 int clk_lane = dssdev->phy.dsi.clk_lane;
1340 int data1_lane = dssdev->phy.dsi.data1_lane;
1341 int data2_lane = dssdev->phy.dsi.data2_lane;
1342 int clk_pol = dssdev->phy.dsi.clk_pol;
1343 int data1_pol = dssdev->phy.dsi.data1_pol;
1344 int data2_pol = dssdev->phy.dsi.data2_pol;
1345
1346 r = dsi_read_reg(DSI_COMPLEXIO_CFG1);
1347 r = FLD_MOD(r, clk_lane, 2, 0);
1348 r = FLD_MOD(r, clk_pol, 3, 3);
1349 r = FLD_MOD(r, data1_lane, 6, 4);
1350 r = FLD_MOD(r, data1_pol, 7, 7);
1351 r = FLD_MOD(r, data2_lane, 10, 8);
1352 r = FLD_MOD(r, data2_pol, 11, 11);
1353 dsi_write_reg(DSI_COMPLEXIO_CFG1, r);
1354
1355 /* The configuration of the DSI complex I/O (number of data lanes,
1356 position, differential order) should not be changed while
1357 DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for
1358 the hardware to take into account a new configuration of the complex
1359 I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to
1360 follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1,
1361 then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set
1362 DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the
1363 DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the
1364 DSI complex I/O configuration is unknown. */
1365
1366 /*
1367 REG_FLD_MOD(DSI_CTRL, 1, 0, 0);
1368 REG_FLD_MOD(DSI_CTRL, 0, 0, 0);
1369 REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20);
1370 REG_FLD_MOD(DSI_CTRL, 1, 0, 0);
1371 */
1372}
1373
1374static inline unsigned ns2ddr(unsigned ns)
1375{
1376 /* convert time in ns to ddr ticks, rounding up */
1377 unsigned long ddr_clk = dsi.current_cinfo.clkin4ddr / 4;
1378 return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
1379}
1380
1381static inline unsigned ddr2ns(unsigned ddr)
1382{
1383 unsigned long ddr_clk = dsi.current_cinfo.clkin4ddr / 4;
1384 return ddr * 1000 * 1000 / (ddr_clk / 1000);
1385}
1386
1387static void dsi_complexio_timings(void)
1388{
1389 u32 r;
1390 u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
1391 u32 tlpx_half, tclk_trail, tclk_zero;
1392 u32 tclk_prepare;
1393
1394 /* calculate timings */
1395
1396 /* 1 * DDR_CLK = 2 * UI */
1397
1398 /* min 40ns + 4*UI max 85ns + 6*UI */
1399 ths_prepare = ns2ddr(70) + 2;
1400
1401 /* min 145ns + 10*UI */
1402 ths_prepare_ths_zero = ns2ddr(175) + 2;
1403
1404 /* min max(8*UI, 60ns+4*UI) */
1405 ths_trail = ns2ddr(60) + 5;
1406
1407 /* min 100ns */
1408 ths_exit = ns2ddr(145);
1409
1410 /* tlpx min 50n */
1411 tlpx_half = ns2ddr(25);
1412
1413 /* min 60ns */
1414 tclk_trail = ns2ddr(60) + 2;
1415
1416 /* min 38ns, max 95ns */
1417 tclk_prepare = ns2ddr(65);
1418
1419 /* min tclk-prepare + tclk-zero = 300ns */
1420 tclk_zero = ns2ddr(260);
1421
1422 DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
1423 ths_prepare, ddr2ns(ths_prepare),
1424 ths_prepare_ths_zero, ddr2ns(ths_prepare_ths_zero));
1425 DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
1426 ths_trail, ddr2ns(ths_trail),
1427 ths_exit, ddr2ns(ths_exit));
1428
1429 DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
1430 "tclk_zero %u (%uns)\n",
1431 tlpx_half, ddr2ns(tlpx_half),
1432 tclk_trail, ddr2ns(tclk_trail),
1433 tclk_zero, ddr2ns(tclk_zero));
1434 DSSDBG("tclk_prepare %u (%uns)\n",
1435 tclk_prepare, ddr2ns(tclk_prepare));
1436
1437 /* program timings */
1438
1439 r = dsi_read_reg(DSI_DSIPHY_CFG0);
1440 r = FLD_MOD(r, ths_prepare, 31, 24);
1441 r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
1442 r = FLD_MOD(r, ths_trail, 15, 8);
1443 r = FLD_MOD(r, ths_exit, 7, 0);
1444 dsi_write_reg(DSI_DSIPHY_CFG0, r);
1445
1446 r = dsi_read_reg(DSI_DSIPHY_CFG1);
1447 r = FLD_MOD(r, tlpx_half, 22, 16);
1448 r = FLD_MOD(r, tclk_trail, 15, 8);
1449 r = FLD_MOD(r, tclk_zero, 7, 0);
1450 dsi_write_reg(DSI_DSIPHY_CFG1, r);
1451
1452 r = dsi_read_reg(DSI_DSIPHY_CFG2);
1453 r = FLD_MOD(r, tclk_prepare, 7, 0);
1454 dsi_write_reg(DSI_DSIPHY_CFG2, r);
1455}
1456
1457
1458static int dsi_complexio_init(struct omap_dss_device *dssdev)
1459{
1460 int r = 0;
1461
1462 DSSDBG("dsi_complexio_init\n");
1463
1464 /* CIO_CLK_ICG, enable L3 clk to CIO */
1465 REG_FLD_MOD(DSI_CLK_CTRL, 1, 14, 14);
1466
1467 /* A dummy read using the SCP interface to any DSIPHY register is
1468 * required after DSIPHY reset to complete the reset of the DSI complex
1469 * I/O. */
1470 dsi_read_reg(DSI_DSIPHY_CFG5);
1471
1472 if (wait_for_bit_change(DSI_DSIPHY_CFG5, 30, 1) != 1) {
1473 DSSERR("ComplexIO PHY not coming out of reset.\n");
1474 r = -ENODEV;
1475 goto err;
1476 }
1477
1478 dsi_complexio_config(dssdev);
1479
1480 r = dsi_complexio_power(DSI_COMPLEXIO_POWER_ON);
1481
1482 if (r)
1483 goto err;
1484
1485 if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
1486 DSSERR("ComplexIO not coming out of reset.\n");
1487 r = -ENODEV;
1488 goto err;
1489 }
1490
1491 if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 21, 1) != 1) {
1492 DSSERR("ComplexIO LDO power down.\n");
1493 r = -ENODEV;
1494 goto err;
1495 }
1496
1497 dsi_complexio_timings();
1498
1499 /*
1500 The configuration of the DSI complex I/O (number of data lanes,
1501 position, differential order) should not be changed while
1502 DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. For the
1503 hardware to recognize a new configuration of the complex I/O (done
1504 in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to follow
1505 this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, next
1506 reset the DSS.DSI_CTRL[0] IF_EN to 0, then set DSS.DSI_CLK_CTRL[20]
1507 LP_CLK_ENABLE to 1, and finally, set again the DSS.DSI_CTRL[0] IF_EN
1508 bit to 1. If the sequence is not followed, the DSi complex I/O
1509 configuration is undetermined.
1510 */
1511 dsi_if_enable(1);
1512 dsi_if_enable(0);
1513 REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
1514 dsi_if_enable(1);
1515 dsi_if_enable(0);
1516
1517 DSSDBG("CIO init done\n");
1518err:
1519 return r;
1520}
1521
1522static void dsi_complexio_uninit(void)
1523{
1524 dsi_complexio_power(DSI_COMPLEXIO_POWER_OFF);
1525}
1526
1527static int _dsi_wait_reset(void)
1528{
1529 int i = 0;
1530
1531 while (REG_GET(DSI_SYSSTATUS, 0, 0) == 0) {
1532 if (i++ > 5) {
1533 DSSERR("soft reset failed\n");
1534 return -ENODEV;
1535 }
1536 udelay(1);
1537 }
1538
1539 return 0;
1540}
1541
1542static int _dsi_reset(void)
1543{
1544 /* Soft reset */
1545 REG_FLD_MOD(DSI_SYSCONFIG, 1, 1, 1);
1546 return _dsi_wait_reset();
1547}
1548
1549static void dsi_reset_tx_fifo(int channel)
1550{
1551 u32 mask;
1552 u32 l;
1553
1554 /* set fifosize of the channel to 0, then return the old size */
1555 l = dsi_read_reg(DSI_TX_FIFO_VC_SIZE);
1556
1557 mask = FLD_MASK((8 * channel) + 7, (8 * channel) + 4);
1558 dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l & ~mask);
1559
1560 dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l);
1561}
1562
1563static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
1564 enum fifo_size size3, enum fifo_size size4)
1565{
1566 u32 r = 0;
1567 int add = 0;
1568 int i;
1569
1570 dsi.vc[0].fifo_size = size1;
1571 dsi.vc[1].fifo_size = size2;
1572 dsi.vc[2].fifo_size = size3;
1573 dsi.vc[3].fifo_size = size4;
1574
1575 for (i = 0; i < 4; i++) {
1576 u8 v;
1577 int size = dsi.vc[i].fifo_size;
1578
1579 if (add + size > 4) {
1580 DSSERR("Illegal FIFO configuration\n");
1581 BUG();
1582 }
1583
1584 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
1585 r |= v << (8 * i);
1586 /*DSSDBG("TX FIFO vc %d: size %d, add %d\n", i, size, add); */
1587 add += size;
1588 }
1589
1590 dsi_write_reg(DSI_TX_FIFO_VC_SIZE, r);
1591}
1592
1593static void dsi_config_rx_fifo(enum fifo_size size1, enum fifo_size size2,
1594 enum fifo_size size3, enum fifo_size size4)
1595{
1596 u32 r = 0;
1597 int add = 0;
1598 int i;
1599
1600 dsi.vc[0].fifo_size = size1;
1601 dsi.vc[1].fifo_size = size2;
1602 dsi.vc[2].fifo_size = size3;
1603 dsi.vc[3].fifo_size = size4;
1604
1605 for (i = 0; i < 4; i++) {
1606 u8 v;
1607 int size = dsi.vc[i].fifo_size;
1608
1609 if (add + size > 4) {
1610 DSSERR("Illegal FIFO configuration\n");
1611 BUG();
1612 }
1613
1614 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
1615 r |= v << (8 * i);
1616 /*DSSDBG("RX FIFO vc %d: size %d, add %d\n", i, size, add); */
1617 add += size;
1618 }
1619
1620 dsi_write_reg(DSI_RX_FIFO_VC_SIZE, r);
1621}
1622
1623static int dsi_force_tx_stop_mode_io(void)
1624{
1625 u32 r;
1626
1627 r = dsi_read_reg(DSI_TIMING1);
1628 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
1629 dsi_write_reg(DSI_TIMING1, r);
1630
1631 if (wait_for_bit_change(DSI_TIMING1, 15, 0) != 0) {
1632 DSSERR("TX_STOP bit not going down\n");
1633 return -EIO;
1634 }
1635
1636 return 0;
1637}
1638
1639static void dsi_vc_print_status(int channel)
1640{
1641 u32 r;
1642
1643 r = dsi_read_reg(DSI_VC_CTRL(channel));
1644 DSSDBG("vc %d: TX_FIFO_NOT_EMPTY %d, BTA_EN %d, VC_BUSY %d, "
1645 "TX_FIFO_FULL %d, RX_FIFO_NOT_EMPTY %d, ",
1646 channel,
1647 FLD_GET(r, 5, 5),
1648 FLD_GET(r, 6, 6),
1649 FLD_GET(r, 15, 15),
1650 FLD_GET(r, 16, 16),
1651 FLD_GET(r, 20, 20));
1652
1653 r = dsi_read_reg(DSI_TX_FIFO_VC_EMPTINESS);
1654 DSSDBG("EMPTINESS %d\n", (r >> (8 * channel)) & 0xff);
1655}
1656
1657static int dsi_vc_enable(int channel, bool enable)
1658{
1659 if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
1660 DSSDBG("dsi_vc_enable channel %d, enable %d\n",
1661 channel, enable);
1662
1663 enable = enable ? 1 : 0;
1664
1665 REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 0, 0);
1666
1667 if (wait_for_bit_change(DSI_VC_CTRL(channel), 0, enable) != enable) {
1668 DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
1669 return -EIO;
1670 }
1671
1672 return 0;
1673}
1674
1675static void dsi_vc_initial_config(int channel)
1676{
1677 u32 r;
1678
1679 DSSDBGF("%d", channel);
1680
1681 r = dsi_read_reg(DSI_VC_CTRL(channel));
1682
1683 if (FLD_GET(r, 15, 15)) /* VC_BUSY */
1684 DSSERR("VC(%d) busy when trying to configure it!\n",
1685 channel);
1686
1687 r = FLD_MOD(r, 0, 1, 1); /* SOURCE, 0 = L4 */
1688 r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN */
1689 r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */
1690 r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */
1691 r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
1692 r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
1693 r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
1694
1695 r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
1696 r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
1697
1698 dsi_write_reg(DSI_VC_CTRL(channel), r);
1699
1700 dsi.vc[channel].mode = DSI_VC_MODE_L4;
1701}
1702
1703static void dsi_vc_config_l4(int channel)
1704{
1705 if (dsi.vc[channel].mode == DSI_VC_MODE_L4)
1706 return;
1707
1708 DSSDBGF("%d", channel);
1709
1710 dsi_vc_enable(channel, 0);
1711
1712 if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
1713 DSSERR("vc(%d) busy when trying to config for L4\n", channel);
1714
1715 REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
1716
1717 dsi_vc_enable(channel, 1);
1718
1719 dsi.vc[channel].mode = DSI_VC_MODE_L4;
1720}
1721
1722static void dsi_vc_config_vp(int channel)
1723{
1724 if (dsi.vc[channel].mode == DSI_VC_MODE_VP)
1725 return;
1726
1727 DSSDBGF("%d", channel);
1728
1729 dsi_vc_enable(channel, 0);
1730
1731 if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
1732 DSSERR("vc(%d) busy when trying to config for VP\n", channel);
1733
1734 REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */
1735
1736 dsi_vc_enable(channel, 1);
1737
1738 dsi.vc[channel].mode = DSI_VC_MODE_VP;
1739}
1740
1741
1742static void dsi_vc_enable_hs(int channel, bool enable)
1743{
1744 DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
1745
1746 dsi_vc_enable(channel, 0);
1747 dsi_if_enable(0);
1748
1749 REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 9, 9);
1750
1751 dsi_vc_enable(channel, 1);
1752 dsi_if_enable(1);
1753
1754 dsi_force_tx_stop_mode_io();
1755}
1756
1757static void dsi_vc_flush_long_data(int channel)
1758{
1759 while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
1760 u32 val;
1761 val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
1762 DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
1763 (val >> 0) & 0xff,
1764 (val >> 8) & 0xff,
1765 (val >> 16) & 0xff,
1766 (val >> 24) & 0xff);
1767 }
1768}
1769
1770static void dsi_show_rx_ack_with_err(u16 err)
1771{
1772 DSSERR("\tACK with ERROR (%#x):\n", err);
1773 if (err & (1 << 0))
1774 DSSERR("\t\tSoT Error\n");
1775 if (err & (1 << 1))
1776 DSSERR("\t\tSoT Sync Error\n");
1777 if (err & (1 << 2))
1778 DSSERR("\t\tEoT Sync Error\n");
1779 if (err & (1 << 3))
1780 DSSERR("\t\tEscape Mode Entry Command Error\n");
1781 if (err & (1 << 4))
1782 DSSERR("\t\tLP Transmit Sync Error\n");
1783 if (err & (1 << 5))
1784 DSSERR("\t\tHS Receive Timeout Error\n");
1785 if (err & (1 << 6))
1786 DSSERR("\t\tFalse Control Error\n");
1787 if (err & (1 << 7))
1788 DSSERR("\t\t(reserved7)\n");
1789 if (err & (1 << 8))
1790 DSSERR("\t\tECC Error, single-bit (corrected)\n");
1791 if (err & (1 << 9))
1792 DSSERR("\t\tECC Error, multi-bit (not corrected)\n");
1793 if (err & (1 << 10))
1794 DSSERR("\t\tChecksum Error\n");
1795 if (err & (1 << 11))
1796 DSSERR("\t\tData type not recognized\n");
1797 if (err & (1 << 12))
1798 DSSERR("\t\tInvalid VC ID\n");
1799 if (err & (1 << 13))
1800 DSSERR("\t\tInvalid Transmission Length\n");
1801 if (err & (1 << 14))
1802 DSSERR("\t\t(reserved14)\n");
1803 if (err & (1 << 15))
1804 DSSERR("\t\tDSI Protocol Violation\n");
1805}
1806
1807static u16 dsi_vc_flush_receive_data(int channel)
1808{
1809 /* RX_FIFO_NOT_EMPTY */
1810 while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
1811 u32 val;
1812 u8 dt;
1813 val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
1814 DSSDBG("\trawval %#08x\n", val);
1815 dt = FLD_GET(val, 5, 0);
1816 if (dt == DSI_DT_RX_ACK_WITH_ERR) {
1817 u16 err = FLD_GET(val, 23, 8);
1818 dsi_show_rx_ack_with_err(err);
1819 } else if (dt == DSI_DT_RX_SHORT_READ_1) {
1820 DSSDBG("\tDCS short response, 1 byte: %#x\n",
1821 FLD_GET(val, 23, 8));
1822 } else if (dt == DSI_DT_RX_SHORT_READ_2) {
1823 DSSDBG("\tDCS short response, 2 byte: %#x\n",
1824 FLD_GET(val, 23, 8));
1825 } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
1826 DSSDBG("\tDCS long response, len %d\n",
1827 FLD_GET(val, 23, 8));
1828 dsi_vc_flush_long_data(channel);
1829 } else {
1830 DSSERR("\tunknown datatype 0x%02x\n", dt);
1831 }
1832 }
1833 return 0;
1834}
1835
1836static int dsi_vc_send_bta(int channel)
1837{
1838 if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO &&
1839 (dsi.debug_write || dsi.debug_read))
1840 DSSDBG("dsi_vc_send_bta %d\n", channel);
1841
1842 WARN_ON(!mutex_is_locked(&dsi.bus_lock));
1843
1844 if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */
1845 DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
1846 dsi_vc_flush_receive_data(channel);
1847 }
1848
1849 REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
1850
1851 return 0;
1852}
1853
1854int dsi_vc_send_bta_sync(int channel)
1855{
1856 int r = 0;
1857 u32 err;
1858
1859 INIT_COMPLETION(dsi.bta_completion);
1860
1861 dsi_vc_enable_bta_irq(channel);
1862
1863 r = dsi_vc_send_bta(channel);
1864 if (r)
1865 goto err;
1866
1867 if (wait_for_completion_timeout(&dsi.bta_completion,
1868 msecs_to_jiffies(500)) == 0) {
1869 DSSERR("Failed to receive BTA\n");
1870 r = -EIO;
1871 goto err;
1872 }
1873
1874 err = dsi_get_errors();
1875 if (err) {
1876 DSSERR("Error while sending BTA: %x\n", err);
1877 r = -EIO;
1878 goto err;
1879 }
1880err:
1881 dsi_vc_disable_bta_irq(channel);
1882
1883 return r;
1884}
1885EXPORT_SYMBOL(dsi_vc_send_bta_sync);
1886
1887static inline void dsi_vc_write_long_header(int channel, u8 data_type,
1888 u16 len, u8 ecc)
1889{
1890 u32 val;
1891 u8 data_id;
1892
1893 WARN_ON(!mutex_is_locked(&dsi.bus_lock));
1894
1895 /*data_id = data_type | channel << 6; */
1896 data_id = data_type | dsi.vc[channel].dest_per << 6;
1897
1898 val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
1899 FLD_VAL(ecc, 31, 24);
1900
1901 dsi_write_reg(DSI_VC_LONG_PACKET_HEADER(channel), val);
1902}
1903
1904static inline void dsi_vc_write_long_payload(int channel,
1905 u8 b1, u8 b2, u8 b3, u8 b4)
1906{
1907 u32 val;
1908
1909 val = b4 << 24 | b3 << 16 | b2 << 8 | b1 << 0;
1910
1911/* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
1912 b1, b2, b3, b4, val); */
1913
1914 dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
1915}
1916
1917static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
1918 u8 ecc)
1919{
1920 /*u32 val; */
1921 int i;
1922 u8 *p;
1923 int r = 0;
1924 u8 b1, b2, b3, b4;
1925
1926 if (dsi.debug_write)
1927 DSSDBG("dsi_vc_send_long, %d bytes\n", len);
1928
1929 /* len + header */
1930 if (dsi.vc[channel].fifo_size * 32 * 4 < len + 4) {
1931 DSSERR("unable to send long packet: packet too long.\n");
1932 return -EINVAL;
1933 }
1934
1935 dsi_vc_config_l4(channel);
1936
1937 dsi_vc_write_long_header(channel, data_type, len, ecc);
1938
1939 /*dsi_vc_print_status(0); */
1940
1941 p = data;
1942 for (i = 0; i < len >> 2; i++) {
1943 if (dsi.debug_write)
1944 DSSDBG("\tsending full packet %d\n", i);
1945 /*dsi_vc_print_status(0); */
1946
1947 b1 = *p++;
1948 b2 = *p++;
1949 b3 = *p++;
1950 b4 = *p++;
1951
1952 dsi_vc_write_long_payload(channel, b1, b2, b3, b4);
1953 }
1954
1955 i = len % 4;
1956 if (i) {
1957 b1 = 0; b2 = 0; b3 = 0;
1958
1959 if (dsi.debug_write)
1960 DSSDBG("\tsending remainder bytes %d\n", i);
1961
1962 switch (i) {
1963 case 3:
1964 b1 = *p++;
1965 b2 = *p++;
1966 b3 = *p++;
1967 break;
1968 case 2:
1969 b1 = *p++;
1970 b2 = *p++;
1971 break;
1972 case 1:
1973 b1 = *p++;
1974 break;
1975 }
1976
1977 dsi_vc_write_long_payload(channel, b1, b2, b3, 0);
1978 }
1979
1980 return r;
1981}
1982
1983static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
1984{
1985 u32 r;
1986 u8 data_id;
1987
1988 WARN_ON(!mutex_is_locked(&dsi.bus_lock));
1989
1990 if (dsi.debug_write)
1991 DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
1992 channel,
1993 data_type, data & 0xff, (data >> 8) & 0xff);
1994
1995 dsi_vc_config_l4(channel);
1996
1997 if (FLD_GET(dsi_read_reg(DSI_VC_CTRL(channel)), 16, 16)) {
1998 DSSERR("ERROR FIFO FULL, aborting transfer\n");
1999 return -EINVAL;
2000 }
2001
2002 data_id = data_type | channel << 6;
2003
2004 r = (data_id << 0) | (data << 8) | (ecc << 24);
2005
2006 dsi_write_reg(DSI_VC_SHORT_PACKET_HEADER(channel), r);
2007
2008 return 0;
2009}
2010
2011int dsi_vc_send_null(int channel)
2012{
2013 u8 nullpkg[] = {0, 0, 0, 0};
2014 return dsi_vc_send_long(0, DSI_DT_NULL_PACKET, nullpkg, 4, 0);
2015}
2016EXPORT_SYMBOL(dsi_vc_send_null);
2017
2018int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len)
2019{
2020 int r;
2021
2022 BUG_ON(len == 0);
2023
2024 if (len == 1) {
2025 r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_0,
2026 data[0], 0);
2027 } else if (len == 2) {
2028 r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_1,
2029 data[0] | (data[1] << 8), 0);
2030 } else {
2031 /* 0x39 = DCS Long Write */
2032 r = dsi_vc_send_long(channel, DSI_DT_DCS_LONG_WRITE,
2033 data, len, 0);
2034 }
2035
2036 return r;
2037}
2038EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
2039
2040int dsi_vc_dcs_write(int channel, u8 *data, int len)
2041{
2042 int r;
2043
2044 r = dsi_vc_dcs_write_nosync(channel, data, len);
2045 if (r)
2046 return r;
2047
2048 r = dsi_vc_send_bta_sync(channel);
2049
2050 return r;
2051}
2052EXPORT_SYMBOL(dsi_vc_dcs_write);
2053
2054int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
2055{
2056 u32 val;
2057 u8 dt;
2058 int r;
2059
2060 if (dsi.debug_read)
2061 DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %u)\n", channel, dcs_cmd);
2062
2063 r = dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0);
2064 if (r)
2065 return r;
2066
2067 r = dsi_vc_send_bta_sync(channel);
2068 if (r)
2069 return r;
2070
2071 /* RX_FIFO_NOT_EMPTY */
2072 if (REG_GET(DSI_VC_CTRL(channel), 20, 20) == 0) {
2073 DSSERR("RX fifo empty when trying to read.\n");
2074 return -EIO;
2075 }
2076
2077 val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
2078 if (dsi.debug_read)
2079 DSSDBG("\theader: %08x\n", val);
2080 dt = FLD_GET(val, 5, 0);
2081 if (dt == DSI_DT_RX_ACK_WITH_ERR) {
2082 u16 err = FLD_GET(val, 23, 8);
2083 dsi_show_rx_ack_with_err(err);
2084 return -EIO;
2085
2086 } else if (dt == DSI_DT_RX_SHORT_READ_1) {
2087 u8 data = FLD_GET(val, 15, 8);
2088 if (dsi.debug_read)
2089 DSSDBG("\tDCS short response, 1 byte: %02x\n", data);
2090
2091 if (buflen < 1)
2092 return -EIO;
2093
2094 buf[0] = data;
2095
2096 return 1;
2097 } else if (dt == DSI_DT_RX_SHORT_READ_2) {
2098 u16 data = FLD_GET(val, 23, 8);
2099 if (dsi.debug_read)
2100 DSSDBG("\tDCS short response, 2 byte: %04x\n", data);
2101
2102 if (buflen < 2)
2103 return -EIO;
2104
2105 buf[0] = data & 0xff;
2106 buf[1] = (data >> 8) & 0xff;
2107
2108 return 2;
2109 } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
2110 int w;
2111 int len = FLD_GET(val, 23, 8);
2112 if (dsi.debug_read)
2113 DSSDBG("\tDCS long response, len %d\n", len);
2114
2115 if (len > buflen)
2116 return -EIO;
2117
2118 /* two byte checksum ends the packet, not included in len */
2119 for (w = 0; w < len + 2;) {
2120 int b;
2121 val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
2122 if (dsi.debug_read)
2123 DSSDBG("\t\t%02x %02x %02x %02x\n",
2124 (val >> 0) & 0xff,
2125 (val >> 8) & 0xff,
2126 (val >> 16) & 0xff,
2127 (val >> 24) & 0xff);
2128
2129 for (b = 0; b < 4; ++b) {
2130 if (w < len)
2131 buf[w] = (val >> (b * 8)) & 0xff;
2132 /* we discard the 2 byte checksum */
2133 ++w;
2134 }
2135 }
2136
2137 return len;
2138
2139 } else {
2140 DSSERR("\tunknown datatype 0x%02x\n", dt);
2141 return -EIO;
2142 }
2143}
2144EXPORT_SYMBOL(dsi_vc_dcs_read);
2145
2146
2147int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
2148{
2149 int r;
2150 r = dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
2151 len, 0);
2152
2153 if (r)
2154 return r;
2155
2156 r = dsi_vc_send_bta_sync(channel);
2157
2158 return r;
2159}
2160EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
2161
2162static void dsi_set_lp_rx_timeout(unsigned long ns)
2163{
2164 u32 r;
2165 unsigned x4, x16;
2166 unsigned long fck;
2167 unsigned long ticks;
2168
2169 /* ticks in DSI_FCK */
2170
2171 fck = dsi_fclk_rate();
2172 ticks = (fck / 1000 / 1000) * ns / 1000;
2173 x4 = 0;
2174 x16 = 0;
2175
2176 if (ticks > 0x1fff) {
2177 ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
2178 x4 = 1;
2179 x16 = 0;
2180 }
2181
2182 if (ticks > 0x1fff) {
2183 ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
2184 x4 = 0;
2185 x16 = 1;
2186 }
2187
2188 if (ticks > 0x1fff) {
2189 ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
2190 x4 = 1;
2191 x16 = 1;
2192 }
2193
2194 if (ticks > 0x1fff) {
2195 DSSWARN("LP_TX_TO over limit, setting it to max\n");
2196 ticks = 0x1fff;
2197 x4 = 1;
2198 x16 = 1;
2199 }
2200
2201 r = dsi_read_reg(DSI_TIMING2);
2202 r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */
2203 r = FLD_MOD(r, x16, 14, 14); /* LP_RX_TO_X16 */
2204 r = FLD_MOD(r, x4, 13, 13); /* LP_RX_TO_X4 */
2205 r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */
2206 dsi_write_reg(DSI_TIMING2, r);
2207
2208 DSSDBG("LP_RX_TO %lu ns (%#lx ticks%s%s)\n",
2209 (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
2210 (fck / 1000 / 1000),
2211 ticks, x4 ? " x4" : "", x16 ? " x16" : "");
2212}
2213
2214static void dsi_set_ta_timeout(unsigned long ns)
2215{
2216 u32 r;
2217 unsigned x8, x16;
2218 unsigned long fck;
2219 unsigned long ticks;
2220
2221 /* ticks in DSI_FCK */
2222 fck = dsi_fclk_rate();
2223 ticks = (fck / 1000 / 1000) * ns / 1000;
2224 x8 = 0;
2225 x16 = 0;
2226
2227 if (ticks > 0x1fff) {
2228 ticks = (fck / 1000 / 1000) * ns / 1000 / 8;
2229 x8 = 1;
2230 x16 = 0;
2231 }
2232
2233 if (ticks > 0x1fff) {
2234 ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
2235 x8 = 0;
2236 x16 = 1;
2237 }
2238
2239 if (ticks > 0x1fff) {
2240 ticks = (fck / 1000 / 1000) * ns / 1000 / (8 * 16);
2241 x8 = 1;
2242 x16 = 1;
2243 }
2244
2245 if (ticks > 0x1fff) {
2246 DSSWARN("TA_TO over limit, setting it to max\n");
2247 ticks = 0x1fff;
2248 x8 = 1;
2249 x16 = 1;
2250 }
2251
2252 r = dsi_read_reg(DSI_TIMING1);
2253 r = FLD_MOD(r, 1, 31, 31); /* TA_TO */
2254 r = FLD_MOD(r, x16, 30, 30); /* TA_TO_X16 */
2255 r = FLD_MOD(r, x8, 29, 29); /* TA_TO_X8 */
2256 r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */
2257 dsi_write_reg(DSI_TIMING1, r);
2258
2259 DSSDBG("TA_TO %lu ns (%#lx ticks%s%s)\n",
2260 (ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1) * 1000) /
2261 (fck / 1000 / 1000),
2262 ticks, x8 ? " x8" : "", x16 ? " x16" : "");
2263}
2264
2265static void dsi_set_stop_state_counter(unsigned long ns)
2266{
2267 u32 r;
2268 unsigned x4, x16;
2269 unsigned long fck;
2270 unsigned long ticks;
2271
2272 /* ticks in DSI_FCK */
2273
2274 fck = dsi_fclk_rate();
2275 ticks = (fck / 1000 / 1000) * ns / 1000;
2276 x4 = 0;
2277 x16 = 0;
2278
2279 if (ticks > 0x1fff) {
2280 ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
2281 x4 = 1;
2282 x16 = 0;
2283 }
2284
2285 if (ticks > 0x1fff) {
2286 ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
2287 x4 = 0;
2288 x16 = 1;
2289 }
2290
2291 if (ticks > 0x1fff) {
2292 ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
2293 x4 = 1;
2294 x16 = 1;
2295 }
2296
2297 if (ticks > 0x1fff) {
2298 DSSWARN("STOP_STATE_COUNTER_IO over limit, "
2299 "setting it to max\n");
2300 ticks = 0x1fff;
2301 x4 = 1;
2302 x16 = 1;
2303 }
2304
2305 r = dsi_read_reg(DSI_TIMING1);
2306 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
2307 r = FLD_MOD(r, x16, 14, 14); /* STOP_STATE_X16_IO */
2308 r = FLD_MOD(r, x4, 13, 13); /* STOP_STATE_X4_IO */
2309 r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */
2310 dsi_write_reg(DSI_TIMING1, r);
2311
2312 DSSDBG("STOP_STATE_COUNTER %lu ns (%#lx ticks%s%s)\n",
2313 (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
2314 (fck / 1000 / 1000),
2315 ticks, x4 ? " x4" : "", x16 ? " x16" : "");
2316}
2317
2318static void dsi_set_hs_tx_timeout(unsigned long ns)
2319{
2320 u32 r;
2321 unsigned x4, x16;
2322 unsigned long fck;
2323 unsigned long ticks;
2324
2325 /* ticks in TxByteClkHS */
2326
2327 fck = dsi_get_txbyteclkhs();
2328 ticks = (fck / 1000 / 1000) * ns / 1000;
2329 x4 = 0;
2330 x16 = 0;
2331
2332 if (ticks > 0x1fff) {
2333 ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
2334 x4 = 1;
2335 x16 = 0;
2336 }
2337
2338 if (ticks > 0x1fff) {
2339 ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
2340 x4 = 0;
2341 x16 = 1;
2342 }
2343
2344 if (ticks > 0x1fff) {
2345 ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
2346 x4 = 1;
2347 x16 = 1;
2348 }
2349
2350 if (ticks > 0x1fff) {
2351 DSSWARN("HS_TX_TO over limit, setting it to max\n");
2352 ticks = 0x1fff;
2353 x4 = 1;
2354 x16 = 1;
2355 }
2356
2357 r = dsi_read_reg(DSI_TIMING2);
2358 r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */
2359 r = FLD_MOD(r, x16, 30, 30); /* HS_TX_TO_X16 */
2360 r = FLD_MOD(r, x4, 29, 29); /* HS_TX_TO_X8 (4 really) */
2361 r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */
2362 dsi_write_reg(DSI_TIMING2, r);
2363
2364 DSSDBG("HS_TX_TO %lu ns (%#lx ticks%s%s)\n",
2365 (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
2366 (fck / 1000 / 1000),
2367 ticks, x4 ? " x4" : "", x16 ? " x16" : "");
2368}
2369static int dsi_proto_config(struct omap_dss_device *dssdev)
2370{
2371 u32 r;
2372 int buswidth = 0;
2373
2374 dsi_config_tx_fifo(DSI_FIFO_SIZE_128,
2375 DSI_FIFO_SIZE_0,
2376 DSI_FIFO_SIZE_0,
2377 DSI_FIFO_SIZE_0);
2378
2379 dsi_config_rx_fifo(DSI_FIFO_SIZE_128,
2380 DSI_FIFO_SIZE_0,
2381 DSI_FIFO_SIZE_0,
2382 DSI_FIFO_SIZE_0);
2383
2384 /* XXX what values for the timeouts? */
2385 dsi_set_stop_state_counter(1000);
2386 dsi_set_ta_timeout(6400000);
2387 dsi_set_lp_rx_timeout(48000);
2388 dsi_set_hs_tx_timeout(1000000);
2389
2390 switch (dssdev->ctrl.pixel_size) {
2391 case 16:
2392 buswidth = 0;
2393 break;
2394 case 18:
2395 buswidth = 1;
2396 break;
2397 case 24:
2398 buswidth = 2;
2399 break;
2400 default:
2401 BUG();
2402 }
2403
2404 r = dsi_read_reg(DSI_CTRL);
2405 r = FLD_MOD(r, 1, 1, 1); /* CS_RX_EN */
2406 r = FLD_MOD(r, 1, 2, 2); /* ECC_RX_EN */
2407 r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */
2408 r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/
2409 r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */
2410 r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */
2411 r = FLD_MOD(r, 2, 13, 12); /* LINE_BUFFER, 2 lines */
2412 r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */
2413 r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */
2414 r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
2415 r = FLD_MOD(r, 0, 25, 25); /* DCS_CMD_CODE, 1=start, 0=continue */
2416
2417 dsi_write_reg(DSI_CTRL, r);
2418
2419 dsi_vc_initial_config(0);
2420
2421 /* set all vc targets to peripheral 0 */
2422 dsi.vc[0].dest_per = 0;
2423 dsi.vc[1].dest_per = 0;
2424 dsi.vc[2].dest_per = 0;
2425 dsi.vc[3].dest_per = 0;
2426
2427 return 0;
2428}
2429
2430static void dsi_proto_timings(struct omap_dss_device *dssdev)
2431{
2432 unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
2433 unsigned tclk_pre, tclk_post;
2434 unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
2435 unsigned ths_trail, ths_exit;
2436 unsigned ddr_clk_pre, ddr_clk_post;
2437 unsigned enter_hs_mode_lat, exit_hs_mode_lat;
2438 unsigned ths_eot;
2439 u32 r;
2440
2441 r = dsi_read_reg(DSI_DSIPHY_CFG0);
2442 ths_prepare = FLD_GET(r, 31, 24);
2443 ths_prepare_ths_zero = FLD_GET(r, 23, 16);
2444 ths_zero = ths_prepare_ths_zero - ths_prepare;
2445 ths_trail = FLD_GET(r, 15, 8);
2446 ths_exit = FLD_GET(r, 7, 0);
2447
2448 r = dsi_read_reg(DSI_DSIPHY_CFG1);
2449 tlpx = FLD_GET(r, 22, 16) * 2;
2450 tclk_trail = FLD_GET(r, 15, 8);
2451 tclk_zero = FLD_GET(r, 7, 0);
2452
2453 r = dsi_read_reg(DSI_DSIPHY_CFG2);
2454 tclk_prepare = FLD_GET(r, 7, 0);
2455
2456 /* min 8*UI */
2457 tclk_pre = 20;
2458 /* min 60ns + 52*UI */
2459 tclk_post = ns2ddr(60) + 26;
2460
2461 /* ths_eot is 2 for 2 datalanes and 4 for 1 datalane */
2462 if (dssdev->phy.dsi.data1_lane != 0 &&
2463 dssdev->phy.dsi.data2_lane != 0)
2464 ths_eot = 2;
2465 else
2466 ths_eot = 4;
2467
2468 ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
2469 4);
2470 ddr_clk_post = DIV_ROUND_UP(tclk_post + ths_trail, 4) + ths_eot;
2471
2472 BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
2473 BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);
2474
2475 r = dsi_read_reg(DSI_CLK_TIMING);
2476 r = FLD_MOD(r, ddr_clk_pre, 15, 8);
2477 r = FLD_MOD(r, ddr_clk_post, 7, 0);
2478 dsi_write_reg(DSI_CLK_TIMING, r);
2479
2480 DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
2481 ddr_clk_pre,
2482 ddr_clk_post);
2483
2484 enter_hs_mode_lat = 1 + DIV_ROUND_UP(tlpx, 4) +
2485 DIV_ROUND_UP(ths_prepare, 4) +
2486 DIV_ROUND_UP(ths_zero + 3, 4);
2487
2488 exit_hs_mode_lat = DIV_ROUND_UP(ths_trail + ths_exit, 4) + 1 + ths_eot;
2489
2490 r = FLD_VAL(enter_hs_mode_lat, 31, 16) |
2491 FLD_VAL(exit_hs_mode_lat, 15, 0);
2492 dsi_write_reg(DSI_VM_TIMING7, r);
2493
2494 DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
2495 enter_hs_mode_lat, exit_hs_mode_lat);
2496}
2497
2498
2499#define DSI_DECL_VARS \
2500 int __dsi_cb = 0; u32 __dsi_cv = 0;
2501
2502#define DSI_FLUSH(ch) \
2503 if (__dsi_cb > 0) { \
2504 /*DSSDBG("sending long packet %#010x\n", __dsi_cv);*/ \
2505 dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \
2506 __dsi_cb = __dsi_cv = 0; \
2507 }
2508
2509#define DSI_PUSH(ch, data) \
2510 do { \
2511 __dsi_cv |= (data) << (__dsi_cb * 8); \
2512 /*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \
2513 if (++__dsi_cb > 3) \
2514 DSI_FLUSH(ch); \
2515 } while (0)
2516
2517static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
2518 int x, int y, int w, int h)
2519{
2520 /* Note: supports only 24bit colors in 32bit container */
2521 int first = 1;
2522 int fifo_stalls = 0;
2523 int max_dsi_packet_size;
2524 int max_data_per_packet;
2525 int max_pixels_per_packet;
2526 int pixels_left;
2527 int bytespp = dssdev->ctrl.pixel_size / 8;
2528 int scr_width;
2529 u32 __iomem *data;
2530 int start_offset;
2531 int horiz_inc;
2532 int current_x;
2533 struct omap_overlay *ovl;
2534
2535 debug_irq = 0;
2536
2537 DSSDBG("dsi_update_screen_l4 (%d,%d %dx%d)\n",
2538 x, y, w, h);
2539
2540 ovl = dssdev->manager->overlays[0];
2541
2542 if (ovl->info.color_mode != OMAP_DSS_COLOR_RGB24U)
2543 return -EINVAL;
2544
2545 if (dssdev->ctrl.pixel_size != 24)
2546 return -EINVAL;
2547
2548 scr_width = ovl->info.screen_width;
2549 data = ovl->info.vaddr;
2550
2551 start_offset = scr_width * y + x;
2552 horiz_inc = scr_width - w;
2553 current_x = x;
2554
2555 /* We need header(4) + DCSCMD(1) + pixels(numpix*bytespp) bytes
2556 * in fifo */
2557
2558 /* When using CPU, max long packet size is TX buffer size */
2559 max_dsi_packet_size = dsi.vc[0].fifo_size * 32 * 4;
2560
2561 /* we seem to get better perf if we divide the tx fifo to half,
2562 and while the other half is being sent, we fill the other half
2563 max_dsi_packet_size /= 2; */
2564
2565 max_data_per_packet = max_dsi_packet_size - 4 - 1;
2566
2567 max_pixels_per_packet = max_data_per_packet / bytespp;
2568
2569 DSSDBG("max_pixels_per_packet %d\n", max_pixels_per_packet);
2570
2571 pixels_left = w * h;
2572
2573 DSSDBG("total pixels %d\n", pixels_left);
2574
2575 data += start_offset;
2576
2577 while (pixels_left > 0) {
2578 /* 0x2c = write_memory_start */
2579 /* 0x3c = write_memory_continue */
2580 u8 dcs_cmd = first ? 0x2c : 0x3c;
2581 int pixels;
2582 DSI_DECL_VARS;
2583 first = 0;
2584
2585#if 1
2586 /* using fifo not empty */
2587 /* TX_FIFO_NOT_EMPTY */
2588 while (FLD_GET(dsi_read_reg(DSI_VC_CTRL(0)), 5, 5)) {
2589 udelay(1);
2590 fifo_stalls++;
2591 if (fifo_stalls > 0xfffff) {
2592 DSSERR("fifo stalls overflow, pixels left %d\n",
2593 pixels_left);
2594 dsi_if_enable(0);
2595 return -EIO;
2596 }
2597 }
2598#elif 1
2599 /* using fifo emptiness */
2600 while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 <
2601 max_dsi_packet_size) {
2602 fifo_stalls++;
2603 if (fifo_stalls > 0xfffff) {
2604 DSSERR("fifo stalls overflow, pixels left %d\n",
2605 pixels_left);
2606 dsi_if_enable(0);
2607 return -EIO;
2608 }
2609 }
2610#else
2611 while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 == 0) {
2612 fifo_stalls++;
2613 if (fifo_stalls > 0xfffff) {
2614 DSSERR("fifo stalls overflow, pixels left %d\n",
2615 pixels_left);
2616 dsi_if_enable(0);
2617 return -EIO;
2618 }
2619 }
2620#endif
2621 pixels = min(max_pixels_per_packet, pixels_left);
2622
2623 pixels_left -= pixels;
2624
2625 dsi_vc_write_long_header(0, DSI_DT_DCS_LONG_WRITE,
2626 1 + pixels * bytespp, 0);
2627
2628 DSI_PUSH(0, dcs_cmd);
2629
2630 while (pixels-- > 0) {
2631 u32 pix = __raw_readl(data++);
2632
2633 DSI_PUSH(0, (pix >> 16) & 0xff);
2634 DSI_PUSH(0, (pix >> 8) & 0xff);
2635 DSI_PUSH(0, (pix >> 0) & 0xff);
2636
2637 current_x++;
2638 if (current_x == x+w) {
2639 current_x = x;
2640 data += horiz_inc;
2641 }
2642 }
2643
2644 DSI_FLUSH(0);
2645 }
2646
2647 return 0;
2648}
2649
2650static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
2651 u16 x, u16 y, u16 w, u16 h)
2652{
2653 unsigned bytespp;
2654 unsigned bytespl;
2655 unsigned bytespf;
2656 unsigned total_len;
2657 unsigned packet_payload;
2658 unsigned packet_len;
2659 u32 l;
2660 bool use_te_trigger;
2661 const unsigned channel = 0;
2662 /* line buffer is 1024 x 24bits */
2663 /* XXX: for some reason using full buffer size causes considerable TX
2664 * slowdown with update sizes that fill the whole buffer */
2665 const unsigned line_buf_size = 1023 * 3;
2666
2667 use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;
2668
2669 if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
2670 DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
2671 x, y, w, h);
2672
2673 bytespp = dssdev->ctrl.pixel_size / 8;
2674 bytespl = w * bytespp;
2675 bytespf = bytespl * h;
2676
2677 /* NOTE: packet_payload has to be equal to N * bytespl, where N is
2678 * number of lines in a packet. See errata about VP_CLK_RATIO */
2679
2680 if (bytespf < line_buf_size)
2681 packet_payload = bytespf;
2682 else
2683 packet_payload = (line_buf_size) / bytespl * bytespl;
2684
2685 packet_len = packet_payload + 1; /* 1 byte for DCS cmd */
2686 total_len = (bytespf / packet_payload) * packet_len;
2687
2688 if (bytespf % packet_payload)
2689 total_len += (bytespf % packet_payload) + 1;
2690
2691 if (0)
2692 dsi_vc_print_status(1);
2693
2694 l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
2695 dsi_write_reg(DSI_VC_TE(channel), l);
2696
2697 dsi_vc_write_long_header(channel, DSI_DT_DCS_LONG_WRITE, packet_len, 0);
2698
2699 if (use_te_trigger)
2700 l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
2701 else
2702 l = FLD_MOD(l, 1, 31, 31); /* TE_START */
2703 dsi_write_reg(DSI_VC_TE(channel), l);
2704
2705 /* We put SIDLEMODE to no-idle for the duration of the transfer,
2706 * because DSS interrupts are not capable of waking up the CPU and the
2707 * framedone interrupt could be delayed for quite a long time. I think
2708 * the same goes for any DSS interrupts, but for some reason I have not
2709 * seen the problem anywhere else than here.
2710 */
2711 dispc_disable_sidle();
2712
2713 dss_start_update(dssdev);
2714
2715 if (use_te_trigger) {
2716 /* disable LP_RX_TO, so that we can receive TE. Time to wait
2717 * for TE is longer than the timer allows */
2718 REG_FLD_MOD(DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
2719
2720 dsi_vc_send_bta(channel);
2721
2722#ifdef DSI_CATCH_MISSING_TE
2723 mod_timer(&dsi.te_timer, jiffies + msecs_to_jiffies(250));
2724#endif
2725 }
2726}
2727
2728#ifdef DSI_CATCH_MISSING_TE
2729static void dsi_te_timeout(unsigned long arg)
2730{
2731 DSSERR("TE not received for 250ms!\n");
2732}
2733#endif
2734
2735static void dsi_framedone_irq_callback(void *data, u32 mask)
2736{
2737 /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
2738 * turns itself off. However, DSI still has the pixels in its buffers,
2739 * and is sending the data.
2740 */
2741
2742 /* SIDLEMODE back to smart-idle */
2743 dispc_enable_sidle();
2744
2745 dsi.framedone_received = true;
2746 wake_up(&dsi.waitqueue);
2747}
2748
2749static void dsi_set_update_region(struct omap_dss_device *dssdev,
2750 u16 x, u16 y, u16 w, u16 h)
2751{
2752 spin_lock(&dsi.update_lock);
2753 if (dsi.update_region.dirty) {
2754 dsi.update_region.x = min(x, dsi.update_region.x);
2755 dsi.update_region.y = min(y, dsi.update_region.y);
2756 dsi.update_region.w = max(w, dsi.update_region.w);
2757 dsi.update_region.h = max(h, dsi.update_region.h);
2758 } else {
2759 dsi.update_region.x = x;
2760 dsi.update_region.y = y;
2761 dsi.update_region.w = w;
2762 dsi.update_region.h = h;
2763 }
2764
2765 dsi.update_region.device = dssdev;
2766 dsi.update_region.dirty = true;
2767
2768 spin_unlock(&dsi.update_lock);
2769
2770}
2771
2772static int dsi_set_update_mode(struct omap_dss_device *dssdev,
2773 enum omap_dss_update_mode mode)
2774{
2775 int r = 0;
2776 int i;
2777
2778 WARN_ON(!mutex_is_locked(&dsi.bus_lock));
2779
2780 if (dsi.update_mode != mode) {
2781 dsi.update_mode = mode;
2782
2783 /* Mark the overlays dirty, and do apply(), so that we get the
2784 * overlays configured properly after update mode change. */
2785 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2786 struct omap_overlay *ovl;
2787 ovl = omap_dss_get_overlay(i);
2788 if (ovl->manager == dssdev->manager)
2789 ovl->info_dirty = true;
2790 }
2791
2792 r = dssdev->manager->apply(dssdev->manager);
2793
2794 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE &&
2795 mode == OMAP_DSS_UPDATE_AUTO) {
2796 u16 w, h;
2797
2798 DSSDBG("starting auto update\n");
2799
2800 dssdev->get_resolution(dssdev, &w, &h);
2801
2802 dsi_set_update_region(dssdev, 0, 0, w, h);
2803
2804 dsi_perf_mark_start_auto();
2805
2806 wake_up(&dsi.waitqueue);
2807 }
2808 }
2809
2810 return r;
2811}
2812
2813static int dsi_set_te(struct omap_dss_device *dssdev, bool enable)
2814{
2815 int r;
2816 r = dssdev->driver->enable_te(dssdev, enable);
2817 /* XXX for some reason, DSI TE breaks if we don't wait here.
2818 * Panel bug? Needs more studying */
2819 msleep(100);
2820 return r;
2821}
2822
2823static void dsi_handle_framedone(void)
2824{
2825 int r;
2826 const int channel = 0;
2827 bool use_te_trigger;
2828
2829 use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;
2830
2831 if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
2832 DSSDBG("FRAMEDONE\n");
2833
2834 if (use_te_trigger) {
2835 /* enable LP_RX_TO again after the TE */
2836 REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
2837 }
2838
2839 /* Send BTA after the frame. We need this for the TE to work, as TE
2840 * trigger is only sent for BTAs without preceding packet. Thus we need
2841 * to BTA after the pixel packets so that next BTA will cause TE
2842 * trigger.
2843 *
2844 * This is not needed when TE is not in use, but we do it anyway to
2845 * make sure that the transfer has been completed. It would be more
2846 * optimal, but more complex, to wait only just before starting next
2847 * transfer. */
2848 r = dsi_vc_send_bta_sync(channel);
2849 if (r)
2850 DSSERR("BTA after framedone failed\n");
2851
2852 /* RX_FIFO_NOT_EMPTY */
2853 if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
2854 DSSERR("Received error during frame transfer:\n");
2855 dsi_vc_flush_receive_data(0);
2856 }
2857
2858#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
2859 dispc_fake_vsync_irq();
2860#endif
2861}
2862
2863static int dsi_update_thread(void *data)
2864{
2865 unsigned long timeout;
2866 struct omap_dss_device *device;
2867 u16 x, y, w, h;
2868
2869 while (1) {
2870 bool sched;
2871
2872 wait_event_interruptible(dsi.waitqueue,
2873 dsi.update_mode == OMAP_DSS_UPDATE_AUTO ||
2874 (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL &&
2875 dsi.update_region.dirty == true) ||
2876 kthread_should_stop());
2877
2878 if (kthread_should_stop())
2879 break;
2880
2881 dsi_bus_lock();
2882
2883 if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED ||
2884 kthread_should_stop()) {
2885 dsi_bus_unlock();
2886 break;
2887 }
2888
2889 dsi_perf_mark_setup();
2890
2891 if (dsi.update_region.dirty) {
2892 spin_lock(&dsi.update_lock);
2893 dsi.active_update_region = dsi.update_region;
2894 dsi.update_region.dirty = false;
2895 spin_unlock(&dsi.update_lock);
2896 }
2897
2898 device = dsi.active_update_region.device;
2899 x = dsi.active_update_region.x;
2900 y = dsi.active_update_region.y;
2901 w = dsi.active_update_region.w;
2902 h = dsi.active_update_region.h;
2903
2904 if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
2905
2906 if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL)
2907 dss_setup_partial_planes(device,
2908 &x, &y, &w, &h);
2909
2910 dispc_set_lcd_size(w, h);
2911 }
2912
2913 if (dsi.active_update_region.dirty) {
2914 dsi.active_update_region.dirty = false;
2915 /* XXX TODO we don't need to send the coords, if they
2916 * are the same that are already programmed to the
2917 * panel. That should speed up manual update a bit */
2918 device->driver->setup_update(device, x, y, w, h);
2919 }
2920
2921 dsi_perf_mark_start();
2922
2923 if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
2924 dsi_vc_config_vp(0);
2925
2926 if (dsi.te_enabled && dsi.use_ext_te)
2927 device->driver->wait_for_te(device);
2928
2929 dsi.framedone_received = false;
2930
2931 dsi_update_screen_dispc(device, x, y, w, h);
2932
2933 /* wait for framedone */
2934 timeout = msecs_to_jiffies(1000);
2935 wait_event_timeout(dsi.waitqueue,
2936 dsi.framedone_received == true,
2937 timeout);
2938
2939 if (!dsi.framedone_received) {
2940 DSSERR("framedone timeout\n");
2941 DSSERR("failed update %d,%d %dx%d\n",
2942 x, y, w, h);
2943
2944 dispc_enable_sidle();
2945 dispc_enable_lcd_out(0);
2946
2947 dsi_reset_tx_fifo(0);
2948 } else {
2949 dsi_handle_framedone();
2950 dsi_perf_show("DISPC");
2951 }
2952 } else {
2953 dsi_update_screen_l4(device, x, y, w, h);
2954 dsi_perf_show("L4");
2955 }
2956
2957 sched = atomic_read(&dsi.bus_lock.count) < 0;
2958
2959 complete_all(&dsi.update_completion);
2960
2961 dsi_bus_unlock();
2962
2963 /* XXX We need to give others chance to get the bus lock. Is
2964 * there a better way for this? */
2965 if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO && sched)
2966 schedule_timeout_interruptible(1);
2967 }
2968
2969 DSSDBG("update thread exiting\n");
2970
2971 return 0;
2972}
2973
2974
2975
2976/* Display funcs */
2977
2978static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
2979{
2980 int r;
2981
2982 r = omap_dispc_register_isr(dsi_framedone_irq_callback, NULL,
2983 DISPC_IRQ_FRAMEDONE);
2984 if (r) {
2985 DSSERR("can't get FRAMEDONE irq\n");
2986 return r;
2987 }
2988
2989 dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
2990
2991 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_DSI);
2992 dispc_enable_fifohandcheck(1);
2993
2994 dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
2995
2996 {
2997 struct omap_video_timings timings = {
2998 .hsw = 1,
2999 .hfp = 1,
3000 .hbp = 1,
3001 .vsw = 1,
3002 .vfp = 0,
3003 .vbp = 0,
3004 };
3005
3006 dispc_set_lcd_timings(&timings);
3007 }
3008
3009 return 0;
3010}
3011
3012static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
3013{
3014 omap_dispc_unregister_isr(dsi_framedone_irq_callback, NULL,
3015 DISPC_IRQ_FRAMEDONE);
3016}
3017
3018static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
3019{
3020 struct dsi_clock_info cinfo;
3021 int r;
3022
3023 /* we always use DSS2_FCK as input clock */
3024 cinfo.use_dss2_fck = true;
3025 cinfo.regn = dssdev->phy.dsi.div.regn;
3026 cinfo.regm = dssdev->phy.dsi.div.regm;
3027 cinfo.regm3 = dssdev->phy.dsi.div.regm3;
3028 cinfo.regm4 = dssdev->phy.dsi.div.regm4;
3029 r = dsi_calc_clock_rates(&cinfo);
3030 if (r)
3031 return r;
3032
3033 r = dsi_pll_set_clock_div(&cinfo);
3034 if (r) {
3035 DSSERR("Failed to set dsi clocks\n");
3036 return r;
3037 }
3038
3039 return 0;
3040}
3041
3042static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
3043{
3044 struct dispc_clock_info dispc_cinfo;
3045 int r;
3046 unsigned long long fck;
3047
3048 fck = dsi_get_dsi1_pll_rate();
3049
3050 dispc_cinfo.lck_div = dssdev->phy.dsi.div.lck_div;
3051 dispc_cinfo.pck_div = dssdev->phy.dsi.div.pck_div;
3052
3053 r = dispc_calc_clock_rates(fck, &dispc_cinfo);
3054 if (r) {
3055 DSSERR("Failed to calc dispc clocks\n");
3056 return r;
3057 }
3058
3059 r = dispc_set_clock_div(&dispc_cinfo);
3060 if (r) {
3061 DSSERR("Failed to set dispc clocks\n");
3062 return r;
3063 }
3064
3065 return 0;
3066}
3067
3068static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
3069{
3070 int r;
3071
3072 _dsi_print_reset_status();
3073
3074 r = dsi_pll_init(dssdev, true, true);
3075 if (r)
3076 goto err0;
3077
3078 r = dsi_configure_dsi_clocks(dssdev);
3079 if (r)
3080 goto err1;
3081
3082 dss_select_clk_source(true, true);
3083
3084 DSSDBG("PLL OK\n");
3085
3086 r = dsi_configure_dispc_clocks(dssdev);
3087 if (r)
3088 goto err2;
3089
3090 r = dsi_complexio_init(dssdev);
3091 if (r)
3092 goto err2;
3093
3094 _dsi_print_reset_status();
3095
3096 dsi_proto_timings(dssdev);
3097 dsi_set_lp_clk_divisor(dssdev);
3098
3099 if (1)
3100 _dsi_print_reset_status();
3101
3102 r = dsi_proto_config(dssdev);
3103 if (r)
3104 goto err3;
3105
3106 /* enable interface */
3107 dsi_vc_enable(0, 1);
3108 dsi_if_enable(1);
3109 dsi_force_tx_stop_mode_io();
3110
3111 if (dssdev->driver->enable) {
3112 r = dssdev->driver->enable(dssdev);
3113 if (r)
3114 goto err4;
3115 }
3116
3117 /* enable high-speed after initial config */
3118 dsi_vc_enable_hs(0, 1);
3119
3120 return 0;
3121err4:
3122 dsi_if_enable(0);
3123err3:
3124 dsi_complexio_uninit();
3125err2:
3126 dss_select_clk_source(false, false);
3127err1:
3128 dsi_pll_uninit();
3129err0:
3130 return r;
3131}
3132
3133static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
3134{
3135 if (dssdev->driver->disable)
3136 dssdev->driver->disable(dssdev);
3137
3138 dss_select_clk_source(false, false);
3139 dsi_complexio_uninit();
3140 dsi_pll_uninit();
3141}
3142
3143static int dsi_core_init(void)
3144{
3145 /* Autoidle */
3146 REG_FLD_MOD(DSI_SYSCONFIG, 1, 0, 0);
3147
3148 /* ENWAKEUP */
3149 REG_FLD_MOD(DSI_SYSCONFIG, 1, 2, 2);
3150
3151 /* SIDLEMODE smart-idle */
3152 REG_FLD_MOD(DSI_SYSCONFIG, 2, 4, 3);
3153
3154 _dsi_initialize_irq();
3155
3156 return 0;
3157}
3158
3159static int dsi_display_enable(struct omap_dss_device *dssdev)
3160{
3161 int r = 0;
3162
3163 DSSDBG("dsi_display_enable\n");
3164
3165 mutex_lock(&dsi.lock);
3166 dsi_bus_lock();
3167
3168 r = omap_dss_start_device(dssdev);
3169 if (r) {
3170 DSSERR("failed to start device\n");
3171 goto err0;
3172 }
3173
3174 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
3175 DSSERR("dssdev already enabled\n");
3176 r = -EINVAL;
3177 goto err1;
3178 }
3179
3180 enable_clocks(1);
3181 dsi_enable_pll_clock(1);
3182
3183 r = _dsi_reset();
3184 if (r)
3185 goto err2;
3186
3187 dsi_core_init();
3188
3189 r = dsi_display_init_dispc(dssdev);
3190 if (r)
3191 goto err2;
3192
3193 r = dsi_display_init_dsi(dssdev);
3194 if (r)
3195 goto err3;
3196
3197 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
3198
3199 dsi.use_ext_te = dssdev->phy.dsi.ext_te;
3200 r = dsi_set_te(dssdev, dsi.te_enabled);
3201 if (r)
3202 goto err4;
3203
3204 dsi_set_update_mode(dssdev, dsi.user_update_mode);
3205
3206 dsi_bus_unlock();
3207 mutex_unlock(&dsi.lock);
3208
3209 return 0;
3210
3211err4:
3212
3213 dsi_display_uninit_dsi(dssdev);
3214err3:
3215 dsi_display_uninit_dispc(dssdev);
3216err2:
3217 enable_clocks(0);
3218 dsi_enable_pll_clock(0);
3219err1:
3220 omap_dss_stop_device(dssdev);
3221err0:
3222 dsi_bus_unlock();
3223 mutex_unlock(&dsi.lock);
3224 DSSDBG("dsi_display_enable FAILED\n");
3225 return r;
3226}
3227
3228static void dsi_display_disable(struct omap_dss_device *dssdev)
3229{
3230 DSSDBG("dsi_display_disable\n");
3231
3232 mutex_lock(&dsi.lock);
3233 dsi_bus_lock();
3234
3235 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
3236 dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
3237 goto end;
3238
3239 dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
3240 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
3241
3242 dsi_display_uninit_dispc(dssdev);
3243
3244 dsi_display_uninit_dsi(dssdev);
3245
3246 enable_clocks(0);
3247 dsi_enable_pll_clock(0);
3248
3249 omap_dss_stop_device(dssdev);
3250end:
3251 dsi_bus_unlock();
3252 mutex_unlock(&dsi.lock);
3253}
3254
3255static int dsi_display_suspend(struct omap_dss_device *dssdev)
3256{
3257 DSSDBG("dsi_display_suspend\n");
3258
3259 mutex_lock(&dsi.lock);
3260 dsi_bus_lock();
3261
3262 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
3263 dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
3264 goto end;
3265
3266 dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
3267 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
3268
3269 dsi_display_uninit_dispc(dssdev);
3270
3271 dsi_display_uninit_dsi(dssdev);
3272
3273 enable_clocks(0);
3274 dsi_enable_pll_clock(0);
3275end:
3276 dsi_bus_unlock();
3277 mutex_unlock(&dsi.lock);
3278
3279 return 0;
3280}
3281
3282static int dsi_display_resume(struct omap_dss_device *dssdev)
3283{
3284 int r;
3285
3286 DSSDBG("dsi_display_resume\n");
3287
3288 mutex_lock(&dsi.lock);
3289 dsi_bus_lock();
3290
3291 if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
3292 DSSERR("dssdev not suspended\n");
3293 r = -EINVAL;
3294 goto err0;
3295 }
3296
3297 enable_clocks(1);
3298 dsi_enable_pll_clock(1);
3299
3300 r = _dsi_reset();
3301 if (r)
3302 goto err1;
3303
3304 dsi_core_init();
3305
3306 r = dsi_display_init_dispc(dssdev);
3307 if (r)
3308 goto err1;
3309
3310 r = dsi_display_init_dsi(dssdev);
3311 if (r)
3312 goto err2;
3313
3314 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
3315
3316 r = dsi_set_te(dssdev, dsi.te_enabled);
3317 if (r)
3318 goto err2;
3319
3320 dsi_set_update_mode(dssdev, dsi.user_update_mode);
3321
3322 dsi_bus_unlock();
3323 mutex_unlock(&dsi.lock);
3324
3325 return 0;
3326
3327err2:
3328 dsi_display_uninit_dispc(dssdev);
3329err1:
3330 enable_clocks(0);
3331 dsi_enable_pll_clock(0);
3332err0:
3333 dsi_bus_unlock();
3334 mutex_unlock(&dsi.lock);
3335 DSSDBG("dsi_display_resume FAILED\n");
3336 return r;
3337}
3338
3339static int dsi_display_update(struct omap_dss_device *dssdev,
3340 u16 x, u16 y, u16 w, u16 h)
3341{
3342 int r = 0;
3343 u16 dw, dh;
3344
3345 DSSDBG("dsi_display_update(%d,%d %dx%d)\n", x, y, w, h);
3346
3347 mutex_lock(&dsi.lock);
3348
3349 if (dsi.update_mode != OMAP_DSS_UPDATE_MANUAL)
3350 goto end;
3351
3352 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
3353 goto end;
3354
3355 dssdev->get_resolution(dssdev, &dw, &dh);
3356
3357 if (x > dw || y > dh)
3358 goto end;
3359
3360 if (x + w > dw)
3361 w = dw - x;
3362
3363 if (y + h > dh)
3364 h = dh - y;
3365
3366 if (w == 0 || h == 0)
3367 goto end;
3368
3369 if (w == 1) {
3370 r = -EINVAL;
3371 goto end;
3372 }
3373
3374 dsi_set_update_region(dssdev, x, y, w, h);
3375
3376 wake_up(&dsi.waitqueue);
3377
3378end:
3379 mutex_unlock(&dsi.lock);
3380
3381 return r;
3382}
3383
3384static int dsi_display_sync(struct omap_dss_device *dssdev)
3385{
3386 bool wait;
3387
3388 DSSDBG("dsi_display_sync()\n");
3389
3390 mutex_lock(&dsi.lock);
3391 dsi_bus_lock();
3392
3393 if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL &&
3394 dsi.update_region.dirty) {
3395 INIT_COMPLETION(dsi.update_completion);
3396 wait = true;
3397 } else {
3398 wait = false;
3399 }
3400
3401 dsi_bus_unlock();
3402 mutex_unlock(&dsi.lock);
3403
3404 if (wait)
3405 wait_for_completion_interruptible(&dsi.update_completion);
3406
3407 DSSDBG("dsi_display_sync() done\n");
3408 return 0;
3409}
3410
3411static int dsi_display_set_update_mode(struct omap_dss_device *dssdev,
3412 enum omap_dss_update_mode mode)
3413{
3414 int r = 0;
3415
3416 DSSDBGF("%d", mode);
3417
3418 mutex_lock(&dsi.lock);
3419 dsi_bus_lock();
3420
3421 dsi.user_update_mode = mode;
3422 r = dsi_set_update_mode(dssdev, mode);
3423
3424 dsi_bus_unlock();
3425 mutex_unlock(&dsi.lock);
3426
3427 return r;
3428}
3429
3430static enum omap_dss_update_mode dsi_display_get_update_mode(
3431 struct omap_dss_device *dssdev)
3432{
3433 return dsi.update_mode;
3434}
3435
3436
3437static int dsi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
3438{
3439 int r = 0;
3440
3441 DSSDBGF("%d", enable);
3442
3443 if (!dssdev->driver->enable_te)
3444 return -ENOENT;
3445
3446 dsi_bus_lock();
3447
3448 dsi.te_enabled = enable;
3449
3450 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
3451 goto end;
3452
3453 r = dsi_set_te(dssdev, enable);
3454end:
3455 dsi_bus_unlock();
3456
3457 return r;
3458}
3459
3460static int dsi_display_get_te(struct omap_dss_device *dssdev)
3461{
3462 return dsi.te_enabled;
3463}
3464
3465static int dsi_display_set_rotate(struct omap_dss_device *dssdev, u8 rotate)
3466{
3467
3468 DSSDBGF("%d", rotate);
3469
3470 if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
3471 return -EINVAL;
3472
3473 dsi_bus_lock();
3474 dssdev->driver->set_rotate(dssdev, rotate);
3475 if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) {
3476 u16 w, h;
3477 /* the display dimensions may have changed, so set a new
3478 * update region */
3479 dssdev->get_resolution(dssdev, &w, &h);
3480 dsi_set_update_region(dssdev, 0, 0, w, h);
3481 }
3482 dsi_bus_unlock();
3483
3484 return 0;
3485}
3486
3487static u8 dsi_display_get_rotate(struct omap_dss_device *dssdev)
3488{
3489 if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
3490 return 0;
3491
3492 return dssdev->driver->get_rotate(dssdev);
3493}
3494
3495static int dsi_display_set_mirror(struct omap_dss_device *dssdev, bool mirror)
3496{
3497 DSSDBGF("%d", mirror);
3498
3499 if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
3500 return -EINVAL;
3501
3502 dsi_bus_lock();
3503 dssdev->driver->set_mirror(dssdev, mirror);
3504 dsi_bus_unlock();
3505
3506 return 0;
3507}
3508
3509static bool dsi_display_get_mirror(struct omap_dss_device *dssdev)
3510{
3511 if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
3512 return 0;
3513
3514 return dssdev->driver->get_mirror(dssdev);
3515}
3516
3517static int dsi_display_run_test(struct omap_dss_device *dssdev, int test_num)
3518{
3519 int r;
3520
3521 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
3522 return -EIO;
3523
3524 DSSDBGF("%d", test_num);
3525
3526 dsi_bus_lock();
3527
3528 /* run test first in low speed mode */
3529 dsi_vc_enable_hs(0, 0);
3530
3531 if (dssdev->driver->run_test) {
3532 r = dssdev->driver->run_test(dssdev, test_num);
3533 if (r)
3534 goto end;
3535 }
3536
3537 /* then in high speed */
3538 dsi_vc_enable_hs(0, 1);
3539
3540 if (dssdev->driver->run_test) {
3541 r = dssdev->driver->run_test(dssdev, test_num);
3542 if (r)
3543 goto end;
3544 }
3545
3546end:
3547 dsi_vc_enable_hs(0, 1);
3548
3549 dsi_bus_unlock();
3550
3551 return r;
3552}
3553
3554static int dsi_display_memory_read(struct omap_dss_device *dssdev,
3555 void *buf, size_t size,
3556 u16 x, u16 y, u16 w, u16 h)
3557{
3558 int r;
3559
3560 DSSDBGF("");
3561
3562 if (!dssdev->driver->memory_read)
3563 return -EINVAL;
3564
3565 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
3566 return -EIO;
3567
3568 dsi_bus_lock();
3569
3570 r = dssdev->driver->memory_read(dssdev, buf, size,
3571 x, y, w, h);
3572
3573 /* Memory read usually changes the update area. This will
3574 * force the next update to re-set the update area */
3575 dsi.active_update_region.dirty = true;
3576
3577 dsi_bus_unlock();
3578
3579 return r;
3580}
3581
3582void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
3583 u32 fifo_size, enum omap_burst_size *burst_size,
3584 u32 *fifo_low, u32 *fifo_high)
3585{
3586 unsigned burst_size_bytes;
3587
3588 *burst_size = OMAP_DSS_BURST_16x32;
3589 burst_size_bytes = 16 * 32 / 8;
3590
3591 *fifo_high = fifo_size - burst_size_bytes;
3592 *fifo_low = fifo_size - burst_size_bytes * 8;
3593}
3594
3595int dsi_init_display(struct omap_dss_device *dssdev)
3596{
3597 DSSDBG("DSI init\n");
3598
3599 dssdev->enable = dsi_display_enable;
3600 dssdev->disable = dsi_display_disable;
3601 dssdev->suspend = dsi_display_suspend;
3602 dssdev->resume = dsi_display_resume;
3603 dssdev->update = dsi_display_update;
3604 dssdev->sync = dsi_display_sync;
3605 dssdev->set_update_mode = dsi_display_set_update_mode;
3606 dssdev->get_update_mode = dsi_display_get_update_mode;
3607 dssdev->enable_te = dsi_display_enable_te;
3608 dssdev->get_te = dsi_display_get_te;
3609
3610 dssdev->get_rotate = dsi_display_get_rotate;
3611 dssdev->set_rotate = dsi_display_set_rotate;
3612
3613 dssdev->get_mirror = dsi_display_get_mirror;
3614 dssdev->set_mirror = dsi_display_set_mirror;
3615
3616 dssdev->run_test = dsi_display_run_test;
3617 dssdev->memory_read = dsi_display_memory_read;
3618
3619 /* XXX these should be figured out dynamically */
3620 dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
3621 OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
3622
3623 dsi.vc[0].dssdev = dssdev;
3624 dsi.vc[1].dssdev = dssdev;
3625
3626 return 0;
3627}
3628
3629int dsi_init(struct platform_device *pdev)
3630{
3631 u32 rev;
3632 int r;
3633 struct sched_param param = {
3634 .sched_priority = MAX_USER_RT_PRIO-1
3635 };
3636
3637 spin_lock_init(&dsi.errors_lock);
3638 dsi.errors = 0;
3639
3640 init_completion(&dsi.bta_completion);
3641 init_completion(&dsi.update_completion);
3642
3643 dsi.thread = kthread_create(dsi_update_thread, NULL, "dsi");
3644 if (IS_ERR(dsi.thread)) {
3645 DSSERR("cannot create kthread\n");
3646 r = PTR_ERR(dsi.thread);
3647 goto err0;
3648 }
3649 sched_setscheduler(dsi.thread, SCHED_FIFO, &param);
3650
3651 init_waitqueue_head(&dsi.waitqueue);
3652 spin_lock_init(&dsi.update_lock);
3653
3654 mutex_init(&dsi.lock);
3655 mutex_init(&dsi.bus_lock);
3656
3657#ifdef DSI_CATCH_MISSING_TE
3658 init_timer(&dsi.te_timer);
3659 dsi.te_timer.function = dsi_te_timeout;
3660 dsi.te_timer.data = 0;
3661#endif
3662
3663 dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
3664 dsi.user_update_mode = OMAP_DSS_UPDATE_DISABLED;
3665
3666 dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS);
3667 if (!dsi.base) {
3668 DSSERR("can't ioremap DSI\n");
3669 r = -ENOMEM;
3670 goto err1;
3671 }
3672
3673 dsi.vdds_dsi_reg = regulator_get(&pdev->dev, "vdds_dsi");
3674 if (IS_ERR(dsi.vdds_dsi_reg)) {
3675 iounmap(dsi.base);
3676 DSSERR("can't get VDDS_DSI regulator\n");
3677 r = PTR_ERR(dsi.vdds_dsi_reg);
3678 goto err2;
3679 }
3680
3681 enable_clocks(1);
3682
3683 rev = dsi_read_reg(DSI_REVISION);
3684 printk(KERN_INFO "OMAP DSI rev %d.%d\n",
3685 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
3686
3687 enable_clocks(0);
3688
3689 wake_up_process(dsi.thread);
3690
3691 return 0;
3692err2:
3693 iounmap(dsi.base);
3694err1:
3695 kthread_stop(dsi.thread);
3696err0:
3697 return r;
3698}
3699
3700void dsi_exit(void)
3701{
3702 kthread_stop(dsi.thread);
3703
3704 regulator_put(dsi.vdds_dsi_reg);
3705
3706 iounmap(dsi.base);
3707
3708 DSSDBG("omap_dsi_exit\n");
3709}
3710
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
new file mode 100644
index 000000000000..9b05ee65a15d
--- /dev/null
+++ b/drivers/video/omap2/dss/dss.c
@@ -0,0 +1,596 @@
1/*
2 * linux/drivers/video/omap2/dss/dss.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DSS"
24
25#include <linux/kernel.h>
26#include <linux/io.h>
27#include <linux/err.h>
28#include <linux/delay.h>
29#include <linux/interrupt.h>
30#include <linux/seq_file.h>
31#include <linux/clk.h>
32
33#include <plat/display.h>
34#include "dss.h"
35
36#define DSS_BASE 0x48050000
37
38#define DSS_SZ_REGS SZ_512
39
40struct dss_reg {
41 u16 idx;
42};
43
44#define DSS_REG(idx) ((const struct dss_reg) { idx })
45
46#define DSS_REVISION DSS_REG(0x0000)
47#define DSS_SYSCONFIG DSS_REG(0x0010)
48#define DSS_SYSSTATUS DSS_REG(0x0014)
49#define DSS_IRQSTATUS DSS_REG(0x0018)
50#define DSS_CONTROL DSS_REG(0x0040)
51#define DSS_SDI_CONTROL DSS_REG(0x0044)
52#define DSS_PLL_CONTROL DSS_REG(0x0048)
53#define DSS_SDI_STATUS DSS_REG(0x005C)
54
55#define REG_GET(idx, start, end) \
56 FLD_GET(dss_read_reg(idx), start, end)
57
58#define REG_FLD_MOD(idx, val, start, end) \
59 dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
60
61static struct {
62 void __iomem *base;
63
64 struct clk *dpll4_m4_ck;
65
66 unsigned long cache_req_pck;
67 unsigned long cache_prate;
68 struct dss_clock_info cache_dss_cinfo;
69 struct dispc_clock_info cache_dispc_cinfo;
70
71 u32 ctx[DSS_SZ_REGS / sizeof(u32)];
72} dss;
73
74static int _omap_dss_wait_reset(void);
75
76static inline void dss_write_reg(const struct dss_reg idx, u32 val)
77{
78 __raw_writel(val, dss.base + idx.idx);
79}
80
81static inline u32 dss_read_reg(const struct dss_reg idx)
82{
83 return __raw_readl(dss.base + idx.idx);
84}
85
86#define SR(reg) \
87 dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
88#define RR(reg) \
89 dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
90
91void dss_save_context(void)
92{
93 if (cpu_is_omap24xx())
94 return;
95
96 SR(SYSCONFIG);
97 SR(CONTROL);
98
99#ifdef CONFIG_OMAP2_DSS_SDI
100 SR(SDI_CONTROL);
101 SR(PLL_CONTROL);
102#endif
103}
104
105void dss_restore_context(void)
106{
107 if (_omap_dss_wait_reset())
108 DSSERR("DSS not coming out of reset after sleep\n");
109
110 RR(SYSCONFIG);
111 RR(CONTROL);
112
113#ifdef CONFIG_OMAP2_DSS_SDI
114 RR(SDI_CONTROL);
115 RR(PLL_CONTROL);
116#endif
117}
118
119#undef SR
120#undef RR
121
122void dss_sdi_init(u8 datapairs)
123{
124 u32 l;
125
126 BUG_ON(datapairs > 3 || datapairs < 1);
127
128 l = dss_read_reg(DSS_SDI_CONTROL);
129 l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */
130 l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */
131 l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */
132 dss_write_reg(DSS_SDI_CONTROL, l);
133
134 l = dss_read_reg(DSS_PLL_CONTROL);
135 l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */
136 l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */
137 l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */
138 dss_write_reg(DSS_PLL_CONTROL, l);
139}
140
141int dss_sdi_enable(void)
142{
143 unsigned long timeout;
144
145 dispc_pck_free_enable(1);
146
147 /* Reset SDI PLL */
148 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
149 udelay(1); /* wait 2x PCLK */
150
151 /* Lock SDI PLL */
152 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
153
154 /* Waiting for PLL lock request to complete */
155 timeout = jiffies + msecs_to_jiffies(500);
156 while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
157 if (time_after_eq(jiffies, timeout)) {
158 DSSERR("PLL lock request timed out\n");
159 goto err1;
160 }
161 }
162
163 /* Clearing PLL_GO bit */
164 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
165
166 /* Waiting for PLL to lock */
167 timeout = jiffies + msecs_to_jiffies(500);
168 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
169 if (time_after_eq(jiffies, timeout)) {
170 DSSERR("PLL lock timed out\n");
171 goto err1;
172 }
173 }
174
175 dispc_lcd_enable_signal(1);
176
177 /* Waiting for SDI reset to complete */
178 timeout = jiffies + msecs_to_jiffies(500);
179 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
180 if (time_after_eq(jiffies, timeout)) {
181 DSSERR("SDI reset timed out\n");
182 goto err2;
183 }
184 }
185
186 return 0;
187
188 err2:
189 dispc_lcd_enable_signal(0);
190 err1:
191 /* Reset SDI PLL */
192 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
193
194 dispc_pck_free_enable(0);
195
196 return -ETIMEDOUT;
197}
198
199void dss_sdi_disable(void)
200{
201 dispc_lcd_enable_signal(0);
202
203 dispc_pck_free_enable(0);
204
205 /* Reset SDI PLL */
206 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
207}
208
209void dss_dump_clocks(struct seq_file *s)
210{
211 unsigned long dpll4_ck_rate;
212 unsigned long dpll4_m4_ck_rate;
213
214 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
215
216 dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
217 dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
218
219 seq_printf(s, "- DSS -\n");
220
221 seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
222
223 seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n",
224 dpll4_ck_rate,
225 dpll4_ck_rate / dpll4_m4_ck_rate,
226 dss_clk_get_rate(DSS_CLK_FCK1));
227
228 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
229}
230
231void dss_dump_regs(struct seq_file *s)
232{
233#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
234
235 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
236
237 DUMPREG(DSS_REVISION);
238 DUMPREG(DSS_SYSCONFIG);
239 DUMPREG(DSS_SYSSTATUS);
240 DUMPREG(DSS_IRQSTATUS);
241 DUMPREG(DSS_CONTROL);
242 DUMPREG(DSS_SDI_CONTROL);
243 DUMPREG(DSS_PLL_CONTROL);
244 DUMPREG(DSS_SDI_STATUS);
245
246 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
247#undef DUMPREG
248}
249
250void dss_select_clk_source(bool dsi, bool dispc)
251{
252 u32 r;
253 r = dss_read_reg(DSS_CONTROL);
254 r = FLD_MOD(r, dsi, 1, 1); /* DSI_CLK_SWITCH */
255 r = FLD_MOD(r, dispc, 0, 0); /* DISPC_CLK_SWITCH */
256 dss_write_reg(DSS_CONTROL, r);
257}
258
259int dss_get_dsi_clk_source(void)
260{
261 return FLD_GET(dss_read_reg(DSS_CONTROL), 1, 1);
262}
263
264int dss_get_dispc_clk_source(void)
265{
266 return FLD_GET(dss_read_reg(DSS_CONTROL), 0, 0);
267}
268
269/* calculate clock rates using dividers in cinfo */
270int dss_calc_clock_rates(struct dss_clock_info *cinfo)
271{
272 unsigned long prate;
273
274 if (cinfo->fck_div > 16 || cinfo->fck_div == 0)
275 return -EINVAL;
276
277 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
278
279 cinfo->fck = prate / cinfo->fck_div;
280
281 return 0;
282}
283
284int dss_set_clock_div(struct dss_clock_info *cinfo)
285{
286 unsigned long prate;
287 int r;
288
289 if (cpu_is_omap34xx()) {
290 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
291 DSSDBG("dpll4_m4 = %ld\n", prate);
292
293 r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
294 if (r)
295 return r;
296 }
297
298 DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
299
300 return 0;
301}
302
303int dss_get_clock_div(struct dss_clock_info *cinfo)
304{
305 cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK1);
306
307 if (cpu_is_omap34xx()) {
308 unsigned long prate;
309 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
310 cinfo->fck_div = prate / (cinfo->fck / 2);
311 } else {
312 cinfo->fck_div = 0;
313 }
314
315 return 0;
316}
317
318unsigned long dss_get_dpll4_rate(void)
319{
320 if (cpu_is_omap34xx())
321 return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
322 else
323 return 0;
324}
325
326int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
327 struct dss_clock_info *dss_cinfo,
328 struct dispc_clock_info *dispc_cinfo)
329{
330 unsigned long prate;
331 struct dss_clock_info best_dss;
332 struct dispc_clock_info best_dispc;
333
334 unsigned long fck;
335
336 u16 fck_div;
337
338 int match = 0;
339 int min_fck_per_pck;
340
341 prate = dss_get_dpll4_rate();
342
343 fck = dss_clk_get_rate(DSS_CLK_FCK1);
344 if (req_pck == dss.cache_req_pck &&
345 ((cpu_is_omap34xx() && prate == dss.cache_prate) ||
346 dss.cache_dss_cinfo.fck == fck)) {
347 DSSDBG("dispc clock info found from cache.\n");
348 *dss_cinfo = dss.cache_dss_cinfo;
349 *dispc_cinfo = dss.cache_dispc_cinfo;
350 return 0;
351 }
352
353 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
354
355 if (min_fck_per_pck &&
356 req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
357 DSSERR("Requested pixel clock not possible with the current "
358 "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
359 "the constraint off.\n");
360 min_fck_per_pck = 0;
361 }
362
363retry:
364 memset(&best_dss, 0, sizeof(best_dss));
365 memset(&best_dispc, 0, sizeof(best_dispc));
366
367 if (cpu_is_omap24xx()) {
368 struct dispc_clock_info cur_dispc;
369 /* XXX can we change the clock on omap2? */
370 fck = dss_clk_get_rate(DSS_CLK_FCK1);
371 fck_div = 1;
372
373 dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
374 match = 1;
375
376 best_dss.fck = fck;
377 best_dss.fck_div = fck_div;
378
379 best_dispc = cur_dispc;
380
381 goto found;
382 } else if (cpu_is_omap34xx()) {
383 for (fck_div = 16; fck_div > 0; --fck_div) {
384 struct dispc_clock_info cur_dispc;
385
386 fck = prate / fck_div * 2;
387
388 if (fck > DISPC_MAX_FCK)
389 continue;
390
391 if (min_fck_per_pck &&
392 fck < req_pck * min_fck_per_pck)
393 continue;
394
395 match = 1;
396
397 dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
398
399 if (abs(cur_dispc.pck - req_pck) <
400 abs(best_dispc.pck - req_pck)) {
401
402 best_dss.fck = fck;
403 best_dss.fck_div = fck_div;
404
405 best_dispc = cur_dispc;
406
407 if (cur_dispc.pck == req_pck)
408 goto found;
409 }
410 }
411 } else {
412 BUG();
413 }
414
415found:
416 if (!match) {
417 if (min_fck_per_pck) {
418 DSSERR("Could not find suitable clock settings.\n"
419 "Turning FCK/PCK constraint off and"
420 "trying again.\n");
421 min_fck_per_pck = 0;
422 goto retry;
423 }
424
425 DSSERR("Could not find suitable clock settings.\n");
426
427 return -EINVAL;
428 }
429
430 if (dss_cinfo)
431 *dss_cinfo = best_dss;
432 if (dispc_cinfo)
433 *dispc_cinfo = best_dispc;
434
435 dss.cache_req_pck = req_pck;
436 dss.cache_prate = prate;
437 dss.cache_dss_cinfo = best_dss;
438 dss.cache_dispc_cinfo = best_dispc;
439
440 return 0;
441}
442
443
444
445static irqreturn_t dss_irq_handler_omap2(int irq, void *arg)
446{
447 dispc_irq_handler();
448
449 return IRQ_HANDLED;
450}
451
452static irqreturn_t dss_irq_handler_omap3(int irq, void *arg)
453{
454 u32 irqstatus;
455
456 irqstatus = dss_read_reg(DSS_IRQSTATUS);
457
458 if (irqstatus & (1<<0)) /* DISPC_IRQ */
459 dispc_irq_handler();
460#ifdef CONFIG_OMAP2_DSS_DSI
461 if (irqstatus & (1<<1)) /* DSI_IRQ */
462 dsi_irq_handler();
463#endif
464
465 return IRQ_HANDLED;
466}
467
468static int _omap_dss_wait_reset(void)
469{
470 unsigned timeout = 1000;
471
472 while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) {
473 udelay(1);
474 if (!--timeout) {
475 DSSERR("soft reset failed\n");
476 return -ENODEV;
477 }
478 }
479
480 return 0;
481}
482
483static int _omap_dss_reset(void)
484{
485 /* Soft reset */
486 REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1);
487 return _omap_dss_wait_reset();
488}
489
490void dss_set_venc_output(enum omap_dss_venc_type type)
491{
492 int l = 0;
493
494 if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
495 l = 0;
496 else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
497 l = 1;
498 else
499 BUG();
500
501 /* venc out selection. 0 = comp, 1 = svideo */
502 REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
503}
504
505void dss_set_dac_pwrdn_bgz(bool enable)
506{
507 REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
508}
509
510int dss_init(bool skip_init)
511{
512 int r;
513 u32 rev;
514
515 dss.base = ioremap(DSS_BASE, DSS_SZ_REGS);
516 if (!dss.base) {
517 DSSERR("can't ioremap DSS\n");
518 r = -ENOMEM;
519 goto fail0;
520 }
521
522 if (!skip_init) {
523 /* disable LCD and DIGIT output. This seems to fix the synclost
524 * problem that we get, if the bootloader starts the DSS and
525 * the kernel resets it */
526 omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
527
528 /* We need to wait here a bit, otherwise we sometimes start to
529 * get synclost errors, and after that only power cycle will
530 * restore DSS functionality. I have no idea why this happens.
531 * And we have to wait _before_ resetting the DSS, but after
532 * enabling clocks.
533 */
534 msleep(50);
535
536 _omap_dss_reset();
537 }
538
539 /* autoidle */
540 REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
541
542 /* Select DPLL */
543 REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
544
545#ifdef CONFIG_OMAP2_DSS_VENC
546 REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
547 REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
548 REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
549#endif
550
551 r = request_irq(INT_24XX_DSS_IRQ,
552 cpu_is_omap24xx()
553 ? dss_irq_handler_omap2
554 : dss_irq_handler_omap3,
555 0, "OMAP DSS", NULL);
556
557 if (r < 0) {
558 DSSERR("omap2 dss: request_irq failed\n");
559 goto fail1;
560 }
561
562 if (cpu_is_omap34xx()) {
563 dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
564 if (IS_ERR(dss.dpll4_m4_ck)) {
565 DSSERR("Failed to get dpll4_m4_ck\n");
566 r = PTR_ERR(dss.dpll4_m4_ck);
567 goto fail2;
568 }
569 }
570
571 dss_save_context();
572
573 rev = dss_read_reg(DSS_REVISION);
574 printk(KERN_INFO "OMAP DSS rev %d.%d\n",
575 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
576
577 return 0;
578
579fail2:
580 free_irq(INT_24XX_DSS_IRQ, NULL);
581fail1:
582 iounmap(dss.base);
583fail0:
584 return r;
585}
586
587void dss_exit(void)
588{
589 if (cpu_is_omap34xx())
590 clk_put(dss.dpll4_m4_ck);
591
592 free_irq(INT_24XX_DSS_IRQ, NULL);
593
594 iounmap(dss.base);
595}
596
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
new file mode 100644
index 000000000000..8da5ac42151b
--- /dev/null
+++ b/drivers/video/omap2/dss/dss.h
@@ -0,0 +1,370 @@
1/*
2 * linux/drivers/video/omap2/dss/dss.h
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#ifndef __OMAP2_DSS_H
24#define __OMAP2_DSS_H
25
26#ifdef CONFIG_OMAP2_DSS_DEBUG_SUPPORT
27#define DEBUG
28#endif
29
30#ifdef DEBUG
31extern unsigned int dss_debug;
32#ifdef DSS_SUBSYS_NAME
33#define DSSDBG(format, ...) \
34 if (dss_debug) \
35 printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME ": " format, \
36 ## __VA_ARGS__)
37#else
38#define DSSDBG(format, ...) \
39 if (dss_debug) \
40 printk(KERN_DEBUG "omapdss: " format, ## __VA_ARGS__)
41#endif
42
43#ifdef DSS_SUBSYS_NAME
44#define DSSDBGF(format, ...) \
45 if (dss_debug) \
46 printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME \
47 ": %s(" format ")\n", \
48 __func__, \
49 ## __VA_ARGS__)
50#else
51#define DSSDBGF(format, ...) \
52 if (dss_debug) \
53 printk(KERN_DEBUG "omapdss: " \
54 ": %s(" format ")\n", \
55 __func__, \
56 ## __VA_ARGS__)
57#endif
58
59#else /* DEBUG */
60#define DSSDBG(format, ...)
61#define DSSDBGF(format, ...)
62#endif
63
64
65#ifdef DSS_SUBSYS_NAME
66#define DSSERR(format, ...) \
67 printk(KERN_ERR "omapdss " DSS_SUBSYS_NAME " error: " format, \
68 ## __VA_ARGS__)
69#else
70#define DSSERR(format, ...) \
71 printk(KERN_ERR "omapdss error: " format, ## __VA_ARGS__)
72#endif
73
74#ifdef DSS_SUBSYS_NAME
75#define DSSINFO(format, ...) \
76 printk(KERN_INFO "omapdss " DSS_SUBSYS_NAME ": " format, \
77 ## __VA_ARGS__)
78#else
79#define DSSINFO(format, ...) \
80 printk(KERN_INFO "omapdss: " format, ## __VA_ARGS__)
81#endif
82
83#ifdef DSS_SUBSYS_NAME
84#define DSSWARN(format, ...) \
85 printk(KERN_WARNING "omapdss " DSS_SUBSYS_NAME ": " format, \
86 ## __VA_ARGS__)
87#else
88#define DSSWARN(format, ...) \
89 printk(KERN_WARNING "omapdss: " format, ## __VA_ARGS__)
90#endif
91
92/* OMAP TRM gives bitfields as start:end, where start is the higher bit
93 number. For example 7:0 */
94#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
95#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
96#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
97#define FLD_MOD(orig, val, start, end) \
98 (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
99
100#define DISPC_MAX_FCK 173000000
101
102enum omap_burst_size {
103 OMAP_DSS_BURST_4x32 = 0,
104 OMAP_DSS_BURST_8x32 = 1,
105 OMAP_DSS_BURST_16x32 = 2,
106};
107
108enum omap_parallel_interface_mode {
109 OMAP_DSS_PARALLELMODE_BYPASS, /* MIPI DPI */
110 OMAP_DSS_PARALLELMODE_RFBI, /* MIPI DBI */
111 OMAP_DSS_PARALLELMODE_DSI,
112};
113
114enum dss_clock {
115 DSS_CLK_ICK = 1 << 0,
116 DSS_CLK_FCK1 = 1 << 1,
117 DSS_CLK_FCK2 = 1 << 2,
118 DSS_CLK_54M = 1 << 3,
119 DSS_CLK_96M = 1 << 4,
120};
121
122struct dss_clock_info {
123 /* rates that we get with dividers below */
124 unsigned long fck;
125
126 /* dividers */
127 u16 fck_div;
128};
129
130struct dispc_clock_info {
131 /* rates that we get with dividers below */
132 unsigned long lck;
133 unsigned long pck;
134
135 /* dividers */
136 u16 lck_div;
137 u16 pck_div;
138};
139
140struct dsi_clock_info {
141 /* rates that we get with dividers below */
142 unsigned long fint;
143 unsigned long clkin4ddr;
144 unsigned long clkin;
145 unsigned long dsi1_pll_fclk;
146 unsigned long dsi2_pll_fclk;
147
148 unsigned long lp_clk;
149
150 /* dividers */
151 u16 regn;
152 u16 regm;
153 u16 regm3;
154 u16 regm4;
155
156 u16 lp_clk_div;
157
158 u8 highfreq;
159 bool use_dss2_fck;
160};
161
162struct seq_file;
163struct platform_device;
164
165/* core */
166void dss_clk_enable(enum dss_clock clks);
167void dss_clk_disable(enum dss_clock clks);
168unsigned long dss_clk_get_rate(enum dss_clock clk);
169int dss_need_ctx_restore(void);
170void dss_dump_clocks(struct seq_file *s);
171struct bus_type *dss_get_bus(void);
172
173/* display */
174int dss_suspend_all_devices(void);
175int dss_resume_all_devices(void);
176void dss_disable_all_devices(void);
177
178void dss_init_device(struct platform_device *pdev,
179 struct omap_dss_device *dssdev);
180void dss_uninit_device(struct platform_device *pdev,
181 struct omap_dss_device *dssdev);
182bool dss_use_replication(struct omap_dss_device *dssdev,
183 enum omap_color_mode mode);
184void default_get_overlay_fifo_thresholds(enum omap_plane plane,
185 u32 fifo_size, enum omap_burst_size *burst_size,
186 u32 *fifo_low, u32 *fifo_high);
187
188/* manager */
189int dss_init_overlay_managers(struct platform_device *pdev);
190void dss_uninit_overlay_managers(struct platform_device *pdev);
191int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
192void dss_setup_partial_planes(struct omap_dss_device *dssdev,
193 u16 *x, u16 *y, u16 *w, u16 *h);
194void dss_start_update(struct omap_dss_device *dssdev);
195
196/* overlay */
197void dss_init_overlays(struct platform_device *pdev);
198void dss_uninit_overlays(struct platform_device *pdev);
199int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev);
200void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
201#ifdef L4_EXAMPLE
202void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr);
203#endif
204void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
205
206/* DSS */
207int dss_init(bool skip_init);
208void dss_exit(void);
209
210void dss_save_context(void);
211void dss_restore_context(void);
212
213void dss_dump_regs(struct seq_file *s);
214
215void dss_sdi_init(u8 datapairs);
216int dss_sdi_enable(void);
217void dss_sdi_disable(void);
218
219void dss_select_clk_source(bool dsi, bool dispc);
220int dss_get_dsi_clk_source(void);
221int dss_get_dispc_clk_source(void);
222void dss_set_venc_output(enum omap_dss_venc_type type);
223void dss_set_dac_pwrdn_bgz(bool enable);
224
225unsigned long dss_get_dpll4_rate(void);
226int dss_calc_clock_rates(struct dss_clock_info *cinfo);
227int dss_set_clock_div(struct dss_clock_info *cinfo);
228int dss_get_clock_div(struct dss_clock_info *cinfo);
229int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
230 struct dss_clock_info *dss_cinfo,
231 struct dispc_clock_info *dispc_cinfo);
232
233/* SDI */
234int sdi_init(bool skip_init);
235void sdi_exit(void);
236int sdi_init_display(struct omap_dss_device *display);
237
238/* DSI */
239int dsi_init(struct platform_device *pdev);
240void dsi_exit(void);
241
242void dsi_dump_clocks(struct seq_file *s);
243void dsi_dump_regs(struct seq_file *s);
244
245void dsi_save_context(void);
246void dsi_restore_context(void);
247
248int dsi_init_display(struct omap_dss_device *display);
249void dsi_irq_handler(void);
250unsigned long dsi_get_dsi1_pll_rate(void);
251int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo);
252int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
253 struct dsi_clock_info *cinfo,
254 struct dispc_clock_info *dispc_cinfo);
255int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
256 bool enable_hsdiv);
257void dsi_pll_uninit(void);
258void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
259 u32 fifo_size, enum omap_burst_size *burst_size,
260 u32 *fifo_low, u32 *fifo_high);
261
262/* DPI */
263int dpi_init(void);
264void dpi_exit(void);
265int dpi_init_display(struct omap_dss_device *dssdev);
266
267/* DISPC */
268int dispc_init(void);
269void dispc_exit(void);
270void dispc_dump_clocks(struct seq_file *s);
271void dispc_dump_regs(struct seq_file *s);
272void dispc_irq_handler(void);
273void dispc_fake_vsync_irq(void);
274
275void dispc_save_context(void);
276void dispc_restore_context(void);
277
278void dispc_enable_sidle(void);
279void dispc_disable_sidle(void);
280
281void dispc_lcd_enable_signal_polarity(bool act_high);
282void dispc_lcd_enable_signal(bool enable);
283void dispc_pck_free_enable(bool enable);
284void dispc_enable_fifohandcheck(bool enable);
285
286void dispc_set_lcd_size(u16 width, u16 height);
287void dispc_set_digit_size(u16 width, u16 height);
288u32 dispc_get_plane_fifo_size(enum omap_plane plane);
289void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
290void dispc_enable_fifomerge(bool enable);
291void dispc_set_burst_size(enum omap_plane plane,
292 enum omap_burst_size burst_size);
293
294void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr);
295void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
296void dispc_set_plane_pos(enum omap_plane plane, u16 x, u16 y);
297void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height);
298void dispc_set_channel_out(enum omap_plane plane,
299 enum omap_channel channel_out);
300
301int dispc_setup_plane(enum omap_plane plane,
302 u32 paddr, u16 screen_width,
303 u16 pos_x, u16 pos_y,
304 u16 width, u16 height,
305 u16 out_width, u16 out_height,
306 enum omap_color_mode color_mode,
307 bool ilace,
308 enum omap_dss_rotation_type rotation_type,
309 u8 rotation, bool mirror,
310 u8 global_alpha);
311
312bool dispc_go_busy(enum omap_channel channel);
313void dispc_go(enum omap_channel channel);
314void dispc_enable_lcd_out(bool enable);
315void dispc_enable_digit_out(bool enable);
316int dispc_enable_plane(enum omap_plane plane, bool enable);
317void dispc_enable_replication(enum omap_plane plane, bool enable);
318
319void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode);
320void dispc_set_tft_data_lines(u8 data_lines);
321void dispc_set_lcd_display_type(enum omap_lcd_display_type type);
322void dispc_set_loadmode(enum omap_dss_load_mode mode);
323
324void dispc_set_default_color(enum omap_channel channel, u32 color);
325u32 dispc_get_default_color(enum omap_channel channel);
326void dispc_set_trans_key(enum omap_channel ch,
327 enum omap_dss_trans_key_type type,
328 u32 trans_key);
329void dispc_get_trans_key(enum omap_channel ch,
330 enum omap_dss_trans_key_type *type,
331 u32 *trans_key);
332void dispc_enable_trans_key(enum omap_channel ch, bool enable);
333void dispc_enable_alpha_blending(enum omap_channel ch, bool enable);
334bool dispc_trans_key_enabled(enum omap_channel ch);
335bool dispc_alpha_blending_enabled(enum omap_channel ch);
336
337bool dispc_lcd_timings_ok(struct omap_video_timings *timings);
338void dispc_set_lcd_timings(struct omap_video_timings *timings);
339unsigned long dispc_fclk_rate(void);
340unsigned long dispc_lclk_rate(void);
341unsigned long dispc_pclk_rate(void);
342void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb);
343void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
344 struct dispc_clock_info *cinfo);
345int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
346 struct dispc_clock_info *cinfo);
347int dispc_set_clock_div(struct dispc_clock_info *cinfo);
348int dispc_get_clock_div(struct dispc_clock_info *cinfo);
349
350
351/* VENC */
352int venc_init(struct platform_device *pdev);
353void venc_exit(void);
354void venc_dump_regs(struct seq_file *s);
355int venc_init_display(struct omap_dss_device *display);
356
357/* RFBI */
358int rfbi_init(void);
359void rfbi_exit(void);
360void rfbi_dump_regs(struct seq_file *s);
361
362int rfbi_configure(int rfbi_module, int bpp, int lines);
363void rfbi_enable_rfbi(bool enable);
364void rfbi_transfer_area(u16 width, u16 height,
365 void (callback)(void *data), void *data);
366void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
367unsigned long rfbi_get_max_tx_rate(void);
368int rfbi_init_display(struct omap_dss_device *display);
369
370#endif
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
new file mode 100644
index 000000000000..27d9c465c851
--- /dev/null
+++ b/drivers/video/omap2/dss/manager.c
@@ -0,0 +1,1487 @@
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/module.h>
27#include <linux/platform_device.h>
28#include <linux/spinlock.h>
29#include <linux/jiffies.h>
30
31#include <plat/display.h>
32#include <plat/cpu.h>
33
34#include "dss.h"
35
36static int num_managers;
37static struct list_head manager_list;
38
39static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
40{
41 return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
42}
43
44static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
45{
46 return snprintf(buf, PAGE_SIZE, "%s\n",
47 mgr->device ? mgr->device->name : "<none>");
48}
49
50static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
51 const char *buf, size_t size)
52{
53 int r = 0;
54 size_t len = size;
55 struct omap_dss_device *dssdev = NULL;
56
57 int match(struct omap_dss_device *dssdev, void *data)
58 {
59 const char *str = data;
60 return sysfs_streq(dssdev->name, str);
61 }
62
63 if (buf[size-1] == '\n')
64 --len;
65
66 if (len > 0)
67 dssdev = omap_dss_find_device((void *)buf, match);
68
69 if (len > 0 && dssdev == NULL)
70 return -EINVAL;
71
72 if (dssdev)
73 DSSDBG("display %s found\n", dssdev->name);
74
75 if (mgr->device) {
76 r = mgr->unset_device(mgr);
77 if (r) {
78 DSSERR("failed to unset display\n");
79 goto put_device;
80 }
81 }
82
83 if (dssdev) {
84 r = mgr->set_device(mgr, dssdev);
85 if (r) {
86 DSSERR("failed to set manager\n");
87 goto put_device;
88 }
89
90 r = mgr->apply(mgr);
91 if (r) {
92 DSSERR("failed to apply dispc config\n");
93 goto put_device;
94 }
95 }
96
97put_device:
98 if (dssdev)
99 omap_dss_put_device(dssdev);
100
101 return r ? r : size;
102}
103
104static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
105 char *buf)
106{
107 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.default_color);
108}
109
110static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
111 const char *buf, size_t size)
112{
113 struct omap_overlay_manager_info info;
114 u32 color;
115 int r;
116
117 if (sscanf(buf, "%d", &color) != 1)
118 return -EINVAL;
119
120 mgr->get_manager_info(mgr, &info);
121
122 info.default_color = color;
123
124 r = mgr->set_manager_info(mgr, &info);
125 if (r)
126 return r;
127
128 r = mgr->apply(mgr);
129 if (r)
130 return r;
131
132 return size;
133}
134
135static const char *trans_key_type_str[] = {
136 "gfx-destination",
137 "video-source",
138};
139
140static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
141 char *buf)
142{
143 enum omap_dss_trans_key_type key_type;
144
145 key_type = mgr->info.trans_key_type;
146 BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
147
148 return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
149}
150
151static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
152 const char *buf, size_t size)
153{
154 enum omap_dss_trans_key_type key_type;
155 struct omap_overlay_manager_info info;
156 int r;
157
158 for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
159 key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
160 if (sysfs_streq(buf, trans_key_type_str[key_type]))
161 break;
162 }
163
164 if (key_type == ARRAY_SIZE(trans_key_type_str))
165 return -EINVAL;
166
167 mgr->get_manager_info(mgr, &info);
168
169 info.trans_key_type = key_type;
170
171 r = mgr->set_manager_info(mgr, &info);
172 if (r)
173 return r;
174
175 r = mgr->apply(mgr);
176 if (r)
177 return r;
178
179 return size;
180}
181
182static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
183 char *buf)
184{
185 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_key);
186}
187
188static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
189 const char *buf, size_t size)
190{
191 struct omap_overlay_manager_info info;
192 u32 key_value;
193 int r;
194
195 if (sscanf(buf, "%d", &key_value) != 1)
196 return -EINVAL;
197
198 mgr->get_manager_info(mgr, &info);
199
200 info.trans_key = key_value;
201
202 r = mgr->set_manager_info(mgr, &info);
203 if (r)
204 return r;
205
206 r = mgr->apply(mgr);
207 if (r)
208 return r;
209
210 return size;
211}
212
213static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
214 char *buf)
215{
216 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled);
217}
218
219static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
220 const char *buf, size_t size)
221{
222 struct omap_overlay_manager_info info;
223 int enable;
224 int r;
225
226 if (sscanf(buf, "%d", &enable) != 1)
227 return -EINVAL;
228
229 mgr->get_manager_info(mgr, &info);
230
231 info.trans_enabled = enable ? true : false;
232
233 r = mgr->set_manager_info(mgr, &info);
234 if (r)
235 return r;
236
237 r = mgr->apply(mgr);
238 if (r)
239 return r;
240
241 return size;
242}
243
244static ssize_t manager_alpha_blending_enabled_show(
245 struct omap_overlay_manager *mgr, char *buf)
246{
247 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.alpha_enabled);
248}
249
250static ssize_t manager_alpha_blending_enabled_store(
251 struct omap_overlay_manager *mgr,
252 const char *buf, size_t size)
253{
254 struct omap_overlay_manager_info info;
255 int enable;
256 int r;
257
258 if (sscanf(buf, "%d", &enable) != 1)
259 return -EINVAL;
260
261 mgr->get_manager_info(mgr, &info);
262
263 info.alpha_enabled = enable ? true : false;
264
265 r = mgr->set_manager_info(mgr, &info);
266 if (r)
267 return r;
268
269 r = mgr->apply(mgr);
270 if (r)
271 return r;
272
273 return size;
274}
275
276struct manager_attribute {
277 struct attribute attr;
278 ssize_t (*show)(struct omap_overlay_manager *, char *);
279 ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
280};
281
282#define MANAGER_ATTR(_name, _mode, _show, _store) \
283 struct manager_attribute manager_attr_##_name = \
284 __ATTR(_name, _mode, _show, _store)
285
286static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
287static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
288 manager_display_show, manager_display_store);
289static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
290 manager_default_color_show, manager_default_color_store);
291static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
292 manager_trans_key_type_show, manager_trans_key_type_store);
293static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
294 manager_trans_key_value_show, manager_trans_key_value_store);
295static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
296 manager_trans_key_enabled_show,
297 manager_trans_key_enabled_store);
298static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
299 manager_alpha_blending_enabled_show,
300 manager_alpha_blending_enabled_store);
301
302
303static struct attribute *manager_sysfs_attrs[] = {
304 &manager_attr_name.attr,
305 &manager_attr_display.attr,
306 &manager_attr_default_color.attr,
307 &manager_attr_trans_key_type.attr,
308 &manager_attr_trans_key_value.attr,
309 &manager_attr_trans_key_enabled.attr,
310 &manager_attr_alpha_blending_enabled.attr,
311 NULL
312};
313
314static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
315 char *buf)
316{
317 struct omap_overlay_manager *manager;
318 struct manager_attribute *manager_attr;
319
320 manager = container_of(kobj, struct omap_overlay_manager, kobj);
321 manager_attr = container_of(attr, struct manager_attribute, attr);
322
323 if (!manager_attr->show)
324 return -ENOENT;
325
326 return manager_attr->show(manager, buf);
327}
328
329static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
330 const char *buf, size_t size)
331{
332 struct omap_overlay_manager *manager;
333 struct manager_attribute *manager_attr;
334
335 manager = container_of(kobj, struct omap_overlay_manager, kobj);
336 manager_attr = container_of(attr, struct manager_attribute, attr);
337
338 if (!manager_attr->store)
339 return -ENOENT;
340
341 return manager_attr->store(manager, buf, size);
342}
343
344static struct sysfs_ops manager_sysfs_ops = {
345 .show = manager_attr_show,
346 .store = manager_attr_store,
347};
348
349static struct kobj_type manager_ktype = {
350 .sysfs_ops = &manager_sysfs_ops,
351 .default_attrs = manager_sysfs_attrs,
352};
353
354/*
355 * We have 4 levels of cache for the dispc settings. First two are in SW and
356 * the latter two in HW.
357 *
358 * +--------------------+
359 * |overlay/manager_info|
360 * +--------------------+
361 * v
362 * apply()
363 * v
364 * +--------------------+
365 * | dss_cache |
366 * +--------------------+
367 * v
368 * configure()
369 * v
370 * +--------------------+
371 * | shadow registers |
372 * +--------------------+
373 * v
374 * VFP or lcd/digit_enable
375 * v
376 * +--------------------+
377 * | registers |
378 * +--------------------+
379 */
380
381struct overlay_cache_data {
382 /* If true, cache changed, but not written to shadow registers. Set
383 * in apply(), cleared when registers written. */
384 bool dirty;
385 /* If true, shadow registers contain changed values not yet in real
386 * registers. Set when writing to shadow registers, cleared at
387 * VSYNC/EVSYNC */
388 bool shadow_dirty;
389
390 bool enabled;
391
392 u32 paddr;
393 void __iomem *vaddr;
394 u16 screen_width;
395 u16 width;
396 u16 height;
397 enum omap_color_mode color_mode;
398 u8 rotation;
399 enum omap_dss_rotation_type rotation_type;
400 bool mirror;
401
402 u16 pos_x;
403 u16 pos_y;
404 u16 out_width; /* if 0, out_width == width */
405 u16 out_height; /* if 0, out_height == height */
406 u8 global_alpha;
407
408 enum omap_channel channel;
409 bool replication;
410 bool ilace;
411
412 enum omap_burst_size burst_size;
413 u32 fifo_low;
414 u32 fifo_high;
415
416 bool manual_update;
417};
418
419struct manager_cache_data {
420 /* If true, cache changed, but not written to shadow registers. Set
421 * in apply(), cleared when registers written. */
422 bool dirty;
423 /* If true, shadow registers contain changed values not yet in real
424 * registers. Set when writing to shadow registers, cleared at
425 * VSYNC/EVSYNC */
426 bool shadow_dirty;
427
428 u32 default_color;
429
430 enum omap_dss_trans_key_type trans_key_type;
431 u32 trans_key;
432 bool trans_enabled;
433
434 bool alpha_enabled;
435
436 bool manual_upd_display;
437 bool manual_update;
438 bool do_manual_update;
439
440 /* manual update region */
441 u16 x, y, w, h;
442};
443
444static struct {
445 spinlock_t lock;
446 struct overlay_cache_data overlay_cache[3];
447 struct manager_cache_data manager_cache[2];
448
449 bool irq_enabled;
450} dss_cache;
451
452
453
454static int omap_dss_set_device(struct omap_overlay_manager *mgr,
455 struct omap_dss_device *dssdev)
456{
457 int i;
458 int r;
459
460 if (dssdev->manager) {
461 DSSERR("display '%s' already has a manager '%s'\n",
462 dssdev->name, dssdev->manager->name);
463 return -EINVAL;
464 }
465
466 if ((mgr->supported_displays & dssdev->type) == 0) {
467 DSSERR("display '%s' does not support manager '%s'\n",
468 dssdev->name, mgr->name);
469 return -EINVAL;
470 }
471
472 for (i = 0; i < mgr->num_overlays; i++) {
473 struct omap_overlay *ovl = mgr->overlays[i];
474
475 if (ovl->manager != mgr || !ovl->info.enabled)
476 continue;
477
478 r = dss_check_overlay(ovl, dssdev);
479 if (r)
480 return r;
481 }
482
483 dssdev->manager = mgr;
484 mgr->device = dssdev;
485 mgr->device_changed = true;
486
487 return 0;
488}
489
490static int omap_dss_unset_device(struct omap_overlay_manager *mgr)
491{
492 if (!mgr->device) {
493 DSSERR("failed to unset display, display not set.\n");
494 return -EINVAL;
495 }
496
497 mgr->device->manager = NULL;
498 mgr->device = NULL;
499 mgr->device_changed = true;
500
501 return 0;
502}
503
504static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
505{
506 unsigned long timeout = msecs_to_jiffies(500);
507 struct manager_cache_data *mc;
508 enum omap_channel channel;
509 u32 irq;
510 int r;
511 int i;
512
513 if (!mgr->device)
514 return 0;
515
516 if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
517 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
518 channel = OMAP_DSS_CHANNEL_DIGIT;
519 } else {
520 if (mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
521 enum omap_dss_update_mode mode;
522 mode = mgr->device->get_update_mode(mgr->device);
523 if (mode != OMAP_DSS_UPDATE_AUTO)
524 return 0;
525
526 irq = DISPC_IRQ_FRAMEDONE;
527 } else {
528 irq = DISPC_IRQ_VSYNC;
529 }
530 channel = OMAP_DSS_CHANNEL_LCD;
531 }
532
533 mc = &dss_cache.manager_cache[mgr->id];
534 i = 0;
535 while (1) {
536 unsigned long flags;
537 bool shadow_dirty, dirty;
538
539 spin_lock_irqsave(&dss_cache.lock, flags);
540 dirty = mc->dirty;
541 shadow_dirty = mc->shadow_dirty;
542 spin_unlock_irqrestore(&dss_cache.lock, flags);
543
544 if (!dirty && !shadow_dirty) {
545 r = 0;
546 break;
547 }
548
549 /* 4 iterations is the worst case:
550 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
551 * 2 - first VSYNC, dirty = true
552 * 3 - dirty = false, shadow_dirty = true
553 * 4 - shadow_dirty = false */
554 if (i++ == 3) {
555 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
556 mgr->id);
557 r = 0;
558 break;
559 }
560
561 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
562 if (r == -ERESTARTSYS)
563 break;
564
565 if (r) {
566 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
567 break;
568 }
569 }
570
571 return r;
572}
573
574int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
575{
576 unsigned long timeout = msecs_to_jiffies(500);
577 enum omap_channel channel;
578 struct overlay_cache_data *oc;
579 struct omap_dss_device *dssdev;
580 u32 irq;
581 int r;
582 int i;
583
584 if (!ovl->manager || !ovl->manager->device)
585 return 0;
586
587 dssdev = ovl->manager->device;
588
589 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
590 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
591 channel = OMAP_DSS_CHANNEL_DIGIT;
592 } else {
593 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
594 enum omap_dss_update_mode mode;
595 mode = dssdev->get_update_mode(dssdev);
596 if (mode != OMAP_DSS_UPDATE_AUTO)
597 return 0;
598
599 irq = DISPC_IRQ_FRAMEDONE;
600 } else {
601 irq = DISPC_IRQ_VSYNC;
602 }
603 channel = OMAP_DSS_CHANNEL_LCD;
604 }
605
606 oc = &dss_cache.overlay_cache[ovl->id];
607 i = 0;
608 while (1) {
609 unsigned long flags;
610 bool shadow_dirty, dirty;
611
612 spin_lock_irqsave(&dss_cache.lock, flags);
613 dirty = oc->dirty;
614 shadow_dirty = oc->shadow_dirty;
615 spin_unlock_irqrestore(&dss_cache.lock, flags);
616
617 if (!dirty && !shadow_dirty) {
618 r = 0;
619 break;
620 }
621
622 /* 4 iterations is the worst case:
623 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
624 * 2 - first VSYNC, dirty = true
625 * 3 - dirty = false, shadow_dirty = true
626 * 4 - shadow_dirty = false */
627 if (i++ == 3) {
628 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
629 ovl->id);
630 r = 0;
631 break;
632 }
633
634 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
635 if (r == -ERESTARTSYS)
636 break;
637
638 if (r) {
639 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
640 break;
641 }
642 }
643
644 return r;
645}
646
647static int overlay_enabled(struct omap_overlay *ovl)
648{
649 return ovl->info.enabled && ovl->manager && ovl->manager->device;
650}
651
652/* Is rect1 a subset of rect2? */
653static bool rectangle_subset(int x1, int y1, int w1, int h1,
654 int x2, int y2, int w2, int h2)
655{
656 if (x1 < x2 || y1 < y2)
657 return false;
658
659 if (x1 + w1 > x2 + w2)
660 return false;
661
662 if (y1 + h1 > y2 + h2)
663 return false;
664
665 return true;
666}
667
668/* Do rect1 and rect2 overlap? */
669static bool rectangle_intersects(int x1, int y1, int w1, int h1,
670 int x2, int y2, int w2, int h2)
671{
672 if (x1 >= x2 + w2)
673 return false;
674
675 if (x2 >= x1 + w1)
676 return false;
677
678 if (y1 >= y2 + h2)
679 return false;
680
681 if (y2 >= y1 + h1)
682 return false;
683
684 return true;
685}
686
687static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
688{
689 if (oc->out_width != 0 && oc->width != oc->out_width)
690 return true;
691
692 if (oc->out_height != 0 && oc->height != oc->out_height)
693 return true;
694
695 return false;
696}
697
698static int configure_overlay(enum omap_plane plane)
699{
700 struct overlay_cache_data *c;
701 struct manager_cache_data *mc;
702 u16 outw, outh;
703 u16 x, y, w, h;
704 u32 paddr;
705 int r;
706
707 DSSDBGF("%d", plane);
708
709 c = &dss_cache.overlay_cache[plane];
710
711 if (!c->enabled) {
712 dispc_enable_plane(plane, 0);
713 return 0;
714 }
715
716 mc = &dss_cache.manager_cache[c->channel];
717
718 x = c->pos_x;
719 y = c->pos_y;
720 w = c->width;
721 h = c->height;
722 outw = c->out_width == 0 ? c->width : c->out_width;
723 outh = c->out_height == 0 ? c->height : c->out_height;
724 paddr = c->paddr;
725
726 if (c->manual_update && mc->do_manual_update) {
727 unsigned bpp;
728 /* If the overlay is outside the update region, disable it */
729 if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
730 x, y, outw, outh)) {
731 dispc_enable_plane(plane, 0);
732 return 0;
733 }
734
735 switch (c->color_mode) {
736 case OMAP_DSS_COLOR_RGB16:
737 case OMAP_DSS_COLOR_ARGB16:
738 case OMAP_DSS_COLOR_YUV2:
739 case OMAP_DSS_COLOR_UYVY:
740 bpp = 16;
741 break;
742
743 case OMAP_DSS_COLOR_RGB24P:
744 bpp = 24;
745 break;
746
747 case OMAP_DSS_COLOR_RGB24U:
748 case OMAP_DSS_COLOR_ARGB32:
749 case OMAP_DSS_COLOR_RGBA32:
750 case OMAP_DSS_COLOR_RGBX32:
751 bpp = 32;
752 break;
753
754 default:
755 BUG();
756 }
757
758 if (dispc_is_overlay_scaled(c)) {
759 /* If the overlay is scaled, the update area has
760 * already been enlarged to cover the whole overlay. We
761 * only need to adjust x/y here */
762 x = c->pos_x - mc->x;
763 y = c->pos_y - mc->y;
764 } else {
765 if (mc->x > c->pos_x) {
766 x = 0;
767 w -= (mc->x - c->pos_x);
768 paddr += (mc->x - c->pos_x) * bpp / 8;
769 } else {
770 x = c->pos_x - mc->x;
771 }
772
773 if (mc->y > c->pos_y) {
774 y = 0;
775 h -= (mc->y - c->pos_y);
776 paddr += (mc->y - c->pos_y) * c->screen_width *
777 bpp / 8;
778 } else {
779 y = c->pos_y - mc->y;
780 }
781
782 if (mc->w < (x+w))
783 w -= (x+w) - (mc->w);
784
785 if (mc->h < (y+h))
786 h -= (y+h) - (mc->h);
787
788 outw = w;
789 outh = h;
790 }
791 }
792
793 r = dispc_setup_plane(plane,
794 paddr,
795 c->screen_width,
796 x, y,
797 w, h,
798 outw, outh,
799 c->color_mode,
800 c->ilace,
801 c->rotation_type,
802 c->rotation,
803 c->mirror,
804 c->global_alpha);
805
806 if (r) {
807 /* this shouldn't happen */
808 DSSERR("dispc_setup_plane failed for ovl %d\n", plane);
809 dispc_enable_plane(plane, 0);
810 return r;
811 }
812
813 dispc_enable_replication(plane, c->replication);
814
815 dispc_set_burst_size(plane, c->burst_size);
816 dispc_setup_plane_fifo(plane, c->fifo_low, c->fifo_high);
817
818 dispc_enable_plane(plane, 1);
819
820 return 0;
821}
822
823static void configure_manager(enum omap_channel channel)
824{
825 struct manager_cache_data *c;
826
827 DSSDBGF("%d", channel);
828
829 c = &dss_cache.manager_cache[channel];
830
831 dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
832 dispc_enable_trans_key(channel, c->trans_enabled);
833 dispc_enable_alpha_blending(channel, c->alpha_enabled);
834}
835
836/* configure_dispc() tries to write values from cache to shadow registers.
837 * It writes only to those managers/overlays that are not busy.
838 * returns 0 if everything could be written to shadow registers.
839 * returns 1 if not everything could be written to shadow registers. */
840static int configure_dispc(void)
841{
842 struct overlay_cache_data *oc;
843 struct manager_cache_data *mc;
844 const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
845 const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
846 int i;
847 int r;
848 bool mgr_busy[2];
849 bool mgr_go[2];
850 bool busy;
851
852 r = 0;
853 busy = false;
854
855 mgr_busy[0] = dispc_go_busy(0);
856 mgr_busy[1] = dispc_go_busy(1);
857 mgr_go[0] = false;
858 mgr_go[1] = false;
859
860 /* Commit overlay settings */
861 for (i = 0; i < num_ovls; ++i) {
862 oc = &dss_cache.overlay_cache[i];
863 mc = &dss_cache.manager_cache[oc->channel];
864
865 if (!oc->dirty)
866 continue;
867
868 if (oc->manual_update && !mc->do_manual_update)
869 continue;
870
871 if (mgr_busy[oc->channel]) {
872 busy = true;
873 continue;
874 }
875
876 r = configure_overlay(i);
877 if (r)
878 DSSERR("configure_overlay %d failed\n", i);
879
880 oc->dirty = false;
881 oc->shadow_dirty = true;
882 mgr_go[oc->channel] = true;
883 }
884
885 /* Commit manager settings */
886 for (i = 0; i < num_mgrs; ++i) {
887 mc = &dss_cache.manager_cache[i];
888
889 if (!mc->dirty)
890 continue;
891
892 if (mc->manual_update && !mc->do_manual_update)
893 continue;
894
895 if (mgr_busy[i]) {
896 busy = true;
897 continue;
898 }
899
900 configure_manager(i);
901 mc->dirty = false;
902 mc->shadow_dirty = true;
903 mgr_go[i] = true;
904 }
905
906 /* set GO */
907 for (i = 0; i < num_mgrs; ++i) {
908 mc = &dss_cache.manager_cache[i];
909
910 if (!mgr_go[i])
911 continue;
912
913 /* We don't need GO with manual update display. LCD iface will
914 * always be turned off after frame, and new settings will be
915 * taken in to use at next update */
916 if (!mc->manual_upd_display)
917 dispc_go(i);
918 }
919
920 if (busy)
921 r = 1;
922 else
923 r = 0;
924
925 return r;
926}
927
928/* Configure dispc for partial update. Return possibly modified update
929 * area */
930void dss_setup_partial_planes(struct omap_dss_device *dssdev,
931 u16 *xi, u16 *yi, u16 *wi, u16 *hi)
932{
933 struct overlay_cache_data *oc;
934 struct manager_cache_data *mc;
935 const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
936 struct omap_overlay_manager *mgr;
937 int i;
938 u16 x, y, w, h;
939 unsigned long flags;
940
941 x = *xi;
942 y = *yi;
943 w = *wi;
944 h = *hi;
945
946 DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n",
947 *xi, *yi, *wi, *hi);
948
949 mgr = dssdev->manager;
950
951 if (!mgr) {
952 DSSDBG("no manager\n");
953 return;
954 }
955
956 spin_lock_irqsave(&dss_cache.lock, flags);
957
958 /* We need to show the whole overlay if it is scaled. So look for
959 * those, and make the update area larger if found.
960 * Also mark the overlay cache dirty */
961 for (i = 0; i < num_ovls; ++i) {
962 unsigned x1, y1, x2, y2;
963 unsigned outw, outh;
964
965 oc = &dss_cache.overlay_cache[i];
966
967 if (oc->channel != mgr->id)
968 continue;
969
970 oc->dirty = true;
971
972 if (!oc->enabled)
973 continue;
974
975 if (!dispc_is_overlay_scaled(oc))
976 continue;
977
978 outw = oc->out_width == 0 ? oc->width : oc->out_width;
979 outh = oc->out_height == 0 ? oc->height : oc->out_height;
980
981 /* is the overlay outside the update region? */
982 if (!rectangle_intersects(x, y, w, h,
983 oc->pos_x, oc->pos_y,
984 outw, outh))
985 continue;
986
987 /* if the overlay totally inside the update region? */
988 if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
989 x, y, w, h))
990 continue;
991
992 if (x > oc->pos_x)
993 x1 = oc->pos_x;
994 else
995 x1 = x;
996
997 if (y > oc->pos_y)
998 y1 = oc->pos_y;
999 else
1000 y1 = y;
1001
1002 if ((x + w) < (oc->pos_x + outw))
1003 x2 = oc->pos_x + outw;
1004 else
1005 x2 = x + w;
1006
1007 if ((y + h) < (oc->pos_y + outh))
1008 y2 = oc->pos_y + outh;
1009 else
1010 y2 = y + h;
1011
1012 x = x1;
1013 y = y1;
1014 w = x2 - x1;
1015 h = y2 - y1;
1016
1017 DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n",
1018 i, x, y, w, h);
1019 }
1020
1021 mc = &dss_cache.manager_cache[mgr->id];
1022 mc->do_manual_update = true;
1023 mc->x = x;
1024 mc->y = y;
1025 mc->w = w;
1026 mc->h = h;
1027
1028 configure_dispc();
1029
1030 mc->do_manual_update = false;
1031
1032 spin_unlock_irqrestore(&dss_cache.lock, flags);
1033
1034 *xi = x;
1035 *yi = y;
1036 *wi = w;
1037 *hi = h;
1038}
1039
1040void dss_start_update(struct omap_dss_device *dssdev)
1041{
1042 struct manager_cache_data *mc;
1043 struct overlay_cache_data *oc;
1044 const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
1045 const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
1046 struct omap_overlay_manager *mgr;
1047 int i;
1048
1049 mgr = dssdev->manager;
1050
1051 for (i = 0; i < num_ovls; ++i) {
1052 oc = &dss_cache.overlay_cache[i];
1053 if (oc->channel != mgr->id)
1054 continue;
1055
1056 oc->shadow_dirty = false;
1057 }
1058
1059 for (i = 0; i < num_mgrs; ++i) {
1060 mc = &dss_cache.manager_cache[i];
1061 if (mgr->id != i)
1062 continue;
1063
1064 mc->shadow_dirty = false;
1065 }
1066
1067 dispc_enable_lcd_out(1);
1068}
1069
1070static void dss_apply_irq_handler(void *data, u32 mask)
1071{
1072 struct manager_cache_data *mc;
1073 struct overlay_cache_data *oc;
1074 const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
1075 const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
1076 int i, r;
1077 bool mgr_busy[2];
1078
1079 mgr_busy[0] = dispc_go_busy(0);
1080 mgr_busy[1] = dispc_go_busy(1);
1081
1082 spin_lock(&dss_cache.lock);
1083
1084 for (i = 0; i < num_ovls; ++i) {
1085 oc = &dss_cache.overlay_cache[i];
1086 if (!mgr_busy[oc->channel])
1087 oc->shadow_dirty = false;
1088 }
1089
1090 for (i = 0; i < num_mgrs; ++i) {
1091 mc = &dss_cache.manager_cache[i];
1092 if (!mgr_busy[i])
1093 mc->shadow_dirty = false;
1094 }
1095
1096 r = configure_dispc();
1097 if (r == 1)
1098 goto end;
1099
1100 /* re-read busy flags */
1101 mgr_busy[0] = dispc_go_busy(0);
1102 mgr_busy[1] = dispc_go_busy(1);
1103
1104 /* keep running as long as there are busy managers, so that
1105 * we can collect overlay-applied information */
1106 for (i = 0; i < num_mgrs; ++i) {
1107 if (mgr_busy[i])
1108 goto end;
1109 }
1110
1111 omap_dispc_unregister_isr(dss_apply_irq_handler, NULL,
1112 DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1113 DISPC_IRQ_EVSYNC_EVEN);
1114 dss_cache.irq_enabled = false;
1115
1116end:
1117 spin_unlock(&dss_cache.lock);
1118}
1119
1120static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
1121{
1122 struct overlay_cache_data *oc;
1123 struct manager_cache_data *mc;
1124 int i;
1125 struct omap_overlay *ovl;
1126 int num_planes_enabled = 0;
1127 bool use_fifomerge;
1128 unsigned long flags;
1129 int r;
1130
1131 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
1132
1133 spin_lock_irqsave(&dss_cache.lock, flags);
1134
1135 /* Configure overlays */
1136 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1137 struct omap_dss_device *dssdev;
1138
1139 ovl = omap_dss_get_overlay(i);
1140
1141 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1142 continue;
1143
1144 oc = &dss_cache.overlay_cache[ovl->id];
1145
1146 if (!overlay_enabled(ovl)) {
1147 if (oc->enabled) {
1148 oc->enabled = false;
1149 oc->dirty = true;
1150 }
1151 continue;
1152 }
1153
1154 if (!ovl->info_dirty) {
1155 if (oc->enabled)
1156 ++num_planes_enabled;
1157 continue;
1158 }
1159
1160 dssdev = ovl->manager->device;
1161
1162 if (dss_check_overlay(ovl, dssdev)) {
1163 if (oc->enabled) {
1164 oc->enabled = false;
1165 oc->dirty = true;
1166 }
1167 continue;
1168 }
1169
1170 ovl->info_dirty = false;
1171 oc->dirty = true;
1172
1173 oc->paddr = ovl->info.paddr;
1174 oc->vaddr = ovl->info.vaddr;
1175 oc->screen_width = ovl->info.screen_width;
1176 oc->width = ovl->info.width;
1177 oc->height = ovl->info.height;
1178 oc->color_mode = ovl->info.color_mode;
1179 oc->rotation = ovl->info.rotation;
1180 oc->rotation_type = ovl->info.rotation_type;
1181 oc->mirror = ovl->info.mirror;
1182 oc->pos_x = ovl->info.pos_x;
1183 oc->pos_y = ovl->info.pos_y;
1184 oc->out_width = ovl->info.out_width;
1185 oc->out_height = ovl->info.out_height;
1186 oc->global_alpha = ovl->info.global_alpha;
1187
1188 oc->replication =
1189 dss_use_replication(dssdev, ovl->info.color_mode);
1190
1191 oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
1192
1193 oc->channel = ovl->manager->id;
1194
1195 oc->enabled = true;
1196
1197 oc->manual_update =
1198 dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
1199 dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
1200
1201 ++num_planes_enabled;
1202 }
1203
1204 /* Configure managers */
1205 list_for_each_entry(mgr, &manager_list, list) {
1206 struct omap_dss_device *dssdev;
1207
1208 if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC))
1209 continue;
1210
1211 mc = &dss_cache.manager_cache[mgr->id];
1212
1213 if (mgr->device_changed) {
1214 mgr->device_changed = false;
1215 mgr->info_dirty = true;
1216 }
1217
1218 if (!mgr->info_dirty)
1219 continue;
1220
1221 if (!mgr->device)
1222 continue;
1223
1224 dssdev = mgr->device;
1225
1226 mgr->info_dirty = false;
1227 mc->dirty = true;
1228
1229 mc->default_color = mgr->info.default_color;
1230 mc->trans_key_type = mgr->info.trans_key_type;
1231 mc->trans_key = mgr->info.trans_key;
1232 mc->trans_enabled = mgr->info.trans_enabled;
1233 mc->alpha_enabled = mgr->info.alpha_enabled;
1234
1235 mc->manual_upd_display =
1236 dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
1237
1238 mc->manual_update =
1239 dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
1240 dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
1241 }
1242
1243 /* XXX TODO: Try to get fifomerge working. The problem is that it
1244 * affects both managers, not individually but at the same time. This
1245 * means the change has to be well synchronized. I guess the proper way
1246 * is to have a two step process for fifo merge:
1247 * fifomerge enable:
1248 * 1. disable other planes, leaving one plane enabled
1249 * 2. wait until the planes are disabled on HW
1250 * 3. config merged fifo thresholds, enable fifomerge
1251 * fifomerge disable:
1252 * 1. config unmerged fifo thresholds, disable fifomerge
1253 * 2. wait until fifo changes are in HW
1254 * 3. enable planes
1255 */
1256 use_fifomerge = false;
1257
1258 /* Configure overlay fifos */
1259 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1260 struct omap_dss_device *dssdev;
1261 u32 size;
1262
1263 ovl = omap_dss_get_overlay(i);
1264
1265 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1266 continue;
1267
1268 oc = &dss_cache.overlay_cache[ovl->id];
1269
1270 if (!oc->enabled)
1271 continue;
1272
1273 dssdev = ovl->manager->device;
1274
1275 size = dispc_get_plane_fifo_size(ovl->id);
1276 if (use_fifomerge)
1277 size *= 3;
1278
1279 switch (dssdev->type) {
1280 case OMAP_DISPLAY_TYPE_DPI:
1281 case OMAP_DISPLAY_TYPE_DBI:
1282 case OMAP_DISPLAY_TYPE_SDI:
1283 case OMAP_DISPLAY_TYPE_VENC:
1284 default_get_overlay_fifo_thresholds(ovl->id, size,
1285 &oc->burst_size, &oc->fifo_low,
1286 &oc->fifo_high);
1287 break;
1288#ifdef CONFIG_OMAP2_DSS_DSI
1289 case OMAP_DISPLAY_TYPE_DSI:
1290 dsi_get_overlay_fifo_thresholds(ovl->id, size,
1291 &oc->burst_size, &oc->fifo_low,
1292 &oc->fifo_high);
1293 break;
1294#endif
1295 default:
1296 BUG();
1297 }
1298 }
1299
1300 r = 0;
1301 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
1302 if (!dss_cache.irq_enabled) {
1303 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL,
1304 DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1305 DISPC_IRQ_EVSYNC_EVEN);
1306 dss_cache.irq_enabled = true;
1307 }
1308 configure_dispc();
1309 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
1310
1311 spin_unlock_irqrestore(&dss_cache.lock, flags);
1312
1313 return r;
1314}
1315
1316static int dss_check_manager(struct omap_overlay_manager *mgr)
1317{
1318 /* OMAP supports only graphics source transparency color key and alpha
1319 * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */
1320
1321 if (mgr->info.alpha_enabled && mgr->info.trans_enabled &&
1322 mgr->info.trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST)
1323 return -EINVAL;
1324
1325 return 0;
1326}
1327
1328static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
1329 struct omap_overlay_manager_info *info)
1330{
1331 int r;
1332 struct omap_overlay_manager_info old_info;
1333
1334 old_info = mgr->info;
1335 mgr->info = *info;
1336
1337 r = dss_check_manager(mgr);
1338 if (r) {
1339 mgr->info = old_info;
1340 return r;
1341 }
1342
1343 mgr->info_dirty = true;
1344
1345 return 0;
1346}
1347
1348static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
1349 struct omap_overlay_manager_info *info)
1350{
1351 *info = mgr->info;
1352}
1353
1354static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
1355{
1356 ++num_managers;
1357 list_add_tail(&manager->list, &manager_list);
1358}
1359
1360int dss_init_overlay_managers(struct platform_device *pdev)
1361{
1362 int i, r;
1363
1364 spin_lock_init(&dss_cache.lock);
1365
1366 INIT_LIST_HEAD(&manager_list);
1367
1368 num_managers = 0;
1369
1370 for (i = 0; i < 2; ++i) {
1371 struct omap_overlay_manager *mgr;
1372 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1373
1374 BUG_ON(mgr == NULL);
1375
1376 switch (i) {
1377 case 0:
1378 mgr->name = "lcd";
1379 mgr->id = OMAP_DSS_CHANNEL_LCD;
1380 mgr->supported_displays =
1381 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
1382 OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI;
1383 break;
1384 case 1:
1385 mgr->name = "tv";
1386 mgr->id = OMAP_DSS_CHANNEL_DIGIT;
1387 mgr->supported_displays = OMAP_DISPLAY_TYPE_VENC;
1388 break;
1389 }
1390
1391 mgr->set_device = &omap_dss_set_device;
1392 mgr->unset_device = &omap_dss_unset_device;
1393 mgr->apply = &omap_dss_mgr_apply;
1394 mgr->set_manager_info = &omap_dss_mgr_set_info;
1395 mgr->get_manager_info = &omap_dss_mgr_get_info;
1396 mgr->wait_for_go = &dss_mgr_wait_for_go;
1397
1398 mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
1399
1400 dss_overlay_setup_dispc_manager(mgr);
1401
1402 omap_dss_add_overlay_manager(mgr);
1403
1404 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1405 &pdev->dev.kobj, "manager%d", i);
1406
1407 if (r) {
1408 DSSERR("failed to create sysfs file\n");
1409 continue;
1410 }
1411 }
1412
1413#ifdef L4_EXAMPLE
1414 {
1415 int omap_dss_mgr_apply_l4(struct omap_overlay_manager *mgr)
1416 {
1417 DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name);
1418
1419 return 0;
1420 }
1421
1422 struct omap_overlay_manager *mgr;
1423 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1424
1425 BUG_ON(mgr == NULL);
1426
1427 mgr->name = "l4";
1428 mgr->supported_displays =
1429 OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI;
1430
1431 mgr->set_device = &omap_dss_set_device;
1432 mgr->unset_device = &omap_dss_unset_device;
1433 mgr->apply = &omap_dss_mgr_apply_l4;
1434 mgr->set_manager_info = &omap_dss_mgr_set_info;
1435 mgr->get_manager_info = &omap_dss_mgr_get_info;
1436
1437 dss_overlay_setup_l4_manager(mgr);
1438
1439 omap_dss_add_overlay_manager(mgr);
1440
1441 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1442 &pdev->dev.kobj, "managerl4");
1443
1444 if (r)
1445 DSSERR("failed to create sysfs file\n");
1446 }
1447#endif
1448
1449 return 0;
1450}
1451
1452void dss_uninit_overlay_managers(struct platform_device *pdev)
1453{
1454 struct omap_overlay_manager *mgr;
1455
1456 while (!list_empty(&manager_list)) {
1457 mgr = list_first_entry(&manager_list,
1458 struct omap_overlay_manager, list);
1459 list_del(&mgr->list);
1460 kobject_del(&mgr->kobj);
1461 kobject_put(&mgr->kobj);
1462 kfree(mgr);
1463 }
1464
1465 num_managers = 0;
1466}
1467
1468int omap_dss_get_num_overlay_managers(void)
1469{
1470 return num_managers;
1471}
1472EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
1473
1474struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
1475{
1476 int i = 0;
1477 struct omap_overlay_manager *mgr;
1478
1479 list_for_each_entry(mgr, &manager_list, list) {
1480 if (i++ == num)
1481 return mgr;
1482 }
1483
1484 return NULL;
1485}
1486EXPORT_SYMBOL(omap_dss_get_overlay_manager);
1487
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
new file mode 100644
index 000000000000..b7f9a7339842
--- /dev/null
+++ b/drivers/video/omap2/dss/overlay.c
@@ -0,0 +1,680 @@
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
33#include <plat/display.h>
34#include <plat/cpu.h>
35
36#include "dss.h"
37
38static int num_overlays;
39static struct list_head overlay_list;
40
41static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
42{
43 return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
44}
45
46static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
47{
48 return snprintf(buf, PAGE_SIZE, "%s\n",
49 ovl->manager ? ovl->manager->name : "<none>");
50}
51
52static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
53 size_t size)
54{
55 int i, r;
56 struct omap_overlay_manager *mgr = NULL;
57 struct omap_overlay_manager *old_mgr;
58 int len = size;
59
60 if (buf[size-1] == '\n')
61 --len;
62
63 if (len > 0) {
64 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
65 mgr = omap_dss_get_overlay_manager(i);
66
67 if (strncmp(buf, mgr->name, len) == 0)
68 break;
69
70 mgr = NULL;
71 }
72 }
73
74 if (len > 0 && mgr == NULL)
75 return -EINVAL;
76
77 if (mgr)
78 DSSDBG("manager %s found\n", mgr->name);
79
80 if (mgr == ovl->manager)
81 return size;
82
83 old_mgr = ovl->manager;
84
85 /* detach old manager */
86 if (old_mgr) {
87 r = ovl->unset_manager(ovl);
88 if (r) {
89 DSSERR("detach failed\n");
90 return r;
91 }
92
93 r = old_mgr->apply(old_mgr);
94 if (r)
95 return r;
96 }
97
98 if (mgr) {
99 r = ovl->set_manager(ovl, mgr);
100 if (r) {
101 DSSERR("Failed to attach overlay\n");
102 return r;
103 }
104
105 r = mgr->apply(mgr);
106 if (r)
107 return r;
108 }
109
110 return size;
111}
112
113static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
114{
115 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
116 ovl->info.width, ovl->info.height);
117}
118
119static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
120{
121 return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width);
122}
123
124static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
125{
126 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
127 ovl->info.pos_x, ovl->info.pos_y);
128}
129
130static ssize_t overlay_position_store(struct omap_overlay *ovl,
131 const char *buf, size_t size)
132{
133 int r;
134 char *last;
135 struct omap_overlay_info info;
136
137 ovl->get_overlay_info(ovl, &info);
138
139 info.pos_x = simple_strtoul(buf, &last, 10);
140 ++last;
141 if (last - buf >= size)
142 return -EINVAL;
143
144 info.pos_y = simple_strtoul(last, &last, 10);
145
146 r = ovl->set_overlay_info(ovl, &info);
147 if (r)
148 return r;
149
150 if (ovl->manager) {
151 r = ovl->manager->apply(ovl->manager);
152 if (r)
153 return r;
154 }
155
156 return size;
157}
158
159static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
160{
161 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
162 ovl->info.out_width, ovl->info.out_height);
163}
164
165static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
166 const char *buf, size_t size)
167{
168 int r;
169 char *last;
170 struct omap_overlay_info info;
171
172 ovl->get_overlay_info(ovl, &info);
173
174 info.out_width = simple_strtoul(buf, &last, 10);
175 ++last;
176 if (last - buf >= size)
177 return -EINVAL;
178
179 info.out_height = simple_strtoul(last, &last, 10);
180
181 r = ovl->set_overlay_info(ovl, &info);
182 if (r)
183 return r;
184
185 if (ovl->manager) {
186 r = ovl->manager->apply(ovl->manager);
187 if (r)
188 return r;
189 }
190
191 return size;
192}
193
194static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
195{
196 return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled);
197}
198
199static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
200 size_t size)
201{
202 int r;
203 struct omap_overlay_info info;
204
205 ovl->get_overlay_info(ovl, &info);
206
207 info.enabled = simple_strtoul(buf, NULL, 10);
208
209 r = ovl->set_overlay_info(ovl, &info);
210 if (r)
211 return r;
212
213 if (ovl->manager) {
214 r = ovl->manager->apply(ovl->manager);
215 if (r)
216 return r;
217 }
218
219 return size;
220}
221
222static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
223{
224 return snprintf(buf, PAGE_SIZE, "%d\n",
225 ovl->info.global_alpha);
226}
227
228static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
229 const char *buf, size_t size)
230{
231 int r;
232 struct omap_overlay_info info;
233
234 ovl->get_overlay_info(ovl, &info);
235
236 /* Video1 plane does not support global alpha
237 * to always make it 255 completely opaque
238 */
239 if (ovl->id == OMAP_DSS_VIDEO1)
240 info.global_alpha = 255;
241 else
242 info.global_alpha = simple_strtoul(buf, NULL, 10);
243
244 r = ovl->set_overlay_info(ovl, &info);
245 if (r)
246 return r;
247
248 if (ovl->manager) {
249 r = ovl->manager->apply(ovl->manager);
250 if (r)
251 return r;
252 }
253
254 return size;
255}
256
257struct overlay_attribute {
258 struct attribute attr;
259 ssize_t (*show)(struct omap_overlay *, char *);
260 ssize_t (*store)(struct omap_overlay *, const char *, size_t);
261};
262
263#define OVERLAY_ATTR(_name, _mode, _show, _store) \
264 struct overlay_attribute overlay_attr_##_name = \
265 __ATTR(_name, _mode, _show, _store)
266
267static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
268static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
269 overlay_manager_show, overlay_manager_store);
270static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
271static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
272static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
273 overlay_position_show, overlay_position_store);
274static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
275 overlay_output_size_show, overlay_output_size_store);
276static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
277 overlay_enabled_show, overlay_enabled_store);
278static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
279 overlay_global_alpha_show, overlay_global_alpha_store);
280
281static struct attribute *overlay_sysfs_attrs[] = {
282 &overlay_attr_name.attr,
283 &overlay_attr_manager.attr,
284 &overlay_attr_input_size.attr,
285 &overlay_attr_screen_width.attr,
286 &overlay_attr_position.attr,
287 &overlay_attr_output_size.attr,
288 &overlay_attr_enabled.attr,
289 &overlay_attr_global_alpha.attr,
290 NULL
291};
292
293static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
294 char *buf)
295{
296 struct omap_overlay *overlay;
297 struct overlay_attribute *overlay_attr;
298
299 overlay = container_of(kobj, struct omap_overlay, kobj);
300 overlay_attr = container_of(attr, struct overlay_attribute, attr);
301
302 if (!overlay_attr->show)
303 return -ENOENT;
304
305 return overlay_attr->show(overlay, buf);
306}
307
308static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
309 const char *buf, size_t size)
310{
311 struct omap_overlay *overlay;
312 struct overlay_attribute *overlay_attr;
313
314 overlay = container_of(kobj, struct omap_overlay, kobj);
315 overlay_attr = container_of(attr, struct overlay_attribute, attr);
316
317 if (!overlay_attr->store)
318 return -ENOENT;
319
320 return overlay_attr->store(overlay, buf, size);
321}
322
323static struct sysfs_ops overlay_sysfs_ops = {
324 .show = overlay_attr_show,
325 .store = overlay_attr_store,
326};
327
328static struct kobj_type overlay_ktype = {
329 .sysfs_ops = &overlay_sysfs_ops,
330 .default_attrs = overlay_sysfs_attrs,
331};
332
333/* Check if overlay parameters are compatible with display */
334int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
335{
336 struct omap_overlay_info *info;
337 u16 outw, outh;
338 u16 dw, dh;
339
340 if (!dssdev)
341 return 0;
342
343 if (!ovl->info.enabled)
344 return 0;
345
346 info = &ovl->info;
347
348 if (info->paddr == 0) {
349 DSSDBG("check_overlay failed: paddr 0\n");
350 return -EINVAL;
351 }
352
353 dssdev->get_resolution(dssdev, &dw, &dh);
354
355 DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n",
356 ovl->id,
357 info->pos_x, info->pos_y,
358 info->width, info->height,
359 info->out_width, info->out_height,
360 dw, dh);
361
362 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
363 outw = info->width;
364 outh = info->height;
365 } else {
366 if (info->out_width == 0)
367 outw = info->width;
368 else
369 outw = info->out_width;
370
371 if (info->out_height == 0)
372 outh = info->height;
373 else
374 outh = info->out_height;
375 }
376
377 if (dw < info->pos_x + outw) {
378 DSSDBG("check_overlay failed 1: %d < %d + %d\n",
379 dw, info->pos_x, outw);
380 return -EINVAL;
381 }
382
383 if (dh < info->pos_y + outh) {
384 DSSDBG("check_overlay failed 2: %d < %d + %d\n",
385 dh, info->pos_y, outh);
386 return -EINVAL;
387 }
388
389 if ((ovl->supported_modes & info->color_mode) == 0) {
390 DSSERR("overlay doesn't support mode %d\n", info->color_mode);
391 return -EINVAL;
392 }
393
394 return 0;
395}
396
397static int dss_ovl_set_overlay_info(struct omap_overlay *ovl,
398 struct omap_overlay_info *info)
399{
400 int r;
401 struct omap_overlay_info old_info;
402
403 old_info = ovl->info;
404 ovl->info = *info;
405
406 if (ovl->manager) {
407 r = dss_check_overlay(ovl, ovl->manager->device);
408 if (r) {
409 ovl->info = old_info;
410 return r;
411 }
412 }
413
414 ovl->info_dirty = true;
415
416 return 0;
417}
418
419static void dss_ovl_get_overlay_info(struct omap_overlay *ovl,
420 struct omap_overlay_info *info)
421{
422 *info = ovl->info;
423}
424
425static int dss_ovl_wait_for_go(struct omap_overlay *ovl)
426{
427 return dss_mgr_wait_for_go_ovl(ovl);
428}
429
430static int omap_dss_set_manager(struct omap_overlay *ovl,
431 struct omap_overlay_manager *mgr)
432{
433 if (!mgr)
434 return -EINVAL;
435
436 if (ovl->manager) {
437 DSSERR("overlay '%s' already has a manager '%s'\n",
438 ovl->name, ovl->manager->name);
439 return -EINVAL;
440 }
441
442 if (ovl->info.enabled) {
443 DSSERR("overlay has to be disabled to change the manager\n");
444 return -EINVAL;
445 }
446
447 ovl->manager = mgr;
448
449 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
450 /* XXX: on manual update display, in auto update mode, a bug happens
451 * here. When an overlay is first enabled on LCD, then it's disabled,
452 * and the manager is changed to TV, we sometimes get SYNC_LOST_DIGIT
453 * errors. Waiting before changing the channel_out fixes it. I'm
454 * guessing that the overlay is still somehow being used for the LCD,
455 * but I don't understand how or why. */
456 msleep(40);
457 dispc_set_channel_out(ovl->id, mgr->id);
458 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
459
460 return 0;
461}
462
463static int omap_dss_unset_manager(struct omap_overlay *ovl)
464{
465 int r;
466
467 if (!ovl->manager) {
468 DSSERR("failed to detach overlay: manager not set\n");
469 return -EINVAL;
470 }
471
472 if (ovl->info.enabled) {
473 DSSERR("overlay has to be disabled to unset the manager\n");
474 return -EINVAL;
475 }
476
477 r = ovl->wait_for_go(ovl);
478 if (r)
479 return r;
480
481 ovl->manager = NULL;
482
483 return 0;
484}
485
486int omap_dss_get_num_overlays(void)
487{
488 return num_overlays;
489}
490EXPORT_SYMBOL(omap_dss_get_num_overlays);
491
492struct omap_overlay *omap_dss_get_overlay(int num)
493{
494 int i = 0;
495 struct omap_overlay *ovl;
496
497 list_for_each_entry(ovl, &overlay_list, list) {
498 if (i++ == num)
499 return ovl;
500 }
501
502 return NULL;
503}
504EXPORT_SYMBOL(omap_dss_get_overlay);
505
506static void omap_dss_add_overlay(struct omap_overlay *overlay)
507{
508 ++num_overlays;
509 list_add_tail(&overlay->list, &overlay_list);
510}
511
512static struct omap_overlay *dispc_overlays[3];
513
514void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr)
515{
516 mgr->num_overlays = 3;
517 mgr->overlays = dispc_overlays;
518}
519
520#ifdef L4_EXAMPLE
521static struct omap_overlay *l4_overlays[1];
522void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr)
523{
524 mgr->num_overlays = 1;
525 mgr->overlays = l4_overlays;
526}
527#endif
528
529void dss_init_overlays(struct platform_device *pdev)
530{
531 int i, r;
532
533 INIT_LIST_HEAD(&overlay_list);
534
535 num_overlays = 0;
536
537 for (i = 0; i < 3; ++i) {
538 struct omap_overlay *ovl;
539 ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
540
541 BUG_ON(ovl == NULL);
542
543 switch (i) {
544 case 0:
545 ovl->name = "gfx";
546 ovl->id = OMAP_DSS_GFX;
547 ovl->supported_modes = cpu_is_omap34xx() ?
548 OMAP_DSS_COLOR_GFX_OMAP3 :
549 OMAP_DSS_COLOR_GFX_OMAP2;
550 ovl->caps = OMAP_DSS_OVL_CAP_DISPC;
551 ovl->info.global_alpha = 255;
552 break;
553 case 1:
554 ovl->name = "vid1";
555 ovl->id = OMAP_DSS_VIDEO1;
556 ovl->supported_modes = cpu_is_omap34xx() ?
557 OMAP_DSS_COLOR_VID1_OMAP3 :
558 OMAP_DSS_COLOR_VID_OMAP2;
559 ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
560 OMAP_DSS_OVL_CAP_DISPC;
561 ovl->info.global_alpha = 255;
562 break;
563 case 2:
564 ovl->name = "vid2";
565 ovl->id = OMAP_DSS_VIDEO2;
566 ovl->supported_modes = cpu_is_omap34xx() ?
567 OMAP_DSS_COLOR_VID2_OMAP3 :
568 OMAP_DSS_COLOR_VID_OMAP2;
569 ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
570 OMAP_DSS_OVL_CAP_DISPC;
571 ovl->info.global_alpha = 255;
572 break;
573 }
574
575 ovl->set_manager = &omap_dss_set_manager;
576 ovl->unset_manager = &omap_dss_unset_manager;
577 ovl->set_overlay_info = &dss_ovl_set_overlay_info;
578 ovl->get_overlay_info = &dss_ovl_get_overlay_info;
579 ovl->wait_for_go = &dss_ovl_wait_for_go;
580
581 omap_dss_add_overlay(ovl);
582
583 r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
584 &pdev->dev.kobj, "overlay%d", i);
585
586 if (r) {
587 DSSERR("failed to create sysfs file\n");
588 continue;
589 }
590
591 dispc_overlays[i] = ovl;
592 }
593
594#ifdef L4_EXAMPLE
595 {
596 struct omap_overlay *ovl;
597 ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
598
599 BUG_ON(ovl == NULL);
600
601 ovl->name = "l4";
602 ovl->supported_modes = OMAP_DSS_COLOR_RGB24U;
603
604 ovl->set_manager = &omap_dss_set_manager;
605 ovl->unset_manager = &omap_dss_unset_manager;
606 ovl->set_overlay_info = &dss_ovl_set_overlay_info;
607 ovl->get_overlay_info = &dss_ovl_get_overlay_info;
608
609 omap_dss_add_overlay(ovl);
610
611 r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
612 &pdev->dev.kobj, "overlayl4");
613
614 if (r)
615 DSSERR("failed to create sysfs file\n");
616
617 l4_overlays[0] = ovl;
618 }
619#endif
620}
621
622/* connect overlays to the new device, if not already connected. if force
623 * selected, connect always. */
624void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
625{
626 int i;
627 struct omap_overlay_manager *lcd_mgr;
628 struct omap_overlay_manager *tv_mgr;
629 struct omap_overlay_manager *mgr = NULL;
630
631 lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD);
632 tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV);
633
634 if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
635 if (!lcd_mgr->device || force) {
636 if (lcd_mgr->device)
637 lcd_mgr->unset_device(lcd_mgr);
638 lcd_mgr->set_device(lcd_mgr, dssdev);
639 mgr = lcd_mgr;
640 }
641 }
642
643 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
644 if (!tv_mgr->device || force) {
645 if (tv_mgr->device)
646 tv_mgr->unset_device(tv_mgr);
647 tv_mgr->set_device(tv_mgr, dssdev);
648 mgr = tv_mgr;
649 }
650 }
651
652 if (mgr) {
653 for (i = 0; i < 3; i++) {
654 struct omap_overlay *ovl;
655 ovl = omap_dss_get_overlay(i);
656 if (!ovl->manager || force) {
657 if (ovl->manager)
658 omap_dss_unset_manager(ovl);
659 omap_dss_set_manager(ovl, mgr);
660 }
661 }
662 }
663}
664
665void dss_uninit_overlays(struct platform_device *pdev)
666{
667 struct omap_overlay *ovl;
668
669 while (!list_empty(&overlay_list)) {
670 ovl = list_first_entry(&overlay_list,
671 struct omap_overlay, list);
672 list_del(&ovl->list);
673 kobject_del(&ovl->kobj);
674 kobject_put(&ovl->kobj);
675 kfree(ovl);
676 }
677
678 num_overlays = 0;
679}
680
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
new file mode 100644
index 000000000000..d0b3006ad8a5
--- /dev/null
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -0,0 +1,1309 @@
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 MEASURE_PERF*/
40
41#define RFBI_BASE 0x48050800
42
43struct rfbi_reg { u16 idx; };
44
45#define RFBI_REG(idx) ((const struct rfbi_reg) { idx })
46
47#define RFBI_REVISION RFBI_REG(0x0000)
48#define RFBI_SYSCONFIG RFBI_REG(0x0010)
49#define RFBI_SYSSTATUS RFBI_REG(0x0014)
50#define RFBI_CONTROL RFBI_REG(0x0040)
51#define RFBI_PIXEL_CNT RFBI_REG(0x0044)
52#define RFBI_LINE_NUMBER RFBI_REG(0x0048)
53#define RFBI_CMD RFBI_REG(0x004c)
54#define RFBI_PARAM RFBI_REG(0x0050)
55#define RFBI_DATA RFBI_REG(0x0054)
56#define RFBI_READ RFBI_REG(0x0058)
57#define RFBI_STATUS RFBI_REG(0x005c)
58
59#define RFBI_CONFIG(n) RFBI_REG(0x0060 + (n)*0x18)
60#define RFBI_ONOFF_TIME(n) RFBI_REG(0x0064 + (n)*0x18)
61#define RFBI_CYCLE_TIME(n) RFBI_REG(0x0068 + (n)*0x18)
62#define RFBI_DATA_CYCLE1(n) RFBI_REG(0x006c + (n)*0x18)
63#define RFBI_DATA_CYCLE2(n) RFBI_REG(0x0070 + (n)*0x18)
64#define RFBI_DATA_CYCLE3(n) RFBI_REG(0x0074 + (n)*0x18)
65
66#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090)
67#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094)
68
69#define RFBI_CMD_FIFO_LEN_BYTES (16 * sizeof(struct update_param))
70
71#define REG_FLD_MOD(idx, val, start, end) \
72 rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
73
74/* To work around an RFBI transfer rate limitation */
75#define OMAP_RFBI_RATE_LIMIT 1
76
77enum omap_rfbi_cycleformat {
78 OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0,
79 OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1,
80 OMAP_DSS_RFBI_CYCLEFORMAT_3_1 = 2,
81 OMAP_DSS_RFBI_CYCLEFORMAT_3_2 = 3,
82};
83
84enum omap_rfbi_datatype {
85 OMAP_DSS_RFBI_DATATYPE_12 = 0,
86 OMAP_DSS_RFBI_DATATYPE_16 = 1,
87 OMAP_DSS_RFBI_DATATYPE_18 = 2,
88 OMAP_DSS_RFBI_DATATYPE_24 = 3,
89};
90
91enum omap_rfbi_parallelmode {
92 OMAP_DSS_RFBI_PARALLELMODE_8 = 0,
93 OMAP_DSS_RFBI_PARALLELMODE_9 = 1,
94 OMAP_DSS_RFBI_PARALLELMODE_12 = 2,
95 OMAP_DSS_RFBI_PARALLELMODE_16 = 3,
96};
97
98enum update_cmd {
99 RFBI_CMD_UPDATE = 0,
100 RFBI_CMD_SYNC = 1,
101};
102
103static int rfbi_convert_timings(struct rfbi_timings *t);
104static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
105static void process_cmd_fifo(void);
106
107static struct {
108 void __iomem *base;
109
110 unsigned long l4_khz;
111
112 enum omap_rfbi_datatype datatype;
113 enum omap_rfbi_parallelmode parallelmode;
114
115 enum omap_rfbi_te_mode te_mode;
116 int te_enabled;
117
118 void (*framedone_callback)(void *data);
119 void *framedone_callback_data;
120
121 struct omap_dss_device *dssdev[2];
122
123 struct kfifo *cmd_fifo;
124 spinlock_t cmd_lock;
125 struct completion cmd_done;
126 atomic_t cmd_fifo_full;
127 atomic_t cmd_pending;
128#ifdef MEASURE_PERF
129 unsigned perf_bytes;
130 ktime_t perf_setup_time;
131 ktime_t perf_start_time;
132#endif
133} rfbi;
134
135struct update_region {
136 u16 x;
137 u16 y;
138 u16 w;
139 u16 h;
140};
141
142struct update_param {
143 u8 rfbi_module;
144 u8 cmd;
145
146 union {
147 struct update_region r;
148 struct completion *sync;
149 } par;
150};
151
152static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
153{
154 __raw_writel(val, rfbi.base + idx.idx);
155}
156
157static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
158{
159 return __raw_readl(rfbi.base + idx.idx);
160}
161
162static void rfbi_enable_clocks(bool enable)
163{
164 if (enable)
165 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
166 else
167 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
168}
169
170void omap_rfbi_write_command(const void *buf, u32 len)
171{
172 rfbi_enable_clocks(1);
173 switch (rfbi.parallelmode) {
174 case OMAP_DSS_RFBI_PARALLELMODE_8:
175 {
176 const u8 *b = buf;
177 for (; len; len--)
178 rfbi_write_reg(RFBI_CMD, *b++);
179 break;
180 }
181
182 case OMAP_DSS_RFBI_PARALLELMODE_16:
183 {
184 const u16 *w = buf;
185 BUG_ON(len & 1);
186 for (; len; len -= 2)
187 rfbi_write_reg(RFBI_CMD, *w++);
188 break;
189 }
190
191 case OMAP_DSS_RFBI_PARALLELMODE_9:
192 case OMAP_DSS_RFBI_PARALLELMODE_12:
193 default:
194 BUG();
195 }
196 rfbi_enable_clocks(0);
197}
198EXPORT_SYMBOL(omap_rfbi_write_command);
199
200void omap_rfbi_read_data(void *buf, u32 len)
201{
202 rfbi_enable_clocks(1);
203 switch (rfbi.parallelmode) {
204 case OMAP_DSS_RFBI_PARALLELMODE_8:
205 {
206 u8 *b = buf;
207 for (; len; len--) {
208 rfbi_write_reg(RFBI_READ, 0);
209 *b++ = rfbi_read_reg(RFBI_READ);
210 }
211 break;
212 }
213
214 case OMAP_DSS_RFBI_PARALLELMODE_16:
215 {
216 u16 *w = buf;
217 BUG_ON(len & ~1);
218 for (; len; len -= 2) {
219 rfbi_write_reg(RFBI_READ, 0);
220 *w++ = rfbi_read_reg(RFBI_READ);
221 }
222 break;
223 }
224
225 case OMAP_DSS_RFBI_PARALLELMODE_9:
226 case OMAP_DSS_RFBI_PARALLELMODE_12:
227 default:
228 BUG();
229 }
230 rfbi_enable_clocks(0);
231}
232EXPORT_SYMBOL(omap_rfbi_read_data);
233
234void omap_rfbi_write_data(const void *buf, u32 len)
235{
236 rfbi_enable_clocks(1);
237 switch (rfbi.parallelmode) {
238 case OMAP_DSS_RFBI_PARALLELMODE_8:
239 {
240 const u8 *b = buf;
241 for (; len; len--)
242 rfbi_write_reg(RFBI_PARAM, *b++);
243 break;
244 }
245
246 case OMAP_DSS_RFBI_PARALLELMODE_16:
247 {
248 const u16 *w = buf;
249 BUG_ON(len & 1);
250 for (; len; len -= 2)
251 rfbi_write_reg(RFBI_PARAM, *w++);
252 break;
253 }
254
255 case OMAP_DSS_RFBI_PARALLELMODE_9:
256 case OMAP_DSS_RFBI_PARALLELMODE_12:
257 default:
258 BUG();
259
260 }
261 rfbi_enable_clocks(0);
262}
263EXPORT_SYMBOL(omap_rfbi_write_data);
264
265void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
266 u16 x, u16 y,
267 u16 w, u16 h)
268{
269 int start_offset = scr_width * y + x;
270 int horiz_offset = scr_width - w;
271 int i;
272
273 rfbi_enable_clocks(1);
274
275 if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
276 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
277 const u16 __iomem *pd = buf;
278 pd += start_offset;
279
280 for (; h; --h) {
281 for (i = 0; i < w; ++i) {
282 const u8 __iomem *b = (const u8 __iomem *)pd;
283 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
284 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
285 ++pd;
286 }
287 pd += horiz_offset;
288 }
289 } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_24 &&
290 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
291 const u32 __iomem *pd = buf;
292 pd += start_offset;
293
294 for (; h; --h) {
295 for (i = 0; i < w; ++i) {
296 const u8 __iomem *b = (const u8 __iomem *)pd;
297 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+2));
298 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
299 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
300 ++pd;
301 }
302 pd += horiz_offset;
303 }
304 } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
305 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_16) {
306 const u16 __iomem *pd = buf;
307 pd += start_offset;
308
309 for (; h; --h) {
310 for (i = 0; i < w; ++i) {
311 rfbi_write_reg(RFBI_PARAM, __raw_readw(pd));
312 ++pd;
313 }
314 pd += horiz_offset;
315 }
316 } else {
317 BUG();
318 }
319
320 rfbi_enable_clocks(0);
321}
322EXPORT_SYMBOL(omap_rfbi_write_pixels);
323
324#ifdef MEASURE_PERF
325static void perf_mark_setup(void)
326{
327 rfbi.perf_setup_time = ktime_get();
328}
329
330static void perf_mark_start(void)
331{
332 rfbi.perf_start_time = ktime_get();
333}
334
335static void 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 t = ktime_get();
342
343 setup_time = ktime_sub(rfbi.perf_start_time, rfbi.perf_setup_time);
344 setup_us = (u32)ktime_to_us(setup_time);
345 if (setup_us == 0)
346 setup_us = 1;
347
348 trans_time = ktime_sub(t, rfbi.perf_start_time);
349 trans_us = (u32)ktime_to_us(trans_time);
350 if (trans_us == 0)
351 trans_us = 1;
352
353 total_us = setup_us + trans_us;
354
355 total_bytes = rfbi.perf_bytes;
356
357 DSSINFO("%s update %u us + %u us = %u us (%uHz), %u bytes, "
358 "%u kbytes/sec\n",
359 name,
360 setup_us,
361 trans_us,
362 total_us,
363 1000*1000 / total_us,
364 total_bytes,
365 total_bytes * 1000 / total_us);
366}
367#else
368#define perf_mark_setup()
369#define perf_mark_start()
370#define perf_show(x)
371#endif
372
373void rfbi_transfer_area(u16 width, u16 height,
374 void (callback)(void *data), void *data)
375{
376 u32 l;
377
378 /*BUG_ON(callback == 0);*/
379 BUG_ON(rfbi.framedone_callback != NULL);
380
381 DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
382
383 dispc_set_lcd_size(width, height);
384
385 dispc_enable_lcd_out(1);
386
387 rfbi.framedone_callback = callback;
388 rfbi.framedone_callback_data = data;
389
390 rfbi_enable_clocks(1);
391
392 rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
393
394 l = rfbi_read_reg(RFBI_CONTROL);
395 l = FLD_MOD(l, 1, 0, 0); /* enable */
396 if (!rfbi.te_enabled)
397 l = FLD_MOD(l, 1, 4, 4); /* ITE */
398
399 perf_mark_start();
400
401 rfbi_write_reg(RFBI_CONTROL, l);
402}
403
404static void framedone_callback(void *data, u32 mask)
405{
406 void (*callback)(void *data);
407
408 DSSDBG("FRAMEDONE\n");
409
410 perf_show("DISPC");
411
412 REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
413
414 rfbi_enable_clocks(0);
415
416 callback = rfbi.framedone_callback;
417 rfbi.framedone_callback = NULL;
418
419 /*callback(rfbi.framedone_callback_data);*/
420
421 atomic_set(&rfbi.cmd_pending, 0);
422
423 process_cmd_fifo();
424}
425
426#if 1 /* VERBOSE */
427static void rfbi_print_timings(void)
428{
429 u32 l;
430 u32 time;
431
432 l = rfbi_read_reg(RFBI_CONFIG(0));
433 time = 1000000000 / rfbi.l4_khz;
434 if (l & (1 << 4))
435 time *= 2;
436
437 DSSDBG("Tick time %u ps\n", time);
438 l = rfbi_read_reg(RFBI_ONOFF_TIME(0));
439 DSSDBG("CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
440 "REONTIME %d, REOFFTIME %d\n",
441 l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
442 (l >> 20) & 0x0f, (l >> 24) & 0x3f);
443
444 l = rfbi_read_reg(RFBI_CYCLE_TIME(0));
445 DSSDBG("WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
446 "ACCESSTIME %d\n",
447 (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
448 (l >> 22) & 0x3f);
449}
450#else
451static void rfbi_print_timings(void) {}
452#endif
453
454
455
456
457static u32 extif_clk_period;
458
459static inline unsigned long round_to_extif_ticks(unsigned long ps, int div)
460{
461 int bus_tick = extif_clk_period * div;
462 return (ps + bus_tick - 1) / bus_tick * bus_tick;
463}
464
465static int calc_reg_timing(struct rfbi_timings *t, int div)
466{
467 t->clk_div = div;
468
469 t->cs_on_time = round_to_extif_ticks(t->cs_on_time, div);
470
471 t->we_on_time = round_to_extif_ticks(t->we_on_time, div);
472 t->we_off_time = round_to_extif_ticks(t->we_off_time, div);
473 t->we_cycle_time = round_to_extif_ticks(t->we_cycle_time, div);
474
475 t->re_on_time = round_to_extif_ticks(t->re_on_time, div);
476 t->re_off_time = round_to_extif_ticks(t->re_off_time, div);
477 t->re_cycle_time = round_to_extif_ticks(t->re_cycle_time, div);
478
479 t->access_time = round_to_extif_ticks(t->access_time, div);
480 t->cs_off_time = round_to_extif_ticks(t->cs_off_time, div);
481 t->cs_pulse_width = round_to_extif_ticks(t->cs_pulse_width, div);
482
483 DSSDBG("[reg]cson %d csoff %d reon %d reoff %d\n",
484 t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
485 DSSDBG("[reg]weon %d weoff %d recyc %d wecyc %d\n",
486 t->we_on_time, t->we_off_time, t->re_cycle_time,
487 t->we_cycle_time);
488 DSSDBG("[reg]rdaccess %d cspulse %d\n",
489 t->access_time, t->cs_pulse_width);
490
491 return rfbi_convert_timings(t);
492}
493
494static int calc_extif_timings(struct rfbi_timings *t)
495{
496 u32 max_clk_div;
497 int div;
498
499 rfbi_get_clk_info(&extif_clk_period, &max_clk_div);
500 for (div = 1; div <= max_clk_div; div++) {
501 if (calc_reg_timing(t, div) == 0)
502 break;
503 }
504
505 if (div <= max_clk_div)
506 return 0;
507
508 DSSERR("can't setup timings\n");
509 return -1;
510}
511
512
513void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
514{
515 int r;
516
517 if (!t->converted) {
518 r = calc_extif_timings(t);
519 if (r < 0)
520 DSSERR("Failed to calc timings\n");
521 }
522
523 BUG_ON(!t->converted);
524
525 rfbi_enable_clocks(1);
526 rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]);
527 rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]);
528
529 /* TIMEGRANULARITY */
530 REG_FLD_MOD(RFBI_CONFIG(rfbi_module),
531 (t->tim[2] ? 1 : 0), 4, 4);
532
533 rfbi_print_timings();
534 rfbi_enable_clocks(0);
535}
536
537static int ps_to_rfbi_ticks(int time, int div)
538{
539 unsigned long tick_ps;
540 int ret;
541
542 /* Calculate in picosecs to yield more exact results */
543 tick_ps = 1000000000 / (rfbi.l4_khz) * div;
544
545 ret = (time + tick_ps - 1) / tick_ps;
546
547 return ret;
548}
549
550#ifdef OMAP_RFBI_RATE_LIMIT
551unsigned long rfbi_get_max_tx_rate(void)
552{
553 unsigned long l4_rate, dss1_rate;
554 int min_l4_ticks = 0;
555 int i;
556
557 /* According to TI this can't be calculated so make the
558 * adjustments for a couple of known frequencies and warn for
559 * others.
560 */
561 static const struct {
562 unsigned long l4_clk; /* HZ */
563 unsigned long dss1_clk; /* HZ */
564 unsigned long min_l4_ticks;
565 } ftab[] = {
566 { 55, 132, 7, }, /* 7.86 MPix/s */
567 { 110, 110, 12, }, /* 9.16 MPix/s */
568 { 110, 132, 10, }, /* 11 Mpix/s */
569 { 120, 120, 10, }, /* 12 Mpix/s */
570 { 133, 133, 10, }, /* 13.3 Mpix/s */
571 };
572
573 l4_rate = rfbi.l4_khz / 1000;
574 dss1_rate = dss_clk_get_rate(DSS_CLK_FCK1) / 1000000;
575
576 for (i = 0; i < ARRAY_SIZE(ftab); i++) {
577 /* Use a window instead of an exact match, to account
578 * for different DPLL multiplier / divider pairs.
579 */
580 if (abs(ftab[i].l4_clk - l4_rate) < 3 &&
581 abs(ftab[i].dss1_clk - dss1_rate) < 3) {
582 min_l4_ticks = ftab[i].min_l4_ticks;
583 break;
584 }
585 }
586 if (i == ARRAY_SIZE(ftab)) {
587 /* Can't be sure, return anyway the maximum not
588 * rate-limited. This might cause a problem only for the
589 * tearing synchronisation.
590 */
591 DSSERR("can't determine maximum RFBI transfer rate\n");
592 return rfbi.l4_khz * 1000;
593 }
594 return rfbi.l4_khz * 1000 / min_l4_ticks;
595}
596#else
597int rfbi_get_max_tx_rate(void)
598{
599 return rfbi.l4_khz * 1000;
600}
601#endif
602
603static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
604{
605 *clk_period = 1000000000 / rfbi.l4_khz;
606 *max_clk_div = 2;
607}
608
609static int rfbi_convert_timings(struct rfbi_timings *t)
610{
611 u32 l;
612 int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
613 int actim, recyc, wecyc;
614 int div = t->clk_div;
615
616 if (div <= 0 || div > 2)
617 return -1;
618
619 /* Make sure that after conversion it still holds that:
620 * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
621 * csoff > cson, csoff >= max(weoff, reoff), actim > reon
622 */
623 weon = ps_to_rfbi_ticks(t->we_on_time, div);
624 weoff = ps_to_rfbi_ticks(t->we_off_time, div);
625 if (weoff <= weon)
626 weoff = weon + 1;
627 if (weon > 0x0f)
628 return -1;
629 if (weoff > 0x3f)
630 return -1;
631
632 reon = ps_to_rfbi_ticks(t->re_on_time, div);
633 reoff = ps_to_rfbi_ticks(t->re_off_time, div);
634 if (reoff <= reon)
635 reoff = reon + 1;
636 if (reon > 0x0f)
637 return -1;
638 if (reoff > 0x3f)
639 return -1;
640
641 cson = ps_to_rfbi_ticks(t->cs_on_time, div);
642 csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
643 if (csoff <= cson)
644 csoff = cson + 1;
645 if (csoff < max(weoff, reoff))
646 csoff = max(weoff, reoff);
647 if (cson > 0x0f)
648 return -1;
649 if (csoff > 0x3f)
650 return -1;
651
652 l = cson;
653 l |= csoff << 4;
654 l |= weon << 10;
655 l |= weoff << 14;
656 l |= reon << 20;
657 l |= reoff << 24;
658
659 t->tim[0] = l;
660
661 actim = ps_to_rfbi_ticks(t->access_time, div);
662 if (actim <= reon)
663 actim = reon + 1;
664 if (actim > 0x3f)
665 return -1;
666
667 wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
668 if (wecyc < weoff)
669 wecyc = weoff;
670 if (wecyc > 0x3f)
671 return -1;
672
673 recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
674 if (recyc < reoff)
675 recyc = reoff;
676 if (recyc > 0x3f)
677 return -1;
678
679 cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
680 if (cs_pulse > 0x3f)
681 return -1;
682
683 l = wecyc;
684 l |= recyc << 6;
685 l |= cs_pulse << 12;
686 l |= actim << 22;
687
688 t->tim[1] = l;
689
690 t->tim[2] = div - 1;
691
692 t->converted = 1;
693
694 return 0;
695}
696
697/* xxx FIX module selection missing */
698int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
699 unsigned hs_pulse_time, unsigned vs_pulse_time,
700 int hs_pol_inv, int vs_pol_inv, int extif_div)
701{
702 int hs, vs;
703 int min;
704 u32 l;
705
706 hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
707 vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
708 if (hs < 2)
709 return -EDOM;
710 if (mode == OMAP_DSS_RFBI_TE_MODE_2)
711 min = 2;
712 else /* OMAP_DSS_RFBI_TE_MODE_1 */
713 min = 4;
714 if (vs < min)
715 return -EDOM;
716 if (vs == hs)
717 return -EINVAL;
718 rfbi.te_mode = mode;
719 DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n",
720 mode, hs, vs, hs_pol_inv, vs_pol_inv);
721
722 rfbi_enable_clocks(1);
723 rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
724 rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
725
726 l = rfbi_read_reg(RFBI_CONFIG(0));
727 if (hs_pol_inv)
728 l &= ~(1 << 21);
729 else
730 l |= 1 << 21;
731 if (vs_pol_inv)
732 l &= ~(1 << 20);
733 else
734 l |= 1 << 20;
735 rfbi_enable_clocks(0);
736
737 return 0;
738}
739EXPORT_SYMBOL(omap_rfbi_setup_te);
740
741/* xxx FIX module selection missing */
742int omap_rfbi_enable_te(bool enable, unsigned line)
743{
744 u32 l;
745
746 DSSDBG("te %d line %d mode %d\n", enable, line, rfbi.te_mode);
747 if (line > (1 << 11) - 1)
748 return -EINVAL;
749
750 rfbi_enable_clocks(1);
751 l = rfbi_read_reg(RFBI_CONFIG(0));
752 l &= ~(0x3 << 2);
753 if (enable) {
754 rfbi.te_enabled = 1;
755 l |= rfbi.te_mode << 2;
756 } else
757 rfbi.te_enabled = 0;
758 rfbi_write_reg(RFBI_CONFIG(0), l);
759 rfbi_write_reg(RFBI_LINE_NUMBER, line);
760 rfbi_enable_clocks(0);
761
762 return 0;
763}
764EXPORT_SYMBOL(omap_rfbi_enable_te);
765
766#if 0
767static void rfbi_enable_config(int enable1, int enable2)
768{
769 u32 l;
770 int cs = 0;
771
772 if (enable1)
773 cs |= 1<<0;
774 if (enable2)
775 cs |= 1<<1;
776
777 rfbi_enable_clocks(1);
778
779 l = rfbi_read_reg(RFBI_CONTROL);
780
781 l = FLD_MOD(l, cs, 3, 2);
782 l = FLD_MOD(l, 0, 1, 1);
783
784 rfbi_write_reg(RFBI_CONTROL, l);
785
786
787 l = rfbi_read_reg(RFBI_CONFIG(0));
788 l = FLD_MOD(l, 0, 3, 2); /* TRIGGERMODE: ITE */
789 /*l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
790 /*l |= FLD_VAL(0, 8, 7); */ /* L4FORMAT, 1pix/L4 */
791
792 l = FLD_MOD(l, 0, 16, 16); /* A0POLARITY */
793 l = FLD_MOD(l, 1, 20, 20); /* TE_VSYNC_POLARITY */
794 l = FLD_MOD(l, 1, 21, 21); /* HSYNCPOLARITY */
795
796 l = FLD_MOD(l, OMAP_DSS_RFBI_PARALLELMODE_8, 1, 0);
797 rfbi_write_reg(RFBI_CONFIG(0), l);
798
799 rfbi_enable_clocks(0);
800}
801#endif
802
803int rfbi_configure(int rfbi_module, int bpp, int lines)
804{
805 u32 l;
806 int cycle1 = 0, cycle2 = 0, cycle3 = 0;
807 enum omap_rfbi_cycleformat cycleformat;
808 enum omap_rfbi_datatype datatype;
809 enum omap_rfbi_parallelmode parallelmode;
810
811 switch (bpp) {
812 case 12:
813 datatype = OMAP_DSS_RFBI_DATATYPE_12;
814 break;
815 case 16:
816 datatype = OMAP_DSS_RFBI_DATATYPE_16;
817 break;
818 case 18:
819 datatype = OMAP_DSS_RFBI_DATATYPE_18;
820 break;
821 case 24:
822 datatype = OMAP_DSS_RFBI_DATATYPE_24;
823 break;
824 default:
825 BUG();
826 return 1;
827 }
828 rfbi.datatype = datatype;
829
830 switch (lines) {
831 case 8:
832 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_8;
833 break;
834 case 9:
835 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_9;
836 break;
837 case 12:
838 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_12;
839 break;
840 case 16:
841 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_16;
842 break;
843 default:
844 BUG();
845 return 1;
846 }
847 rfbi.parallelmode = parallelmode;
848
849 if ((bpp % lines) == 0) {
850 switch (bpp / lines) {
851 case 1:
852 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_1_1;
853 break;
854 case 2:
855 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_2_1;
856 break;
857 case 3:
858 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_1;
859 break;
860 default:
861 BUG();
862 return 1;
863 }
864 } else if ((2 * bpp % lines) == 0) {
865 if ((2 * bpp / lines) == 3)
866 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_2;
867 else {
868 BUG();
869 return 1;
870 }
871 } else {
872 BUG();
873 return 1;
874 }
875
876 switch (cycleformat) {
877 case OMAP_DSS_RFBI_CYCLEFORMAT_1_1:
878 cycle1 = lines;
879 break;
880
881 case OMAP_DSS_RFBI_CYCLEFORMAT_2_1:
882 cycle1 = lines;
883 cycle2 = lines;
884 break;
885
886 case OMAP_DSS_RFBI_CYCLEFORMAT_3_1:
887 cycle1 = lines;
888 cycle2 = lines;
889 cycle3 = lines;
890 break;
891
892 case OMAP_DSS_RFBI_CYCLEFORMAT_3_2:
893 cycle1 = lines;
894 cycle2 = (lines / 2) | ((lines / 2) << 16);
895 cycle3 = (lines << 16);
896 break;
897 }
898
899 rfbi_enable_clocks(1);
900
901 REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */
902
903 l = 0;
904 l |= FLD_VAL(parallelmode, 1, 0);
905 l |= FLD_VAL(0, 3, 2); /* TRIGGERMODE: ITE */
906 l |= FLD_VAL(0, 4, 4); /* TIMEGRANULARITY */
907 l |= FLD_VAL(datatype, 6, 5);
908 /* l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
909 l |= FLD_VAL(0, 8, 7); /* L4FORMAT, 1pix/L4 */
910 l |= FLD_VAL(cycleformat, 10, 9);
911 l |= FLD_VAL(0, 12, 11); /* UNUSEDBITS */
912 l |= FLD_VAL(0, 16, 16); /* A0POLARITY */
913 l |= FLD_VAL(0, 17, 17); /* REPOLARITY */
914 l |= FLD_VAL(0, 18, 18); /* WEPOLARITY */
915 l |= FLD_VAL(0, 19, 19); /* CSPOLARITY */
916 l |= FLD_VAL(1, 20, 20); /* TE_VSYNC_POLARITY */
917 l |= FLD_VAL(1, 21, 21); /* HSYNCPOLARITY */
918 rfbi_write_reg(RFBI_CONFIG(rfbi_module), l);
919
920 rfbi_write_reg(RFBI_DATA_CYCLE1(rfbi_module), cycle1);
921 rfbi_write_reg(RFBI_DATA_CYCLE2(rfbi_module), cycle2);
922 rfbi_write_reg(RFBI_DATA_CYCLE3(rfbi_module), cycle3);
923
924
925 l = rfbi_read_reg(RFBI_CONTROL);
926 l = FLD_MOD(l, rfbi_module+1, 3, 2); /* Select CSx */
927 l = FLD_MOD(l, 0, 1, 1); /* clear bypass */
928 rfbi_write_reg(RFBI_CONTROL, l);
929
930
931 DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n",
932 bpp, lines, cycle1, cycle2, cycle3);
933
934 rfbi_enable_clocks(0);
935
936 return 0;
937}
938EXPORT_SYMBOL(rfbi_configure);
939
940static int rfbi_find_display(struct omap_dss_device *dssdev)
941{
942 if (dssdev == rfbi.dssdev[0])
943 return 0;
944
945 if (dssdev == rfbi.dssdev[1])
946 return 1;
947
948 BUG();
949 return -1;
950}
951
952
953static void signal_fifo_waiters(void)
954{
955 if (atomic_read(&rfbi.cmd_fifo_full) > 0) {
956 /* DSSDBG("SIGNALING: Fifo not full for waiter!\n"); */
957 complete(&rfbi.cmd_done);
958 atomic_dec(&rfbi.cmd_fifo_full);
959 }
960}
961
962/* returns 1 for async op, and 0 for sync op */
963static int do_update(struct omap_dss_device *dssdev, struct update_region *upd)
964{
965 u16 x = upd->x;
966 u16 y = upd->y;
967 u16 w = upd->w;
968 u16 h = upd->h;
969
970 perf_mark_setup();
971
972 if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
973 /*dssdev->driver->enable_te(dssdev, 1); */
974 dss_setup_partial_planes(dssdev, &x, &y, &w, &h);
975 }
976
977#ifdef MEASURE_PERF
978 rfbi.perf_bytes = w * h * 2; /* XXX always 16bit */
979#endif
980
981 dssdev->driver->setup_update(dssdev, x, y, w, h);
982
983 if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
984 rfbi_transfer_area(w, h, NULL, NULL);
985 return 1;
986 } else {
987 struct omap_overlay *ovl;
988 void __iomem *addr;
989 int scr_width;
990
991 ovl = dssdev->manager->overlays[0];
992 scr_width = ovl->info.screen_width;
993 addr = ovl->info.vaddr;
994
995 omap_rfbi_write_pixels(addr, scr_width, x, y, w, h);
996
997 perf_show("L4");
998
999 return 0;
1000 }
1001}
1002
1003static void process_cmd_fifo(void)
1004{
1005 int len;
1006 struct update_param p;
1007 struct omap_dss_device *dssdev;
1008 unsigned long flags;
1009
1010 if (atomic_inc_return(&rfbi.cmd_pending) != 1)
1011 return;
1012
1013 while (true) {
1014 spin_lock_irqsave(rfbi.cmd_fifo->lock, flags);
1015
1016 len = __kfifo_get(rfbi.cmd_fifo, (unsigned char *)&p,
1017 sizeof(struct update_param));
1018 if (len == 0) {
1019 DSSDBG("nothing more in fifo\n");
1020 atomic_set(&rfbi.cmd_pending, 0);
1021 spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags);
1022 break;
1023 }
1024
1025 /* DSSDBG("fifo full %d\n", rfbi.cmd_fifo_full.counter);*/
1026
1027 spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags);
1028
1029 BUG_ON(len != sizeof(struct update_param));
1030 BUG_ON(p.rfbi_module > 1);
1031
1032 dssdev = rfbi.dssdev[p.rfbi_module];
1033
1034 if (p.cmd == RFBI_CMD_UPDATE) {
1035 if (do_update(dssdev, &p.par.r))
1036 break; /* async op */
1037 } else if (p.cmd == RFBI_CMD_SYNC) {
1038 DSSDBG("Signaling SYNC done!\n");
1039 complete(p.par.sync);
1040 } else
1041 BUG();
1042 }
1043
1044 signal_fifo_waiters();
1045}
1046
1047static void rfbi_push_cmd(struct update_param *p)
1048{
1049 int ret;
1050
1051 while (1) {
1052 unsigned long flags;
1053 int available;
1054
1055 spin_lock_irqsave(rfbi.cmd_fifo->lock, flags);
1056 available = RFBI_CMD_FIFO_LEN_BYTES -
1057 __kfifo_len(rfbi.cmd_fifo);
1058
1059/* DSSDBG("%d bytes left in fifo\n", available); */
1060 if (available < sizeof(struct update_param)) {
1061 DSSDBG("Going to wait because FIFO FULL..\n");
1062 spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags);
1063 atomic_inc(&rfbi.cmd_fifo_full);
1064 wait_for_completion(&rfbi.cmd_done);
1065 /*DSSDBG("Woke up because fifo not full anymore\n");*/
1066 continue;
1067 }
1068
1069 ret = __kfifo_put(rfbi.cmd_fifo, (unsigned char *)p,
1070 sizeof(struct update_param));
1071/* DSSDBG("pushed %d bytes\n", ret);*/
1072
1073 spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags);
1074
1075 BUG_ON(ret != sizeof(struct update_param));
1076
1077 break;
1078 }
1079}
1080
1081static void rfbi_push_update(int rfbi_module, int x, int y, int w, int h)
1082{
1083 struct update_param p;
1084
1085 p.rfbi_module = rfbi_module;
1086 p.cmd = RFBI_CMD_UPDATE;
1087
1088 p.par.r.x = x;
1089 p.par.r.y = y;
1090 p.par.r.w = w;
1091 p.par.r.h = h;
1092
1093 DSSDBG("RFBI pushed %d,%d %dx%d\n", x, y, w, h);
1094
1095 rfbi_push_cmd(&p);
1096
1097 process_cmd_fifo();
1098}
1099
1100static void rfbi_push_sync(int rfbi_module, struct completion *sync_comp)
1101{
1102 struct update_param p;
1103
1104 p.rfbi_module = rfbi_module;
1105 p.cmd = RFBI_CMD_SYNC;
1106 p.par.sync = sync_comp;
1107
1108 rfbi_push_cmd(&p);
1109
1110 DSSDBG("RFBI sync pushed to cmd fifo\n");
1111
1112 process_cmd_fifo();
1113}
1114
1115void rfbi_dump_regs(struct seq_file *s)
1116{
1117#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
1118
1119 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
1120
1121 DUMPREG(RFBI_REVISION);
1122 DUMPREG(RFBI_SYSCONFIG);
1123 DUMPREG(RFBI_SYSSTATUS);
1124 DUMPREG(RFBI_CONTROL);
1125 DUMPREG(RFBI_PIXEL_CNT);
1126 DUMPREG(RFBI_LINE_NUMBER);
1127 DUMPREG(RFBI_CMD);
1128 DUMPREG(RFBI_PARAM);
1129 DUMPREG(RFBI_DATA);
1130 DUMPREG(RFBI_READ);
1131 DUMPREG(RFBI_STATUS);
1132
1133 DUMPREG(RFBI_CONFIG(0));
1134 DUMPREG(RFBI_ONOFF_TIME(0));
1135 DUMPREG(RFBI_CYCLE_TIME(0));
1136 DUMPREG(RFBI_DATA_CYCLE1(0));
1137 DUMPREG(RFBI_DATA_CYCLE2(0));
1138 DUMPREG(RFBI_DATA_CYCLE3(0));
1139
1140 DUMPREG(RFBI_CONFIG(1));
1141 DUMPREG(RFBI_ONOFF_TIME(1));
1142 DUMPREG(RFBI_CYCLE_TIME(1));
1143 DUMPREG(RFBI_DATA_CYCLE1(1));
1144 DUMPREG(RFBI_DATA_CYCLE2(1));
1145 DUMPREG(RFBI_DATA_CYCLE3(1));
1146
1147 DUMPREG(RFBI_VSYNC_WIDTH);
1148 DUMPREG(RFBI_HSYNC_WIDTH);
1149
1150 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
1151#undef DUMPREG
1152}
1153
1154int rfbi_init(void)
1155{
1156 u32 rev;
1157 u32 l;
1158
1159 spin_lock_init(&rfbi.cmd_lock);
1160 rfbi.cmd_fifo = kfifo_alloc(RFBI_CMD_FIFO_LEN_BYTES, GFP_KERNEL,
1161 &rfbi.cmd_lock);
1162 if (IS_ERR(rfbi.cmd_fifo))
1163 return -ENOMEM;
1164
1165 init_completion(&rfbi.cmd_done);
1166 atomic_set(&rfbi.cmd_fifo_full, 0);
1167 atomic_set(&rfbi.cmd_pending, 0);
1168
1169 rfbi.base = ioremap(RFBI_BASE, SZ_256);
1170 if (!rfbi.base) {
1171 DSSERR("can't ioremap RFBI\n");
1172 return -ENOMEM;
1173 }
1174
1175 rfbi_enable_clocks(1);
1176
1177 msleep(10);
1178
1179 rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
1180
1181 /* Enable autoidle and smart-idle */
1182 l = rfbi_read_reg(RFBI_SYSCONFIG);
1183 l |= (1 << 0) | (2 << 3);
1184 rfbi_write_reg(RFBI_SYSCONFIG, l);
1185
1186 rev = rfbi_read_reg(RFBI_REVISION);
1187 printk(KERN_INFO "OMAP RFBI rev %d.%d\n",
1188 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
1189
1190 rfbi_enable_clocks(0);
1191
1192 return 0;
1193}
1194
1195void rfbi_exit(void)
1196{
1197 DSSDBG("rfbi_exit\n");
1198
1199 kfifo_free(rfbi.cmd_fifo);
1200
1201 iounmap(rfbi.base);
1202}
1203
1204/* struct omap_display support */
1205static int rfbi_display_update(struct omap_dss_device *dssdev,
1206 u16 x, u16 y, u16 w, u16 h)
1207{
1208 int rfbi_module;
1209
1210 if (w == 0 || h == 0)
1211 return 0;
1212
1213 rfbi_module = rfbi_find_display(dssdev);
1214
1215 rfbi_push_update(rfbi_module, x, y, w, h);
1216
1217 return 0;
1218}
1219
1220static int rfbi_display_sync(struct omap_dss_device *dssdev)
1221{
1222 struct completion sync_comp;
1223 int rfbi_module;
1224
1225 rfbi_module = rfbi_find_display(dssdev);
1226
1227 init_completion(&sync_comp);
1228 rfbi_push_sync(rfbi_module, &sync_comp);
1229 DSSDBG("Waiting for SYNC to happen...\n");
1230 wait_for_completion(&sync_comp);
1231 DSSDBG("Released from SYNC\n");
1232 return 0;
1233}
1234
1235static int rfbi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
1236{
1237 dssdev->driver->enable_te(dssdev, enable);
1238 return 0;
1239}
1240
1241static int rfbi_display_enable(struct omap_dss_device *dssdev)
1242{
1243 int r;
1244
1245 r = omap_dss_start_device(dssdev);
1246 if (r) {
1247 DSSERR("failed to start device\n");
1248 goto err0;
1249 }
1250
1251 r = omap_dispc_register_isr(framedone_callback, NULL,
1252 DISPC_IRQ_FRAMEDONE);
1253 if (r) {
1254 DSSERR("can't get FRAMEDONE irq\n");
1255 goto err1;
1256 }
1257
1258 dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
1259
1260 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_RFBI);
1261
1262 dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
1263
1264 rfbi_configure(dssdev->phy.rfbi.channel,
1265 dssdev->ctrl.pixel_size,
1266 dssdev->phy.rfbi.data_lines);
1267
1268 rfbi_set_timings(dssdev->phy.rfbi.channel,
1269 &dssdev->ctrl.rfbi_timings);
1270
1271
1272 if (dssdev->driver->enable) {
1273 r = dssdev->driver->enable(dssdev);
1274 if (r)
1275 goto err2;
1276 }
1277
1278 return 0;
1279err2:
1280 omap_dispc_unregister_isr(framedone_callback, NULL,
1281 DISPC_IRQ_FRAMEDONE);
1282err1:
1283 omap_dss_stop_device(dssdev);
1284err0:
1285 return r;
1286}
1287
1288static void rfbi_display_disable(struct omap_dss_device *dssdev)
1289{
1290 dssdev->driver->disable(dssdev);
1291 omap_dispc_unregister_isr(framedone_callback, NULL,
1292 DISPC_IRQ_FRAMEDONE);
1293 omap_dss_stop_device(dssdev);
1294}
1295
1296int rfbi_init_display(struct omap_dss_device *dssdev)
1297{
1298 dssdev->enable = rfbi_display_enable;
1299 dssdev->disable = rfbi_display_disable;
1300 dssdev->update = rfbi_display_update;
1301 dssdev->sync = rfbi_display_sync;
1302 dssdev->enable_te = rfbi_display_enable_te;
1303
1304 rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
1305
1306 dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
1307
1308 return 0;
1309}
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
new file mode 100644
index 000000000000..c24f307d3da1
--- /dev/null
+++ b/drivers/video/omap2/dss/sdi.c
@@ -0,0 +1,277 @@
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
44static int 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 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
61 DSSERR("dssdev already enabled\n");
62 r = -EINVAL;
63 goto err1;
64 }
65
66 /* In case of skip_init sdi_init has already enabled the clocks */
67 if (!sdi.skip_init)
68 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
69
70 sdi_basic_init();
71
72 /* 15.5.9.1.2 */
73 dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF;
74
75 dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
76 dssdev->panel.acb);
77
78 if (!sdi.skip_init) {
79 r = dss_calc_clock_div(1, t->pixel_clock * 1000,
80 &dss_cinfo, &dispc_cinfo);
81 } else {
82 r = dss_get_clock_div(&dss_cinfo);
83 r = dispc_get_clock_div(&dispc_cinfo);
84 }
85
86 if (r)
87 goto err2;
88
89 fck = dss_cinfo.fck;
90 lck_div = dispc_cinfo.lck_div;
91 pck_div = dispc_cinfo.pck_div;
92
93 pck = fck / lck_div / pck_div / 1000;
94
95 if (pck != t->pixel_clock) {
96 DSSWARN("Could not find exact pixel clock. Requested %d kHz, "
97 "got %lu kHz\n",
98 t->pixel_clock, pck);
99
100 t->pixel_clock = pck;
101 }
102
103
104 dispc_set_lcd_timings(t);
105
106 r = dss_set_clock_div(&dss_cinfo);
107 if (r)
108 goto err2;
109
110 r = dispc_set_clock_div(&dispc_cinfo);
111 if (r)
112 goto err2;
113
114 if (!sdi.skip_init) {
115 dss_sdi_init(dssdev->phy.sdi.datapairs);
116 r = dss_sdi_enable();
117 if (r)
118 goto err1;
119 mdelay(2);
120 }
121
122 dispc_enable_lcd_out(1);
123
124 if (dssdev->driver->enable) {
125 r = dssdev->driver->enable(dssdev);
126 if (r)
127 goto err3;
128 }
129
130 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
131
132 sdi.skip_init = 0;
133
134 return 0;
135err3:
136 dispc_enable_lcd_out(0);
137err2:
138 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
139err1:
140 omap_dss_stop_device(dssdev);
141err0:
142 return r;
143}
144
145static int sdi_display_resume(struct omap_dss_device *dssdev);
146
147static void sdi_display_disable(struct omap_dss_device *dssdev)
148{
149 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
150 return;
151
152 if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
153 if (sdi_display_resume(dssdev))
154 return;
155
156 if (dssdev->driver->disable)
157 dssdev->driver->disable(dssdev);
158
159 dispc_enable_lcd_out(0);
160
161 dss_sdi_disable();
162
163 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
164
165 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
166
167 omap_dss_stop_device(dssdev);
168}
169
170static int sdi_display_suspend(struct omap_dss_device *dssdev)
171{
172 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
173 return -EINVAL;
174
175 if (dssdev->driver->suspend)
176 dssdev->driver->suspend(dssdev);
177
178 dispc_enable_lcd_out(0);
179
180 dss_sdi_disable();
181
182 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
183
184 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
185
186 return 0;
187}
188
189static int sdi_display_resume(struct omap_dss_device *dssdev)
190{
191 int r;
192
193 if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
194 return -EINVAL;
195
196 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
197
198 r = dss_sdi_enable();
199 if (r)
200 goto err;
201 mdelay(2);
202
203 dispc_enable_lcd_out(1);
204
205 if (dssdev->driver->resume)
206 dssdev->driver->resume(dssdev);
207
208 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
209
210 return 0;
211err:
212 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
213 return r;
214}
215
216static int sdi_display_set_update_mode(struct omap_dss_device *dssdev,
217 enum omap_dss_update_mode mode)
218{
219 if (mode == OMAP_DSS_UPDATE_MANUAL)
220 return -EINVAL;
221
222 if (mode == OMAP_DSS_UPDATE_DISABLED) {
223 dispc_enable_lcd_out(0);
224 sdi.update_enabled = 0;
225 } else {
226 dispc_enable_lcd_out(1);
227 sdi.update_enabled = 1;
228 }
229
230 return 0;
231}
232
233static enum omap_dss_update_mode sdi_display_get_update_mode(
234 struct omap_dss_device *dssdev)
235{
236 return sdi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
237 OMAP_DSS_UPDATE_DISABLED;
238}
239
240static void sdi_get_timings(struct omap_dss_device *dssdev,
241 struct omap_video_timings *timings)
242{
243 *timings = dssdev->panel.timings;
244}
245
246int sdi_init_display(struct omap_dss_device *dssdev)
247{
248 DSSDBG("SDI init\n");
249
250 dssdev->enable = sdi_display_enable;
251 dssdev->disable = sdi_display_disable;
252 dssdev->suspend = sdi_display_suspend;
253 dssdev->resume = sdi_display_resume;
254 dssdev->set_update_mode = sdi_display_set_update_mode;
255 dssdev->get_update_mode = sdi_display_get_update_mode;
256 dssdev->get_timings = sdi_get_timings;
257
258 return 0;
259}
260
261int sdi_init(bool skip_init)
262{
263 /* we store this for first display enable, then clear it */
264 sdi.skip_init = skip_init;
265
266 /*
267 * Enable clocks already here, otherwise there would be a toggle
268 * of them until sdi_display_enable is called.
269 */
270 if (skip_init)
271 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
272 return 0;
273}
274
275void sdi_exit(void)
276{
277}
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
new file mode 100644
index 000000000000..749a5a0f5be4
--- /dev/null
+++ b/drivers/video/omap2/dss/venc.c
@@ -0,0 +1,797 @@
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
403
404
405
406
407/* driver */
408static int venc_panel_probe(struct omap_dss_device *dssdev)
409{
410 dssdev->panel.timings = omap_dss_pal_timings;
411
412 return 0;
413}
414
415static void venc_panel_remove(struct omap_dss_device *dssdev)
416{
417}
418
419static int venc_panel_enable(struct omap_dss_device *dssdev)
420{
421 int r = 0;
422
423 /* wait couple of vsyncs until enabling the LCD */
424 msleep(50);
425
426 if (dssdev->platform_enable)
427 r = dssdev->platform_enable(dssdev);
428
429 return r;
430}
431
432static void venc_panel_disable(struct omap_dss_device *dssdev)
433{
434 if (dssdev->platform_disable)
435 dssdev->platform_disable(dssdev);
436
437 /* wait at least 5 vsyncs after disabling the LCD */
438
439 msleep(100);
440}
441
442static int venc_panel_suspend(struct omap_dss_device *dssdev)
443{
444 venc_panel_disable(dssdev);
445 return 0;
446}
447
448static int venc_panel_resume(struct omap_dss_device *dssdev)
449{
450 return venc_panel_enable(dssdev);
451}
452
453static struct omap_dss_driver venc_driver = {
454 .probe = venc_panel_probe,
455 .remove = venc_panel_remove,
456
457 .enable = venc_panel_enable,
458 .disable = venc_panel_disable,
459 .suspend = venc_panel_suspend,
460 .resume = venc_panel_resume,
461
462 .driver = {
463 .name = "venc",
464 .owner = THIS_MODULE,
465 },
466};
467/* driver end */
468
469
470
471int venc_init(struct platform_device *pdev)
472{
473 u8 rev_id;
474
475 mutex_init(&venc.venc_lock);
476
477 venc.wss_data = 0;
478
479 venc.base = ioremap(VENC_BASE, SZ_1K);
480 if (!venc.base) {
481 DSSERR("can't ioremap VENC\n");
482 return -ENOMEM;
483 }
484
485 venc.vdda_dac_reg = regulator_get(&pdev->dev, "vdda_dac");
486 if (IS_ERR(venc.vdda_dac_reg)) {
487 iounmap(venc.base);
488 DSSERR("can't get VDDA_DAC regulator\n");
489 return PTR_ERR(venc.vdda_dac_reg);
490 }
491
492 venc_enable_clocks(1);
493
494 rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
495 printk(KERN_INFO "OMAP VENC rev %d\n", rev_id);
496
497 venc_enable_clocks(0);
498
499 return omap_dss_register_driver(&venc_driver);
500}
501
502void venc_exit(void)
503{
504 omap_dss_unregister_driver(&venc_driver);
505
506 regulator_put(venc.vdda_dac_reg);
507
508 iounmap(venc.base);
509}
510
511static void venc_power_on(struct omap_dss_device *dssdev)
512{
513 u32 l;
514
515 venc_enable_clocks(1);
516
517 venc_reset();
518 venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
519
520 dss_set_venc_output(dssdev->phy.venc.type);
521 dss_set_dac_pwrdn_bgz(1);
522
523 l = 0;
524
525 if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
526 l |= 1 << 1;
527 else /* S-Video */
528 l |= (1 << 0) | (1 << 2);
529
530 if (dssdev->phy.venc.invert_polarity == false)
531 l |= 1 << 3;
532
533 venc_write_reg(VENC_OUTPUT_CONTROL, l);
534
535 dispc_set_digit_size(dssdev->panel.timings.x_res,
536 dssdev->panel.timings.y_res/2);
537
538 regulator_enable(venc.vdda_dac_reg);
539
540 if (dssdev->platform_enable)
541 dssdev->platform_enable(dssdev);
542
543 dispc_enable_digit_out(1);
544}
545
546static void venc_power_off(struct omap_dss_device *dssdev)
547{
548 venc_write_reg(VENC_OUTPUT_CONTROL, 0);
549 dss_set_dac_pwrdn_bgz(0);
550
551 dispc_enable_digit_out(0);
552
553 if (dssdev->platform_disable)
554 dssdev->platform_disable(dssdev);
555
556 regulator_disable(venc.vdda_dac_reg);
557
558 venc_enable_clocks(0);
559}
560
561static int venc_enable_display(struct omap_dss_device *dssdev)
562{
563 int r = 0;
564
565 DSSDBG("venc_enable_display\n");
566
567 mutex_lock(&venc.venc_lock);
568
569 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
570 r = -EINVAL;
571 goto err;
572 }
573
574 venc_power_on(dssdev);
575
576 venc.wss_data = 0;
577
578 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
579err:
580 mutex_unlock(&venc.venc_lock);
581
582 return r;
583}
584
585static void venc_disable_display(struct omap_dss_device *dssdev)
586{
587 DSSDBG("venc_disable_display\n");
588
589 mutex_lock(&venc.venc_lock);
590
591 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
592 goto end;
593
594 if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
595 /* suspended is the same as disabled with venc */
596 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
597 goto end;
598 }
599
600 venc_power_off(dssdev);
601
602 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
603end:
604 mutex_unlock(&venc.venc_lock);
605}
606
607static int venc_display_suspend(struct omap_dss_device *dssdev)
608{
609 int r = 0;
610
611 DSSDBG("venc_display_suspend\n");
612
613 mutex_lock(&venc.venc_lock);
614
615 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
616 r = -EINVAL;
617 goto err;
618 }
619
620 venc_power_off(dssdev);
621
622 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
623err:
624 mutex_unlock(&venc.venc_lock);
625
626 return r;
627}
628
629static int venc_display_resume(struct omap_dss_device *dssdev)
630{
631 int r = 0;
632
633 DSSDBG("venc_display_resume\n");
634
635 mutex_lock(&venc.venc_lock);
636
637 if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
638 r = -EINVAL;
639 goto err;
640 }
641
642 venc_power_on(dssdev);
643
644 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
645err:
646 mutex_unlock(&venc.venc_lock);
647
648 return r;
649}
650
651static void venc_get_timings(struct omap_dss_device *dssdev,
652 struct omap_video_timings *timings)
653{
654 *timings = dssdev->panel.timings;
655}
656
657static void venc_set_timings(struct omap_dss_device *dssdev,
658 struct omap_video_timings *timings)
659{
660 DSSDBG("venc_set_timings\n");
661
662 /* Reset WSS data when the TV standard changes. */
663 if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings)))
664 venc.wss_data = 0;
665
666 dssdev->panel.timings = *timings;
667 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
668 /* turn the venc off and on to get new timings to use */
669 venc_disable_display(dssdev);
670 venc_enable_display(dssdev);
671 }
672}
673
674static int venc_check_timings(struct omap_dss_device *dssdev,
675 struct omap_video_timings *timings)
676{
677 DSSDBG("venc_check_timings\n");
678
679 if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
680 return 0;
681
682 if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
683 return 0;
684
685 return -EINVAL;
686}
687
688static u32 venc_get_wss(struct omap_dss_device *dssdev)
689{
690 /* Invert due to VENC_L21_WC_CTL:INV=1 */
691 return (venc.wss_data >> 8) ^ 0xfffff;
692}
693
694static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
695{
696 const struct venc_config *config;
697
698 DSSDBG("venc_set_wss\n");
699
700 mutex_lock(&venc.venc_lock);
701
702 config = venc_timings_to_config(&dssdev->panel.timings);
703
704 /* Invert due to VENC_L21_WC_CTL:INV=1 */
705 venc.wss_data = (wss ^ 0xfffff) << 8;
706
707 venc_enable_clocks(1);
708
709 venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
710 venc.wss_data);
711
712 venc_enable_clocks(0);
713
714 mutex_unlock(&venc.venc_lock);
715
716 return 0;
717}
718
719static enum omap_dss_update_mode venc_display_get_update_mode(
720 struct omap_dss_device *dssdev)
721{
722 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
723 return OMAP_DSS_UPDATE_AUTO;
724 else
725 return OMAP_DSS_UPDATE_DISABLED;
726}
727
728int venc_init_display(struct omap_dss_device *dssdev)
729{
730 DSSDBG("init_display\n");
731
732 dssdev->enable = venc_enable_display;
733 dssdev->disable = venc_disable_display;
734 dssdev->suspend = venc_display_suspend;
735 dssdev->resume = venc_display_resume;
736 dssdev->get_timings = venc_get_timings;
737 dssdev->set_timings = venc_set_timings;
738 dssdev->check_timings = venc_check_timings;
739 dssdev->get_wss = venc_get_wss;
740 dssdev->set_wss = venc_set_wss;
741 dssdev->get_update_mode = venc_display_get_update_mode;
742
743 return 0;
744}
745
746void venc_dump_regs(struct seq_file *s)
747{
748#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
749
750 venc_enable_clocks(1);
751
752 DUMPREG(VENC_F_CONTROL);
753 DUMPREG(VENC_VIDOUT_CTRL);
754 DUMPREG(VENC_SYNC_CTRL);
755 DUMPREG(VENC_LLEN);
756 DUMPREG(VENC_FLENS);
757 DUMPREG(VENC_HFLTR_CTRL);
758 DUMPREG(VENC_CC_CARR_WSS_CARR);
759 DUMPREG(VENC_C_PHASE);
760 DUMPREG(VENC_GAIN_U);
761 DUMPREG(VENC_GAIN_V);
762 DUMPREG(VENC_GAIN_Y);
763 DUMPREG(VENC_BLACK_LEVEL);
764 DUMPREG(VENC_BLANK_LEVEL);
765 DUMPREG(VENC_X_COLOR);
766 DUMPREG(VENC_M_CONTROL);
767 DUMPREG(VENC_BSTAMP_WSS_DATA);
768 DUMPREG(VENC_S_CARR);
769 DUMPREG(VENC_LINE21);
770 DUMPREG(VENC_LN_SEL);
771 DUMPREG(VENC_L21__WC_CTL);
772 DUMPREG(VENC_HTRIGGER_VTRIGGER);
773 DUMPREG(VENC_SAVID__EAVID);
774 DUMPREG(VENC_FLEN__FAL);
775 DUMPREG(VENC_LAL__PHASE_RESET);
776 DUMPREG(VENC_HS_INT_START_STOP_X);
777 DUMPREG(VENC_HS_EXT_START_STOP_X);
778 DUMPREG(VENC_VS_INT_START_X);
779 DUMPREG(VENC_VS_INT_STOP_X__VS_INT_START_Y);
780 DUMPREG(VENC_VS_INT_STOP_Y__VS_EXT_START_X);
781 DUMPREG(VENC_VS_EXT_STOP_X__VS_EXT_START_Y);
782 DUMPREG(VENC_VS_EXT_STOP_Y);
783 DUMPREG(VENC_AVID_START_STOP_X);
784 DUMPREG(VENC_AVID_START_STOP_Y);
785 DUMPREG(VENC_FID_INT_START_X__FID_INT_START_Y);
786 DUMPREG(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);
787 DUMPREG(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);
788 DUMPREG(VENC_TVDETGP_INT_START_STOP_X);
789 DUMPREG(VENC_TVDETGP_INT_START_STOP_Y);
790 DUMPREG(VENC_GEN_CTRL);
791 DUMPREG(VENC_OUTPUT_CONTROL);
792 DUMPREG(VENC_OUTPUT_TEST);
793
794 venc_enable_clocks(0);
795
796#undef DUMPREG
797}
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
new file mode 100644
index 000000000000..bb694cc52a50
--- /dev/null
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -0,0 +1,37 @@
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_FORCE_AUTO_UPDATE
22 bool "Force main display to automatic update mode"
23 depends on FB_OMAP2
24 help
25 Forces main display to automatic update mode (if possible),
26 and also enables tearsync (if possible). By default
27 displays that support manual update are started in manual
28 update mode.
29
30config FB_OMAP2_NUM_FBS
31 int "Number of framebuffers"
32 range 1 10
33 default 3
34 depends on FB_OMAP2
35 help
36 Select the number of framebuffers created. OMAP2/3 has 3 overlays
37 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..4c4bafdfaa43
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -0,0 +1,755 @@
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->get_resolution(display, &dw, &dh);
171
172 if (x + w > dw || y + h > dh)
173 return -EINVAL;
174
175 return display->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->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->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 || !display->get_update_mode)
237 return -EINVAL;
238
239 m = display->get_update_mode(display);
240
241 switch (m) {
242 case OMAP_DSS_UPDATE_DISABLED:
243 *mode = OMAPFB_UPDATE_DISABLED;
244 break;
245 case OMAP_DSS_UPDATE_AUTO:
246 *mode = OMAPFB_AUTO_UPDATE;
247 break;
248 case OMAP_DSS_UPDATE_MANUAL:
249 *mode = OMAPFB_MANUAL_UPDATE;
250 break;
251 default:
252 BUG();
253 }
254
255 return 0;
256}
257
258/* XXX this color key handling is a hack... */
259static struct omapfb_color_key omapfb_color_keys[2];
260
261static int _omapfb_set_color_key(struct omap_overlay_manager *mgr,
262 struct omapfb_color_key *ck)
263{
264 struct omap_overlay_manager_info info;
265 enum omap_dss_trans_key_type kt;
266 int r;
267
268 mgr->get_manager_info(mgr, &info);
269
270 if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {
271 info.trans_enabled = false;
272 omapfb_color_keys[mgr->id] = *ck;
273
274 r = mgr->set_manager_info(mgr, &info);
275 if (r)
276 return r;
277
278 r = mgr->apply(mgr);
279
280 return r;
281 }
282
283 switch (ck->key_type) {
284 case OMAPFB_COLOR_KEY_GFX_DST:
285 kt = OMAP_DSS_COLOR_KEY_GFX_DST;
286 break;
287 case OMAPFB_COLOR_KEY_VID_SRC:
288 kt = OMAP_DSS_COLOR_KEY_VID_SRC;
289 break;
290 default:
291 return -EINVAL;
292 }
293
294 info.default_color = ck->background;
295 info.trans_key = ck->trans_key;
296 info.trans_key_type = kt;
297 info.trans_enabled = true;
298
299 omapfb_color_keys[mgr->id] = *ck;
300
301 r = mgr->set_manager_info(mgr, &info);
302 if (r)
303 return r;
304
305 r = mgr->apply(mgr);
306
307 return r;
308}
309
310static int omapfb_set_color_key(struct fb_info *fbi,
311 struct omapfb_color_key *ck)
312{
313 struct omapfb_info *ofbi = FB2OFB(fbi);
314 struct omapfb2_device *fbdev = ofbi->fbdev;
315 int r;
316 int i;
317 struct omap_overlay_manager *mgr = NULL;
318
319 omapfb_lock(fbdev);
320
321 for (i = 0; i < ofbi->num_overlays; i++) {
322 if (ofbi->overlays[i]->manager) {
323 mgr = ofbi->overlays[i]->manager;
324 break;
325 }
326 }
327
328 if (!mgr) {
329 r = -EINVAL;
330 goto err;
331 }
332
333 r = _omapfb_set_color_key(mgr, ck);
334err:
335 omapfb_unlock(fbdev);
336
337 return r;
338}
339
340static int omapfb_get_color_key(struct fb_info *fbi,
341 struct omapfb_color_key *ck)
342{
343 struct omapfb_info *ofbi = FB2OFB(fbi);
344 struct omapfb2_device *fbdev = ofbi->fbdev;
345 struct omap_overlay_manager *mgr = NULL;
346 int r = 0;
347 int i;
348
349 omapfb_lock(fbdev);
350
351 for (i = 0; i < ofbi->num_overlays; i++) {
352 if (ofbi->overlays[i]->manager) {
353 mgr = ofbi->overlays[i]->manager;
354 break;
355 }
356 }
357
358 if (!mgr) {
359 r = -EINVAL;
360 goto err;
361 }
362
363 *ck = omapfb_color_keys[mgr->id];
364err:
365 omapfb_unlock(fbdev);
366
367 return r;
368}
369
370static int omapfb_memory_read(struct fb_info *fbi,
371 struct omapfb_memory_read *mr)
372{
373 struct omap_dss_device *display = fb2display(fbi);
374 void *buf;
375 int r;
376
377 if (!display || !display->memory_read)
378 return -ENOENT;
379
380 if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
381 return -EFAULT;
382
383 if (mr->w * mr->h * 3 > mr->buffer_size)
384 return -EINVAL;
385
386 buf = vmalloc(mr->buffer_size);
387 if (!buf) {
388 DBG("vmalloc failed\n");
389 return -ENOMEM;
390 }
391
392 r = display->memory_read(display, buf, mr->buffer_size,
393 mr->x, mr->y, mr->w, mr->h);
394
395 if (r > 0) {
396 if (copy_to_user(mr->buffer, buf, mr->buffer_size))
397 r = -EFAULT;
398 }
399
400 vfree(buf);
401
402 return r;
403}
404
405static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,
406 struct omapfb_ovl_colormode *mode)
407{
408 int ovl_idx = mode->overlay_idx;
409 int mode_idx = mode->mode_idx;
410 struct omap_overlay *ovl;
411 enum omap_color_mode supported_modes;
412 struct fb_var_screeninfo var;
413 int i;
414
415 if (ovl_idx >= fbdev->num_overlays)
416 return -ENODEV;
417 ovl = fbdev->overlays[ovl_idx];
418 supported_modes = ovl->supported_modes;
419
420 mode_idx = mode->mode_idx;
421
422 for (i = 0; i < sizeof(supported_modes) * 8; i++) {
423 if (!(supported_modes & (1 << i)))
424 continue;
425 /*
426 * It's possible that the FB doesn't support a mode
427 * that is supported by the overlay, so call the
428 * following here.
429 */
430 if (dss_mode_to_fb_mode(1 << i, &var) < 0)
431 continue;
432
433 mode_idx--;
434 if (mode_idx < 0)
435 break;
436 }
437
438 if (i == sizeof(supported_modes) * 8)
439 return -ENOENT;
440
441 mode->bits_per_pixel = var.bits_per_pixel;
442 mode->nonstd = var.nonstd;
443 mode->red = var.red;
444 mode->green = var.green;
445 mode->blue = var.blue;
446 mode->transp = var.transp;
447
448 return 0;
449}
450
451static int omapfb_wait_for_go(struct fb_info *fbi)
452{
453 struct omapfb_info *ofbi = FB2OFB(fbi);
454 int r = 0;
455 int i;
456
457 for (i = 0; i < ofbi->num_overlays; ++i) {
458 struct omap_overlay *ovl = ofbi->overlays[i];
459 r = ovl->wait_for_go(ovl);
460 if (r)
461 break;
462 }
463
464 return r;
465}
466
467int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
468{
469 struct omapfb_info *ofbi = FB2OFB(fbi);
470 struct omapfb2_device *fbdev = ofbi->fbdev;
471 struct omap_dss_device *display = fb2display(fbi);
472
473 union {
474 struct omapfb_update_window_old uwnd_o;
475 struct omapfb_update_window uwnd;
476 struct omapfb_plane_info plane_info;
477 struct omapfb_caps caps;
478 struct omapfb_mem_info mem_info;
479 struct omapfb_color_key color_key;
480 struct omapfb_ovl_colormode ovl_colormode;
481 enum omapfb_update_mode update_mode;
482 int test_num;
483 struct omapfb_memory_read memory_read;
484 struct omapfb_vram_info vram_info;
485 struct omapfb_tearsync_info tearsync_info;
486 } p;
487
488 int r = 0;
489
490 switch (cmd) {
491 case OMAPFB_SYNC_GFX:
492 DBG("ioctl SYNC_GFX\n");
493 if (!display || !display->sync) {
494 /* DSS1 never returns an error here, so we neither */
495 /*r = -EINVAL;*/
496 break;
497 }
498
499 r = display->sync(display);
500 break;
501
502 case OMAPFB_UPDATE_WINDOW_OLD:
503 DBG("ioctl UPDATE_WINDOW_OLD\n");
504 if (!display || !display->update) {
505 r = -EINVAL;
506 break;
507 }
508
509 if (copy_from_user(&p.uwnd_o,
510 (void __user *)arg,
511 sizeof(p.uwnd_o))) {
512 r = -EFAULT;
513 break;
514 }
515
516 r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y,
517 p.uwnd_o.width, p.uwnd_o.height);
518 break;
519
520 case OMAPFB_UPDATE_WINDOW:
521 DBG("ioctl UPDATE_WINDOW\n");
522 if (!display || !display->update) {
523 r = -EINVAL;
524 break;
525 }
526
527 if (copy_from_user(&p.uwnd, (void __user *)arg,
528 sizeof(p.uwnd))) {
529 r = -EFAULT;
530 break;
531 }
532
533 r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y,
534 p.uwnd.width, p.uwnd.height);
535 break;
536
537 case OMAPFB_SETUP_PLANE:
538 DBG("ioctl SETUP_PLANE\n");
539 if (copy_from_user(&p.plane_info, (void __user *)arg,
540 sizeof(p.plane_info)))
541 r = -EFAULT;
542 else
543 r = omapfb_setup_plane(fbi, &p.plane_info);
544 break;
545
546 case OMAPFB_QUERY_PLANE:
547 DBG("ioctl QUERY_PLANE\n");
548 r = omapfb_query_plane(fbi, &p.plane_info);
549 if (r < 0)
550 break;
551 if (copy_to_user((void __user *)arg, &p.plane_info,
552 sizeof(p.plane_info)))
553 r = -EFAULT;
554 break;
555
556 case OMAPFB_SETUP_MEM:
557 DBG("ioctl SETUP_MEM\n");
558 if (copy_from_user(&p.mem_info, (void __user *)arg,
559 sizeof(p.mem_info)))
560 r = -EFAULT;
561 else
562 r = omapfb_setup_mem(fbi, &p.mem_info);
563 break;
564
565 case OMAPFB_QUERY_MEM:
566 DBG("ioctl QUERY_MEM\n");
567 r = omapfb_query_mem(fbi, &p.mem_info);
568 if (r < 0)
569 break;
570 if (copy_to_user((void __user *)arg, &p.mem_info,
571 sizeof(p.mem_info)))
572 r = -EFAULT;
573 break;
574
575 case OMAPFB_GET_CAPS:
576 DBG("ioctl GET_CAPS\n");
577 if (!display) {
578 r = -EINVAL;
579 break;
580 }
581
582 memset(&p.caps, 0, sizeof(p.caps));
583 if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
584 p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE;
585 if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM)
586 p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC;
587
588 if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
589 r = -EFAULT;
590 break;
591
592 case OMAPFB_GET_OVERLAY_COLORMODE:
593 DBG("ioctl GET_OVERLAY_COLORMODE\n");
594 if (copy_from_user(&p.ovl_colormode, (void __user *)arg,
595 sizeof(p.ovl_colormode))) {
596 r = -EFAULT;
597 break;
598 }
599 r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);
600 if (r < 0)
601 break;
602 if (copy_to_user((void __user *)arg, &p.ovl_colormode,
603 sizeof(p.ovl_colormode)))
604 r = -EFAULT;
605 break;
606
607 case OMAPFB_SET_UPDATE_MODE:
608 DBG("ioctl SET_UPDATE_MODE\n");
609 if (get_user(p.update_mode, (int __user *)arg))
610 r = -EFAULT;
611 else
612 r = omapfb_set_update_mode(fbi, p.update_mode);
613 break;
614
615 case OMAPFB_GET_UPDATE_MODE:
616 DBG("ioctl GET_UPDATE_MODE\n");
617 r = omapfb_get_update_mode(fbi, &p.update_mode);
618 if (r)
619 break;
620 if (put_user(p.update_mode,
621 (enum omapfb_update_mode __user *)arg))
622 r = -EFAULT;
623 break;
624
625 case OMAPFB_SET_COLOR_KEY:
626 DBG("ioctl SET_COLOR_KEY\n");
627 if (copy_from_user(&p.color_key, (void __user *)arg,
628 sizeof(p.color_key)))
629 r = -EFAULT;
630 else
631 r = omapfb_set_color_key(fbi, &p.color_key);
632 break;
633
634 case OMAPFB_GET_COLOR_KEY:
635 DBG("ioctl GET_COLOR_KEY\n");
636 r = omapfb_get_color_key(fbi, &p.color_key);
637 if (r)
638 break;
639 if (copy_to_user((void __user *)arg, &p.color_key,
640 sizeof(p.color_key)))
641 r = -EFAULT;
642 break;
643
644 case OMAPFB_WAITFORVSYNC:
645 DBG("ioctl WAITFORVSYNC\n");
646 if (!display) {
647 r = -EINVAL;
648 break;
649 }
650
651 r = display->wait_vsync(display);
652 break;
653
654 case OMAPFB_WAITFORGO:
655 DBG("ioctl WAITFORGO\n");
656 if (!display) {
657 r = -EINVAL;
658 break;
659 }
660
661 r = omapfb_wait_for_go(fbi);
662 break;
663
664 /* LCD and CTRL tests do the same thing for backward
665 * compatibility */
666 case OMAPFB_LCD_TEST:
667 DBG("ioctl LCD_TEST\n");
668 if (get_user(p.test_num, (int __user *)arg)) {
669 r = -EFAULT;
670 break;
671 }
672 if (!display || !display->run_test) {
673 r = -EINVAL;
674 break;
675 }
676
677 r = display->run_test(display, p.test_num);
678
679 break;
680
681 case OMAPFB_CTRL_TEST:
682 DBG("ioctl CTRL_TEST\n");
683 if (get_user(p.test_num, (int __user *)arg)) {
684 r = -EFAULT;
685 break;
686 }
687 if (!display || !display->run_test) {
688 r = -EINVAL;
689 break;
690 }
691
692 r = display->run_test(display, p.test_num);
693
694 break;
695
696 case OMAPFB_MEMORY_READ:
697 DBG("ioctl MEMORY_READ\n");
698
699 if (copy_from_user(&p.memory_read, (void __user *)arg,
700 sizeof(p.memory_read))) {
701 r = -EFAULT;
702 break;
703 }
704
705 r = omapfb_memory_read(fbi, &p.memory_read);
706
707 break;
708
709 case OMAPFB_GET_VRAM_INFO: {
710 unsigned long vram, free, largest;
711
712 DBG("ioctl GET_VRAM_INFO\n");
713
714 omap_vram_get_info(&vram, &free, &largest);
715 p.vram_info.total = vram;
716 p.vram_info.free = free;
717 p.vram_info.largest_free_block = largest;
718
719 if (copy_to_user((void __user *)arg, &p.vram_info,
720 sizeof(p.vram_info)))
721 r = -EFAULT;
722 break;
723 }
724
725 case OMAPFB_SET_TEARSYNC: {
726 DBG("ioctl SET_TEARSYNC\n");
727
728 if (copy_from_user(&p.tearsync_info, (void __user *)arg,
729 sizeof(p.tearsync_info))) {
730 r = -EFAULT;
731 break;
732 }
733
734 if (!display->enable_te) {
735 r = -ENODEV;
736 break;
737 }
738
739 r = display->enable_te(display, !!p.tearsync_info.enabled);
740
741 break;
742 }
743
744 default:
745 dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
746 r = -EINVAL;
747 }
748
749 if (r < 0)
750 DBG("ioctl failed: %d\n", r);
751
752 return r;
753}
754
755
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
new file mode 100644
index 000000000000..ef299839858a
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -0,0 +1,2261 @@
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/fb.h>
26#include <linux/dma-mapping.h>
27#include <linux/vmalloc.h>
28#include <linux/device.h>
29#include <linux/platform_device.h>
30#include <linux/omapfb.h>
31
32#include <plat/display.h>
33#include <plat/vram.h>
34#include <plat/vrfb.h>
35
36#include "omapfb.h"
37
38#define MODULE_NAME "omapfb"
39
40#define OMAPFB_PLANE_XRES_MIN 8
41#define OMAPFB_PLANE_YRES_MIN 8
42
43static char *def_mode;
44static char *def_vram;
45static int def_vrfb;
46static int def_rotate;
47static int def_mirror;
48
49#ifdef DEBUG
50unsigned int omapfb_debug;
51module_param_named(debug, omapfb_debug, bool, 0644);
52static unsigned int omapfb_test_pattern;
53module_param_named(test, omapfb_test_pattern, bool, 0644);
54#endif
55
56static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
57
58#ifdef DEBUG
59static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
60{
61 struct fb_var_screeninfo *var = &fbi->var;
62 struct fb_fix_screeninfo *fix = &fbi->fix;
63 void __iomem *addr = fbi->screen_base;
64 const unsigned bytespp = var->bits_per_pixel >> 3;
65 const unsigned line_len = fix->line_length / bytespp;
66
67 int r = (color >> 16) & 0xff;
68 int g = (color >> 8) & 0xff;
69 int b = (color >> 0) & 0xff;
70
71 if (var->bits_per_pixel == 16) {
72 u16 __iomem *p = (u16 __iomem *)addr;
73 p += y * line_len + x;
74
75 r = r * 32 / 256;
76 g = g * 64 / 256;
77 b = b * 32 / 256;
78
79 __raw_writew((r << 11) | (g << 5) | (b << 0), p);
80 } else if (var->bits_per_pixel == 24) {
81 u8 __iomem *p = (u8 __iomem *)addr;
82 p += (y * line_len + x) * 3;
83
84 __raw_writeb(b, p + 0);
85 __raw_writeb(g, p + 1);
86 __raw_writeb(r, p + 2);
87 } else if (var->bits_per_pixel == 32) {
88 u32 __iomem *p = (u32 __iomem *)addr;
89 p += y * line_len + x;
90 __raw_writel(color, p);
91 }
92}
93
94static void fill_fb(struct fb_info *fbi)
95{
96 struct fb_var_screeninfo *var = &fbi->var;
97 const short w = var->xres_virtual;
98 const short h = var->yres_virtual;
99 void __iomem *addr = fbi->screen_base;
100 int y, x;
101
102 if (!addr)
103 return;
104
105 DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);
106
107 for (y = 0; y < h; y++) {
108 for (x = 0; x < w; x++) {
109 if (x < 20 && y < 20)
110 draw_pixel(fbi, x, y, 0xffffff);
111 else if (x < 20 && (y > 20 && y < h - 20))
112 draw_pixel(fbi, x, y, 0xff);
113 else if (y < 20 && (x > 20 && x < w - 20))
114 draw_pixel(fbi, x, y, 0xff00);
115 else if (x > w - 20 && (y > 20 && y < h - 20))
116 draw_pixel(fbi, x, y, 0xff0000);
117 else if (y > h - 20 && (x > 20 && x < w - 20))
118 draw_pixel(fbi, x, y, 0xffff00);
119 else if (x == 20 || x == w - 20 ||
120 y == 20 || y == h - 20)
121 draw_pixel(fbi, x, y, 0xffffff);
122 else if (x == y || w - x == h - y)
123 draw_pixel(fbi, x, y, 0xff00ff);
124 else if (w - x == y || x == h - y)
125 draw_pixel(fbi, x, y, 0x00ffff);
126 else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) {
127 int t = x * 3 / w;
128 unsigned r = 0, g = 0, b = 0;
129 unsigned c;
130 if (var->bits_per_pixel == 16) {
131 if (t == 0)
132 b = (y % 32) * 256 / 32;
133 else if (t == 1)
134 g = (y % 64) * 256 / 64;
135 else if (t == 2)
136 r = (y % 32) * 256 / 32;
137 } else {
138 if (t == 0)
139 b = (y % 256);
140 else if (t == 1)
141 g = (y % 256);
142 else if (t == 2)
143 r = (y % 256);
144 }
145 c = (r << 16) | (g << 8) | (b << 0);
146 draw_pixel(fbi, x, y, c);
147 } else {
148 draw_pixel(fbi, x, y, 0);
149 }
150 }
151 }
152}
153#endif
154
155static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot)
156{
157 struct vrfb *vrfb = &ofbi->region.vrfb;
158 unsigned offset;
159
160 switch (rot) {
161 case FB_ROTATE_UR:
162 offset = 0;
163 break;
164 case FB_ROTATE_CW:
165 offset = vrfb->yoffset;
166 break;
167 case FB_ROTATE_UD:
168 offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;
169 break;
170 case FB_ROTATE_CCW:
171 offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;
172 break;
173 default:
174 BUG();
175 }
176
177 offset *= vrfb->bytespp;
178
179 return offset;
180}
181
182static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi, int rot)
183{
184 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
185 return ofbi->region.vrfb.paddr[rot]
186 + omapfb_get_vrfb_offset(ofbi, rot);
187 } else {
188 return ofbi->region.paddr;
189 }
190}
191
192static u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)
193{
194 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
195 return ofbi->region.vrfb.paddr[0];
196 else
197 return ofbi->region.paddr;
198}
199
200static void __iomem *omapfb_get_region_vaddr(struct omapfb_info *ofbi)
201{
202 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
203 return ofbi->region.vrfb.vaddr[0];
204 else
205 return ofbi->region.vaddr;
206}
207
208static struct omapfb_colormode omapfb_colormodes[] = {
209 {
210 .dssmode = OMAP_DSS_COLOR_UYVY,
211 .bits_per_pixel = 16,
212 .nonstd = OMAPFB_COLOR_YUV422,
213 }, {
214 .dssmode = OMAP_DSS_COLOR_YUV2,
215 .bits_per_pixel = 16,
216 .nonstd = OMAPFB_COLOR_YUY422,
217 }, {
218 .dssmode = OMAP_DSS_COLOR_ARGB16,
219 .bits_per_pixel = 16,
220 .red = { .length = 4, .offset = 8, .msb_right = 0 },
221 .green = { .length = 4, .offset = 4, .msb_right = 0 },
222 .blue = { .length = 4, .offset = 0, .msb_right = 0 },
223 .transp = { .length = 4, .offset = 12, .msb_right = 0 },
224 }, {
225 .dssmode = OMAP_DSS_COLOR_RGB16,
226 .bits_per_pixel = 16,
227 .red = { .length = 5, .offset = 11, .msb_right = 0 },
228 .green = { .length = 6, .offset = 5, .msb_right = 0 },
229 .blue = { .length = 5, .offset = 0, .msb_right = 0 },
230 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
231 }, {
232 .dssmode = OMAP_DSS_COLOR_RGB24P,
233 .bits_per_pixel = 24,
234 .red = { .length = 8, .offset = 16, .msb_right = 0 },
235 .green = { .length = 8, .offset = 8, .msb_right = 0 },
236 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
237 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
238 }, {
239 .dssmode = OMAP_DSS_COLOR_RGB24U,
240 .bits_per_pixel = 32,
241 .red = { .length = 8, .offset = 16, .msb_right = 0 },
242 .green = { .length = 8, .offset = 8, .msb_right = 0 },
243 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
244 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
245 }, {
246 .dssmode = OMAP_DSS_COLOR_ARGB32,
247 .bits_per_pixel = 32,
248 .red = { .length = 8, .offset = 16, .msb_right = 0 },
249 .green = { .length = 8, .offset = 8, .msb_right = 0 },
250 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
251 .transp = { .length = 8, .offset = 24, .msb_right = 0 },
252 }, {
253 .dssmode = OMAP_DSS_COLOR_RGBA32,
254 .bits_per_pixel = 32,
255 .red = { .length = 8, .offset = 24, .msb_right = 0 },
256 .green = { .length = 8, .offset = 16, .msb_right = 0 },
257 .blue = { .length = 8, .offset = 8, .msb_right = 0 },
258 .transp = { .length = 8, .offset = 0, .msb_right = 0 },
259 }, {
260 .dssmode = OMAP_DSS_COLOR_RGBX32,
261 .bits_per_pixel = 32,
262 .red = { .length = 8, .offset = 24, .msb_right = 0 },
263 .green = { .length = 8, .offset = 16, .msb_right = 0 },
264 .blue = { .length = 8, .offset = 8, .msb_right = 0 },
265 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
266 },
267};
268
269static bool cmp_var_to_colormode(struct fb_var_screeninfo *var,
270 struct omapfb_colormode *color)
271{
272 bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)
273 {
274 return f1->length == f2->length &&
275 f1->offset == f2->offset &&
276 f1->msb_right == f2->msb_right;
277 }
278
279 if (var->bits_per_pixel == 0 ||
280 var->red.length == 0 ||
281 var->blue.length == 0 ||
282 var->green.length == 0)
283 return 0;
284
285 return var->bits_per_pixel == color->bits_per_pixel &&
286 cmp_component(&var->red, &color->red) &&
287 cmp_component(&var->green, &color->green) &&
288 cmp_component(&var->blue, &color->blue) &&
289 cmp_component(&var->transp, &color->transp);
290}
291
292static void assign_colormode_to_var(struct fb_var_screeninfo *var,
293 struct omapfb_colormode *color)
294{
295 var->bits_per_pixel = color->bits_per_pixel;
296 var->nonstd = color->nonstd;
297 var->red = color->red;
298 var->green = color->green;
299 var->blue = color->blue;
300 var->transp = color->transp;
301}
302
303static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var,
304 enum omap_color_mode *mode)
305{
306 enum omap_color_mode dssmode;
307 int i;
308
309 /* first match with nonstd field */
310 if (var->nonstd) {
311 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
312 struct omapfb_colormode *m = &omapfb_colormodes[i];
313 if (var->nonstd == m->nonstd) {
314 assign_colormode_to_var(var, m);
315 *mode = m->dssmode;
316 return 0;
317 }
318 }
319
320 return -EINVAL;
321 }
322
323 /* then try exact match of bpp and colors */
324 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
325 struct omapfb_colormode *m = &omapfb_colormodes[i];
326 if (cmp_var_to_colormode(var, m)) {
327 assign_colormode_to_var(var, m);
328 *mode = m->dssmode;
329 return 0;
330 }
331 }
332
333 /* match with bpp if user has not filled color fields
334 * properly */
335 switch (var->bits_per_pixel) {
336 case 1:
337 dssmode = OMAP_DSS_COLOR_CLUT1;
338 break;
339 case 2:
340 dssmode = OMAP_DSS_COLOR_CLUT2;
341 break;
342 case 4:
343 dssmode = OMAP_DSS_COLOR_CLUT4;
344 break;
345 case 8:
346 dssmode = OMAP_DSS_COLOR_CLUT8;
347 break;
348 case 12:
349 dssmode = OMAP_DSS_COLOR_RGB12U;
350 break;
351 case 16:
352 dssmode = OMAP_DSS_COLOR_RGB16;
353 break;
354 case 24:
355 dssmode = OMAP_DSS_COLOR_RGB24P;
356 break;
357 case 32:
358 dssmode = OMAP_DSS_COLOR_RGB24U;
359 break;
360 default:
361 return -EINVAL;
362 }
363
364 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
365 struct omapfb_colormode *m = &omapfb_colormodes[i];
366 if (dssmode == m->dssmode) {
367 assign_colormode_to_var(var, m);
368 *mode = m->dssmode;
369 return 0;
370 }
371 }
372
373 return -EINVAL;
374}
375
376static int check_fb_res_bounds(struct fb_var_screeninfo *var)
377{
378 int xres_min = OMAPFB_PLANE_XRES_MIN;
379 int xres_max = 2048;
380 int yres_min = OMAPFB_PLANE_YRES_MIN;
381 int yres_max = 2048;
382
383 /* XXX: some applications seem to set virtual res to 0. */
384 if (var->xres_virtual == 0)
385 var->xres_virtual = var->xres;
386
387 if (var->yres_virtual == 0)
388 var->yres_virtual = var->yres;
389
390 if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)
391 return -EINVAL;
392
393 if (var->xres < xres_min)
394 var->xres = xres_min;
395 if (var->yres < yres_min)
396 var->yres = yres_min;
397 if (var->xres > xres_max)
398 var->xres = xres_max;
399 if (var->yres > yres_max)
400 var->yres = yres_max;
401
402 if (var->xres > var->xres_virtual)
403 var->xres = var->xres_virtual;
404 if (var->yres > var->yres_virtual)
405 var->yres = var->yres_virtual;
406
407 return 0;
408}
409
410static void shrink_height(unsigned long max_frame_size,
411 struct fb_var_screeninfo *var)
412{
413 DBG("can't fit FB into memory, reducing y\n");
414 var->yres_virtual = max_frame_size /
415 (var->xres_virtual * var->bits_per_pixel >> 3);
416
417 if (var->yres_virtual < OMAPFB_PLANE_YRES_MIN)
418 var->yres_virtual = OMAPFB_PLANE_YRES_MIN;
419
420 if (var->yres > var->yres_virtual)
421 var->yres = var->yres_virtual;
422}
423
424static void shrink_width(unsigned long max_frame_size,
425 struct fb_var_screeninfo *var)
426{
427 DBG("can't fit FB into memory, reducing x\n");
428 var->xres_virtual = max_frame_size / var->yres_virtual /
429 (var->bits_per_pixel >> 3);
430
431 if (var->xres_virtual < OMAPFB_PLANE_XRES_MIN)
432 var->xres_virtual = OMAPFB_PLANE_XRES_MIN;
433
434 if (var->xres > var->xres_virtual)
435 var->xres = var->xres_virtual;
436}
437
438static int check_vrfb_fb_size(unsigned long region_size,
439 const struct fb_var_screeninfo *var)
440{
441 unsigned long min_phys_size = omap_vrfb_min_phys_size(var->xres_virtual,
442 var->yres_virtual, var->bits_per_pixel >> 3);
443
444 return min_phys_size > region_size ? -EINVAL : 0;
445}
446
447static int check_fb_size(const struct omapfb_info *ofbi,
448 struct fb_var_screeninfo *var)
449{
450 unsigned long max_frame_size = ofbi->region.size;
451 int bytespp = var->bits_per_pixel >> 3;
452 unsigned long line_size = var->xres_virtual * bytespp;
453
454 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
455 /* One needs to check for both VRFB and OMAPFB limitations. */
456 if (check_vrfb_fb_size(max_frame_size, var))
457 shrink_height(omap_vrfb_max_height(
458 max_frame_size, var->xres_virtual, bytespp) *
459 line_size, var);
460
461 if (check_vrfb_fb_size(max_frame_size, var)) {
462 DBG("cannot fit FB to memory\n");
463 return -EINVAL;
464 }
465
466 return 0;
467 }
468
469 DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);
470
471 if (line_size * var->yres_virtual > max_frame_size)
472 shrink_height(max_frame_size, var);
473
474 if (line_size * var->yres_virtual > max_frame_size) {
475 shrink_width(max_frame_size, var);
476 line_size = var->xres_virtual * bytespp;
477 }
478
479 if (line_size * var->yres_virtual > max_frame_size) {
480 DBG("cannot fit FB to memory\n");
481 return -EINVAL;
482 }
483
484 return 0;
485}
486
487/*
488 * Consider if VRFB assisted rotation is in use and if the virtual space for
489 * the zero degree view needs to be mapped. The need for mapping also acts as
490 * the trigger for setting up the hardware on the context in question. This
491 * ensures that one does not attempt to access the virtual view before the
492 * hardware is serving the address translations.
493 */
494static int setup_vrfb_rotation(struct fb_info *fbi)
495{
496 struct omapfb_info *ofbi = FB2OFB(fbi);
497 struct omapfb2_mem_region *rg = &ofbi->region;
498 struct vrfb *vrfb = &rg->vrfb;
499 struct fb_var_screeninfo *var = &fbi->var;
500 struct fb_fix_screeninfo *fix = &fbi->fix;
501 unsigned bytespp;
502 bool yuv_mode;
503 enum omap_color_mode mode;
504 int r;
505 bool reconf;
506
507 if (!rg->size || ofbi->rotation_type != OMAP_DSS_ROT_VRFB)
508 return 0;
509
510 DBG("setup_vrfb_rotation\n");
511
512 r = fb_mode_to_dss_mode(var, &mode);
513 if (r)
514 return r;
515
516 bytespp = var->bits_per_pixel >> 3;
517
518 yuv_mode = mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY;
519
520 /* We need to reconfigure VRFB if the resolution changes, if yuv mode
521 * is enabled/disabled, or if bytes per pixel changes */
522
523 /* XXX we shouldn't allow this when framebuffer is mmapped */
524
525 reconf = false;
526
527 if (yuv_mode != vrfb->yuv_mode)
528 reconf = true;
529 else if (bytespp != vrfb->bytespp)
530 reconf = true;
531 else if (vrfb->xres != var->xres_virtual ||
532 vrfb->yres != var->yres_virtual)
533 reconf = true;
534
535 if (vrfb->vaddr[0] && reconf) {
536 fbi->screen_base = NULL;
537 fix->smem_start = 0;
538 fix->smem_len = 0;
539 iounmap(vrfb->vaddr[0]);
540 vrfb->vaddr[0] = NULL;
541 DBG("setup_vrfb_rotation: reset fb\n");
542 }
543
544 if (vrfb->vaddr[0])
545 return 0;
546
547 omap_vrfb_setup(&rg->vrfb, rg->paddr,
548 var->xres_virtual,
549 var->yres_virtual,
550 bytespp, yuv_mode);
551
552 /* Now one can ioremap the 0 angle view */
553 r = omap_vrfb_map_angle(vrfb, var->yres_virtual, 0);
554 if (r)
555 return r;
556
557 /* used by open/write in fbmem.c */
558 fbi->screen_base = ofbi->region.vrfb.vaddr[0];
559
560 fix->smem_start = ofbi->region.vrfb.paddr[0];
561
562 switch (var->nonstd) {
563 case OMAPFB_COLOR_YUV422:
564 case OMAPFB_COLOR_YUY422:
565 fix->line_length =
566 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
567 break;
568 default:
569 fix->line_length =
570 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
571 break;
572 }
573
574 fix->smem_len = var->yres_virtual * fix->line_length;
575
576 return 0;
577}
578
579int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
580 struct fb_var_screeninfo *var)
581{
582 int i;
583
584 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
585 struct omapfb_colormode *mode = &omapfb_colormodes[i];
586 if (dssmode == mode->dssmode) {
587 assign_colormode_to_var(var, mode);
588 return 0;
589 }
590 }
591 return -ENOENT;
592}
593
594void set_fb_fix(struct fb_info *fbi)
595{
596 struct fb_fix_screeninfo *fix = &fbi->fix;
597 struct fb_var_screeninfo *var = &fbi->var;
598 struct omapfb_info *ofbi = FB2OFB(fbi);
599 struct omapfb2_mem_region *rg = &ofbi->region;
600
601 DBG("set_fb_fix\n");
602
603 /* used by open/write in fbmem.c */
604 fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
605
606 /* used by mmap in fbmem.c */
607 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
608 switch (var->nonstd) {
609 case OMAPFB_COLOR_YUV422:
610 case OMAPFB_COLOR_YUY422:
611 fix->line_length =
612 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
613 break;
614 default:
615 fix->line_length =
616 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
617 break;
618 }
619
620 fix->smem_len = var->yres_virtual * fix->line_length;
621 } else {
622 fix->line_length =
623 (var->xres_virtual * var->bits_per_pixel) >> 3;
624 fix->smem_len = rg->size;
625 }
626
627 fix->smem_start = omapfb_get_region_paddr(ofbi);
628
629 fix->type = FB_TYPE_PACKED_PIXELS;
630
631 if (var->nonstd)
632 fix->visual = FB_VISUAL_PSEUDOCOLOR;
633 else {
634 switch (var->bits_per_pixel) {
635 case 32:
636 case 24:
637 case 16:
638 case 12:
639 fix->visual = FB_VISUAL_TRUECOLOR;
640 /* 12bpp is stored in 16 bits */
641 break;
642 case 1:
643 case 2:
644 case 4:
645 case 8:
646 fix->visual = FB_VISUAL_PSEUDOCOLOR;
647 break;
648 }
649 }
650
651 fix->accel = FB_ACCEL_NONE;
652
653 fix->xpanstep = 1;
654 fix->ypanstep = 1;
655}
656
657/* check new var and possibly modify it to be ok */
658int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
659{
660 struct omapfb_info *ofbi = FB2OFB(fbi);
661 struct omap_dss_device *display = fb2display(fbi);
662 enum omap_color_mode mode = 0;
663 int i;
664 int r;
665
666 DBG("check_fb_var %d\n", ofbi->id);
667
668 if (ofbi->region.size == 0)
669 return 0;
670
671 r = fb_mode_to_dss_mode(var, &mode);
672 if (r) {
673 DBG("cannot convert var to omap dss mode\n");
674 return r;
675 }
676
677 for (i = 0; i < ofbi->num_overlays; ++i) {
678 if ((ofbi->overlays[i]->supported_modes & mode) == 0) {
679 DBG("invalid mode\n");
680 return -EINVAL;
681 }
682 }
683
684 if (var->rotate < 0 || var->rotate > 3)
685 return -EINVAL;
686
687 if (check_fb_res_bounds(var))
688 return -EINVAL;
689
690 if (check_fb_size(ofbi, var))
691 return -EINVAL;
692
693 if (var->xres + var->xoffset > var->xres_virtual)
694 var->xoffset = var->xres_virtual - var->xres;
695 if (var->yres + var->yoffset > var->yres_virtual)
696 var->yoffset = var->yres_virtual - var->yres;
697
698 DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n",
699 var->xres, var->yres,
700 var->xres_virtual, var->yres_virtual);
701
702 var->height = -1;
703 var->width = -1;
704 var->grayscale = 0;
705
706 if (display && display->get_timings) {
707 struct omap_video_timings timings;
708 display->get_timings(display, &timings);
709
710 /* pixclock in ps, the rest in pixclock */
711 var->pixclock = timings.pixel_clock != 0 ?
712 KHZ2PICOS(timings.pixel_clock) :
713 0;
714 var->left_margin = timings.hfp;
715 var->right_margin = timings.hbp;
716 var->upper_margin = timings.vfp;
717 var->lower_margin = timings.vbp;
718 var->hsync_len = timings.hsw;
719 var->vsync_len = timings.vsw;
720 } else {
721 var->pixclock = 0;
722 var->left_margin = 0;
723 var->right_margin = 0;
724 var->upper_margin = 0;
725 var->lower_margin = 0;
726 var->hsync_len = 0;
727 var->vsync_len = 0;
728 }
729
730 /* TODO: get these from panel->config */
731 var->vmode = FB_VMODE_NONINTERLACED;
732 var->sync = 0;
733
734 return 0;
735}
736
737/*
738 * ---------------------------------------------------------------------------
739 * fbdev framework callbacks
740 * ---------------------------------------------------------------------------
741 */
742static int omapfb_open(struct fb_info *fbi, int user)
743{
744 return 0;
745}
746
747static int omapfb_release(struct fb_info *fbi, int user)
748{
749#if 0
750 struct omapfb_info *ofbi = FB2OFB(fbi);
751 struct omapfb2_device *fbdev = ofbi->fbdev;
752 struct omap_dss_device *display = fb2display(fbi);
753
754 DBG("Closing fb with plane index %d\n", ofbi->id);
755
756 omapfb_lock(fbdev);
757
758 if (display && display->get_update_mode && display->update) {
759 /* XXX this update should be removed, I think. But it's
760 * good for debugging */
761 if (display->get_update_mode(display) ==
762 OMAP_DSS_UPDATE_MANUAL) {
763 u16 w, h;
764
765 if (display->sync)
766 display->sync(display);
767
768 display->get_resolution(display, &w, &h);
769 display->update(display, 0, 0, w, h);
770 }
771 }
772
773 if (display && display->sync)
774 display->sync(display);
775
776 omapfb_unlock(fbdev);
777#endif
778 return 0;
779}
780
781static unsigned calc_rotation_offset_dma(struct fb_var_screeninfo *var,
782 struct fb_fix_screeninfo *fix, int rotation)
783{
784 unsigned offset;
785
786 offset = var->yoffset * fix->line_length +
787 var->xoffset * (var->bits_per_pixel >> 3);
788
789 return offset;
790}
791
792static unsigned calc_rotation_offset_vrfb(struct fb_var_screeninfo *var,
793 struct fb_fix_screeninfo *fix, int rotation)
794{
795 unsigned offset;
796
797 if (rotation == FB_ROTATE_UD)
798 offset = (var->yres_virtual - var->yres) *
799 fix->line_length;
800 else if (rotation == FB_ROTATE_CW)
801 offset = (var->yres_virtual - var->yres) *
802 (var->bits_per_pixel >> 3);
803 else
804 offset = 0;
805
806 if (rotation == FB_ROTATE_UR)
807 offset += var->yoffset * fix->line_length +
808 var->xoffset * (var->bits_per_pixel >> 3);
809 else if (rotation == FB_ROTATE_UD)
810 offset -= var->yoffset * fix->line_length +
811 var->xoffset * (var->bits_per_pixel >> 3);
812 else if (rotation == FB_ROTATE_CW)
813 offset -= var->xoffset * fix->line_length +
814 var->yoffset * (var->bits_per_pixel >> 3);
815 else if (rotation == FB_ROTATE_CCW)
816 offset += var->xoffset * fix->line_length +
817 var->yoffset * (var->bits_per_pixel >> 3);
818
819 return offset;
820}
821
822
823/* setup overlay according to the fb */
824static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
825 u16 posx, u16 posy, u16 outw, u16 outh)
826{
827 int r = 0;
828 struct omapfb_info *ofbi = FB2OFB(fbi);
829 struct fb_var_screeninfo *var = &fbi->var;
830 struct fb_fix_screeninfo *fix = &fbi->fix;
831 enum omap_color_mode mode = 0;
832 int offset;
833 u32 data_start_p;
834 void __iomem *data_start_v;
835 struct omap_overlay_info info;
836 int xres, yres;
837 int screen_width;
838 int mirror;
839 int rotation = var->rotate;
840 int i;
841
842 for (i = 0; i < ofbi->num_overlays; i++) {
843 if (ovl != ofbi->overlays[i])
844 continue;
845
846 rotation = (rotation + ofbi->rotation[i]) % 4;
847 break;
848 }
849
850 DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
851 posx, posy, outw, outh);
852
853 if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {
854 xres = var->yres;
855 yres = var->xres;
856 } else {
857 xres = var->xres;
858 yres = var->yres;
859 }
860
861
862 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
863 data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
864 data_start_v = NULL;
865 } else {
866 data_start_p = omapfb_get_region_paddr(ofbi);
867 data_start_v = omapfb_get_region_vaddr(ofbi);
868 }
869
870 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
871 offset = calc_rotation_offset_vrfb(var, fix, rotation);
872 else
873 offset = calc_rotation_offset_dma(var, fix, rotation);
874
875 data_start_p += offset;
876 data_start_v += offset;
877
878 if (offset)
879 DBG("offset %d, %d = %d\n",
880 var->xoffset, var->yoffset, offset);
881
882 DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);
883
884 r = fb_mode_to_dss_mode(var, &mode);
885 if (r) {
886 DBG("fb_mode_to_dss_mode failed");
887 goto err;
888 }
889
890 switch (var->nonstd) {
891 case OMAPFB_COLOR_YUV422:
892 case OMAPFB_COLOR_YUY422:
893 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
894 screen_width = fix->line_length
895 / (var->bits_per_pixel >> 2);
896 break;
897 }
898 default:
899 screen_width = fix->line_length / (var->bits_per_pixel >> 3);
900 break;
901 }
902
903 ovl->get_overlay_info(ovl, &info);
904
905 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
906 mirror = 0;
907 else
908 mirror = ofbi->mirror;
909
910 info.paddr = data_start_p;
911 info.vaddr = data_start_v;
912 info.screen_width = screen_width;
913 info.width = xres;
914 info.height = yres;
915 info.color_mode = mode;
916 info.rotation_type = ofbi->rotation_type;
917 info.rotation = rotation;
918 info.mirror = mirror;
919
920 info.pos_x = posx;
921 info.pos_y = posy;
922 info.out_width = outw;
923 info.out_height = outh;
924
925 r = ovl->set_overlay_info(ovl, &info);
926 if (r) {
927 DBG("ovl->setup_overlay_info failed\n");
928 goto err;
929 }
930
931 return 0;
932
933err:
934 DBG("setup_overlay failed\n");
935 return r;
936}
937
938/* apply var to the overlay */
939int omapfb_apply_changes(struct fb_info *fbi, int init)
940{
941 int r = 0;
942 struct omapfb_info *ofbi = FB2OFB(fbi);
943 struct fb_var_screeninfo *var = &fbi->var;
944 struct omap_overlay *ovl;
945 u16 posx, posy;
946 u16 outw, outh;
947 int i;
948
949#ifdef DEBUG
950 if (omapfb_test_pattern)
951 fill_fb(fbi);
952#endif
953
954 for (i = 0; i < ofbi->num_overlays; i++) {
955 ovl = ofbi->overlays[i];
956
957 DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
958
959 if (ofbi->region.size == 0) {
960 /* the fb is not available. disable the overlay */
961 omapfb_overlay_enable(ovl, 0);
962 if (!init && ovl->manager)
963 ovl->manager->apply(ovl->manager);
964 continue;
965 }
966
967 if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
968 int rotation = (var->rotate + ofbi->rotation[i]) % 4;
969 if (rotation == FB_ROTATE_CW ||
970 rotation == FB_ROTATE_CCW) {
971 outw = var->yres;
972 outh = var->xres;
973 } else {
974 outw = var->xres;
975 outh = var->yres;
976 }
977 } else {
978 outw = ovl->info.out_width;
979 outh = ovl->info.out_height;
980 }
981
982 if (init) {
983 posx = 0;
984 posy = 0;
985 } else {
986 posx = ovl->info.pos_x;
987 posy = ovl->info.pos_y;
988 }
989
990 r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
991 if (r)
992 goto err;
993
994 if (!init && ovl->manager)
995 ovl->manager->apply(ovl->manager);
996 }
997 return 0;
998err:
999 DBG("apply_changes failed\n");
1000 return r;
1001}
1002
1003/* checks var and eventually tweaks it to something supported,
1004 * DO NOT MODIFY PAR */
1005static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
1006{
1007 int r;
1008
1009 DBG("check_var(%d)\n", FB2OFB(fbi)->id);
1010
1011 r = check_fb_var(fbi, var);
1012
1013 return r;
1014}
1015
1016/* set the video mode according to info->var */
1017static int omapfb_set_par(struct fb_info *fbi)
1018{
1019 int r;
1020
1021 DBG("set_par(%d)\n", FB2OFB(fbi)->id);
1022
1023 set_fb_fix(fbi);
1024
1025 r = setup_vrfb_rotation(fbi);
1026 if (r)
1027 return r;
1028
1029 r = omapfb_apply_changes(fbi, 0);
1030
1031 return r;
1032}
1033
1034static int omapfb_pan_display(struct fb_var_screeninfo *var,
1035 struct fb_info *fbi)
1036{
1037 struct fb_var_screeninfo new_var;
1038 int r;
1039
1040 DBG("pan_display(%d)\n", FB2OFB(fbi)->id);
1041
1042 if (var->xoffset == fbi->var.xoffset &&
1043 var->yoffset == fbi->var.yoffset)
1044 return 0;
1045
1046 new_var = fbi->var;
1047 new_var.xoffset = var->xoffset;
1048 new_var.yoffset = var->yoffset;
1049
1050 fbi->var = new_var;
1051
1052 r = omapfb_apply_changes(fbi, 0);
1053
1054 return r;
1055}
1056
1057static void mmap_user_open(struct vm_area_struct *vma)
1058{
1059 struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
1060
1061 atomic_inc(&ofbi->map_count);
1062}
1063
1064static void mmap_user_close(struct vm_area_struct *vma)
1065{
1066 struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
1067
1068 atomic_dec(&ofbi->map_count);
1069}
1070
1071static struct vm_operations_struct mmap_user_ops = {
1072 .open = mmap_user_open,
1073 .close = mmap_user_close,
1074};
1075
1076static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
1077{
1078 struct omapfb_info *ofbi = FB2OFB(fbi);
1079 struct fb_fix_screeninfo *fix = &fbi->fix;
1080 unsigned long off;
1081 unsigned long start;
1082 u32 len;
1083
1084 if (vma->vm_end - vma->vm_start == 0)
1085 return 0;
1086 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1087 return -EINVAL;
1088 off = vma->vm_pgoff << PAGE_SHIFT;
1089
1090 start = omapfb_get_region_paddr(ofbi);
1091 len = fix->smem_len;
1092 if (off >= len)
1093 return -EINVAL;
1094 if ((vma->vm_end - vma->vm_start + off) > len)
1095 return -EINVAL;
1096
1097 off += start;
1098
1099 DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
1100
1101 vma->vm_pgoff = off >> PAGE_SHIFT;
1102 vma->vm_flags |= VM_IO | VM_RESERVED;
1103 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1104 vma->vm_ops = &mmap_user_ops;
1105 vma->vm_private_data = ofbi;
1106 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
1107 vma->vm_end - vma->vm_start, vma->vm_page_prot))
1108 return -EAGAIN;
1109 /* vm_ops.open won't be called for mmap itself. */
1110 atomic_inc(&ofbi->map_count);
1111 return 0;
1112}
1113
1114/* Store a single color palette entry into a pseudo palette or the hardware
1115 * palette if one is available. For now we support only 16bpp and thus store
1116 * the entry only to the pseudo palette.
1117 */
1118static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
1119 u_int blue, u_int transp, int update_hw_pal)
1120{
1121 /*struct omapfb_info *ofbi = FB2OFB(fbi);*/
1122 /*struct omapfb2_device *fbdev = ofbi->fbdev;*/
1123 struct fb_var_screeninfo *var = &fbi->var;
1124 int r = 0;
1125
1126 enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */
1127
1128 /*switch (plane->color_mode) {*/
1129 switch (mode) {
1130 case OMAPFB_COLOR_YUV422:
1131 case OMAPFB_COLOR_YUV420:
1132 case OMAPFB_COLOR_YUY422:
1133 r = -EINVAL;
1134 break;
1135 case OMAPFB_COLOR_CLUT_8BPP:
1136 case OMAPFB_COLOR_CLUT_4BPP:
1137 case OMAPFB_COLOR_CLUT_2BPP:
1138 case OMAPFB_COLOR_CLUT_1BPP:
1139 /*
1140 if (fbdev->ctrl->setcolreg)
1141 r = fbdev->ctrl->setcolreg(regno, red, green, blue,
1142 transp, update_hw_pal);
1143 */
1144 /* Fallthrough */
1145 r = -EINVAL;
1146 break;
1147 case OMAPFB_COLOR_RGB565:
1148 case OMAPFB_COLOR_RGB444:
1149 case OMAPFB_COLOR_RGB24P:
1150 case OMAPFB_COLOR_RGB24U:
1151 if (r != 0)
1152 break;
1153
1154 if (regno < 0) {
1155 r = -EINVAL;
1156 break;
1157 }
1158
1159 if (regno < 16) {
1160 u16 pal;
1161 pal = ((red >> (16 - var->red.length)) <<
1162 var->red.offset) |
1163 ((green >> (16 - var->green.length)) <<
1164 var->green.offset) |
1165 (blue >> (16 - var->blue.length));
1166 ((u32 *)(fbi->pseudo_palette))[regno] = pal;
1167 }
1168 break;
1169 default:
1170 BUG();
1171 }
1172 return r;
1173}
1174
1175static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
1176 u_int transp, struct fb_info *info)
1177{
1178 DBG("setcolreg\n");
1179
1180 return _setcolreg(info, regno, red, green, blue, transp, 1);
1181}
1182
1183static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1184{
1185 int count, index, r;
1186 u16 *red, *green, *blue, *transp;
1187 u16 trans = 0xffff;
1188
1189 DBG("setcmap\n");
1190
1191 red = cmap->red;
1192 green = cmap->green;
1193 blue = cmap->blue;
1194 transp = cmap->transp;
1195 index = cmap->start;
1196
1197 for (count = 0; count < cmap->len; count++) {
1198 if (transp)
1199 trans = *transp++;
1200 r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
1201 count == cmap->len - 1);
1202 if (r != 0)
1203 return r;
1204 }
1205
1206 return 0;
1207}
1208
1209static int omapfb_blank(int blank, struct fb_info *fbi)
1210{
1211 struct omapfb_info *ofbi = FB2OFB(fbi);
1212 struct omapfb2_device *fbdev = ofbi->fbdev;
1213 struct omap_dss_device *display = fb2display(fbi);
1214 int do_update = 0;
1215 int r = 0;
1216
1217 omapfb_lock(fbdev);
1218
1219 switch (blank) {
1220 case FB_BLANK_UNBLANK:
1221 if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
1222 goto exit;
1223
1224 if (display->resume)
1225 r = display->resume(display);
1226
1227 if (r == 0 && display->get_update_mode &&
1228 display->get_update_mode(display) ==
1229 OMAP_DSS_UPDATE_MANUAL)
1230 do_update = 1;
1231
1232 break;
1233
1234 case FB_BLANK_NORMAL:
1235 /* FB_BLANK_NORMAL could be implemented.
1236 * Needs DSS additions. */
1237 case FB_BLANK_VSYNC_SUSPEND:
1238 case FB_BLANK_HSYNC_SUSPEND:
1239 case FB_BLANK_POWERDOWN:
1240 if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
1241 goto exit;
1242
1243 if (display->suspend)
1244 r = display->suspend(display);
1245
1246 break;
1247
1248 default:
1249 r = -EINVAL;
1250 }
1251
1252exit:
1253 omapfb_unlock(fbdev);
1254
1255 if (r == 0 && do_update && display->update) {
1256 u16 w, h;
1257 display->get_resolution(display, &w, &h);
1258
1259 r = display->update(display, 0, 0, w, h);
1260 }
1261
1262 return r;
1263}
1264
1265#if 0
1266/* XXX fb_read and fb_write are needed for VRFB */
1267ssize_t omapfb_write(struct fb_info *info, const char __user *buf,
1268 size_t count, loff_t *ppos)
1269{
1270 DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
1271 /* XXX needed for VRFB */
1272 return count;
1273}
1274#endif
1275
1276static struct fb_ops omapfb_ops = {
1277 .owner = THIS_MODULE,
1278 .fb_open = omapfb_open,
1279 .fb_release = omapfb_release,
1280 .fb_fillrect = cfb_fillrect,
1281 .fb_copyarea = cfb_copyarea,
1282 .fb_imageblit = cfb_imageblit,
1283 .fb_blank = omapfb_blank,
1284 .fb_ioctl = omapfb_ioctl,
1285 .fb_check_var = omapfb_check_var,
1286 .fb_set_par = omapfb_set_par,
1287 .fb_pan_display = omapfb_pan_display,
1288 .fb_mmap = omapfb_mmap,
1289 .fb_setcolreg = omapfb_setcolreg,
1290 .fb_setcmap = omapfb_setcmap,
1291 /*.fb_write = omapfb_write,*/
1292};
1293
1294static void omapfb_free_fbmem(struct fb_info *fbi)
1295{
1296 struct omapfb_info *ofbi = FB2OFB(fbi);
1297 struct omapfb2_device *fbdev = ofbi->fbdev;
1298 struct omapfb2_mem_region *rg;
1299
1300 rg = &ofbi->region;
1301
1302 if (rg->paddr)
1303 if (omap_vram_free(rg->paddr, rg->size))
1304 dev_err(fbdev->dev, "VRAM FREE failed\n");
1305
1306 if (rg->vaddr)
1307 iounmap(rg->vaddr);
1308
1309 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1310 /* unmap the 0 angle rotation */
1311 if (rg->vrfb.vaddr[0]) {
1312 iounmap(rg->vrfb.vaddr[0]);
1313 omap_vrfb_release_ctx(&rg->vrfb);
1314 }
1315 }
1316
1317 rg->vaddr = NULL;
1318 rg->paddr = 0;
1319 rg->alloc = 0;
1320 rg->size = 0;
1321}
1322
1323static void clear_fb_info(struct fb_info *fbi)
1324{
1325 memset(&fbi->var, 0, sizeof(fbi->var));
1326 memset(&fbi->fix, 0, sizeof(fbi->fix));
1327 strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
1328}
1329
1330static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
1331{
1332 int i;
1333
1334 DBG("free all fbmem\n");
1335
1336 for (i = 0; i < fbdev->num_fbs; i++) {
1337 struct fb_info *fbi = fbdev->fbs[i];
1338 omapfb_free_fbmem(fbi);
1339 clear_fb_info(fbi);
1340 }
1341
1342 return 0;
1343}
1344
1345static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
1346 unsigned long paddr)
1347{
1348 struct omapfb_info *ofbi = FB2OFB(fbi);
1349 struct omapfb2_device *fbdev = ofbi->fbdev;
1350 struct omapfb2_mem_region *rg;
1351 void __iomem *vaddr;
1352 int r;
1353
1354 rg = &ofbi->region;
1355 memset(rg, 0, sizeof(*rg));
1356
1357 size = PAGE_ALIGN(size);
1358
1359 if (!paddr) {
1360 DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
1361 r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr);
1362 } else {
1363 DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
1364 ofbi->id);
1365 r = omap_vram_reserve(paddr, size);
1366 }
1367
1368 if (r) {
1369 dev_err(fbdev->dev, "failed to allocate framebuffer\n");
1370 return -ENOMEM;
1371 }
1372
1373 if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {
1374 vaddr = ioremap_wc(paddr, size);
1375
1376 if (!vaddr) {
1377 dev_err(fbdev->dev, "failed to ioremap framebuffer\n");
1378 omap_vram_free(paddr, size);
1379 return -ENOMEM;
1380 }
1381
1382 DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);
1383 } else {
1384 r = omap_vrfb_request_ctx(&rg->vrfb);
1385 if (r) {
1386 dev_err(fbdev->dev, "vrfb create ctx failed\n");
1387 return r;
1388 }
1389
1390 vaddr = NULL;
1391 }
1392
1393 rg->paddr = paddr;
1394 rg->vaddr = vaddr;
1395 rg->size = size;
1396 rg->alloc = 1;
1397
1398 return 0;
1399}
1400
1401/* allocate fbmem using display resolution as reference */
1402static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
1403 unsigned long paddr)
1404{
1405 struct omapfb_info *ofbi = FB2OFB(fbi);
1406 struct omap_dss_device *display;
1407 int bytespp;
1408
1409 display = fb2display(fbi);
1410
1411 if (!display)
1412 return 0;
1413
1414 switch (display->get_recommended_bpp(display)) {
1415 case 16:
1416 bytespp = 2;
1417 break;
1418 case 24:
1419 bytespp = 4;
1420 break;
1421 default:
1422 bytespp = 4;
1423 break;
1424 }
1425
1426 if (!size) {
1427 u16 w, h;
1428
1429 display->get_resolution(display, &w, &h);
1430
1431 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1432 size = max(omap_vrfb_min_phys_size(w, h, bytespp),
1433 omap_vrfb_min_phys_size(h, w, bytespp));
1434
1435 DBG("adjusting fb mem size for VRFB, %u -> %lu\n",
1436 w * h * bytespp, size);
1437 } else {
1438 size = w * h * bytespp;
1439 }
1440 }
1441
1442 if (!size)
1443 return 0;
1444
1445 return omapfb_alloc_fbmem(fbi, size, paddr);
1446}
1447
1448static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt)
1449{
1450 enum omap_color_mode mode;
1451
1452 switch (fmt) {
1453 case OMAPFB_COLOR_RGB565:
1454 mode = OMAP_DSS_COLOR_RGB16;
1455 break;
1456 case OMAPFB_COLOR_YUV422:
1457 mode = OMAP_DSS_COLOR_YUV2;
1458 break;
1459 case OMAPFB_COLOR_CLUT_8BPP:
1460 mode = OMAP_DSS_COLOR_CLUT8;
1461 break;
1462 case OMAPFB_COLOR_CLUT_4BPP:
1463 mode = OMAP_DSS_COLOR_CLUT4;
1464 break;
1465 case OMAPFB_COLOR_CLUT_2BPP:
1466 mode = OMAP_DSS_COLOR_CLUT2;
1467 break;
1468 case OMAPFB_COLOR_CLUT_1BPP:
1469 mode = OMAP_DSS_COLOR_CLUT1;
1470 break;
1471 case OMAPFB_COLOR_RGB444:
1472 mode = OMAP_DSS_COLOR_RGB12U;
1473 break;
1474 case OMAPFB_COLOR_YUY422:
1475 mode = OMAP_DSS_COLOR_UYVY;
1476 break;
1477 case OMAPFB_COLOR_ARGB16:
1478 mode = OMAP_DSS_COLOR_ARGB16;
1479 break;
1480 case OMAPFB_COLOR_RGB24U:
1481 mode = OMAP_DSS_COLOR_RGB24U;
1482 break;
1483 case OMAPFB_COLOR_RGB24P:
1484 mode = OMAP_DSS_COLOR_RGB24P;
1485 break;
1486 case OMAPFB_COLOR_ARGB32:
1487 mode = OMAP_DSS_COLOR_ARGB32;
1488 break;
1489 case OMAPFB_COLOR_RGBA32:
1490 mode = OMAP_DSS_COLOR_RGBA32;
1491 break;
1492 case OMAPFB_COLOR_RGBX32:
1493 mode = OMAP_DSS_COLOR_RGBX32;
1494 break;
1495 default:
1496 mode = -EINVAL;
1497 }
1498
1499 return mode;
1500}
1501
1502static int omapfb_parse_vram_param(const char *param, int max_entries,
1503 unsigned long *sizes, unsigned long *paddrs)
1504{
1505 int fbnum;
1506 unsigned long size;
1507 unsigned long paddr = 0;
1508 char *p, *start;
1509
1510 start = (char *)param;
1511
1512 while (1) {
1513 p = start;
1514
1515 fbnum = simple_strtoul(p, &p, 10);
1516
1517 if (p == param)
1518 return -EINVAL;
1519
1520 if (*p != ':')
1521 return -EINVAL;
1522
1523 if (fbnum >= max_entries)
1524 return -EINVAL;
1525
1526 size = memparse(p + 1, &p);
1527
1528 if (!size)
1529 return -EINVAL;
1530
1531 paddr = 0;
1532
1533 if (*p == '@') {
1534 paddr = simple_strtoul(p + 1, &p, 16);
1535
1536 if (!paddr)
1537 return -EINVAL;
1538
1539 }
1540
1541 paddrs[fbnum] = paddr;
1542 sizes[fbnum] = size;
1543
1544 if (*p == 0)
1545 break;
1546
1547 if (*p != ',')
1548 return -EINVAL;
1549
1550 ++p;
1551
1552 start = p;
1553 }
1554
1555 return 0;
1556}
1557
1558static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
1559{
1560 int i, r;
1561 unsigned long vram_sizes[10];
1562 unsigned long vram_paddrs[10];
1563
1564 memset(&vram_sizes, 0, sizeof(vram_sizes));
1565 memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1566
1567 if (def_vram && omapfb_parse_vram_param(def_vram, 10,
1568 vram_sizes, vram_paddrs)) {
1569 dev_err(fbdev->dev, "failed to parse vram parameter\n");
1570
1571 memset(&vram_sizes, 0, sizeof(vram_sizes));
1572 memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1573 }
1574
1575 if (fbdev->dev->platform_data) {
1576 struct omapfb_platform_data *opd;
1577 opd = fbdev->dev->platform_data;
1578 for (i = 0; i < opd->mem_desc.region_cnt; ++i) {
1579 if (!vram_sizes[i]) {
1580 unsigned long size;
1581 unsigned long paddr;
1582
1583 size = opd->mem_desc.region[i].size;
1584 paddr = opd->mem_desc.region[i].paddr;
1585
1586 vram_sizes[i] = size;
1587 vram_paddrs[i] = paddr;
1588 }
1589 }
1590 }
1591
1592 for (i = 0; i < fbdev->num_fbs; i++) {
1593 /* allocate memory automatically only for fb0, or if
1594 * excplicitly defined with vram or plat data option */
1595 if (i == 0 || vram_sizes[i] != 0) {
1596 r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
1597 vram_sizes[i], vram_paddrs[i]);
1598
1599 if (r)
1600 return r;
1601 }
1602 }
1603
1604 for (i = 0; i < fbdev->num_fbs; i++) {
1605 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1606 struct omapfb2_mem_region *rg;
1607 rg = &ofbi->region;
1608
1609 DBG("region%d phys %08x virt %p size=%lu\n",
1610 i,
1611 rg->paddr,
1612 rg->vaddr,
1613 rg->size);
1614 }
1615
1616 return 0;
1617}
1618
1619int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
1620{
1621 struct omapfb_info *ofbi = FB2OFB(fbi);
1622 struct omapfb2_device *fbdev = ofbi->fbdev;
1623 struct omap_dss_device *display = fb2display(fbi);
1624 struct omapfb2_mem_region *rg = &ofbi->region;
1625 unsigned long old_size = rg->size;
1626 unsigned long old_paddr = rg->paddr;
1627 int old_type = rg->type;
1628 int r;
1629
1630 if (type > OMAPFB_MEMTYPE_MAX)
1631 return -EINVAL;
1632
1633 size = PAGE_ALIGN(size);
1634
1635 if (old_size == size && old_type == type)
1636 return 0;
1637
1638 if (display && display->sync)
1639 display->sync(display);
1640
1641 omapfb_free_fbmem(fbi);
1642
1643 if (size == 0) {
1644 clear_fb_info(fbi);
1645 return 0;
1646 }
1647
1648 r = omapfb_alloc_fbmem(fbi, size, 0);
1649
1650 if (r) {
1651 if (old_size)
1652 omapfb_alloc_fbmem(fbi, old_size, old_paddr);
1653
1654 if (rg->size == 0)
1655 clear_fb_info(fbi);
1656
1657 return r;
1658 }
1659
1660 if (old_size == size)
1661 return 0;
1662
1663 if (old_size == 0) {
1664 DBG("initializing fb %d\n", ofbi->id);
1665 r = omapfb_fb_init(fbdev, fbi);
1666 if (r) {
1667 DBG("omapfb_fb_init failed\n");
1668 goto err;
1669 }
1670 r = omapfb_apply_changes(fbi, 1);
1671 if (r) {
1672 DBG("omapfb_apply_changes failed\n");
1673 goto err;
1674 }
1675 } else {
1676 struct fb_var_screeninfo new_var;
1677 memcpy(&new_var, &fbi->var, sizeof(new_var));
1678 r = check_fb_var(fbi, &new_var);
1679 if (r)
1680 goto err;
1681 memcpy(&fbi->var, &new_var, sizeof(fbi->var));
1682 set_fb_fix(fbi);
1683 r = setup_vrfb_rotation(fbi);
1684 if (r)
1685 goto err;
1686 }
1687
1688 return 0;
1689err:
1690 omapfb_free_fbmem(fbi);
1691 clear_fb_info(fbi);
1692 return r;
1693}
1694
1695/* initialize fb_info, var, fix to something sane based on the display */
1696static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
1697{
1698 struct fb_var_screeninfo *var = &fbi->var;
1699 struct omap_dss_device *display = fb2display(fbi);
1700 struct omapfb_info *ofbi = FB2OFB(fbi);
1701 int r = 0;
1702
1703 fbi->fbops = &omapfb_ops;
1704 fbi->flags = FBINFO_FLAG_DEFAULT;
1705 fbi->pseudo_palette = fbdev->pseudo_palette;
1706
1707 if (ofbi->region.size == 0) {
1708 clear_fb_info(fbi);
1709 return 0;
1710 }
1711
1712 var->nonstd = 0;
1713 var->bits_per_pixel = 0;
1714
1715 var->rotate = def_rotate;
1716
1717 /*
1718 * Check if there is a default color format set in the board file,
1719 * and use this format instead the default deducted from the
1720 * display bpp.
1721 */
1722 if (fbdev->dev->platform_data) {
1723 struct omapfb_platform_data *opd;
1724 int id = ofbi->id;
1725
1726 opd = fbdev->dev->platform_data;
1727 if (opd->mem_desc.region[id].format_used) {
1728 enum omap_color_mode mode;
1729 enum omapfb_color_format format;
1730
1731 format = opd->mem_desc.region[id].format;
1732 mode = fb_format_to_dss_mode(format);
1733 if (mode < 0) {
1734 r = mode;
1735 goto err;
1736 }
1737 r = dss_mode_to_fb_mode(mode, var);
1738 if (r < 0)
1739 goto err;
1740 }
1741 }
1742
1743 if (display) {
1744 u16 w, h;
1745 int rotation = (var->rotate + ofbi->rotation[0]) % 4;
1746
1747 display->get_resolution(display, &w, &h);
1748
1749 if (rotation == FB_ROTATE_CW ||
1750 rotation == FB_ROTATE_CCW) {
1751 var->xres = h;
1752 var->yres = w;
1753 } else {
1754 var->xres = w;
1755 var->yres = h;
1756 }
1757
1758 var->xres_virtual = var->xres;
1759 var->yres_virtual = var->yres;
1760
1761 if (!var->bits_per_pixel) {
1762 switch (display->get_recommended_bpp(display)) {
1763 case 16:
1764 var->bits_per_pixel = 16;
1765 break;
1766 case 24:
1767 var->bits_per_pixel = 32;
1768 break;
1769 default:
1770 dev_err(fbdev->dev, "illegal display "
1771 "bpp\n");
1772 return -EINVAL;
1773 }
1774 }
1775 } else {
1776 /* if there's no display, let's just guess some basic values */
1777 var->xres = 320;
1778 var->yres = 240;
1779 var->xres_virtual = var->xres;
1780 var->yres_virtual = var->yres;
1781 if (!var->bits_per_pixel)
1782 var->bits_per_pixel = 16;
1783 }
1784
1785 r = check_fb_var(fbi, var);
1786 if (r)
1787 goto err;
1788
1789 set_fb_fix(fbi);
1790 r = setup_vrfb_rotation(fbi);
1791 if (r)
1792 goto err;
1793
1794 r = fb_alloc_cmap(&fbi->cmap, 256, 0);
1795 if (r)
1796 dev_err(fbdev->dev, "unable to allocate color map memory\n");
1797
1798err:
1799 return r;
1800}
1801
1802static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
1803{
1804 fb_dealloc_cmap(&fbi->cmap);
1805}
1806
1807
1808static void omapfb_free_resources(struct omapfb2_device *fbdev)
1809{
1810 int i;
1811
1812 DBG("free_resources\n");
1813
1814 if (fbdev == NULL)
1815 return;
1816
1817 for (i = 0; i < fbdev->num_fbs; i++)
1818 unregister_framebuffer(fbdev->fbs[i]);
1819
1820 /* free the reserved fbmem */
1821 omapfb_free_all_fbmem(fbdev);
1822
1823 for (i = 0; i < fbdev->num_fbs; i++) {
1824 fbinfo_cleanup(fbdev, fbdev->fbs[i]);
1825 framebuffer_release(fbdev->fbs[i]);
1826 }
1827
1828 for (i = 0; i < fbdev->num_displays; i++) {
1829 if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
1830 fbdev->displays[i]->disable(fbdev->displays[i]);
1831
1832 omap_dss_put_device(fbdev->displays[i]);
1833 }
1834
1835 dev_set_drvdata(fbdev->dev, NULL);
1836 kfree(fbdev);
1837}
1838
1839static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
1840{
1841 int r, i;
1842
1843 fbdev->num_fbs = 0;
1844
1845 DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);
1846
1847 /* allocate fb_infos */
1848 for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
1849 struct fb_info *fbi;
1850 struct omapfb_info *ofbi;
1851
1852 fbi = framebuffer_alloc(sizeof(struct omapfb_info),
1853 fbdev->dev);
1854
1855 if (fbi == NULL) {
1856 dev_err(fbdev->dev,
1857 "unable to allocate memory for plane info\n");
1858 return -ENOMEM;
1859 }
1860
1861 clear_fb_info(fbi);
1862
1863 fbdev->fbs[i] = fbi;
1864
1865 ofbi = FB2OFB(fbi);
1866 ofbi->fbdev = fbdev;
1867 ofbi->id = i;
1868
1869 /* assign these early, so that fb alloc can use them */
1870 ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
1871 OMAP_DSS_ROT_DMA;
1872 ofbi->mirror = def_mirror;
1873
1874 fbdev->num_fbs++;
1875 }
1876
1877 DBG("fb_infos allocated\n");
1878
1879 /* assign overlays for the fbs */
1880 for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
1881 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1882
1883 ofbi->overlays[0] = fbdev->overlays[i];
1884 ofbi->num_overlays = 1;
1885 }
1886
1887 /* allocate fb memories */
1888 r = omapfb_allocate_all_fbs(fbdev);
1889 if (r) {
1890 dev_err(fbdev->dev, "failed to allocate fbmem\n");
1891 return r;
1892 }
1893
1894 DBG("fbmems allocated\n");
1895
1896 /* setup fb_infos */
1897 for (i = 0; i < fbdev->num_fbs; i++) {
1898 r = omapfb_fb_init(fbdev, fbdev->fbs[i]);
1899 if (r) {
1900 dev_err(fbdev->dev, "failed to setup fb_info\n");
1901 return r;
1902 }
1903 }
1904
1905 DBG("fb_infos initialized\n");
1906
1907 for (i = 0; i < fbdev->num_fbs; i++) {
1908 r = register_framebuffer(fbdev->fbs[i]);
1909 if (r != 0) {
1910 dev_err(fbdev->dev,
1911 "registering framebuffer %d failed\n", i);
1912 return r;
1913 }
1914 }
1915
1916 DBG("framebuffers registered\n");
1917
1918 for (i = 0; i < fbdev->num_fbs; i++) {
1919 r = omapfb_apply_changes(fbdev->fbs[i], 1);
1920 if (r) {
1921 dev_err(fbdev->dev, "failed to change mode\n");
1922 return r;
1923 }
1924 }
1925
1926 DBG("create sysfs for fbs\n");
1927 r = omapfb_create_sysfs(fbdev);
1928 if (r) {
1929 dev_err(fbdev->dev, "failed to create sysfs entries\n");
1930 return r;
1931 }
1932
1933 /* Enable fb0 */
1934 if (fbdev->num_fbs > 0) {
1935 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
1936
1937 if (ofbi->num_overlays > 0) {
1938 struct omap_overlay *ovl = ofbi->overlays[0];
1939
1940 r = omapfb_overlay_enable(ovl, 1);
1941
1942 if (r) {
1943 dev_err(fbdev->dev,
1944 "failed to enable overlay\n");
1945 return r;
1946 }
1947 }
1948 }
1949
1950 DBG("create_framebuffers done\n");
1951
1952 return 0;
1953}
1954
1955static int omapfb_mode_to_timings(const char *mode_str,
1956 struct omap_video_timings *timings, u8 *bpp)
1957{
1958 struct fb_info fbi;
1959 struct fb_var_screeninfo var;
1960 struct fb_ops fbops;
1961 int r;
1962
1963#ifdef CONFIG_OMAP2_DSS_VENC
1964 if (strcmp(mode_str, "pal") == 0) {
1965 *timings = omap_dss_pal_timings;
1966 *bpp = 0;
1967 return 0;
1968 } else if (strcmp(mode_str, "ntsc") == 0) {
1969 *timings = omap_dss_ntsc_timings;
1970 *bpp = 0;
1971 return 0;
1972 }
1973#endif
1974
1975 /* this is quite a hack, but I wanted to use the modedb and for
1976 * that we need fb_info and var, so we create dummy ones */
1977
1978 memset(&fbi, 0, sizeof(fbi));
1979 memset(&var, 0, sizeof(var));
1980 memset(&fbops, 0, sizeof(fbops));
1981 fbi.fbops = &fbops;
1982
1983 r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24);
1984
1985 if (r != 0) {
1986 timings->pixel_clock = PICOS2KHZ(var.pixclock);
1987 timings->hfp = var.left_margin;
1988 timings->hbp = var.right_margin;
1989 timings->vfp = var.upper_margin;
1990 timings->vbp = var.lower_margin;
1991 timings->hsw = var.hsync_len;
1992 timings->vsw = var.vsync_len;
1993 timings->x_res = var.xres;
1994 timings->y_res = var.yres;
1995
1996 switch (var.bits_per_pixel) {
1997 case 16:
1998 *bpp = 16;
1999 break;
2000 case 24:
2001 case 32:
2002 default:
2003 *bpp = 24;
2004 break;
2005 }
2006
2007 return 0;
2008 } else {
2009 return -EINVAL;
2010 }
2011}
2012
2013static int omapfb_set_def_mode(struct omap_dss_device *display, char *mode_str)
2014{
2015 int r;
2016 u8 bpp;
2017 struct omap_video_timings timings;
2018
2019 r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
2020 if (r)
2021 return r;
2022
2023 display->panel.recommended_bpp = bpp;
2024
2025 if (!display->check_timings || !display->set_timings)
2026 return -EINVAL;
2027
2028 r = display->check_timings(display, &timings);
2029 if (r)
2030 return r;
2031
2032 display->set_timings(display, &timings);
2033
2034 return 0;
2035}
2036
2037static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
2038{
2039 char *str, *options, *this_opt;
2040 int r = 0;
2041
2042 str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL);
2043 strcpy(str, def_mode);
2044 options = str;
2045
2046 while (!r && (this_opt = strsep(&options, ",")) != NULL) {
2047 char *p, *display_str, *mode_str;
2048 struct omap_dss_device *display;
2049 int i;
2050
2051 p = strchr(this_opt, ':');
2052 if (!p) {
2053 r = -EINVAL;
2054 break;
2055 }
2056
2057 *p = 0;
2058 display_str = this_opt;
2059 mode_str = p + 1;
2060
2061 display = NULL;
2062 for (i = 0; i < fbdev->num_displays; ++i) {
2063 if (strcmp(fbdev->displays[i]->name,
2064 display_str) == 0) {
2065 display = fbdev->displays[i];
2066 break;
2067 }
2068 }
2069
2070 if (!display) {
2071 r = -EINVAL;
2072 break;
2073 }
2074
2075 r = omapfb_set_def_mode(display, mode_str);
2076 if (r)
2077 break;
2078 }
2079
2080 kfree(str);
2081
2082 return r;
2083}
2084
2085static int omapfb_probe(struct platform_device *pdev)
2086{
2087 struct omapfb2_device *fbdev = NULL;
2088 int r = 0;
2089 int i;
2090 struct omap_overlay *ovl;
2091 struct omap_dss_device *def_display;
2092 struct omap_dss_device *dssdev;
2093
2094 DBG("omapfb_probe\n");
2095
2096 if (pdev->num_resources != 0) {
2097 dev_err(&pdev->dev, "probed for an unknown device\n");
2098 r = -ENODEV;
2099 goto err0;
2100 }
2101
2102 fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL);
2103 if (fbdev == NULL) {
2104 r = -ENOMEM;
2105 goto err0;
2106 }
2107
2108 mutex_init(&fbdev->mtx);
2109
2110 fbdev->dev = &pdev->dev;
2111 platform_set_drvdata(pdev, fbdev);
2112
2113 fbdev->num_displays = 0;
2114 dssdev = NULL;
2115 for_each_dss_dev(dssdev) {
2116 omap_dss_get_device(dssdev);
2117 fbdev->displays[fbdev->num_displays++] = dssdev;
2118 }
2119
2120 if (fbdev->num_displays == 0) {
2121 dev_err(&pdev->dev, "no displays\n");
2122 r = -EINVAL;
2123 goto cleanup;
2124 }
2125
2126 fbdev->num_overlays = omap_dss_get_num_overlays();
2127 for (i = 0; i < fbdev->num_overlays; i++)
2128 fbdev->overlays[i] = omap_dss_get_overlay(i);
2129
2130 fbdev->num_managers = omap_dss_get_num_overlay_managers();
2131 for (i = 0; i < fbdev->num_managers; i++)
2132 fbdev->managers[i] = omap_dss_get_overlay_manager(i);
2133
2134 if (def_mode && strlen(def_mode) > 0) {
2135 if (omapfb_parse_def_modes(fbdev))
2136 dev_warn(&pdev->dev, "cannot parse default modes\n");
2137 }
2138
2139 r = omapfb_create_framebuffers(fbdev);
2140 if (r)
2141 goto cleanup;
2142
2143 for (i = 0; i < fbdev->num_managers; i++) {
2144 struct omap_overlay_manager *mgr;
2145 mgr = fbdev->managers[i];
2146 r = mgr->apply(mgr);
2147 if (r)
2148 dev_warn(fbdev->dev, "failed to apply dispc config\n");
2149 }
2150
2151 DBG("mgr->apply'ed\n");
2152
2153 /* gfx overlay should be the default one. find a display
2154 * connected to that, and use it as default display */
2155 ovl = omap_dss_get_overlay(0);
2156 if (ovl->manager && ovl->manager->device) {
2157 def_display = ovl->manager->device;
2158 } else {
2159 dev_warn(&pdev->dev, "cannot find default display\n");
2160 def_display = NULL;
2161 }
2162
2163 if (def_display) {
2164#ifndef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
2165 u16 w, h;
2166#endif
2167 r = def_display->enable(def_display);
2168 if (r)
2169 dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
2170 def_display->name);
2171
2172 /* set the update mode */
2173 if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
2174#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
2175 if (def_display->enable_te)
2176 def_display->enable_te(def_display, 1);
2177 if (def_display->set_update_mode)
2178 def_display->set_update_mode(def_display,
2179 OMAP_DSS_UPDATE_AUTO);
2180#else /* MANUAL_UPDATE */
2181 if (def_display->enable_te)
2182 def_display->enable_te(def_display, 0);
2183 if (def_display->set_update_mode)
2184 def_display->set_update_mode(def_display,
2185 OMAP_DSS_UPDATE_MANUAL);
2186
2187 def_display->get_resolution(def_display, &w, &h);
2188 def_display->update(def_display, 0, 0, w, h);
2189#endif
2190 } else {
2191 if (def_display->set_update_mode)
2192 def_display->set_update_mode(def_display,
2193 OMAP_DSS_UPDATE_AUTO);
2194 }
2195 }
2196
2197 return 0;
2198
2199cleanup:
2200 omapfb_free_resources(fbdev);
2201err0:
2202 dev_err(&pdev->dev, "failed to setup omapfb\n");
2203 return r;
2204}
2205
2206static int omapfb_remove(struct platform_device *pdev)
2207{
2208 struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
2209
2210 /* FIXME: wait till completion of pending events */
2211
2212 omapfb_remove_sysfs(fbdev);
2213
2214 omapfb_free_resources(fbdev);
2215
2216 return 0;
2217}
2218
2219static struct platform_driver omapfb_driver = {
2220 .probe = omapfb_probe,
2221 .remove = omapfb_remove,
2222 .driver = {
2223 .name = "omapfb",
2224 .owner = THIS_MODULE,
2225 },
2226};
2227
2228static int __init omapfb_init(void)
2229{
2230 DBG("omapfb_init\n");
2231
2232 if (platform_driver_register(&omapfb_driver)) {
2233 printk(KERN_ERR "failed to register omapfb driver\n");
2234 return -ENODEV;
2235 }
2236
2237 return 0;
2238}
2239
2240static void __exit omapfb_exit(void)
2241{
2242 DBG("omapfb_exit\n");
2243 platform_driver_unregister(&omapfb_driver);
2244}
2245
2246module_param_named(mode, def_mode, charp, 0);
2247module_param_named(vram, def_vram, charp, 0);
2248module_param_named(rotate, def_rotate, int, 0);
2249module_param_named(vrfb, def_vrfb, bool, 0);
2250module_param_named(mirror, def_mirror, bool, 0);
2251
2252/* late_initcall to let panel/ctrl drivers loaded first.
2253 * I guess better option would be a more dynamic approach,
2254 * so that omapfb reacts to new panels when they are loaded */
2255late_initcall(omapfb_init);
2256/*module_init(omapfb_init);*/
2257module_exit(omapfb_exit);
2258
2259MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
2260MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
2261MODULE_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..f7c9c739e5ef
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -0,0 +1,146 @@
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
88struct omapfb_colormode {
89 enum omap_color_mode dssmode;
90 u32 bits_per_pixel;
91 u32 nonstd;
92 struct fb_bitfield red;
93 struct fb_bitfield green;
94 struct fb_bitfield blue;
95 struct fb_bitfield transp;
96};
97
98void set_fb_fix(struct fb_info *fbi);
99int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var);
100int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type);
101int omapfb_apply_changes(struct fb_info *fbi, int init);
102
103int omapfb_create_sysfs(struct omapfb2_device *fbdev);
104void omapfb_remove_sysfs(struct omapfb2_device *fbdev);
105
106int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg);
107
108int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
109 struct fb_var_screeninfo *var);
110
111/* find the display connected to this fb, if any */
112static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
113{
114 struct omapfb_info *ofbi = FB2OFB(fbi);
115 int i;
116
117 /* XXX: returns the display connected to first attached overlay */
118 for (i = 0; i < ofbi->num_overlays; i++) {
119 if (ofbi->overlays[i]->manager)
120 return ofbi->overlays[i]->manager->device;
121 }
122
123 return NULL;
124}
125
126static inline void omapfb_lock(struct omapfb2_device *fbdev)
127{
128 mutex_lock(&fbdev->mtx);
129}
130
131static inline void omapfb_unlock(struct omapfb2_device *fbdev)
132{
133 mutex_unlock(&fbdev->mtx);
134}
135
136static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
137 int enable)
138{
139 struct omap_overlay_info info;
140
141 ovl->get_overlay_info(ovl, &info);
142 info.enabled = enable;
143 return ovl->set_overlay_info(ovl, &info);
144}
145
146#endif
diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c
new file mode 100644
index 000000000000..55a4de5e5d10
--- /dev/null
+++ b/drivers/video/omap2/vram.c
@@ -0,0 +1,655 @@
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/seq_file.h>
27#include <linux/bootmem.h>
28#include <linux/completion.h>
29#include <linux/debugfs.h>
30#include <linux/jiffies.h>
31#include <linux/module.h>
32
33#include <asm/setup.h>
34
35#include <plat/sram.h>
36#include <plat/vram.h>
37#include <plat/dma.h>
38
39#ifdef DEBUG
40#define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__)
41#else
42#define DBG(format, ...)
43#endif
44
45#define OMAP2_SRAM_START 0x40200000
46/* Maximum size, in reality this is smaller if SRAM is partially locked. */
47#define OMAP2_SRAM_SIZE 0xa0000 /* 640k */
48
49/* postponed regions are used to temporarily store region information at boot
50 * time when we cannot yet allocate the region list */
51#define MAX_POSTPONED_REGIONS 10
52
53static bool vram_initialized;
54static int postponed_cnt;
55static struct {
56 unsigned long paddr;
57 size_t size;
58} postponed_regions[MAX_POSTPONED_REGIONS];
59
60struct vram_alloc {
61 struct list_head list;
62 unsigned long paddr;
63 unsigned pages;
64};
65
66struct vram_region {
67 struct list_head list;
68 struct list_head alloc_list;
69 unsigned long paddr;
70 unsigned pages;
71};
72
73static DEFINE_MUTEX(region_mutex);
74static LIST_HEAD(region_list);
75
76static inline int region_mem_type(unsigned long paddr)
77{
78 if (paddr >= OMAP2_SRAM_START &&
79 paddr < OMAP2_SRAM_START + OMAP2_SRAM_SIZE)
80 return OMAP_VRAM_MEMTYPE_SRAM;
81 else
82 return OMAP_VRAM_MEMTYPE_SDRAM;
83}
84
85static struct vram_region *omap_vram_create_region(unsigned long paddr,
86 unsigned pages)
87{
88 struct vram_region *rm;
89
90 rm = kzalloc(sizeof(*rm), GFP_KERNEL);
91
92 if (rm) {
93 INIT_LIST_HEAD(&rm->alloc_list);
94 rm->paddr = paddr;
95 rm->pages = pages;
96 }
97
98 return rm;
99}
100
101#if 0
102static void omap_vram_free_region(struct vram_region *vr)
103{
104 list_del(&vr->list);
105 kfree(vr);
106}
107#endif
108
109static struct vram_alloc *omap_vram_create_allocation(struct vram_region *vr,
110 unsigned long paddr, unsigned pages)
111{
112 struct vram_alloc *va;
113 struct vram_alloc *new;
114
115 new = kzalloc(sizeof(*va), GFP_KERNEL);
116
117 if (!new)
118 return NULL;
119
120 new->paddr = paddr;
121 new->pages = pages;
122
123 list_for_each_entry(va, &vr->alloc_list, list) {
124 if (va->paddr > new->paddr)
125 break;
126 }
127
128 list_add_tail(&new->list, &va->list);
129
130 return new;
131}
132
133static void omap_vram_free_allocation(struct vram_alloc *va)
134{
135 list_del(&va->list);
136 kfree(va);
137}
138
139int omap_vram_add_region(unsigned long paddr, size_t size)
140{
141 struct vram_region *rm;
142 unsigned pages;
143
144 if (vram_initialized) {
145 DBG("adding region paddr %08lx size %d\n",
146 paddr, size);
147
148 size &= PAGE_MASK;
149 pages = size >> PAGE_SHIFT;
150
151 rm = omap_vram_create_region(paddr, pages);
152 if (rm == NULL)
153 return -ENOMEM;
154
155 list_add(&rm->list, &region_list);
156 } else {
157 if (postponed_cnt == MAX_POSTPONED_REGIONS)
158 return -ENOMEM;
159
160 postponed_regions[postponed_cnt].paddr = paddr;
161 postponed_regions[postponed_cnt].size = size;
162
163 ++postponed_cnt;
164 }
165 return 0;
166}
167
168int omap_vram_free(unsigned long paddr, size_t size)
169{
170 struct vram_region *rm;
171 struct vram_alloc *alloc;
172 unsigned start, end;
173
174 DBG("free mem paddr %08lx size %d\n", paddr, size);
175
176 size = PAGE_ALIGN(size);
177
178 mutex_lock(&region_mutex);
179
180 list_for_each_entry(rm, &region_list, list) {
181 list_for_each_entry(alloc, &rm->alloc_list, list) {
182 start = alloc->paddr;
183 end = alloc->paddr + (alloc->pages >> PAGE_SHIFT);
184
185 if (start >= paddr && end < paddr + size)
186 goto found;
187 }
188 }
189
190 mutex_unlock(&region_mutex);
191 return -EINVAL;
192
193found:
194 omap_vram_free_allocation(alloc);
195
196 mutex_unlock(&region_mutex);
197 return 0;
198}
199EXPORT_SYMBOL(omap_vram_free);
200
201static int _omap_vram_reserve(unsigned long paddr, unsigned pages)
202{
203 struct vram_region *rm;
204 struct vram_alloc *alloc;
205 size_t size;
206
207 size = pages << PAGE_SHIFT;
208
209 list_for_each_entry(rm, &region_list, list) {
210 unsigned long start, end;
211
212 DBG("checking region %lx %d\n", rm->paddr, rm->pages);
213
214 if (region_mem_type(rm->paddr) != region_mem_type(paddr))
215 continue;
216
217 start = rm->paddr;
218 end = start + (rm->pages << PAGE_SHIFT) - 1;
219 if (start > paddr || end < paddr + size - 1)
220 continue;
221
222 DBG("block ok, checking allocs\n");
223
224 list_for_each_entry(alloc, &rm->alloc_list, list) {
225 end = alloc->paddr - 1;
226
227 if (start <= paddr && end >= paddr + size - 1)
228 goto found;
229
230 start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
231 }
232
233 end = rm->paddr + (rm->pages << PAGE_SHIFT) - 1;
234
235 if (!(start <= paddr && end >= paddr + size - 1))
236 continue;
237found:
238 DBG("found area start %lx, end %lx\n", start, end);
239
240 if (omap_vram_create_allocation(rm, paddr, pages) == NULL)
241 return -ENOMEM;
242
243 return 0;
244 }
245
246 return -ENOMEM;
247}
248
249int omap_vram_reserve(unsigned long paddr, size_t size)
250{
251 unsigned pages;
252 int r;
253
254 DBG("reserve mem paddr %08lx size %d\n", paddr, size);
255
256 size = PAGE_ALIGN(size);
257 pages = size >> PAGE_SHIFT;
258
259 mutex_lock(&region_mutex);
260
261 r = _omap_vram_reserve(paddr, pages);
262
263 mutex_unlock(&region_mutex);
264
265 return r;
266}
267EXPORT_SYMBOL(omap_vram_reserve);
268
269static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data)
270{
271 struct completion *compl = data;
272 complete(compl);
273}
274
275static int _omap_vram_clear(u32 paddr, unsigned pages)
276{
277 struct completion compl;
278 unsigned elem_count;
279 unsigned frame_count;
280 int r;
281 int lch;
282
283 init_completion(&compl);
284
285 r = omap_request_dma(OMAP_DMA_NO_DEVICE, "VRAM DMA",
286 _omap_vram_dma_cb,
287 &compl, &lch);
288 if (r) {
289 pr_err("VRAM: request_dma failed for memory clear\n");
290 return -EBUSY;
291 }
292
293 elem_count = pages * PAGE_SIZE / 4;
294 frame_count = 1;
295
296 omap_set_dma_transfer_params(lch, OMAP_DMA_DATA_TYPE_S32,
297 elem_count, frame_count,
298 OMAP_DMA_SYNC_ELEMENT,
299 0, 0);
300
301 omap_set_dma_dest_params(lch, 0, OMAP_DMA_AMODE_POST_INC,
302 paddr, 0, 0);
303
304 omap_set_dma_color_mode(lch, OMAP_DMA_CONSTANT_FILL, 0x000000);
305
306 omap_start_dma(lch);
307
308 if (wait_for_completion_timeout(&compl, msecs_to_jiffies(1000)) == 0) {
309 omap_stop_dma(lch);
310 pr_err("VRAM: dma timeout while clearing memory\n");
311 r = -EIO;
312 goto err;
313 }
314
315 r = 0;
316err:
317 omap_free_dma(lch);
318
319 return r;
320}
321
322static int _omap_vram_alloc(int mtype, unsigned pages, unsigned long *paddr)
323{
324 struct vram_region *rm;
325 struct vram_alloc *alloc;
326
327 list_for_each_entry(rm, &region_list, list) {
328 unsigned long start, end;
329
330 DBG("checking region %lx %d\n", rm->paddr, rm->pages);
331
332 if (region_mem_type(rm->paddr) != mtype)
333 continue;
334
335 start = rm->paddr;
336
337 list_for_each_entry(alloc, &rm->alloc_list, list) {
338 end = alloc->paddr;
339
340 if (end - start >= pages << PAGE_SHIFT)
341 goto found;
342
343 start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
344 }
345
346 end = rm->paddr + (rm->pages << PAGE_SHIFT);
347found:
348 if (end - start < pages << PAGE_SHIFT)
349 continue;
350
351 DBG("found %lx, end %lx\n", start, end);
352
353 alloc = omap_vram_create_allocation(rm, start, pages);
354 if (alloc == NULL)
355 return -ENOMEM;
356
357 *paddr = start;
358
359 _omap_vram_clear(start, pages);
360
361 return 0;
362 }
363
364 return -ENOMEM;
365}
366
367int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr)
368{
369 unsigned pages;
370 int r;
371
372 BUG_ON(mtype > OMAP_VRAM_MEMTYPE_MAX || !size);
373
374 DBG("alloc mem type %d size %d\n", mtype, size);
375
376 size = PAGE_ALIGN(size);
377 pages = size >> PAGE_SHIFT;
378
379 mutex_lock(&region_mutex);
380
381 r = _omap_vram_alloc(mtype, pages, paddr);
382
383 mutex_unlock(&region_mutex);
384
385 return r;
386}
387EXPORT_SYMBOL(omap_vram_alloc);
388
389void omap_vram_get_info(unsigned long *vram,
390 unsigned long *free_vram,
391 unsigned long *largest_free_block)
392{
393 struct vram_region *vr;
394 struct vram_alloc *va;
395
396 *vram = 0;
397 *free_vram = 0;
398 *largest_free_block = 0;
399
400 mutex_lock(&region_mutex);
401
402 list_for_each_entry(vr, &region_list, list) {
403 unsigned free;
404 unsigned long pa;
405
406 pa = vr->paddr;
407 *vram += vr->pages << PAGE_SHIFT;
408
409 list_for_each_entry(va, &vr->alloc_list, list) {
410 free = va->paddr - pa;
411 *free_vram += free;
412 if (free > *largest_free_block)
413 *largest_free_block = free;
414 pa = va->paddr + (va->pages << PAGE_SHIFT);
415 }
416
417 free = vr->paddr + (vr->pages << PAGE_SHIFT) - pa;
418 *free_vram += free;
419 if (free > *largest_free_block)
420 *largest_free_block = free;
421 }
422
423 mutex_unlock(&region_mutex);
424}
425EXPORT_SYMBOL(omap_vram_get_info);
426
427#if defined(CONFIG_DEBUG_FS)
428static int vram_debug_show(struct seq_file *s, void *unused)
429{
430 struct vram_region *vr;
431 struct vram_alloc *va;
432 unsigned size;
433
434 mutex_lock(&region_mutex);
435
436 list_for_each_entry(vr, &region_list, list) {
437 size = vr->pages << PAGE_SHIFT;
438 seq_printf(s, "%08lx-%08lx (%d bytes)\n",
439 vr->paddr, vr->paddr + size - 1,
440 size);
441
442 list_for_each_entry(va, &vr->alloc_list, list) {
443 size = va->pages << PAGE_SHIFT;
444 seq_printf(s, " %08lx-%08lx (%d bytes)\n",
445 va->paddr, va->paddr + size - 1,
446 size);
447 }
448 }
449
450 mutex_unlock(&region_mutex);
451
452 return 0;
453}
454
455static int vram_debug_open(struct inode *inode, struct file *file)
456{
457 return single_open(file, vram_debug_show, inode->i_private);
458}
459
460static const struct file_operations vram_debug_fops = {
461 .open = vram_debug_open,
462 .read = seq_read,
463 .llseek = seq_lseek,
464 .release = single_release,
465};
466
467static int __init omap_vram_create_debugfs(void)
468{
469 struct dentry *d;
470
471 d = debugfs_create_file("vram", S_IRUGO, NULL,
472 NULL, &vram_debug_fops);
473 if (IS_ERR(d))
474 return PTR_ERR(d);
475
476 return 0;
477}
478#endif
479
480static __init int omap_vram_init(void)
481{
482 int i;
483
484 vram_initialized = 1;
485
486 for (i = 0; i < postponed_cnt; i++)
487 omap_vram_add_region(postponed_regions[i].paddr,
488 postponed_regions[i].size);
489
490#ifdef CONFIG_DEBUG_FS
491 if (omap_vram_create_debugfs())
492 pr_err("VRAM: Failed to create debugfs file\n");
493#endif
494
495 return 0;
496}
497
498arch_initcall(omap_vram_init);
499
500/* boottime vram alloc stuff */
501
502/* set from board file */
503static u32 omap_vram_sram_start __initdata;
504static u32 omap_vram_sram_size __initdata;
505
506/* set from board file */
507static u32 omap_vram_sdram_start __initdata;
508static u32 omap_vram_sdram_size __initdata;
509
510/* set from kernel cmdline */
511static u32 omap_vram_def_sdram_size __initdata;
512static u32 omap_vram_def_sdram_start __initdata;
513
514static void __init omap_vram_early_vram(char **p)
515{
516 omap_vram_def_sdram_size = memparse(*p, p);
517 if (**p == ',')
518 omap_vram_def_sdram_start = simple_strtoul((*p) + 1, p, 16);
519}
520__early_param("vram=", omap_vram_early_vram);
521
522/*
523 * Called from map_io. We need to call to this early enough so that we
524 * can reserve the fixed SDRAM regions before VM could get hold of them.
525 */
526void __init omap_vram_reserve_sdram(void)
527{
528 struct bootmem_data *bdata;
529 unsigned long sdram_start, sdram_size;
530 u32 paddr;
531 u32 size = 0;
532
533 /* cmdline arg overrides the board file definition */
534 if (omap_vram_def_sdram_size) {
535 size = omap_vram_def_sdram_size;
536 paddr = omap_vram_def_sdram_start;
537 }
538
539 if (!size) {
540 size = omap_vram_sdram_size;
541 paddr = omap_vram_sdram_start;
542 }
543
544#ifdef CONFIG_OMAP2_VRAM_SIZE
545 if (!size) {
546 size = CONFIG_OMAP2_VRAM_SIZE * 1024 * 1024;
547 paddr = 0;
548 }
549#endif
550
551 if (!size)
552 return;
553
554 size = PAGE_ALIGN(size);
555
556 bdata = NODE_DATA(0)->bdata;
557 sdram_start = bdata->node_min_pfn << PAGE_SHIFT;
558 sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start;
559
560 if (paddr) {
561 if ((paddr & ~PAGE_MASK) || paddr < sdram_start ||
562 paddr + size > sdram_start + sdram_size) {
563 pr_err("Illegal SDRAM region for VRAM\n");
564 return;
565 }
566
567 if (reserve_bootmem(paddr, size, BOOTMEM_EXCLUSIVE) < 0) {
568 pr_err("FB: failed to reserve VRAM\n");
569 return;
570 }
571 } else {
572 if (size > sdram_size) {
573 pr_err("Illegal SDRAM size for VRAM\n");
574 return;
575 }
576
577 paddr = virt_to_phys(alloc_bootmem_pages(size));
578 BUG_ON(paddr & ~PAGE_MASK);
579 }
580
581 omap_vram_add_region(paddr, size);
582
583 pr_info("Reserving %u bytes SDRAM for VRAM\n", size);
584}
585
586/*
587 * Called at sram init time, before anything is pushed to the SRAM stack.
588 * Because of the stack scheme, we will allocate everything from the
589 * start of the lowest address region to the end of SRAM. This will also
590 * include padding for page alignment and possible holes between regions.
591 *
592 * As opposed to the SDRAM case, we'll also do any dynamic allocations at
593 * this point, since the driver built as a module would have problem with
594 * freeing / reallocating the regions.
595 */
596unsigned long __init omap_vram_reserve_sram(unsigned long sram_pstart,
597 unsigned long sram_vstart,
598 unsigned long sram_size,
599 unsigned long pstart_avail,
600 unsigned long size_avail)
601{
602 unsigned long pend_avail;
603 unsigned long reserved;
604 u32 paddr;
605 u32 size;
606
607 paddr = omap_vram_sram_start;
608 size = omap_vram_sram_size;
609
610 if (!size)
611 return 0;
612
613 reserved = 0;
614 pend_avail = pstart_avail + size_avail;
615
616 if (!paddr) {
617 /* Dynamic allocation */
618 if ((size_avail & PAGE_MASK) < size) {
619 pr_err("Not enough SRAM for VRAM\n");
620 return 0;
621 }
622 size_avail = (size_avail - size) & PAGE_MASK;
623 paddr = pstart_avail + size_avail;
624 }
625
626 if (paddr < sram_pstart ||
627 paddr + size > sram_pstart + sram_size) {
628 pr_err("Illegal SRAM region for VRAM\n");
629 return 0;
630 }
631
632 /* Reserve everything above the start of the region. */
633 if (pend_avail - paddr > reserved)
634 reserved = pend_avail - paddr;
635 size_avail = pend_avail - reserved - pstart_avail;
636
637 omap_vram_add_region(paddr, size);
638
639 if (reserved)
640 pr_info("Reserving %lu bytes SRAM for VRAM\n", reserved);
641
642 return reserved;
643}
644
645void __init omap_vram_set_sdram_vram(u32 size, u32 start)
646{
647 omap_vram_sdram_start = start;
648 omap_vram_sdram_size = size;
649}
650
651void __init omap_vram_set_sram_vram(u32 size, u32 start)
652{
653 omap_vram_sram_start = start;
654 omap_vram_sram_size = size;
655}
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);
diff --git a/include/linux/omapfb.h b/include/linux/omapfb.h
new file mode 100644
index 000000000000..f46c40ac6d45
--- /dev/null
+++ b/include/linux/omapfb.h
@@ -0,0 +1,251 @@
1/*
2 * File: include/linux/omapfb.h
3 *
4 * Framebuffer driver for TI OMAP boards
5 *
6 * Copyright (C) 2004 Nokia Corporation
7 * Author: Imre Deak <imre.deak@nokia.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24#ifndef __LINUX_OMAPFB_H__
25#define __LINUX_OMAPFB_H__
26
27#include <linux/fb.h>
28#include <linux/ioctl.h>
29#include <linux/types.h>
30
31/* IOCTL commands. */
32
33#define OMAP_IOW(num, dtype) _IOW('O', num, dtype)
34#define OMAP_IOR(num, dtype) _IOR('O', num, dtype)
35#define OMAP_IOWR(num, dtype) _IOWR('O', num, dtype)
36#define OMAP_IO(num) _IO('O', num)
37
38#define OMAPFB_MIRROR OMAP_IOW(31, int)
39#define OMAPFB_SYNC_GFX OMAP_IO(37)
40#define OMAPFB_VSYNC OMAP_IO(38)
41#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int)
42#define OMAPFB_GET_CAPS OMAP_IOR(42, struct omapfb_caps)
43#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int)
44#define OMAPFB_LCD_TEST OMAP_IOW(45, int)
45#define OMAPFB_CTRL_TEST OMAP_IOW(46, int)
46#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(47, struct omapfb_update_window_old)
47#define OMAPFB_SET_COLOR_KEY OMAP_IOW(50, struct omapfb_color_key)
48#define OMAPFB_GET_COLOR_KEY OMAP_IOW(51, struct omapfb_color_key)
49#define OMAPFB_SETUP_PLANE OMAP_IOW(52, struct omapfb_plane_info)
50#define OMAPFB_QUERY_PLANE OMAP_IOW(53, struct omapfb_plane_info)
51#define OMAPFB_UPDATE_WINDOW OMAP_IOW(54, struct omapfb_update_window)
52#define OMAPFB_SETUP_MEM OMAP_IOW(55, struct omapfb_mem_info)
53#define OMAPFB_QUERY_MEM OMAP_IOW(56, struct omapfb_mem_info)
54#define OMAPFB_WAITFORVSYNC OMAP_IO(57)
55#define OMAPFB_MEMORY_READ OMAP_IOR(58, struct omapfb_memory_read)
56#define OMAPFB_GET_OVERLAY_COLORMODE OMAP_IOR(59, struct omapfb_ovl_colormode)
57#define OMAPFB_WAITFORGO OMAP_IO(60)
58#define OMAPFB_GET_VRAM_INFO OMAP_IOR(61, struct omapfb_vram_info)
59#define OMAPFB_SET_TEARSYNC OMAP_IOW(62, struct omapfb_tearsync_info)
60
61#define OMAPFB_CAPS_GENERIC_MASK 0x00000fff
62#define OMAPFB_CAPS_LCDC_MASK 0x00fff000
63#define OMAPFB_CAPS_PANEL_MASK 0xff000000
64
65#define OMAPFB_CAPS_MANUAL_UPDATE 0x00001000
66#define OMAPFB_CAPS_TEARSYNC 0x00002000
67#define OMAPFB_CAPS_PLANE_RELOCATE_MEM 0x00004000
68#define OMAPFB_CAPS_PLANE_SCALE 0x00008000
69#define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE 0x00010000
70#define OMAPFB_CAPS_WINDOW_SCALE 0x00020000
71#define OMAPFB_CAPS_WINDOW_OVERLAY 0x00040000
72#define OMAPFB_CAPS_WINDOW_ROTATE 0x00080000
73#define OMAPFB_CAPS_SET_BACKLIGHT 0x01000000
74
75/* Values from DSP must map to lower 16-bits */
76#define OMAPFB_FORMAT_MASK 0x00ff
77#define OMAPFB_FORMAT_FLAG_DOUBLE 0x0100
78#define OMAPFB_FORMAT_FLAG_TEARSYNC 0x0200
79#define OMAPFB_FORMAT_FLAG_FORCE_VSYNC 0x0400
80#define OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY 0x0800
81#define OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY 0x1000
82
83#define OMAPFB_MEMTYPE_SDRAM 0
84#define OMAPFB_MEMTYPE_SRAM 1
85#define OMAPFB_MEMTYPE_MAX 1
86
87enum omapfb_color_format {
88 OMAPFB_COLOR_RGB565 = 0,
89 OMAPFB_COLOR_YUV422,
90 OMAPFB_COLOR_YUV420,
91 OMAPFB_COLOR_CLUT_8BPP,
92 OMAPFB_COLOR_CLUT_4BPP,
93 OMAPFB_COLOR_CLUT_2BPP,
94 OMAPFB_COLOR_CLUT_1BPP,
95 OMAPFB_COLOR_RGB444,
96 OMAPFB_COLOR_YUY422,
97
98 OMAPFB_COLOR_ARGB16,
99 OMAPFB_COLOR_RGB24U, /* RGB24, 32-bit container */
100 OMAPFB_COLOR_RGB24P, /* RGB24, 24-bit container */
101 OMAPFB_COLOR_ARGB32,
102 OMAPFB_COLOR_RGBA32,
103 OMAPFB_COLOR_RGBX32,
104};
105
106struct omapfb_update_window {
107 __u32 x, y;
108 __u32 width, height;
109 __u32 format;
110 __u32 out_x, out_y;
111 __u32 out_width, out_height;
112 __u32 reserved[8];
113};
114
115struct omapfb_update_window_old {
116 __u32 x, y;
117 __u32 width, height;
118 __u32 format;
119};
120
121enum omapfb_plane {
122 OMAPFB_PLANE_GFX = 0,
123 OMAPFB_PLANE_VID1,
124 OMAPFB_PLANE_VID2,
125};
126
127enum omapfb_channel_out {
128 OMAPFB_CHANNEL_OUT_LCD = 0,
129 OMAPFB_CHANNEL_OUT_DIGIT,
130};
131
132struct omapfb_plane_info {
133 __u32 pos_x;
134 __u32 pos_y;
135 __u8 enabled;
136 __u8 channel_out;
137 __u8 mirror;
138 __u8 reserved1;
139 __u32 out_width;
140 __u32 out_height;
141 __u32 reserved2[12];
142};
143
144struct omapfb_mem_info {
145 __u32 size;
146 __u8 type;
147 __u8 reserved[3];
148};
149
150struct omapfb_caps {
151 __u32 ctrl;
152 __u32 plane_color;
153 __u32 wnd_color;
154};
155
156enum omapfb_color_key_type {
157 OMAPFB_COLOR_KEY_DISABLED = 0,
158 OMAPFB_COLOR_KEY_GFX_DST,
159 OMAPFB_COLOR_KEY_VID_SRC,
160};
161
162struct omapfb_color_key {
163 __u8 channel_out;
164 __u32 background;
165 __u32 trans_key;
166 __u8 key_type;
167};
168
169enum omapfb_update_mode {
170 OMAPFB_UPDATE_DISABLED = 0,
171 OMAPFB_AUTO_UPDATE,
172 OMAPFB_MANUAL_UPDATE
173};
174
175struct omapfb_memory_read {
176 __u16 x;
177 __u16 y;
178 __u16 w;
179 __u16 h;
180 size_t buffer_size;
181 void __user *buffer;
182};
183
184struct omapfb_ovl_colormode {
185 __u8 overlay_idx;
186 __u8 mode_idx;
187 __u32 bits_per_pixel;
188 __u32 nonstd;
189 struct fb_bitfield red;
190 struct fb_bitfield green;
191 struct fb_bitfield blue;
192 struct fb_bitfield transp;
193};
194
195struct omapfb_vram_info {
196 __u32 total;
197 __u32 free;
198 __u32 largest_free_block;
199 __u32 reserved[5];
200};
201
202struct omapfb_tearsync_info {
203 __u8 enabled;
204 __u8 reserved1[3];
205 __u16 line;
206 __u16 reserved2;
207};
208
209#ifdef __KERNEL__
210
211#include <plat/board.h>
212
213#ifdef CONFIG_ARCH_OMAP1
214#define OMAPFB_PLANE_NUM 1
215#else
216#define OMAPFB_PLANE_NUM 3
217#endif
218
219struct omapfb_mem_region {
220 u32 paddr;
221 void __iomem *vaddr;
222 unsigned long size;
223 u8 type; /* OMAPFB_PLANE_MEM_* */
224 enum omapfb_color_format format;/* OMAPFB_COLOR_* */
225 unsigned format_used:1; /* Must be set when format is set.
226 * Needed b/c of the badly chosen 0
227 * base for OMAPFB_COLOR_* values
228 */
229 unsigned alloc:1; /* allocated by the driver */
230 unsigned map:1; /* kernel mapped by the driver */
231};
232
233struct omapfb_mem_desc {
234 int region_cnt;
235 struct omapfb_mem_region region[OMAPFB_PLANE_NUM];
236};
237
238struct omapfb_platform_data {
239 struct omap_lcd_config lcd;
240 struct omapfb_mem_desc mem_desc;
241 void *ctrl_platform_data;
242};
243
244/* in arch/arm/plat-omap/fb.c */
245extern void omapfb_set_platform_data(struct omapfb_platform_data *data);
246extern void omapfb_set_ctrl_platform_data(void *pdata);
247extern void omapfb_reserve_sdram(void);
248
249#endif
250
251#endif /* __OMAPFB_H */