1 diff --git a/Documentation/arm/OMAP/DSS b/Documentation/arm/OMAP/DSS
5 +++ b/Documentation/arm/OMAP/DSS
7 +OMAP2/3 Display Subsystem
8 +-------------------------
10 +This is an almost total rewrite of the OMAP FB driver in drivers/video/omap
11 +(let's call it DSS1). The main differences between DSS1 and DSS2 are DSI,
12 +TV-out and multiple display support, but there are lots of small improvements
15 +The DSS2 driver (omapdss module) is in arch/arm/plat-omap/dss/, and the FB,
16 +panel and controller drivers are in drivers/video/omap2/. DSS1 and DSS2 live
17 +currently side by side, you can choose which one to use.
22 +Working and tested features include:
24 +- MIPI DPI (parallel) output
25 +- MIPI DSI output in command mode
26 +- MIPI DBI (RFBI) output
29 +- All pieces can be compiled as a module or inside kernel
30 +- Use DISPC to update any of the outputs
31 +- Use CPU to update RFBI or DSI output
33 +- RGB16, RGB24 packed, RGB24 unpacked
36 +- Adjusting DSS FCK to find a good pixel clock
37 +- Use DSI DPLL to create DSS FCK
39 +Tested boards include:
47 +The DSS driver does not itself have any support for Linux framebuffer, V4L or
48 +such like the current ones, but it has an internal kernel API that upper level
51 +The DSS driver models OMAP's overlays, overlay managers and displays in a
52 +flexible way to enable non-common multi-display configuration. In addition to
53 +modelling the hardware overlays, omapdss supports virtual overlays and overlay
54 +managers. These can be used when updating a display with CPU or system DMA.
56 +Panel and controller drivers
57 +----------------------------
59 +The drivers implement panel or controller specific functionality and are not
60 +usually visible to users except through omapfb driver. They register
61 +themselves to the DSS driver.
66 +The omapfb driver implements arbitrary number of standard linux framebuffers.
67 +These framebuffers can be routed flexibly to any overlays, thus allowing very
68 +dynamic display architecture.
70 +The driver exports some omapfb specific ioctls, which are compatible with the
71 +ioctls in the old driver.
73 +The rest of the non standard features are exported via sysfs. Whether the final
74 +implementation will use sysfs, or ioctls, is still open.
79 +V4L2 is being implemented in TI.
81 +From omapdss point of view the V4L2 drivers should be similar to framebuffer
87 +Some clarification what the different components do:
89 + - Framebuffer is a memory area inside OMAP's SRAM/SDRAM that contains the
90 + pixel data for the image. Framebuffer has width and height and color
92 + - Overlay defines where the pixels are read from and where they go on the
93 + screen. The overlay may be smaller than framebuffer, thus displaying only
94 + part of the framebuffer. The position of the overlay may be changed if
95 + the overlay is smaller than the display.
96 + - Overlay manager combines the overlays in to one image and feeds them to
98 + - Display is the actual physical display device.
100 +A framebuffer can be connected to multiple overlays to show the same pixel data
101 +on all of the overlays. Note that in this case the overlay input sizes must be
102 +the same, but, in case of video overlays, the output size can be different. Any
103 +framebuffer can be connected to any overlay.
105 +An overlay can be connected to one overlay manager. Also DISPC overlays can be
106 +connected only to DISPC overlay managers, and virtual overlays can be only
107 +connected to virtual overlays.
109 +An overlay manager can be connected to one display. There are certain
110 +restrictions which kinds of displays an overlay manager can be connected:
112 + - DISPC TV overlay manager can be only connected to TV display.
113 + - Virtual overlay managers can only be connected to DBI or DSI displays.
114 + - DISPC LCD overlay manager can be connected to all displays, except TV
119 +The sysfs interface is mainly used for testing. I don't think sysfs
120 +interface is the best for this in the final version, but I don't quite know
121 +what would be the best interfaces for these things.
123 +The sysfs interface is divided to two parts: DSS and FB.
125 +/sys/class/graphics/fb? directory:
127 +rotate Rotation 0-3 for 0, 90, 180, 270 degrees
128 +rotate_type 0 = DMA rotation, 1 = VRFB rotation
129 +overlays List of overlay numbers to which framebuffer pixels go
130 +phys_addr Physical address of the framebuffer
131 +virt_addr Virtual address of the framebuffer
132 +size Size of the framebuffer
134 +/sys/devices/platform/omapdss/overlay? directory:
136 +input_size width,height (ie. the framebuffer size)
137 +manager Destination overlay manager name
139 +output_size width,height
142 +global_alpha global alpha 0-255 0=transparent 255=opaque
144 +/sys/devices/platform/omapdss/manager? directory:
145 +display Destination display
147 +alpha_blending_enabled 0=off, 1=on
148 +trans_key_enabled 0=off, 1=on
149 +trans_key_type gfx-destination, video-source
150 +trans_key_value transparency color key (RGB24)
151 +default_color default background color (RGB24)
153 +/sys/devices/platform/omapdss/display? directory:
154 +ctrl_name Controller name
156 +update_mode 0=off, 1=auto, 2=manual
159 +rotate Rotation 0-3 for 0, 90, 180, 270 degrees
160 +timings Display timings (pixclock,xres/hfp/hbp/hsw,yres/vfp/vbp/vsw)
161 + When writing, two special timings are accepted for tv-out:
164 +tear_elim Tearing elimination 0=off, 1=on
166 +There are also some debugfs files at <debugfs>/omapdss/ which show information
167 +about clocks and registers.
172 +The following definitions have been made for the examples below:
174 +ovl0=/sys/devices/platform/omapdss/overlay0
175 +ovl1=/sys/devices/platform/omapdss/overlay1
176 +ovl2=/sys/devices/platform/omapdss/overlay2
178 +mgr0=/sys/devices/platform/omapdss/manager0
179 +mgr1=/sys/devices/platform/omapdss/manager1
181 +lcd=/sys/devices/platform/omapdss/display0
182 +dvi=/sys/devices/platform/omapdss/display1
183 +tv=/sys/devices/platform/omapdss/display2
185 +fb0=/sys/class/graphics/fb0
186 +fb1=/sys/class/graphics/fb1
187 +fb2=/sys/class/graphics/fb2
189 +Default setup on OMAP3 SDP
190 +--------------------------
192 +Here's the default setup on OMAP3 SDP board. All planes go to LCD. DVI
193 +and TV-out are not in use. The columns from left to right are:
194 +framebuffers, overlays, overlay managers, displays. Framebuffers are
195 +handled by omapfb, and the rest by the DSS.
198 +FB1 --- VID1 --+- LCD ---- LCD
199 +FB2 --- VID2 -/ TV ----- TV
201 +Example: Switch from LCD to DVI
202 +----------------------
204 +w=`cat $dvi/timings | cut -d "," -f 2 | cut -d "/" -f 1`
205 +h=`cat $dvi/timings | cut -d "," -f 3 | cut -d "/" -f 1`
207 +echo "0" > $lcd/enabled
208 +echo "" > $mgr0/display
209 +fbset -fb /dev/fb0 -xres $w -yres $h -vxres $w -vyres $h
210 +# at this point you have to switch the dvi/lcd dip-switch from the omap board
211 +echo "dvi" > $mgr0/display
212 +echo "1" > $dvi/enabled
214 +After this the configuration looks like:
216 +FB0 --- GFX -\ -- DVI
217 +FB1 --- VID1 --+- LCD -/ LCD
218 +FB2 --- VID2 -/ TV ----- TV
220 +Example: Clone GFX overlay to LCD and TV
221 +-------------------------------
223 +w=`cat $tv/timings | cut -d "," -f 2 | cut -d "/" -f 1`
224 +h=`cat $tv/timings | cut -d "," -f 3 | cut -d "/" -f 1`
226 +echo "0" > $ovl0/enabled
227 +echo "0" > $ovl1/enabled
229 +echo "" > $fb1/overlays
230 +echo "0,1" > $fb0/overlays
232 +echo "$w,$h" > $ovl1/output_size
233 +echo "tv" > $ovl1/manager
235 +echo "1" > $ovl0/enabled
236 +echo "1" > $ovl1/enabled
238 +echo "1" > $tv/enabled
240 +After this the configuration looks like (only relevant parts shown):
242 +FB0 +-- GFX ---- LCD ---- LCD
243 + \- VID1 ---- TV ---- TV
248 +OMAP FB allocates the framebuffer memory using the OMAP VRAM allocator.
250 +Using DSI DPLL to generate pixel clock it is possible produce the pixel clock
251 +of 86.5MHz (max possible), and with that you get 1280x1024@57 output from DVI.
253 +Rotation and mirroring currently only supports RGB565 and RGB8888 modes. VRFB
254 +does not support mirroring.
256 +VRFB rotation requires much more memory than non-rotated framebuffer, so you
257 +probably need to increase your vram setting before using VRFB rotation. Also,
258 +many applications may not work with VRFB if they do not pay attention to all
259 +framebuffer parameters.
261 +Kernel boot arguments
262 +---------------------
265 + - Amount of total VRAM to preallocate. For example, "10M". omapfb
266 + allocates memory for framebuffers from VRAM.
268 +omapfb.mode=<display>:<mode>[,...]
269 + - Default video mode for specified displays. For example,
270 + "dvi:800x400MR-24@60". See drivers/video/modedb.c.
271 + There are also two special modes: "pal" and "ntsc" that
272 + can be used to tv out.
274 +omapfb.vram=<fbnum>:<size>[@<physaddr>][,...]
275 + - VRAM allocated for a framebuffer. Normally omapfb allocates vram
276 + depending on the display size. With this you can manually allocate
277 + more or define the physical address of each framebuffer. For example,
278 + "1:4M" to allocate 4M for fb1.
281 + - Enable debug printing. You have to have OMAPFB debug support enabled
285 + - Draw test pattern to framebuffer whenever framebuffer settings change.
286 + You need to have OMAPFB debug support enabled in kernel config.
289 + - Use VRFB rotation for all framebuffers.
291 +omapfb.rotate=<angle>
292 + - Default rotation applied to all framebuffers.
293 + 0 - 0 degree rotation
294 + 1 - 90 degree rotation
295 + 2 - 180 degree rotation
296 + 3 - 270 degree rotation
299 + - Default mirror for all framebuffers. Only works with DMA rotation.
301 +omapdss.def_disp=<display>
302 + - Name of default display, to which all overlays will be connected.
303 + Common examples are "lcd" or "tv".
306 + - Enable debug printing. You have to have DSS debug support enabled in
315 +- Lots of checks are missing or implemented just as BUG()
317 +System DMA update for DSI
318 +- Can be used for RGB16 and RGB24P modes. Probably not for RGB24U (how
319 + to skip the empty byte?)
322 +- Not sure if needed
324 diff --git a/MAINTAINERS b/MAINTAINERS
325 index 8824115..3f5d39f 100644
328 @@ -3819,6 +3819,23 @@ L: linux-omap@vger.kernel.org
330 F: drivers/video/omap/
332 +OMAP DISPLAY SUBSYSTEM SUPPORT (DSS2)
333 +M: Tomi Valkeinen <tomi.valkeinen@nokia.com>
334 +L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
335 +L: linux-omap@vger.kernel.org
337 +F: drivers/video/omap2/dss/
338 +F: drivers/video/omap2/vrfb.c
339 +F: drivers/video/omap2/vram.c
340 +F: Documentation/arm/OMAP/DSS
342 +OMAP FRAMEBUFFER SUPPORT (FOR DSS2)
343 +M: Tomi Valkeinen <tomi.valkeinen@nokia.com>
344 +L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
345 +L: linux-omap@vger.kernel.org
347 +F: drivers/video/omap2/omapfb/
350 M: Jarkko Lavinen <jarkko.lavinen@nokia.com>
351 L: linux-omap@vger.kernel.org
352 diff --git a/arch/arm/configs/omap_3430sdp_defconfig b/arch/arm/configs/omap_3430sdp_defconfig
353 index 8a4a7e2..59e26e4 100644
354 --- a/arch/arm/configs/omap_3430sdp_defconfig
355 +++ b/arch/arm/configs/omap_3430sdp_defconfig
356 @@ -1336,10 +1336,33 @@ CONFIG_FB_CFB_IMAGEBLIT=y
358 # CONFIG_FB_S1D13XXX is not set
359 # CONFIG_FB_VIRTUAL is not set
361 -# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
362 +# CONFIG_FB_METRONOME is not set
363 +# CONFIG_FB_MB862XX is not set
364 +# CONFIG_FB_BROADSHEET is not set
365 +# CONFIG_FB_OMAP_LCD_VGA is not set
366 # CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
367 -CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
371 +CONFIG_OMAP2_VRAM_SIZE=4
372 +CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y
373 +# CONFIG_OMAP2_DSS_RFBI is not set
374 +CONFIG_OMAP2_DSS_VENC=y
375 +# CONFIG_OMAP2_DSS_SDI is not set
376 +# CONFIG_OMAP2_DSS_DSI is not set
377 +# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
378 +CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0
380 +CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
381 +# CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set
382 +CONFIG_FB_OMAP2_NUM_FBS=3
385 +# OMAP2/3 Display Device Drivers
387 +CONFIG_PANEL_GENERIC=y
388 +# CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C is not set
389 +CONFIG_PANEL_SHARP_LS037V7DW01=y
390 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
393 diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
394 index ed2a48a..6fbde33 100644
395 --- a/arch/arm/mach-omap1/board-nokia770.c
396 +++ b/arch/arm/mach-omap1/board-nokia770.c
398 #include <linux/platform_device.h>
399 #include <linux/input.h>
400 #include <linux/clk.h>
401 +#include <linux/omapfb.h>
403 #include <linux/spi/spi.h>
404 #include <linux/spi/ads7846.h>
406 #include <mach/keypad.h>
407 #include <mach/common.h>
408 #include <mach/dsp_common.h>
409 -#include <mach/omapfb.h>
410 #include <mach/hwa742.h>
411 #include <mach/lcd_mipid.h>
412 #include <mach/mmc.h>
413 diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
414 index efaf053..60631be 100644
415 --- a/arch/arm/mach-omap2/board-3430sdp.c
416 +++ b/arch/arm/mach-omap2/board-3430sdp.c
418 #include <mach/common.h>
419 #include <mach/dma.h>
420 #include <mach/gpmc.h>
421 +#include <mach/display.h>
423 #include <mach/control.h>
424 #include <mach/keypad.h>
425 @@ -152,31 +153,152 @@ static struct spi_board_info sdp3430_spi_board_info[] __initdata = {
429 -static struct platform_device sdp3430_lcd_device = {
430 - .name = "sdp2430_lcd",
433 +#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 8
434 +#define SDP3430_LCD_PANEL_ENABLE_GPIO 5
436 +static unsigned backlight_gpio;
437 +static unsigned enable_gpio;
438 +static int lcd_enabled;
439 +static int dvi_enabled;
441 +static void __init sdp3430_display_init(void)
445 + enable_gpio = SDP3430_LCD_PANEL_ENABLE_GPIO;
446 + backlight_gpio = SDP3430_LCD_PANEL_BACKLIGHT_GPIO;
448 + r = gpio_request(enable_gpio, "LCD reset");
450 + printk(KERN_ERR "failed to get LCD reset GPIO\n");
454 + r = gpio_request(backlight_gpio, "LCD Backlight");
456 + printk(KERN_ERR "failed to get LCD backlight GPIO\n");
460 + gpio_direction_output(enable_gpio, 0);
461 + gpio_direction_output(backlight_gpio, 0);
465 + gpio_free(enable_gpio);
470 +static int sdp3430_panel_enable_lcd(struct omap_dss_device *dssdev)
473 + printk(KERN_ERR "cannot enable LCD, DVI is enabled\n");
477 + gpio_direction_output(enable_gpio, 1);
478 + gpio_direction_output(backlight_gpio, 1);
485 +static void sdp3430_panel_disable_lcd(struct omap_dss_device *dssdev)
489 + gpio_direction_output(enable_gpio, 0);
490 + gpio_direction_output(backlight_gpio, 0);
493 +static int sdp3430_panel_enable_dvi(struct omap_dss_device *dssdev)
496 + printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
505 +static void sdp3430_panel_disable_dvi(struct omap_dss_device *dssdev)
510 +static int sdp3430_panel_enable_tv(struct omap_dss_device *dssdev)
515 +static void sdp3430_panel_disable_tv(struct omap_dss_device *dssdev)
520 +static struct omap_dss_device sdp3430_lcd_device = {
522 + .driver_name = "sharp_ls_panel",
523 + .type = OMAP_DISPLAY_TYPE_DPI,
524 + .phy.dpi.data_lines = 16,
525 + .platform_enable = sdp3430_panel_enable_lcd,
526 + .platform_disable = sdp3430_panel_disable_lcd,
529 -static struct regulator_consumer_supply sdp3430_vdac_supply = {
531 - .dev = &sdp3430_lcd_device.dev,
532 +static struct omap_dss_device sdp3430_dvi_device = {
534 + .driver_name = "generic_panel",
535 + .type = OMAP_DISPLAY_TYPE_DPI,
536 + .phy.dpi.data_lines = 24,
537 + .platform_enable = sdp3430_panel_enable_dvi,
538 + .platform_disable = sdp3430_panel_disable_dvi,
541 -static struct regulator_consumer_supply sdp3430_vdvi_supply = {
543 - .dev = &sdp3430_lcd_device.dev,
544 +static struct omap_dss_device sdp3430_tv_device = {
546 + .driver_name = "venc",
547 + .type = OMAP_DISPLAY_TYPE_VENC,
548 + .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO,
549 + .platform_enable = sdp3430_panel_enable_tv,
550 + .platform_disable = sdp3430_panel_disable_tv,
553 -static struct platform_device *sdp3430_devices[] __initdata = {
555 +static struct omap_dss_device *sdp3430_dss_devices[] = {
557 + &sdp3430_dvi_device,
558 + &sdp3430_tv_device,
561 -static struct omap_lcd_config sdp3430_lcd_config __initdata = {
562 - .ctrl_name = "internal",
563 +static struct omap_dss_board_info sdp3430_dss_data = {
564 + .num_devices = ARRAY_SIZE(sdp3430_dss_devices),
565 + .devices = sdp3430_dss_devices,
566 + .default_device = &sdp3430_lcd_device,
569 +static struct platform_device sdp3430_dss_device = {
573 + .platform_data = &sdp3430_dss_data,
577 +static struct regulator_consumer_supply sdp3430_vdda_dac_supply = {
578 + .supply = "vdda_dac",
579 + .dev = &sdp3430_dss_device.dev,
582 +static struct platform_device *sdp3430_devices[] __initdata = {
583 + &sdp3430_dss_device,
586 static struct omap_board_config_kernel sdp3430_config[] __initdata = {
587 - { OMAP_TAG_LCD, &sdp3430_lcd_config },
590 static void __init omap_3430sdp_init_irq(void)
591 @@ -392,22 +514,34 @@ static struct regulator_init_data sdp3430_vdac = {
592 | REGULATOR_CHANGE_STATUS,
594 .num_consumer_supplies = 1,
595 - .consumer_supplies = &sdp3430_vdac_supply,
596 + .consumer_supplies = &sdp3430_vdda_dac_supply,
599 /* VPLL2 for digital video outputs */
600 +static struct regulator_consumer_supply sdp3430_vpll2_supplies[] = {
603 + .dev = &sdp3430_lcd_device.dev,
606 + .supply = "vdds_dsi",
607 + .dev = &sdp3430_dss_device.dev,
611 static struct regulator_init_data sdp3430_vpll2 = {
617 .valid_modes_mask = REGULATOR_MODE_NORMAL
618 | REGULATOR_MODE_STANDBY,
619 .valid_ops_mask = REGULATOR_CHANGE_MODE
620 | REGULATOR_CHANGE_STATUS,
622 - .num_consumer_supplies = 1,
623 - .consumer_supplies = &sdp3430_vdvi_supply,
624 + .num_consumer_supplies = ARRAY_SIZE(sdp3430_vpll2_supplies),
625 + .consumer_supplies = sdp3430_vpll2_supplies,
628 static struct twl4030_platform_data sdp3430_twldata = {
629 @@ -499,6 +633,7 @@ static void __init omap_3430sdp_init(void)
633 + sdp3430_display_init();
634 enable_board_wakeup_source();
637 diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c
638 index e2dbedd..8524067 100644
639 --- a/arch/arm/mach-omap2/clock24xx.c
640 +++ b/arch/arm/mach-omap2/clock24xx.c
641 @@ -116,10 +116,10 @@ static struct omap_clk omap24xx_clks[] = {
642 CLK(NULL, "mdm_ick", &mdm_ick, CK_243X),
643 CLK(NULL, "mdm_osc_ck", &mdm_osc_ck, CK_243X),
644 /* DSS domain clocks */
645 - CLK("omapfb", "ick", &dss_ick, CK_243X | CK_242X),
646 - CLK("omapfb", "dss1_fck", &dss1_fck, CK_243X | CK_242X),
647 - CLK("omapfb", "dss2_fck", &dss2_fck, CK_243X | CK_242X),
648 - CLK("omapfb", "tv_fck", &dss_54m_fck, CK_243X | CK_242X),
649 + CLK("omapdss", "ick", &dss_ick, CK_243X | CK_242X),
650 + CLK("omapdss", "dss1_fck", &dss1_fck, CK_243X | CK_242X),
651 + CLK("omapdss", "dss2_fck", &dss2_fck, CK_243X | CK_242X),
652 + CLK("omapdss", "tv_fck", &dss_54m_fck, CK_243X | CK_242X),
653 /* L3 domain clocks */
654 CLK(NULL, "core_l3_ck", &core_l3_ck, CK_243X | CK_242X),
655 CLK(NULL, "ssi_fck", &ssi_ssr_sst_fck, CK_243X | CK_242X),
656 diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
657 index 489556e..0a7e9ac 100644
658 --- a/arch/arm/mach-omap2/clock34xx.c
659 +++ b/arch/arm/mach-omap2/clock34xx.c
660 @@ -236,13 +236,13 @@ static struct omap_clk omap34xx_clks[] = {
661 CLK("omap_rng", "ick", &rng_ick, CK_343X),
662 CLK(NULL, "sha11_ick", &sha11_ick, CK_343X),
663 CLK(NULL, "des1_ick", &des1_ick, CK_343X),
664 - CLK("omapfb", "dss1_fck", &dss1_alwon_fck_3430es1, CK_3430ES1),
665 - CLK("omapfb", "dss1_fck", &dss1_alwon_fck_3430es2, CK_3430ES2),
666 - CLK("omapfb", "tv_fck", &dss_tv_fck, CK_343X),
667 - CLK("omapfb", "video_fck", &dss_96m_fck, CK_343X),
668 - CLK("omapfb", "dss2_fck", &dss2_alwon_fck, CK_343X),
669 - CLK("omapfb", "ick", &dss_ick_3430es1, CK_3430ES1),
670 - CLK("omapfb", "ick", &dss_ick_3430es2, CK_3430ES2),
671 + CLK("omapdss", "dss1_fck", &dss1_alwon_fck_3430es1, CK_3430ES1),
672 + CLK("omapdss", "dss1_fck", &dss1_alwon_fck_3430es2, CK_3430ES2),
673 + CLK("omapdss", "tv_fck", &dss_tv_fck, CK_343X),
674 + CLK("omapdss", "video_fck", &dss_96m_fck, CK_343X),
675 + CLK("omapdss", "dss2_fck", &dss2_alwon_fck, CK_343X),
676 + CLK("omapdss", "ick", &dss_ick_3430es1, CK_3430ES1),
677 + CLK("omapdss", "ick", &dss_ick_3430es2, CK_3430ES2),
678 CLK(NULL, "cam_mclk", &cam_mclk, CK_343X),
679 CLK(NULL, "cam_ick", &cam_ick, CK_343X),
680 CLK(NULL, "csi2_96m_fck", &csi2_96m_fck, CK_343X),
681 diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
682 index e3a3bad..adbb905 100644
683 --- a/arch/arm/mach-omap2/io.c
684 +++ b/arch/arm/mach-omap2/io.c
686 #include <linux/init.h>
687 #include <linux/io.h>
688 #include <linux/clk.h>
689 +#include <linux/omapfb.h>
693 #include <asm/mach/map.h>
695 #include <mach/mux.h>
696 -#include <mach/omapfb.h>
697 #include <mach/sram.h>
698 #include <mach/sdrc.h>
699 #include <mach/gpmc.h>
700 #include <mach/serial.h>
701 +#include <mach/vram.h>
703 #ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdev is ready */
705 @@ -246,6 +247,7 @@ void __init omap2_map_common_io(void)
706 omap2_check_revision();
708 omapfb_reserve_sdram();
709 + omap_vram_reserve_sdram();
713 diff --git a/arch/arm/mach-omap2/sdrc.c b/arch/arm/mach-omap2/sdrc.c
714 index 9e3bd4f..6a5a2c5 100644
715 --- a/arch/arm/mach-omap2/sdrc.c
716 +++ b/arch/arm/mach-omap2/sdrc.c
717 @@ -133,3 +133,19 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
718 (1 << SDRC_POWER_PAGEPOLICY_SHIFT);
719 sdrc_write_reg(l, SDRC_POWER);
722 +void omap2_sms_write_rot_control(u32 val, unsigned ctx)
724 + sms_write_reg(val, SMS_ROT_CONTROL(ctx));
727 +void omap2_sms_write_rot_size(u32 val, unsigned ctx)
729 + sms_write_reg(val, SMS_ROT_SIZE(ctx));
732 +void omap2_sms_write_rot_physical_ba(u32 val, unsigned ctx)
734 + sms_write_reg(val, SMS_ROT_PHYSICAL_BA(ctx));
737 diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c
738 index 3746222..70fbeae 100644
739 --- a/arch/arm/plat-omap/fb.c
740 +++ b/arch/arm/plat-omap/fb.c
742 #include <linux/platform_device.h>
743 #include <linux/bootmem.h>
744 #include <linux/io.h>
745 +#include <linux/omapfb.h>
747 #include <mach/hardware.h>
748 #include <asm/mach/map.h>
750 #include <mach/board.h>
751 #include <mach/sram.h>
752 -#include <mach/omapfb.h>
754 #if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
756 @@ -327,7 +327,33 @@ static inline int omap_init_fb(void)
758 arch_initcall(omap_init_fb);
761 +#elif defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
763 +static u64 omap_fb_dma_mask = ~(u32)0;
764 +static struct omapfb_platform_data omapfb_config;
766 +static struct platform_device omap_fb_device = {
770 + .dma_mask = &omap_fb_dma_mask,
771 + .coherent_dma_mask = ~(u32)0,
772 + .platform_data = &omapfb_config,
774 + .num_resources = 0,
777 +void omapfb_set_platform_data(struct omapfb_platform_data *data)
779 + omapfb_config = *data;
782 +static inline int omap_init_fb(void)
784 + return platform_device_register(&omap_fb_device);
787 +arch_initcall(omap_init_fb);
789 void omapfb_reserve_sdram(void) {}
790 unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
791 @@ -339,5 +365,16 @@ unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
797 +void omapfb_reserve_sdram(void) {}
798 +unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
799 + unsigned long sram_vstart,
800 + unsigned long sram_size,
801 + unsigned long start_avail,
802 + unsigned long size_avail)
808 diff --git a/arch/arm/plat-omap/include/mach/display.h b/arch/arm/plat-omap/include/mach/display.h
810 index 0000000..4c7422e
812 +++ b/arch/arm/plat-omap/include/mach/display.h
815 + * linux/include/asm-arm/arch-omap/display.h
817 + * Copyright (C) 2008 Nokia Corporation
818 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
820 + * This program is free software; you can redistribute it and/or modify it
821 + * under the terms of the GNU General Public License version 2 as published by
822 + * the Free Software Foundation.
824 + * This program is distributed in the hope that it will be useful, but WITHOUT
825 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
826 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
829 + * You should have received a copy of the GNU General Public License along with
830 + * this program. If not, see <http://www.gnu.org/licenses/>.
833 +#ifndef __ASM_ARCH_OMAP_DISPLAY_H
834 +#define __ASM_ARCH_OMAP_DISPLAY_H
836 +#include <linux/list.h>
837 +#include <linux/kobject.h>
838 +#include <linux/device.h>
839 +#include <asm/atomic.h>
841 +#define DISPC_IRQ_FRAMEDONE (1 << 0)
842 +#define DISPC_IRQ_VSYNC (1 << 1)
843 +#define DISPC_IRQ_EVSYNC_EVEN (1 << 2)
844 +#define DISPC_IRQ_EVSYNC_ODD (1 << 3)
845 +#define DISPC_IRQ_ACBIAS_COUNT_STAT (1 << 4)
846 +#define DISPC_IRQ_PROG_LINE_NUM (1 << 5)
847 +#define DISPC_IRQ_GFX_FIFO_UNDERFLOW (1 << 6)
848 +#define DISPC_IRQ_GFX_END_WIN (1 << 7)
849 +#define DISPC_IRQ_PAL_GAMMA_MASK (1 << 8)
850 +#define DISPC_IRQ_OCP_ERR (1 << 9)
851 +#define DISPC_IRQ_VID1_FIFO_UNDERFLOW (1 << 10)
852 +#define DISPC_IRQ_VID1_END_WIN (1 << 11)
853 +#define DISPC_IRQ_VID2_FIFO_UNDERFLOW (1 << 12)
854 +#define DISPC_IRQ_VID2_END_WIN (1 << 13)
855 +#define DISPC_IRQ_SYNC_LOST (1 << 14)
856 +#define DISPC_IRQ_SYNC_LOST_DIGIT (1 << 15)
857 +#define DISPC_IRQ_WAKEUP (1 << 16)
859 +struct omap_dss_device;
860 +struct omap_overlay_manager;
862 +enum omap_display_type {
863 + OMAP_DISPLAY_TYPE_NONE = 0,
864 + OMAP_DISPLAY_TYPE_DPI = 1 << 0,
865 + OMAP_DISPLAY_TYPE_DBI = 1 << 1,
866 + OMAP_DISPLAY_TYPE_SDI = 1 << 2,
867 + OMAP_DISPLAY_TYPE_DSI = 1 << 3,
868 + OMAP_DISPLAY_TYPE_VENC = 1 << 4,
873 + OMAP_DSS_VIDEO1 = 1,
874 + OMAP_DSS_VIDEO2 = 2
878 + OMAP_DSS_CHANNEL_LCD = 0,
879 + OMAP_DSS_CHANNEL_DIGIT = 1,
882 +enum omap_color_mode {
883 + OMAP_DSS_COLOR_CLUT1 = 1 << 0, /* BITMAP 1 */
884 + OMAP_DSS_COLOR_CLUT2 = 1 << 1, /* BITMAP 2 */
885 + OMAP_DSS_COLOR_CLUT4 = 1 << 2, /* BITMAP 4 */
886 + OMAP_DSS_COLOR_CLUT8 = 1 << 3, /* BITMAP 8 */
887 + OMAP_DSS_COLOR_RGB12U = 1 << 4, /* RGB12, 16-bit container */
888 + OMAP_DSS_COLOR_ARGB16 = 1 << 5, /* ARGB16 */
889 + OMAP_DSS_COLOR_RGB16 = 1 << 6, /* RGB16 */
890 + OMAP_DSS_COLOR_RGB24U = 1 << 7, /* RGB24, 32-bit container */
891 + OMAP_DSS_COLOR_RGB24P = 1 << 8, /* RGB24, 24-bit container */
892 + OMAP_DSS_COLOR_YUV2 = 1 << 9, /* YUV2 4:2:2 co-sited */
893 + OMAP_DSS_COLOR_UYVY = 1 << 10, /* UYVY 4:2:2 co-sited */
894 + OMAP_DSS_COLOR_ARGB32 = 1 << 11, /* ARGB32 */
895 + OMAP_DSS_COLOR_RGBA32 = 1 << 12, /* RGBA32 */
896 + OMAP_DSS_COLOR_RGBX32 = 1 << 13, /* RGBx32 */
898 + OMAP_DSS_COLOR_GFX_OMAP3 =
899 + OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
900 + OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
901 + OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
902 + OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
903 + OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
904 + OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
906 + OMAP_DSS_COLOR_VID_OMAP3 =
907 + OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
908 + OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
909 + OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
910 + OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32 |
911 + OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
914 +enum omap_lcd_display_type {
915 + OMAP_DSS_LCD_DISPLAY_STN,
916 + OMAP_DSS_LCD_DISPLAY_TFT,
919 +enum omap_dss_load_mode {
920 + OMAP_DSS_LOAD_CLUT_AND_FRAME = 0,
921 + OMAP_DSS_LOAD_CLUT_ONLY = 1,
922 + OMAP_DSS_LOAD_FRAME_ONLY = 2,
923 + OMAP_DSS_LOAD_CLUT_ONCE_FRAME = 3,
926 +enum omap_dss_trans_key_type {
927 + OMAP_DSS_COLOR_KEY_GFX_DST = 0,
928 + OMAP_DSS_COLOR_KEY_VID_SRC = 1,
931 +enum omap_rfbi_te_mode {
932 + OMAP_DSS_RFBI_TE_MODE_1 = 1,
933 + OMAP_DSS_RFBI_TE_MODE_2 = 2,
936 +enum omap_panel_config {
937 + OMAP_DSS_LCD_IVS = 1<<0,
938 + OMAP_DSS_LCD_IHS = 1<<1,
939 + OMAP_DSS_LCD_IPC = 1<<2,
940 + OMAP_DSS_LCD_IEO = 1<<3,
941 + OMAP_DSS_LCD_RF = 1<<4,
942 + OMAP_DSS_LCD_ONOFF = 1<<5,
944 + OMAP_DSS_LCD_TFT = 1<<20,
947 +enum omap_dss_venc_type {
948 + OMAP_DSS_VENC_TYPE_COMPOSITE,
949 + OMAP_DSS_VENC_TYPE_SVIDEO,
952 +enum omap_display_caps {
953 + OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE = 1 << 0,
956 +enum omap_dss_update_mode {
957 + OMAP_DSS_UPDATE_DISABLED = 0,
958 + OMAP_DSS_UPDATE_AUTO,
959 + OMAP_DSS_UPDATE_MANUAL,
962 +enum omap_dss_display_state {
963 + OMAP_DSS_DISPLAY_DISABLED = 0,
964 + OMAP_DSS_DISPLAY_ACTIVE,
965 + OMAP_DSS_DISPLAY_SUSPENDED,
968 +/* XXX perhaps this should be removed */
969 +enum omap_dss_overlay_managers {
970 + OMAP_DSS_OVL_MGR_LCD,
971 + OMAP_DSS_OVL_MGR_TV,
974 +enum omap_dss_rotation_type {
975 + OMAP_DSS_ROT_DMA = 0,
976 + OMAP_DSS_ROT_VRFB = 1,
979 +enum omap_overlay_caps {
980 + OMAP_DSS_OVL_CAP_SCALE = 1 << 0,
981 + OMAP_DSS_OVL_CAP_DISPC = 1 << 1,
984 +enum omap_overlay_manager_caps {
985 + OMAP_DSS_OVL_MGR_CAP_DISPC = 1 << 0,
990 +struct rfbi_timings {
999 + int cs_pulse_width;
1004 + u32 tim[5]; /* set by rfbi_convert_timings() */
1009 +void omap_rfbi_write_command(const void *buf, u32 len);
1010 +void omap_rfbi_read_data(void *buf, u32 len);
1011 +void omap_rfbi_write_data(const void *buf, u32 len);
1012 +void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
1015 +int omap_rfbi_enable_te(bool enable, unsigned line);
1016 +int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
1017 + unsigned hs_pulse_time, unsigned vs_pulse_time,
1018 + int hs_pol_inv, int vs_pol_inv, int extif_div);
1021 +void dsi_bus_lock(void);
1022 +void dsi_bus_unlock(void);
1023 +int dsi_vc_dcs_write(int channel, u8 *data, int len);
1024 +int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len);
1025 +int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen);
1026 +int dsi_vc_set_max_rx_packet_size(int channel, u16 len);
1027 +int dsi_vc_send_null(int channel);
1028 +int dsi_vc_send_bta_sync(int channel);
1030 +/* Board specific data */
1031 +struct omap_dss_board_info {
1032 + int (*get_last_off_on_transaction_id)(struct device *dev);
1034 + struct omap_dss_device **devices;
1035 + struct omap_dss_device *default_device;
1038 +struct omap_video_timings {
1039 + /* Unit: pixels */
1041 + /* Unit: pixels */
1045 + /* Unit: pixel clocks */
1046 + u16 hsw; /* Horizontal synchronization pulse width */
1047 + /* Unit: pixel clocks */
1048 + u16 hfp; /* Horizontal front porch */
1049 + /* Unit: pixel clocks */
1050 + u16 hbp; /* Horizontal back porch */
1051 + /* Unit: line clocks */
1052 + u16 vsw; /* Vertical synchronization pulse width */
1053 + /* Unit: line clocks */
1054 + u16 vfp; /* Vertical front porch */
1055 + /* Unit: line clocks */
1056 + u16 vbp; /* Vertical back porch */
1059 +#ifdef CONFIG_OMAP2_DSS_VENC
1060 +/* Hardcoded timings for tv modes. Venc only uses these to
1061 + * identify the mode, and does not actually use the configs
1062 + * itself. However, the configs should be something that
1063 + * a normal monitor can also show */
1064 +const extern struct omap_video_timings omap_dss_pal_timings;
1065 +const extern struct omap_video_timings omap_dss_ntsc_timings;
1068 +struct omap_overlay_info {
1072 + void __iomem *vaddr;
1076 + enum omap_color_mode color_mode;
1078 + enum omap_dss_rotation_type rotation_type;
1083 + u16 out_width; /* if 0, out_width == width */
1084 + u16 out_height; /* if 0, out_height == height */
1088 +struct omap_overlay {
1089 + struct kobject kobj;
1090 + struct list_head list;
1092 + /* static fields */
1095 + enum omap_color_mode supported_modes;
1096 + enum omap_overlay_caps caps;
1098 + /* dynamic fields */
1099 + struct omap_overlay_manager *manager;
1100 + struct omap_overlay_info info;
1102 + /* if true, info has been changed, but not applied() yet */
1105 + int (*set_manager)(struct omap_overlay *ovl,
1106 + struct omap_overlay_manager *mgr);
1107 + int (*unset_manager)(struct omap_overlay *ovl);
1109 + int (*set_overlay_info)(struct omap_overlay *ovl,
1110 + struct omap_overlay_info *info);
1111 + void (*get_overlay_info)(struct omap_overlay *ovl,
1112 + struct omap_overlay_info *info);
1114 + int (*wait_for_go)(struct omap_overlay *ovl);
1117 +struct omap_overlay_manager_info {
1118 + u32 default_color;
1120 + enum omap_dss_trans_key_type trans_key_type;
1122 + bool trans_enabled;
1124 + bool alpha_enabled;
1127 +struct omap_overlay_manager {
1128 + struct kobject kobj;
1129 + struct list_head list;
1131 + /* static fields */
1134 + enum omap_overlay_manager_caps caps;
1136 + struct omap_overlay **overlays;
1137 + enum omap_display_type supported_displays;
1139 + /* dynamic fields */
1140 + struct omap_dss_device *device;
1141 + struct omap_overlay_manager_info info;
1143 + bool device_changed;
1144 + /* if true, info has been changed but not applied() yet */
1147 + int (*set_device)(struct omap_overlay_manager *mgr,
1148 + struct omap_dss_device *dssdev);
1149 + int (*unset_device)(struct omap_overlay_manager *mgr);
1151 + int (*set_manager_info)(struct omap_overlay_manager *mgr,
1152 + struct omap_overlay_manager_info *info);
1153 + void (*get_manager_info)(struct omap_overlay_manager *mgr,
1154 + struct omap_overlay_manager_info *info);
1156 + int (*apply)(struct omap_overlay_manager *mgr);
1157 + int (*wait_for_go)(struct omap_overlay_manager *mgr);
1160 +struct omap_dss_device {
1161 + struct device dev;
1163 + enum omap_display_type type;
1186 + unsigned long lp_clk_hz;
1187 + unsigned long ddr_clk_hz;
1194 + enum omap_dss_venc_type type;
1195 + bool invert_polarity;
1200 + struct omap_video_timings timings;
1202 + int acbi; /* ac-bias pin transitions per interrupt */
1203 + /* Unit: line clocks */
1204 + int acb; /* ac-bias pin frequency */
1206 + enum omap_panel_config config;
1208 + u8 recommended_bpp;
1210 + struct omap_dss_device *ctrl;
1215 + struct rfbi_timings rfbi_timings;
1216 + struct omap_dss_device *panel;
1221 + int max_backlight_level;
1225 + /* used to match device to driver */
1226 + const char *driver_name;
1230 + struct omap_dss_driver *driver;
1232 + /* helper variable for driver suspend/resume */
1233 + bool activate_after_resume;
1235 + enum omap_display_caps caps;
1237 + struct omap_overlay_manager *manager;
1239 + enum omap_dss_display_state state;
1241 + int (*enable)(struct omap_dss_device *dssdev);
1242 + void (*disable)(struct omap_dss_device *dssdev);
1244 + int (*suspend)(struct omap_dss_device *dssdev);
1245 + int (*resume)(struct omap_dss_device *dssdev);
1247 + void (*get_resolution)(struct omap_dss_device *dssdev,
1248 + u16 *xres, u16 *yres);
1249 + int (*get_recommended_bpp)(struct omap_dss_device *dssdev);
1251 + int (*check_timings)(struct omap_dss_device *dssdev,
1252 + struct omap_video_timings *timings);
1253 + void (*set_timings)(struct omap_dss_device *dssdev,
1254 + struct omap_video_timings *timings);
1255 + void (*get_timings)(struct omap_dss_device *dssdev,
1256 + struct omap_video_timings *timings);
1257 + int (*update)(struct omap_dss_device *dssdev,
1258 + u16 x, u16 y, u16 w, u16 h);
1259 + int (*sync)(struct omap_dss_device *dssdev);
1260 + int (*wait_vsync)(struct omap_dss_device *dssdev);
1262 + int (*set_update_mode)(struct omap_dss_device *dssdev,
1263 + enum omap_dss_update_mode);
1264 + enum omap_dss_update_mode (*get_update_mode)
1265 + (struct omap_dss_device *dssdev);
1267 + int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
1268 + int (*get_te)(struct omap_dss_device *dssdev);
1270 + u8 (*get_rotate)(struct omap_dss_device *dssdev);
1271 + int (*set_rotate)(struct omap_dss_device *dssdev, u8 rotate);
1273 + bool (*get_mirror)(struct omap_dss_device *dssdev);
1274 + int (*set_mirror)(struct omap_dss_device *dssdev, bool enable);
1276 + int (*run_test)(struct omap_dss_device *dssdev, int test);
1277 + int (*memory_read)(struct omap_dss_device *dssdev,
1278 + void *buf, size_t size,
1279 + u16 x, u16 y, u16 w, u16 h);
1281 + int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
1282 + u32 (*get_wss)(struct omap_dss_device *dssdev);
1284 + /* platform specific */
1285 + int (*platform_enable)(struct omap_dss_device *dssdev);
1286 + void (*platform_disable)(struct omap_dss_device *dssdev);
1287 + int (*set_backlight)(struct omap_dss_device *dssdev, int level);
1288 + int (*get_backlight)(struct omap_dss_device *dssdev);
1291 +struct omap_dss_driver {
1292 + struct device_driver driver;
1294 + int (*probe)(struct omap_dss_device *);
1295 + void (*remove)(struct omap_dss_device *);
1297 + int (*enable)(struct omap_dss_device *display);
1298 + void (*disable)(struct omap_dss_device *display);
1299 + int (*suspend)(struct omap_dss_device *display);
1300 + int (*resume)(struct omap_dss_device *display);
1301 + int (*run_test)(struct omap_dss_device *display, int test);
1303 + void (*setup_update)(struct omap_dss_device *dssdev,
1304 + u16 x, u16 y, u16 w, u16 h);
1306 + int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
1307 + int (*wait_for_te)(struct omap_dss_device *dssdev);
1309 + u8 (*get_rotate)(struct omap_dss_device *dssdev);
1310 + int (*set_rotate)(struct omap_dss_device *dssdev, u8 rotate);
1312 + bool (*get_mirror)(struct omap_dss_device *dssdev);
1313 + int (*set_mirror)(struct omap_dss_device *dssdev, bool enable);
1315 + int (*memory_read)(struct omap_dss_device *dssdev,
1316 + void *buf, size_t size,
1317 + u16 x, u16 y, u16 w, u16 h);
1320 +int omap_dss_register_driver(struct omap_dss_driver *);
1321 +void omap_dss_unregister_driver(struct omap_dss_driver *);
1323 +int omap_dss_register_device(struct omap_dss_device *);
1324 +void omap_dss_unregister_device(struct omap_dss_device *);
1326 +void omap_dss_get_device(struct omap_dss_device *dssdev);
1327 +void omap_dss_put_device(struct omap_dss_device *dssdev);
1328 +#define for_each_dss_dev(d) while ((d = omap_dss_get_next_device(d)) != NULL)
1329 +struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from);
1330 +struct omap_dss_device *omap_dss_find_device(void *data,
1331 + int (*match)(struct omap_dss_device *dssdev, void *data));
1333 +int omap_dss_start_device(struct omap_dss_device *dssdev);
1334 +void omap_dss_stop_device(struct omap_dss_device *dssdev);
1336 +int omap_dss_get_num_overlay_managers(void);
1337 +struct omap_overlay_manager *omap_dss_get_overlay_manager(int num);
1339 +int omap_dss_get_num_overlays(void);
1340 +struct omap_overlay *omap_dss_get_overlay(int num);
1342 +typedef void (*omap_dispc_isr_t) (void *arg, u32 mask);
1343 +int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
1344 +int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
1346 +int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout);
1347 +int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
1348 + unsigned long timeout);
1350 +#define to_dss_driver(x) container_of((x), struct omap_dss_driver, driver)
1351 +#define to_dss_device(x) container_of((x), struct omap_dss_device, dev)
1354 diff --git a/arch/arm/plat-omap/include/mach/omapfb.h b/arch/arm/plat-omap/include/mach/omapfb.h
1355 deleted file mode 100644
1356 index b226bdf..0000000
1357 --- a/arch/arm/plat-omap/include/mach/omapfb.h
1361 - * File: arch/arm/plat-omap/include/mach/omapfb.h
1363 - * Framebuffer driver for TI OMAP boards
1365 - * Copyright (C) 2004 Nokia Corporation
1366 - * Author: Imre Deak <imre.deak@nokia.com>
1368 - * This program is free software; you can redistribute it and/or modify it
1369 - * under the terms of the GNU General Public License as published by the
1370 - * Free Software Foundation; either version 2 of the License, or (at your
1371 - * option) any later version.
1373 - * This program is distributed in the hope that it will be useful, but
1374 - * WITHOUT ANY WARRANTY; without even the implied warranty of
1375 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1376 - * General Public License for more details.
1378 - * You should have received a copy of the GNU General Public License along
1379 - * with this program; if not, write to the Free Software Foundation, Inc.,
1380 - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1386 -#include <asm/ioctl.h>
1387 -#include <asm/types.h>
1389 -/* IOCTL commands. */
1391 -#define OMAP_IOW(num, dtype) _IOW('O', num, dtype)
1392 -#define OMAP_IOR(num, dtype) _IOR('O', num, dtype)
1393 -#define OMAP_IOWR(num, dtype) _IOWR('O', num, dtype)
1394 -#define OMAP_IO(num) _IO('O', num)
1396 -#define OMAPFB_MIRROR OMAP_IOW(31, int)
1397 -#define OMAPFB_SYNC_GFX OMAP_IO(37)
1398 -#define OMAPFB_VSYNC OMAP_IO(38)
1399 -#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int)
1400 -#define OMAPFB_GET_CAPS OMAP_IOR(42, struct omapfb_caps)
1401 -#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int)
1402 -#define OMAPFB_LCD_TEST OMAP_IOW(45, int)
1403 -#define OMAPFB_CTRL_TEST OMAP_IOW(46, int)
1404 -#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(47, struct omapfb_update_window_old)
1405 -#define OMAPFB_SET_COLOR_KEY OMAP_IOW(50, struct omapfb_color_key)
1406 -#define OMAPFB_GET_COLOR_KEY OMAP_IOW(51, struct omapfb_color_key)
1407 -#define OMAPFB_SETUP_PLANE OMAP_IOW(52, struct omapfb_plane_info)
1408 -#define OMAPFB_QUERY_PLANE OMAP_IOW(53, struct omapfb_plane_info)
1409 -#define OMAPFB_UPDATE_WINDOW OMAP_IOW(54, struct omapfb_update_window)
1410 -#define OMAPFB_SETUP_MEM OMAP_IOW(55, struct omapfb_mem_info)
1411 -#define OMAPFB_QUERY_MEM OMAP_IOW(56, struct omapfb_mem_info)
1413 -#define OMAPFB_CAPS_GENERIC_MASK 0x00000fff
1414 -#define OMAPFB_CAPS_LCDC_MASK 0x00fff000
1415 -#define OMAPFB_CAPS_PANEL_MASK 0xff000000
1417 -#define OMAPFB_CAPS_MANUAL_UPDATE 0x00001000
1418 -#define OMAPFB_CAPS_TEARSYNC 0x00002000
1419 -#define OMAPFB_CAPS_PLANE_RELOCATE_MEM 0x00004000
1420 -#define OMAPFB_CAPS_PLANE_SCALE 0x00008000
1421 -#define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE 0x00010000
1422 -#define OMAPFB_CAPS_WINDOW_SCALE 0x00020000
1423 -#define OMAPFB_CAPS_WINDOW_OVERLAY 0x00040000
1424 -#define OMAPFB_CAPS_WINDOW_ROTATE 0x00080000
1425 -#define OMAPFB_CAPS_SET_BACKLIGHT 0x01000000
1427 -/* Values from DSP must map to lower 16-bits */
1428 -#define OMAPFB_FORMAT_MASK 0x00ff
1429 -#define OMAPFB_FORMAT_FLAG_DOUBLE 0x0100
1430 -#define OMAPFB_FORMAT_FLAG_TEARSYNC 0x0200
1431 -#define OMAPFB_FORMAT_FLAG_FORCE_VSYNC 0x0400
1432 -#define OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY 0x0800
1433 -#define OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY 0x1000
1435 -#define OMAPFB_EVENT_READY 1
1436 -#define OMAPFB_EVENT_DISABLED 2
1438 -#define OMAPFB_MEMTYPE_SDRAM 0
1439 -#define OMAPFB_MEMTYPE_SRAM 1
1440 -#define OMAPFB_MEMTYPE_MAX 1
1442 -enum omapfb_color_format {
1443 - OMAPFB_COLOR_RGB565 = 0,
1444 - OMAPFB_COLOR_YUV422,
1445 - OMAPFB_COLOR_YUV420,
1446 - OMAPFB_COLOR_CLUT_8BPP,
1447 - OMAPFB_COLOR_CLUT_4BPP,
1448 - OMAPFB_COLOR_CLUT_2BPP,
1449 - OMAPFB_COLOR_CLUT_1BPP,
1450 - OMAPFB_COLOR_RGB444,
1451 - OMAPFB_COLOR_YUY422,
1454 -struct omapfb_update_window {
1456 - __u32 width, height;
1458 - __u32 out_x, out_y;
1459 - __u32 out_width, out_height;
1460 - __u32 reserved[8];
1463 -struct omapfb_update_window_old {
1465 - __u32 width, height;
1469 -enum omapfb_plane {
1470 - OMAPFB_PLANE_GFX = 0,
1471 - OMAPFB_PLANE_VID1,
1472 - OMAPFB_PLANE_VID2,
1475 -enum omapfb_channel_out {
1476 - OMAPFB_CHANNEL_OUT_LCD = 0,
1477 - OMAPFB_CHANNEL_OUT_DIGIT,
1480 -struct omapfb_plane_info {
1489 - __u32 reserved2[12];
1492 -struct omapfb_mem_info {
1498 -struct omapfb_caps {
1500 - __u32 plane_color;
1504 -enum omapfb_color_key_type {
1505 - OMAPFB_COLOR_KEY_DISABLED = 0,
1506 - OMAPFB_COLOR_KEY_GFX_DST,
1507 - OMAPFB_COLOR_KEY_VID_SRC,
1510 -struct omapfb_color_key {
1517 -enum omapfb_update_mode {
1518 - OMAPFB_UPDATE_DISABLED = 0,
1519 - OMAPFB_AUTO_UPDATE,
1520 - OMAPFB_MANUAL_UPDATE
1525 -#include <linux/completion.h>
1526 -#include <linux/interrupt.h>
1527 -#include <linux/fb.h>
1528 -#include <linux/mutex.h>
1530 -#include <mach/board.h>
1532 -#define OMAP_LCDC_INV_VSYNC 0x0001
1533 -#define OMAP_LCDC_INV_HSYNC 0x0002
1534 -#define OMAP_LCDC_INV_PIX_CLOCK 0x0004
1535 -#define OMAP_LCDC_INV_OUTPUT_EN 0x0008
1536 -#define OMAP_LCDC_HSVS_RISING_EDGE 0x0010
1537 -#define OMAP_LCDC_HSVS_OPPOSITE 0x0020
1539 -#define OMAP_LCDC_SIGNAL_MASK 0x003f
1541 -#define OMAP_LCDC_PANEL_TFT 0x0100
1543 -#define OMAPFB_PLANE_XRES_MIN 8
1544 -#define OMAPFB_PLANE_YRES_MIN 8
1546 -#ifdef CONFIG_ARCH_OMAP1
1547 -#define OMAPFB_PLANE_NUM 1
1549 -#define OMAPFB_PLANE_NUM 3
1552 -struct omapfb_device;
1556 - int config; /* TFT/STN, signal inversion */
1557 - int bpp; /* Pixel format in fb mem */
1558 - int data_lines; /* Lines on LCD HW interface */
1561 - int pixel_clock; /* In kHz */
1562 - int hsw; /* Horizontal synchronization
1564 - int hfp; /* Horizontal front porch */
1565 - int hbp; /* Horizontal back porch */
1566 - int vsw; /* Vertical synchronization
1568 - int vfp; /* Vertical front porch */
1569 - int vbp; /* Vertical back porch */
1570 - int acb; /* ac-bias pin frequency */
1571 - int pcd; /* pixel clock divider.
1572 - Obsolete use pixel_clock instead */
1574 - int (*init) (struct lcd_panel *panel,
1575 - struct omapfb_device *fbdev);
1576 - void (*cleanup) (struct lcd_panel *panel);
1577 - int (*enable) (struct lcd_panel *panel);
1578 - void (*disable) (struct lcd_panel *panel);
1579 - unsigned long (*get_caps) (struct lcd_panel *panel);
1580 - int (*set_bklight_level)(struct lcd_panel *panel,
1581 - unsigned int level);
1582 - unsigned int (*get_bklight_level)(struct lcd_panel *panel);
1583 - unsigned int (*get_bklight_max) (struct lcd_panel *panel);
1584 - int (*run_test) (struct lcd_panel *panel, int test_num);
1587 -struct extif_timings {
1594 - int we_cycle_time;
1595 - int re_cycle_time;
1596 - int cs_pulse_width;
1601 - u32 tim[5]; /* set by extif->convert_timings */
1606 -struct lcd_ctrl_extif {
1607 - int (*init) (struct omapfb_device *fbdev);
1608 - void (*cleanup) (void);
1609 - void (*get_clk_info) (u32 *clk_period, u32 *max_clk_div);
1610 - unsigned long (*get_max_tx_rate)(void);
1611 - int (*convert_timings) (struct extif_timings *timings);
1612 - void (*set_timings) (const struct extif_timings *timings);
1613 - void (*set_bits_per_cycle)(int bpc);
1614 - void (*write_command) (const void *buf, unsigned int len);
1615 - void (*read_data) (void *buf, unsigned int len);
1616 - void (*write_data) (const void *buf, unsigned int len);
1617 - void (*transfer_area) (int width, int height,
1618 - void (callback)(void * data), void *data);
1619 - int (*setup_tearsync) (unsigned pin_cnt,
1620 - unsigned hs_pulse_time, unsigned vs_pulse_time,
1621 - int hs_pol_inv, int vs_pol_inv, int div);
1622 - int (*enable_tearsync) (int enable, unsigned line);
1624 - unsigned long max_transmit_size;
1627 -struct omapfb_notifier_block {
1628 - struct notifier_block nb;
1633 -typedef int (*omapfb_notifier_callback_t)(struct notifier_block *,
1634 - unsigned long event,
1637 -struct omapfb_mem_region {
1639 - void __iomem *vaddr;
1640 - unsigned long size;
1641 - u8 type; /* OMAPFB_PLANE_MEM_* */
1642 - unsigned alloc:1; /* allocated by the driver */
1643 - unsigned map:1; /* kernel mapped by the driver */
1646 -struct omapfb_mem_desc {
1648 - struct omapfb_mem_region region[OMAPFB_PLANE_NUM];
1655 - int (*init) (struct omapfb_device *fbdev,
1657 - struct omapfb_mem_desc *req_md);
1658 - void (*cleanup) (void);
1659 - void (*bind_client) (struct omapfb_notifier_block *nb);
1660 - void (*get_caps) (int plane, struct omapfb_caps *caps);
1661 - int (*set_update_mode)(enum omapfb_update_mode mode);
1662 - enum omapfb_update_mode (*get_update_mode)(void);
1663 - int (*setup_plane) (int plane, int channel_out,
1664 - unsigned long offset,
1666 - int pos_x, int pos_y, int width,
1667 - int height, int color_mode);
1668 - int (*set_rotate) (int angle);
1669 - int (*setup_mem) (int plane, size_t size,
1670 - int mem_type, unsigned long *paddr);
1671 - int (*mmap) (struct fb_info *info,
1672 - struct vm_area_struct *vma);
1673 - int (*set_scale) (int plane,
1674 - int orig_width, int orig_height,
1675 - int out_width, int out_height);
1676 - int (*enable_plane) (int plane, int enable);
1677 - int (*update_window) (struct fb_info *fbi,
1678 - struct omapfb_update_window *win,
1679 - void (*callback)(void *),
1680 - void *callback_data);
1681 - void (*sync) (void);
1682 - void (*suspend) (void);
1683 - void (*resume) (void);
1684 - int (*run_test) (int test_num);
1685 - int (*setcolreg) (u_int regno, u16 red, u16 green,
1686 - u16 blue, u16 transp,
1687 - int update_hw_mem);
1688 - int (*set_color_key) (struct omapfb_color_key *ck);
1689 - int (*get_color_key) (struct omapfb_color_key *ck);
1692 -enum omapfb_state {
1693 - OMAPFB_DISABLED = 0,
1694 - OMAPFB_SUSPENDED= 99,
1695 - OMAPFB_ACTIVE = 100
1698 -struct omapfb_plane_struct {
1700 - struct omapfb_plane_info info;
1701 - enum omapfb_color_format color_mode;
1702 - struct omapfb_device *fbdev;
1705 -struct omapfb_device {
1707 - int ext_lcdc; /* Using external
1709 - struct mutex rqueue_mutex;
1712 - u32 pseudo_palette[17];
1714 - struct lcd_panel *panel; /* LCD panel */
1715 - const struct lcd_ctrl *ctrl; /* LCD controller */
1716 - const struct lcd_ctrl *int_ctrl; /* internal LCD ctrl */
1717 - struct lcd_ctrl_extif *ext_if; /* LCD ctrl external
1719 - struct device *dev;
1720 - struct fb_var_screeninfo new_var; /* for mode changes */
1722 - struct omapfb_mem_desc mem_desc;
1723 - struct fb_info *fb_info[OMAPFB_PLANE_NUM];
1726 -struct omapfb_platform_data {
1727 - struct omap_lcd_config lcd;
1728 - struct omapfb_mem_desc mem_desc;
1729 - void *ctrl_platform_data;
1732 -#ifdef CONFIG_ARCH_OMAP1
1733 -extern struct lcd_ctrl omap1_lcd_ctrl;
1735 -extern struct lcd_ctrl omap2_disp_ctrl;
1738 -extern void omapfb_reserve_sdram(void);
1739 -extern void omapfb_register_panel(struct lcd_panel *panel);
1740 -extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
1741 -extern void omapfb_notify_clients(struct omapfb_device *fbdev,
1742 - unsigned long event);
1743 -extern int omapfb_register_client(struct omapfb_notifier_block *nb,
1744 - omapfb_notifier_callback_t callback,
1745 - void *callback_data);
1746 -extern int omapfb_unregister_client(struct omapfb_notifier_block *nb);
1747 -extern int omapfb_update_window_async(struct fb_info *fbi,
1748 - struct omapfb_update_window *win,
1749 - void (*callback)(void *),
1750 - void *callback_data);
1752 -/* in arch/arm/plat-omap/fb.c */
1753 -extern void omapfb_set_ctrl_platform_data(void *pdata);
1755 -#endif /* __KERNEL__ */
1757 -#endif /* __OMAPFB_H */
1758 diff --git a/arch/arm/plat-omap/include/mach/sdrc.h b/arch/arm/plat-omap/include/mach/sdrc.h
1759 index 1c09c78..3b157ce 100644
1760 --- a/arch/arm/plat-omap/include/mach/sdrc.h
1761 +++ b/arch/arm/plat-omap/include/mach/sdrc.h
1764 /* SMS register offsets - read/write with sms_{read,write}_reg() */
1766 -#define SMS_SYSCONFIG 0x010
1767 +#define SMS_SYSCONFIG 0x010
1768 +#define SMS_ROT_CONTROL(context) (0x180 + 0x10 * context)
1769 +#define SMS_ROT_SIZE(context) (0x184 + 0x10 * context)
1770 +#define SMS_ROT_PHYSICAL_BA(context) (0x188 + 0x10 * context)
1771 /* REVISIT: fill in other SMS registers here */
1774 @@ -121,6 +124,10 @@ int omap2_sdrc_get_params(unsigned long r,
1775 struct omap_sdrc_params **sdrc_cs0,
1776 struct omap_sdrc_params **sdrc_cs1);
1778 +void omap2_sms_write_rot_control(u32 val, unsigned ctx);
1779 +void omap2_sms_write_rot_size(u32 val, unsigned ctx);
1780 +void omap2_sms_write_rot_physical_ba(u32 val, unsigned ctx);
1782 #ifdef CONFIG_ARCH_OMAP2
1784 struct memory_timings {
1785 diff --git a/arch/arm/plat-omap/include/mach/vram.h b/arch/arm/plat-omap/include/mach/vram.h
1786 new file mode 100644
1787 index 0000000..fe72f81
1789 +++ b/arch/arm/plat-omap/include/mach/vram.h
1792 + * VRAM manager for OMAP
1794 + * Copyright (C) 2009 Nokia Corporation
1795 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
1797 + * This program is free software; you can redistribute it and/or modify
1798 + * it under the terms of the GNU General Public License version 2 as
1799 + * published by the Free Software Foundation.
1801 + * This program is distributed in the hope that it will be useful, but
1802 + * WITHOUT ANY WARRANTY; without even the implied warranty of
1803 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1804 + * General Public License for more details.
1806 + * You should have received a copy of the GNU General Public License along
1807 + * with this program; if not, write to the Free Software Foundation, Inc.,
1808 + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1811 +#ifndef __OMAP_VRAM_H__
1812 +#define __OMAP_VRAM_H__
1814 +#include <linux/autoconf.h>
1815 +#include <linux/types.h>
1817 +#define OMAP_VRAM_MEMTYPE_SDRAM 0
1818 +#define OMAP_VRAM_MEMTYPE_SRAM 1
1819 +#define OMAP_VRAM_MEMTYPE_MAX 1
1821 +extern int omap_vram_add_region(unsigned long paddr, size_t size);
1822 +extern int omap_vram_free(unsigned long paddr, size_t size);
1823 +extern int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr);
1824 +extern int omap_vram_reserve(unsigned long paddr, size_t size);
1825 +extern void omap_vram_get_info(unsigned long *vram, unsigned long *free_vram,
1826 + unsigned long *largest_free_block);
1828 +#ifdef CONFIG_OMAP2_VRAM
1829 +extern void omap_vram_set_sdram_vram(u32 size, u32 start);
1830 +extern void omap_vram_set_sram_vram(u32 size, u32 start);
1832 +extern void omap_vram_reserve_sdram(void);
1833 +extern unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
1834 + unsigned long sram_vstart,
1835 + unsigned long sram_size,
1836 + unsigned long pstart_avail,
1837 + unsigned long size_avail);
1839 +static inline void omap_vram_set_sdram_vram(u32 size, u32 start) { }
1840 +static inline void omap_vram_set_sram_vram(u32 size, u32 start) { }
1842 +static inline void omap_vram_reserve_sdram(void) { }
1843 +static inline unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
1844 + unsigned long sram_vstart,
1845 + unsigned long sram_size,
1846 + unsigned long pstart_avail,
1847 + unsigned long size_avail)
1854 diff --git a/arch/arm/plat-omap/include/mach/vrfb.h b/arch/arm/plat-omap/include/mach/vrfb.h
1855 new file mode 100644
1856 index 0000000..8790612
1858 +++ b/arch/arm/plat-omap/include/mach/vrfb.h
1861 + * VRFB Rotation Engine
1863 + * Copyright (C) 2009 Nokia Corporation
1864 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
1866 + * This program is free software; you can redistribute it and/or modify
1867 + * it under the terms of the GNU General Public License version 2 as
1868 + * published by the Free Software Foundation.
1870 + * This program is distributed in the hope that it will be useful, but
1871 + * WITHOUT ANY WARRANTY; without even the implied warranty of
1872 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1873 + * General Public License for more details.
1875 + * You should have received a copy of the GNU General Public License along
1876 + * with this program; if not, write to the Free Software Foundation, Inc.,
1877 + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1880 +#ifndef __OMAP_VRFB_H__
1881 +#define __OMAP_VRFB_H__
1883 +#define OMAP_VRFB_LINE_LEN 2048
1887 + void __iomem *vaddr[4];
1888 + unsigned long paddr[4];
1894 +extern int omap_vrfb_request_ctx(struct vrfb *vrfb);
1895 +extern void omap_vrfb_release_ctx(struct vrfb *vrfb);
1896 +extern void omap_vrfb_suspend_ctx(struct vrfb *vrfb);
1897 +extern void omap_vrfb_resume_ctx(struct vrfb *vrfb);
1898 +extern void omap_vrfb_adjust_size(u16 *width, u16 *height,
1900 +extern void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
1901 + u16 width, u16 height,
1902 + unsigned bytespp, bool yuv_mode);
1903 +extern void omap_vrfb_restore_context(void);
1905 +#endif /* __VRFB_H */
1906 diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
1907 index 75d1f26..aa9fb63 100644
1908 --- a/arch/arm/plat-omap/sram.c
1909 +++ b/arch/arm/plat-omap/sram.c
1911 #include <mach/sram.h>
1912 #include <mach/board.h>
1913 #include <mach/cpu.h>
1914 +#include <mach/vram.h>
1916 #include <mach/control.h>
1918 @@ -185,6 +186,13 @@ void __init omap_detect_sram(void)
1919 omap_sram_start + SRAM_BOOTLOADER_SZ,
1920 omap_sram_size - SRAM_BOOTLOADER_SZ);
1921 omap_sram_size -= reserved;
1923 + reserved = omap_vram_reserve_sram(omap_sram_start, omap_sram_base,
1925 + omap_sram_start + SRAM_BOOTLOADER_SZ,
1926 + omap_sram_size - SRAM_BOOTLOADER_SZ);
1927 + omap_sram_size -= reserved;
1929 omap_sram_ceil = omap_sram_base + omap_sram_size;
1932 diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
1933 index 9bbb285..af0448f 100644
1934 --- a/drivers/video/Kconfig
1935 +++ b/drivers/video/Kconfig
1936 @@ -2161,6 +2161,7 @@ config FB_BROADSHEET
1939 source "drivers/video/omap/Kconfig"
1940 +source "drivers/video/omap2/Kconfig"
1942 source "drivers/video/backlight/Kconfig"
1943 source "drivers/video/display/Kconfig"
1944 diff --git a/drivers/video/Makefile b/drivers/video/Makefile
1945 index 80232e1..0f8da33 100644
1946 --- a/drivers/video/Makefile
1947 +++ b/drivers/video/Makefile
1948 @@ -124,6 +124,7 @@ obj-$(CONFIG_FB_SM501) += sm501fb.o
1949 obj-$(CONFIG_FB_XILINX) += xilinxfb.o
1950 obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
1951 obj-$(CONFIG_FB_OMAP) += omap/
1953 obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
1954 obj-$(CONFIG_FB_CARMINE) += carminefb.o
1955 obj-$(CONFIG_FB_MB862XX) += mb862xx/
1956 diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
1957 index 551e3e9..455c605 100644
1958 --- a/drivers/video/omap/Kconfig
1959 +++ b/drivers/video/omap/Kconfig
1962 tristate "OMAP frame buffer support (EXPERIMENTAL)"
1963 - depends on FB && ARCH_OMAP
1964 + depends on FB && ARCH_OMAP && (OMAP2_DSS = "n")
1966 select FB_CFB_FILLRECT
1967 select FB_CFB_COPYAREA
1968 select FB_CFB_IMAGEBLIT
1969 @@ -72,7 +73,7 @@ config FB_OMAP_LCD_MIPID
1971 config FB_OMAP_BOOTLOADER_INIT
1972 bool "Check bootloader initialization"
1973 - depends on FB_OMAP
1974 + depends on FB_OMAP || FB_OMAP2
1976 Say Y here if you want to enable checking if the bootloader has
1977 already initialized the display controller. In this case the
1978 diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c
1979 index 70dadf9..e0d693e 100644
1980 --- a/drivers/video/omap/blizzard.c
1981 +++ b/drivers/video/omap/blizzard.c
1983 #include <linux/clk.h>
1985 #include <mach/dma.h>
1986 -#include <mach/omapfb.h>
1987 #include <mach/blizzard.h>
1989 +#include "omapfb.h"
1992 #define MODULE_NAME "blizzard"
1993 diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c
1994 index f16e421..3f828e6 100644
1995 --- a/drivers/video/omap/dispc.c
1996 +++ b/drivers/video/omap/dispc.c
1998 #include <linux/vmalloc.h>
1999 #include <linux/clk.h>
2000 #include <linux/io.h>
2001 +#include <linux/platform_device.h>
2003 #include <mach/sram.h>
2004 -#include <mach/omapfb.h>
2005 #include <mach/board.h>
2007 +#include "omapfb.h"
2010 #define MODULE_NAME "dispc"
2011 @@ -188,6 +189,11 @@ static struct {
2012 struct omapfb_color_key color_key;
2015 +static struct platform_device omapdss_device = {
2016 + .name = "omapdss",
2020 static void enable_lcd_clocks(int enable);
2022 static void inline dispc_write_reg(int idx, u32 val)
2023 @@ -907,20 +913,20 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
2025 static int get_dss_clocks(void)
2027 - dispc.dss_ick = clk_get(dispc.fbdev->dev, "ick");
2028 + dispc.dss_ick = clk_get(&omapdss_device.dev, "ick");
2029 if (IS_ERR(dispc.dss_ick)) {
2030 dev_err(dispc.fbdev->dev, "can't get ick\n");
2031 return PTR_ERR(dispc.dss_ick);
2034 - dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck");
2035 + dispc.dss1_fck = clk_get(&omapdss_device.dev, "dss1_fck");
2036 if (IS_ERR(dispc.dss1_fck)) {
2037 dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
2038 clk_put(dispc.dss_ick);
2039 return PTR_ERR(dispc.dss1_fck);
2042 - dispc.dss_54m_fck = clk_get(dispc.fbdev->dev, "tv_fck");
2043 + dispc.dss_54m_fck = clk_get(&omapdss_device.dev, "tv_fck");
2044 if (IS_ERR(dispc.dss_54m_fck)) {
2045 dev_err(dispc.fbdev->dev, "can't get tv_fck\n");
2046 clk_put(dispc.dss_ick);
2047 @@ -1371,6 +1377,12 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
2051 + r = platform_device_register(&omapdss_device);
2053 + dev_err(fbdev->dev, "can't register omapdss device\n");
2057 memset(&dispc, 0, sizeof(dispc));
2059 dispc.base = ioremap(DISPC_BASE, SZ_1K);
2060 @@ -1508,6 +1520,7 @@ static void omap_dispc_cleanup(void)
2061 free_irq(INT_24XX_DSS_IRQ, dispc.fbdev);
2063 iounmap(dispc.base);
2064 + platform_device_unregister(&omapdss_device);
2067 const struct lcd_ctrl omap2_int_ctrl = {
2068 diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c
2069 index ca51583..b84fb7c 100644
2070 --- a/drivers/video/omap/hwa742.c
2071 +++ b/drivers/video/omap/hwa742.c
2073 #include <linux/clk.h>
2075 #include <mach/dma.h>
2076 -#include <mach/omapfb.h>
2077 #include <mach/hwa742.h>
2078 +#include "omapfb.h"
2080 #define HWA742_REV_CODE_REG 0x0
2081 #define HWA742_CONFIG_REG 0x2
2082 diff --git a/drivers/video/omap/lcd_2430sdp.c b/drivers/video/omap/lcd_2430sdp.c
2083 index 393712b..7b7690a 100644
2084 --- a/drivers/video/omap/lcd_2430sdp.c
2085 +++ b/drivers/video/omap/lcd_2430sdp.c
2087 #include <linux/i2c/twl4030.h>
2089 #include <mach/mux.h>
2090 -#include <mach/omapfb.h>
2091 #include <asm/mach-types.h>
2093 +#include "omapfb.h"
2095 #define SDP2430_LCD_PANEL_BACKLIGHT_GPIO 91
2096 #define SDP2430_LCD_PANEL_ENABLE_GPIO 154
2097 #define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 24
2098 diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c
2099 index 1f74399..1d3fd13 100644
2100 --- a/drivers/video/omap/lcd_ams_delta.c
2101 +++ b/drivers/video/omap/lcd_ams_delta.c
2104 #include <mach/board-ams-delta.h>
2105 #include <mach/hardware.h>
2106 -#include <mach/omapfb.h>
2108 +#include "omapfb.h"
2110 #define AMS_DELTA_DEFAULT_CONTRAST 112
2112 diff --git a/drivers/video/omap/lcd_apollon.c b/drivers/video/omap/lcd_apollon.c
2113 index 626ae3a..e099ad1 100644
2114 --- a/drivers/video/omap/lcd_apollon.c
2115 +++ b/drivers/video/omap/lcd_apollon.c
2118 #include <mach/gpio.h>
2119 #include <mach/mux.h>
2120 -#include <mach/omapfb.h>
2122 +#include "omapfb.h"
2124 /* #define USE_35INCH_LCD 1 */
2126 diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c
2127 index 417ae5e..8df6887 100644
2128 --- a/drivers/video/omap/lcd_h3.c
2129 +++ b/drivers/video/omap/lcd_h3.c
2131 #include <linux/i2c/tps65010.h>
2133 #include <mach/gpio.h>
2134 -#include <mach/omapfb.h>
2135 +#include "omapfb.h"
2137 #define MODULE_NAME "omapfb-lcd_h3"
2139 diff --git a/drivers/video/omap/lcd_h4.c b/drivers/video/omap/lcd_h4.c
2140 index 0c398bd..03a06a9 100644
2141 --- a/drivers/video/omap/lcd_h4.c
2142 +++ b/drivers/video/omap/lcd_h4.c
2144 #include <linux/module.h>
2145 #include <linux/platform_device.h>
2147 -#include <mach/omapfb.h>
2148 +#include "omapfb.h"
2150 static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
2152 diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c
2153 index cdbd8bb..18f1422 100644
2154 --- a/drivers/video/omap/lcd_inn1510.c
2155 +++ b/drivers/video/omap/lcd_inn1510.c
2157 #include <linux/io.h>
2159 #include <mach/fpga.h>
2160 -#include <mach/omapfb.h>
2161 +#include "omapfb.h"
2163 static int innovator1510_panel_init(struct lcd_panel *panel,
2164 struct omapfb_device *fbdev)
2165 diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c
2166 index 268f7f8..9fff86f 100644
2167 --- a/drivers/video/omap/lcd_inn1610.c
2168 +++ b/drivers/video/omap/lcd_inn1610.c
2170 #include <linux/platform_device.h>
2172 #include <mach/gpio.h>
2173 -#include <mach/omapfb.h>
2174 +#include "omapfb.h"
2176 #define MODULE_NAME "omapfb-lcd_h3"
2178 diff --git a/drivers/video/omap/lcd_ldp.c b/drivers/video/omap/lcd_ldp.c
2179 index dbfe897..44a43ea 100644
2180 --- a/drivers/video/omap/lcd_ldp.c
2181 +++ b/drivers/video/omap/lcd_ldp.c
2184 #include <mach/gpio.h>
2185 #include <mach/mux.h>
2186 -#include <mach/omapfb.h>
2187 #include <asm/mach-types.h>
2189 +#include "omapfb.h"
2191 #define LCD_PANEL_BACKLIGHT_GPIO (15 + OMAP_MAX_GPIO_LINES)
2192 #define LCD_PANEL_ENABLE_GPIO (7 + OMAP_MAX_GPIO_LINES)
2194 diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c
2195 index 918ee89..62e1975 100644
2196 --- a/drivers/video/omap/lcd_mipid.c
2197 +++ b/drivers/video/omap/lcd_mipid.c
2199 #include <linux/workqueue.h>
2200 #include <linux/spi/spi.h>
2202 -#include <mach/omapfb.h>
2203 #include <mach/lcd_mipid.h>
2205 +#include "omapfb.h"
2207 #define MIPID_MODULE_NAME "lcd_mipid"
2209 #define MIPID_CMD_READ_DISP_ID 0x04
2210 diff --git a/drivers/video/omap/lcd_omap2evm.c b/drivers/video/omap/lcd_omap2evm.c
2211 index 7a2bbe2..c3be87c 100644
2212 --- a/drivers/video/omap/lcd_omap2evm.c
2213 +++ b/drivers/video/omap/lcd_omap2evm.c
2215 #include <linux/i2c/twl4030.h>
2217 #include <mach/mux.h>
2218 -#include <mach/omapfb.h>
2219 #include <asm/mach-types.h>
2221 +#include "omapfb.h"
2223 #define LCD_PANEL_ENABLE_GPIO 154
2224 #define LCD_PANEL_LR 128
2225 #define LCD_PANEL_UD 129
2226 diff --git a/drivers/video/omap/lcd_omap3beagle.c b/drivers/video/omap/lcd_omap3beagle.c
2227 index 4011910..0608a25 100644
2228 --- a/drivers/video/omap/lcd_omap3beagle.c
2229 +++ b/drivers/video/omap/lcd_omap3beagle.c
2231 #include <linux/i2c/twl4030.h>
2233 #include <mach/mux.h>
2234 -#include <mach/omapfb.h>
2235 #include <asm/mach-types.h>
2237 +#include "omapfb.h"
2239 #define LCD_PANEL_ENABLE_GPIO 170
2241 static int omap3beagle_panel_init(struct lcd_panel *panel,
2242 diff --git a/drivers/video/omap/lcd_omap3evm.c b/drivers/video/omap/lcd_omap3evm.c
2243 index b6a4c2c..c204afb 100644
2244 --- a/drivers/video/omap/lcd_omap3evm.c
2245 +++ b/drivers/video/omap/lcd_omap3evm.c
2247 #include <linux/i2c/twl4030.h>
2249 #include <mach/mux.h>
2250 -#include <mach/omapfb.h>
2251 #include <asm/mach-types.h>
2253 +#include "omapfb.h"
2255 #define LCD_PANEL_ENABLE_GPIO 153
2256 #define LCD_PANEL_LR 2
2257 #define LCD_PANEL_UD 3
2258 diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c
2259 index b3fa88b..5755b5c 100644
2260 --- a/drivers/video/omap/lcd_osk.c
2261 +++ b/drivers/video/omap/lcd_osk.c
2264 #include <mach/gpio.h>
2265 #include <mach/mux.h>
2266 -#include <mach/omapfb.h>
2267 +#include "omapfb.h"
2269 static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
2271 diff --git a/drivers/video/omap/lcd_overo.c b/drivers/video/omap/lcd_overo.c
2272 index 2bc5c92..63ebb1f 100644
2273 --- a/drivers/video/omap/lcd_overo.c
2274 +++ b/drivers/video/omap/lcd_overo.c
2277 #include <mach/gpio.h>
2278 #include <mach/mux.h>
2279 -#include <mach/omapfb.h>
2280 #include <asm/mach-types.h>
2282 +#include "omapfb.h"
2284 #define LCD_ENABLE 144
2286 static int overo_panel_init(struct lcd_panel *panel,
2287 diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c
2288 index 4bf3c79..7e11a75 100644
2289 --- a/drivers/video/omap/lcd_palmte.c
2290 +++ b/drivers/video/omap/lcd_palmte.c
2292 #include <linux/io.h>
2294 #include <mach/fpga.h>
2295 -#include <mach/omapfb.h>
2296 +#include "omapfb.h"
2298 static int palmte_panel_init(struct lcd_panel *panel,
2299 struct omapfb_device *fbdev)
2300 diff --git a/drivers/video/omap/lcd_palmtt.c b/drivers/video/omap/lcd_palmtt.c
2301 index 48ea1f9..ff0e6d7 100644
2302 --- a/drivers/video/omap/lcd_palmtt.c
2303 +++ b/drivers/video/omap/lcd_palmtt.c
2304 @@ -30,7 +30,7 @@ GPIO13 - screen blanking
2305 #include <linux/io.h>
2307 #include <mach/gpio.h>
2308 -#include <mach/omapfb.h>
2309 +#include "omapfb.h"
2311 static int palmtt_panel_init(struct lcd_panel *panel,
2312 struct omapfb_device *fbdev)
2313 diff --git a/drivers/video/omap/lcd_palmz71.c b/drivers/video/omap/lcd_palmz71.c
2314 index 0697d29..2334e56 100644
2315 --- a/drivers/video/omap/lcd_palmz71.c
2316 +++ b/drivers/video/omap/lcd_palmz71.c
2318 #include <linux/platform_device.h>
2319 #include <linux/io.h>
2321 -#include <mach/omapfb.h>
2322 +#include "omapfb.h"
2324 static int palmz71_panel_init(struct lcd_panel *panel,
2325 struct omapfb_device *fbdev)
2326 diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c
2327 index ab39492..520ed97 100644
2328 --- a/drivers/video/omap/lcdc.c
2329 +++ b/drivers/video/omap/lcdc.c
2331 #include <linux/clk.h>
2333 #include <mach/dma.h>
2334 -#include <mach/omapfb.h>
2336 #include <asm/mach-types.h>
2338 +#include "omapfb.h"
2342 #define MODULE_NAME "lcdc"
2343 diff --git a/drivers/video/omap/omapfb.h b/drivers/video/omap/omapfb.h
2344 new file mode 100644
2345 index 0000000..46e4714
2347 +++ b/drivers/video/omap/omapfb.h
2350 + * File: drivers/video/omap/omapfb.h
2352 + * Framebuffer driver for TI OMAP boards
2354 + * Copyright (C) 2004 Nokia Corporation
2355 + * Author: Imre Deak <imre.deak@nokia.com>
2357 + * This program is free software; you can redistribute it and/or modify it
2358 + * under the terms of the GNU General Public License as published by the
2359 + * Free Software Foundation; either version 2 of the License, or (at your
2360 + * option) any later version.
2362 + * This program is distributed in the hope that it will be useful, but
2363 + * WITHOUT ANY WARRANTY; without even the implied warranty of
2364 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2365 + * General Public License for more details.
2367 + * You should have received a copy of the GNU General Public License along
2368 + * with this program; if not, write to the Free Software Foundation, Inc.,
2369 + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2375 +#include <linux/fb.h>
2376 +#include <linux/mutex.h>
2377 +#include <linux/omapfb.h>
2379 +#define OMAPFB_EVENT_READY 1
2380 +#define OMAPFB_EVENT_DISABLED 2
2382 +#define OMAP_LCDC_INV_VSYNC 0x0001
2383 +#define OMAP_LCDC_INV_HSYNC 0x0002
2384 +#define OMAP_LCDC_INV_PIX_CLOCK 0x0004
2385 +#define OMAP_LCDC_INV_OUTPUT_EN 0x0008
2386 +#define OMAP_LCDC_HSVS_RISING_EDGE 0x0010
2387 +#define OMAP_LCDC_HSVS_OPPOSITE 0x0020
2389 +#define OMAP_LCDC_SIGNAL_MASK 0x003f
2391 +#define OMAP_LCDC_PANEL_TFT 0x0100
2393 +#define OMAPFB_PLANE_XRES_MIN 8
2394 +#define OMAPFB_PLANE_YRES_MIN 8
2396 +struct omapfb_device;
2400 + int config; /* TFT/STN, signal inversion */
2401 + int bpp; /* Pixel format in fb mem */
2402 + int data_lines; /* Lines on LCD HW interface */
2405 + int pixel_clock; /* In kHz */
2406 + int hsw; /* Horizontal synchronization
2408 + int hfp; /* Horizontal front porch */
2409 + int hbp; /* Horizontal back porch */
2410 + int vsw; /* Vertical synchronization
2412 + int vfp; /* Vertical front porch */
2413 + int vbp; /* Vertical back porch */
2414 + int acb; /* ac-bias pin frequency */
2415 + int pcd; /* pixel clock divider.
2416 + Obsolete use pixel_clock instead */
2418 + int (*init) (struct lcd_panel *panel,
2419 + struct omapfb_device *fbdev);
2420 + void (*cleanup) (struct lcd_panel *panel);
2421 + int (*enable) (struct lcd_panel *panel);
2422 + void (*disable) (struct lcd_panel *panel);
2423 + unsigned long (*get_caps) (struct lcd_panel *panel);
2424 + int (*set_bklight_level)(struct lcd_panel *panel,
2425 + unsigned int level);
2426 + unsigned int (*get_bklight_level)(struct lcd_panel *panel);
2427 + unsigned int (*get_bklight_max) (struct lcd_panel *panel);
2428 + int (*run_test) (struct lcd_panel *panel, int test_num);
2431 +struct extif_timings {
2438 + int we_cycle_time;
2439 + int re_cycle_time;
2440 + int cs_pulse_width;
2445 + u32 tim[5]; /* set by extif->convert_timings */
2450 +struct lcd_ctrl_extif {
2451 + int (*init) (struct omapfb_device *fbdev);
2452 + void (*cleanup) (void);
2453 + void (*get_clk_info) (u32 *clk_period, u32 *max_clk_div);
2454 + unsigned long (*get_max_tx_rate)(void);
2455 + int (*convert_timings) (struct extif_timings *timings);
2456 + void (*set_timings) (const struct extif_timings *timings);
2457 + void (*set_bits_per_cycle)(int bpc);
2458 + void (*write_command) (const void *buf, unsigned int len);
2459 + void (*read_data) (void *buf, unsigned int len);
2460 + void (*write_data) (const void *buf, unsigned int len);
2461 + void (*transfer_area) (int width, int height,
2462 + void (callback)(void *data), void *data);
2463 + int (*setup_tearsync) (unsigned pin_cnt,
2464 + unsigned hs_pulse_time, unsigned vs_pulse_time,
2465 + int hs_pol_inv, int vs_pol_inv, int div);
2466 + int (*enable_tearsync) (int enable, unsigned line);
2468 + unsigned long max_transmit_size;
2471 +struct omapfb_notifier_block {
2472 + struct notifier_block nb;
2477 +typedef int (*omapfb_notifier_callback_t)(struct notifier_block *,
2478 + unsigned long event,
2485 + int (*init) (struct omapfb_device *fbdev,
2487 + struct omapfb_mem_desc *req_md);
2488 + void (*cleanup) (void);
2489 + void (*bind_client) (struct omapfb_notifier_block *nb);
2490 + void (*get_caps) (int plane, struct omapfb_caps *caps);
2491 + int (*set_update_mode)(enum omapfb_update_mode mode);
2492 + enum omapfb_update_mode (*get_update_mode)(void);
2493 + int (*setup_plane) (int plane, int channel_out,
2494 + unsigned long offset,
2496 + int pos_x, int pos_y, int width,
2497 + int height, int color_mode);
2498 + int (*set_rotate) (int angle);
2499 + int (*setup_mem) (int plane, size_t size,
2500 + int mem_type, unsigned long *paddr);
2501 + int (*mmap) (struct fb_info *info,
2502 + struct vm_area_struct *vma);
2503 + int (*set_scale) (int plane,
2504 + int orig_width, int orig_height,
2505 + int out_width, int out_height);
2506 + int (*enable_plane) (int plane, int enable);
2507 + int (*update_window) (struct fb_info *fbi,
2508 + struct omapfb_update_window *win,
2509 + void (*callback)(void *),
2510 + void *callback_data);
2511 + void (*sync) (void);
2512 + void (*suspend) (void);
2513 + void (*resume) (void);
2514 + int (*run_test) (int test_num);
2515 + int (*setcolreg) (u_int regno, u16 red, u16 green,
2516 + u16 blue, u16 transp,
2517 + int update_hw_mem);
2518 + int (*set_color_key) (struct omapfb_color_key *ck);
2519 + int (*get_color_key) (struct omapfb_color_key *ck);
2522 +enum omapfb_state {
2523 + OMAPFB_DISABLED = 0,
2524 + OMAPFB_SUSPENDED = 99,
2525 + OMAPFB_ACTIVE = 100
2528 +struct omapfb_plane_struct {
2530 + struct omapfb_plane_info info;
2531 + enum omapfb_color_format color_mode;
2532 + struct omapfb_device *fbdev;
2535 +struct omapfb_device {
2537 + int ext_lcdc; /* Using external
2539 + struct mutex rqueue_mutex;
2542 + u32 pseudo_palette[17];
2544 + struct lcd_panel *panel; /* LCD panel */
2545 + const struct lcd_ctrl *ctrl; /* LCD controller */
2546 + const struct lcd_ctrl *int_ctrl; /* internal LCD ctrl */
2547 + struct lcd_ctrl_extif *ext_if; /* LCD ctrl external
2549 + struct device *dev;
2550 + struct fb_var_screeninfo new_var; /* for mode changes */
2552 + struct omapfb_mem_desc mem_desc;
2553 + struct fb_info *fb_info[OMAPFB_PLANE_NUM];
2556 +#ifdef CONFIG_ARCH_OMAP1
2557 +extern struct lcd_ctrl omap1_lcd_ctrl;
2559 +extern struct lcd_ctrl omap2_disp_ctrl;
2562 +extern void omapfb_register_panel(struct lcd_panel *panel);
2563 +extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
2564 +extern void omapfb_notify_clients(struct omapfb_device *fbdev,
2565 + unsigned long event);
2566 +extern int omapfb_register_client(struct omapfb_notifier_block *nb,
2567 + omapfb_notifier_callback_t callback,
2568 + void *callback_data);
2569 +extern int omapfb_unregister_client(struct omapfb_notifier_block *nb);
2570 +extern int omapfb_update_window_async(struct fb_info *fbi,
2571 + struct omapfb_update_window *win,
2572 + void (*callback)(void *),
2573 + void *callback_data);
2575 +#endif /* __OMAPFB_H */
2576 diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
2577 index 0d0c8c8..a27614d 100644
2578 --- a/drivers/video/omap/omapfb_main.c
2579 +++ b/drivers/video/omap/omapfb_main.c
2581 #include <linux/uaccess.h>
2583 #include <mach/dma.h>
2584 -#include <mach/omapfb.h>
2586 +#include "omapfb.h"
2590 diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c
2591 index ee01e84..fed7b1b 100644
2592 --- a/drivers/video/omap/rfbi.c
2593 +++ b/drivers/video/omap/rfbi.c
2595 #include <linux/clk.h>
2596 #include <linux/io.h>
2598 -#include <mach/omapfb.h>
2600 +#include "omapfb.h"
2603 /* To work around an RFBI transfer rate limitation */
2604 diff --git a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c
2605 index a769462..6853627 100644
2606 --- a/drivers/video/omap/sossi.c
2607 +++ b/drivers/video/omap/sossi.c
2609 #include <linux/io.h>
2611 #include <mach/dma.h>
2612 -#include <mach/omapfb.h>
2614 +#include "omapfb.h"
2617 #define MODULE_NAME "omapfb-sossi"
2618 diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig
2619 new file mode 100644
2620 index 0000000..d877c36
2622 +++ b/drivers/video/omap2/Kconfig
2630 +source "drivers/video/omap2/dss/Kconfig"
2631 +source "drivers/video/omap2/omapfb/Kconfig"
2632 +source "drivers/video/omap2/displays/Kconfig"
2633 diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile
2634 new file mode 100644
2635 index 0000000..d853d05
2637 +++ b/drivers/video/omap2/Makefile
2639 +obj-$(CONFIG_OMAP2_VRAM) += vram.o
2640 +obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
2645 diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
2646 new file mode 100644
2647 index 0000000..79d2861
2649 +++ b/drivers/video/omap2/displays/Kconfig
2651 +menu "OMAP2/3 Display Device Drivers"
2652 + depends on OMAP2_DSS
2654 +config PANEL_GENERIC
2655 + tristate "Generic Panel"
2657 + Generic panel driver.
2658 + Used for DVI output for Beagle and OMAP3 SDP.
2660 +config PANEL_SAMSUNG_LTE430WQ_F0C
2661 + tristate "Samsung LTE430WQ-F0C LCD Panel"
2662 + depends on OMAP2_DSS
2664 + LCD Panel used on Overo Palo43
2666 +config PANEL_SHARP_LS037V7DW01
2667 + tristate "Sharp LS037V7DW01 LCD Panel"
2668 + depends on OMAP2_DSS
2670 + LCD Panel used in TI's SDP3430 and EVM boards
2673 + tristate "Taal DSI Panel"
2674 + depends on OMAP2_DSS_DSI
2676 + Taal DSI command mode panel from TPO.
2679 diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
2680 new file mode 100644
2681 index 0000000..d44e765
2683 +++ b/drivers/video/omap2/displays/Makefile
2685 +obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
2686 +obj-$(CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C) += panel-samsung-lte430wq-f0c.o
2687 +obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
2689 +obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
2690 diff --git a/drivers/video/omap2/displays/panel-generic.c b/drivers/video/omap2/displays/panel-generic.c
2691 new file mode 100644
2692 index 0000000..738147e
2694 +++ b/drivers/video/omap2/displays/panel-generic.c
2697 + * Generic panel support
2699 + * Copyright (C) 2008 Nokia Corporation
2700 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
2702 + * This program is free software; you can redistribute it and/or modify it
2703 + * under the terms of the GNU General Public License version 2 as published by
2704 + * the Free Software Foundation.
2706 + * This program is distributed in the hope that it will be useful, but WITHOUT
2707 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2708 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
2711 + * You should have received a copy of the GNU General Public License along with
2712 + * this program. If not, see <http://www.gnu.org/licenses/>.
2715 +#include <linux/module.h>
2716 +#include <linux/delay.h>
2718 +#include <mach/display.h>
2720 +static struct omap_video_timings generic_panel_timings = {
2721 + /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
2724 + .pixel_clock = 23500,
2733 +static int generic_panel_probe(struct omap_dss_device *dssdev)
2735 + dssdev->panel.config = OMAP_DSS_LCD_TFT;
2736 + dssdev->panel.timings = generic_panel_timings;
2741 +static void generic_panel_remove(struct omap_dss_device *dssdev)
2745 +static int generic_panel_enable(struct omap_dss_device *dssdev)
2749 + if (dssdev->platform_enable)
2750 + r = dssdev->platform_enable(dssdev);
2755 +static void generic_panel_disable(struct omap_dss_device *dssdev)
2757 + if (dssdev->platform_disable)
2758 + dssdev->platform_disable(dssdev);
2761 +static int generic_panel_suspend(struct omap_dss_device *dssdev)
2763 + generic_panel_disable(dssdev);
2767 +static int generic_panel_resume(struct omap_dss_device *dssdev)
2769 + return generic_panel_enable(dssdev);
2772 +static struct omap_dss_driver generic_driver = {
2773 + .probe = generic_panel_probe,
2774 + .remove = generic_panel_remove,
2776 + .enable = generic_panel_enable,
2777 + .disable = generic_panel_disable,
2778 + .suspend = generic_panel_suspend,
2779 + .resume = generic_panel_resume,
2782 + .name = "generic_panel",
2783 + .owner = THIS_MODULE,
2787 +static int __init generic_panel_drv_init(void)
2789 + return omap_dss_register_driver(&generic_driver);
2792 +static void __exit generic_panel_drv_exit(void)
2794 + omap_dss_unregister_driver(&generic_driver);
2797 +module_init(generic_panel_drv_init);
2798 +module_exit(generic_panel_drv_exit);
2799 +MODULE_LICENSE("GPL");
2800 diff --git a/drivers/video/omap2/displays/panel-samsung-lte430wq-f0c.c b/drivers/video/omap2/displays/panel-samsung-lte430wq-f0c.c
2801 new file mode 100644
2802 index 0000000..eafe581
2804 +++ b/drivers/video/omap2/displays/panel-samsung-lte430wq-f0c.c
2807 + * LCD panel driver for Samsung LTE430WQ-F0C
2809 + * Author: Steve Sakoman <steve@sakoman.com>
2811 + * This program is free software; you can redistribute it and/or modify it
2812 + * under the terms of the GNU General Public License version 2 as published by
2813 + * the Free Software Foundation.
2815 + * This program is distributed in the hope that it will be useful, but WITHOUT
2816 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2817 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
2820 + * You should have received a copy of the GNU General Public License along with
2821 + * this program. If not, see <http://www.gnu.org/licenses/>.
2824 +#include <linux/module.h>
2825 +#include <linux/delay.h>
2827 +#include <mach/display.h>
2829 +static struct omap_video_timings samsung_lte_timings = {
2833 + .pixel_clock = 9200,
2844 +static int samsung_lte_panel_probe(struct omap_dss_device *dssdev)
2846 + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
2848 + dssdev->panel.timings = samsung_lte_timings;
2853 +static void samsung_lte_panel_remove(struct omap_dss_device *dssdev)
2857 +static int samsung_lte_panel_enable(struct omap_dss_device *dssdev)
2861 + /* wait couple of vsyncs until enabling the LCD */
2864 + if (dssdev->platform_enable)
2865 + r = dssdev->platform_enable(dssdev);
2870 +static void samsung_lte_panel_disable(struct omap_dss_device *dssdev)
2872 + if (dssdev->platform_disable)
2873 + dssdev->platform_disable(dssdev);
2875 + /* wait at least 5 vsyncs after disabling the LCD */
2880 +static int samsung_lte_panel_suspend(struct omap_dss_device *dssdev)
2882 + samsung_lte_panel_disable(dssdev);
2886 +static int samsung_lte_panel_resume(struct omap_dss_device *dssdev)
2888 + return samsung_lte_panel_enable(dssdev);
2891 +static struct omap_dss_driver samsung_lte_driver = {
2892 + .probe = samsung_lte_panel_probe,
2893 + .remove = samsung_lte_panel_remove,
2895 + .enable = samsung_lte_panel_enable,
2896 + .disable = samsung_lte_panel_disable,
2897 + .suspend = samsung_lte_panel_suspend,
2898 + .resume = samsung_lte_panel_resume,
2901 + .name = "samsung_lte_panel",
2902 + .owner = THIS_MODULE,
2906 +static int __init samsung_lte_panel_drv_init(void)
2908 + return omap_dss_register_driver(&samsung_lte_driver);
2911 +static void __exit samsung_lte_panel_drv_exit(void)
2913 + omap_dss_unregister_driver(&samsung_lte_driver);
2916 +module_init(samsung_lte_panel_drv_init);
2917 +module_exit(samsung_lte_panel_drv_exit);
2918 +MODULE_LICENSE("GPL");
2919 diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
2920 new file mode 100644
2921 index 0000000..2f8f0df
2923 +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
2926 + * LCD panel driver for Sharp LS037V7DW01
2928 + * Copyright (C) 2008 Nokia Corporation
2929 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
2931 + * This program is free software; you can redistribute it and/or modify it
2932 + * under the terms of the GNU General Public License version 2 as published by
2933 + * the Free Software Foundation.
2935 + * This program is distributed in the hope that it will be useful, but WITHOUT
2936 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2937 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
2940 + * You should have received a copy of the GNU General Public License along with
2941 + * this program. If not, see <http://www.gnu.org/licenses/>.
2944 +#include <linux/module.h>
2945 +#include <linux/delay.h>
2946 +#include <linux/device.h>
2947 +#include <linux/regulator/consumer.h>
2948 +#include <linux/err.h>
2950 +#include <mach/display.h>
2952 +struct sharp_data {
2953 + /* XXX This regulator should actually be in SDP board file, not here,
2954 + * as it doesn't actually power the LCD, but something else that
2955 + * affects the output to LCD (I think. Somebody clarify). It doesn't do
2956 + * harm here, as SDP is the only board using this currently */
2957 + struct regulator *vdvi_reg;
2960 +static struct omap_video_timings sharp_ls_timings = {
2964 + .pixel_clock = 19200,
2975 +static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
2977 + struct sharp_data *sd;
2979 + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
2981 + dssdev->panel.acb = 0x28;
2982 + dssdev->panel.timings = sharp_ls_timings;
2984 + sd = kzalloc(sizeof(*sd), GFP_KERNEL);
2988 + dev_set_drvdata(&dssdev->dev, sd);
2990 + sd->vdvi_reg = regulator_get(&dssdev->dev, "vdvi");
2991 + if (IS_ERR(sd->vdvi_reg)) {
2993 + pr_err("failed to get VDVI regulator\n");
2994 + return PTR_ERR(sd->vdvi_reg);
3000 +static void sharp_ls_panel_remove(struct omap_dss_device *dssdev)
3002 + struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
3004 + regulator_put(sd->vdvi_reg);
3009 +static int sharp_ls_panel_enable(struct omap_dss_device *dssdev)
3011 + struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
3014 + /* wait couple of vsyncs until enabling the LCD */
3017 + regulator_enable(sd->vdvi_reg);
3019 + if (dssdev->platform_enable)
3020 + r = dssdev->platform_enable(dssdev);
3025 +static void sharp_ls_panel_disable(struct omap_dss_device *dssdev)
3027 + struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
3029 + if (dssdev->platform_disable)
3030 + dssdev->platform_disable(dssdev);
3032 + regulator_disable(sd->vdvi_reg);
3034 + /* wait at least 5 vsyncs after disabling the LCD */
3039 +static int sharp_ls_panel_suspend(struct omap_dss_device *dssdev)
3041 + sharp_ls_panel_disable(dssdev);
3045 +static int sharp_ls_panel_resume(struct omap_dss_device *dssdev)
3047 + return sharp_ls_panel_enable(dssdev);
3050 +static struct omap_dss_driver sharp_ls_driver = {
3051 + .probe = sharp_ls_panel_probe,
3052 + .remove = sharp_ls_panel_remove,
3054 + .enable = sharp_ls_panel_enable,
3055 + .disable = sharp_ls_panel_disable,
3056 + .suspend = sharp_ls_panel_suspend,
3057 + .resume = sharp_ls_panel_resume,
3060 + .name = "sharp_ls_panel",
3061 + .owner = THIS_MODULE,
3065 +static int __init sharp_ls_panel_drv_init(void)
3067 + return omap_dss_register_driver(&sharp_ls_driver);
3070 +static void __exit sharp_ls_panel_drv_exit(void)
3072 + omap_dss_unregister_driver(&sharp_ls_driver);
3075 +module_init(sharp_ls_panel_drv_init);
3076 +module_exit(sharp_ls_panel_drv_exit);
3077 +MODULE_LICENSE("GPL");
3078 diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
3079 new file mode 100644
3080 index 0000000..84f0d47
3082 +++ b/drivers/video/omap2/displays/panel-taal.c
3085 + * Taal DSI command mode panel
3087 + * Copyright (C) 2009 Nokia Corporation
3088 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
3090 + * This program is free software; you can redistribute it and/or modify it
3091 + * under the terms of the GNU General Public License version 2 as published by
3092 + * the Free Software Foundation.
3094 + * This program is distributed in the hope that it will be useful, but WITHOUT
3095 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
3096 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
3099 + * You should have received a copy of the GNU General Public License along with
3100 + * this program. If not, see <http://www.gnu.org/licenses/>.
3105 +#include <linux/module.h>
3106 +#include <linux/delay.h>
3107 +#include <linux/err.h>
3108 +#include <linux/jiffies.h>
3109 +#include <linux/sched.h>
3110 +#include <linux/backlight.h>
3111 +#include <linux/fb.h>
3112 +#include <linux/interrupt.h>
3113 +#include <linux/gpio.h>
3114 +#include <linux/completion.h>
3116 +#include <mach/display.h>
3118 +/* DSI Virtual channel. Hardcoded for now. */
3121 +#define DCS_READ_NUM_ERRORS 0x05
3122 +#define DCS_READ_POWER_MODE 0x0a
3123 +#define DCS_READ_MADCTL 0x0b
3124 +#define DCS_READ_PIXEL_FORMAT 0x0c
3125 +#define DCS_SLEEP_IN 0x10
3126 +#define DCS_SLEEP_OUT 0x11
3127 +#define DCS_DISPLAY_OFF 0x28
3128 +#define DCS_DISPLAY_ON 0x29
3129 +#define DCS_COLUMN_ADDR 0x2a
3130 +#define DCS_PAGE_ADDR 0x2b
3131 +#define DCS_MEMORY_WRITE 0x2c
3132 +#define DCS_TEAR_OFF 0x34
3133 +#define DCS_TEAR_ON 0x35
3134 +#define DCS_MEM_ACC_CTRL 0x36
3135 +#define DCS_PIXEL_FORMAT 0x3a
3136 +#define DCS_BRIGHTNESS 0x51
3137 +#define DCS_CTRL_DISPLAY 0x53
3138 +#define DCS_WRITE_CABC 0x55
3139 +#define DCS_READ_CABC 0x56
3140 +#define DCS_GET_ID1 0xda
3141 +#define DCS_GET_ID2 0xdb
3142 +#define DCS_GET_ID3 0xdc
3145 + struct backlight_device *bldev;
3147 + unsigned long hw_guard_end; /* next value of jiffies when we can
3148 + * issue the next sleep in/out command
3150 + unsigned long hw_guard_wait; /* max guard time in jiffies */
3152 + struct omap_dss_device *dssdev;
3160 + struct completion te_completion;
3165 + unsigned cabc_mode;
3167 + bool intro_printed;
3170 +static void hw_guard_start(struct taal_data *td, int guard_msec)
3172 + td->hw_guard_wait = msecs_to_jiffies(guard_msec);
3173 + td->hw_guard_end = jiffies + td->hw_guard_wait;
3176 +static void hw_guard_wait(struct taal_data *td)
3178 + unsigned long wait = td->hw_guard_end - jiffies;
3180 + if ((long)wait > 0 && wait <= td->hw_guard_wait) {
3181 + set_current_state(TASK_UNINTERRUPTIBLE);
3182 + schedule_timeout(wait);
3186 +static int taal_dcs_read_1(u8 dcs_cmd, u8 *data)
3191 + r = dsi_vc_dcs_read(TCH, dcs_cmd, buf, 1);
3201 +static int taal_dcs_write_0(u8 dcs_cmd)
3203 + return dsi_vc_dcs_write(TCH, &dcs_cmd, 1);
3206 +static int taal_dcs_write_1(u8 dcs_cmd, u8 param)
3211 + return dsi_vc_dcs_write(TCH, buf, 2);
3214 +static int taal_sleep_in(struct taal_data *td)
3220 + hw_guard_wait(td);
3222 + cmd = DCS_SLEEP_IN;
3223 + r = dsi_vc_dcs_write_nosync(TCH, &cmd, 1);
3227 + hw_guard_start(td, 120);
3234 +static int taal_sleep_out(struct taal_data *td)
3238 + hw_guard_wait(td);
3240 + r = taal_dcs_write_0(DCS_SLEEP_OUT);
3244 + hw_guard_start(td, 120);
3251 +static int taal_get_id(u8 *id1, u8 *id2, u8 *id3)
3255 + r = taal_dcs_read_1(DCS_GET_ID1, id1);
3258 + r = taal_dcs_read_1(DCS_GET_ID2, id2);
3261 + r = taal_dcs_read_1(DCS_GET_ID3, id3);
3268 +static int taal_set_addr_mode(u8 rotate, bool mirror)
3274 + r = taal_dcs_read_1(DCS_READ_MADCTL, &mode);
3305 + mode &= ~((1<<7) | (1<<6) | (1<<5));
3306 + mode |= (b7 << 7) | (b6 << 6) | (b5 << 5);
3308 + return taal_dcs_write_1(DCS_MEM_ACC_CTRL, mode);
3311 +static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h)
3315 + u16 x2 = x + w - 1;
3317 + u16 y2 = y + h - 1;
3320 + buf[0] = DCS_COLUMN_ADDR;
3321 + buf[1] = (x1 >> 8) & 0xff;
3322 + buf[2] = (x1 >> 0) & 0xff;
3323 + buf[3] = (x2 >> 8) & 0xff;
3324 + buf[4] = (x2 >> 0) & 0xff;
3326 + r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
3330 + buf[0] = DCS_PAGE_ADDR;
3331 + buf[1] = (y1 >> 8) & 0xff;
3332 + buf[2] = (y1 >> 0) & 0xff;
3333 + buf[3] = (y2 >> 8) & 0xff;
3334 + buf[4] = (y2 >> 0) & 0xff;
3336 + r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
3340 + dsi_vc_send_bta_sync(TCH);
3345 +static int taal_bl_update_status(struct backlight_device *dev)
3347 + struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
3348 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3352 + if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
3353 + dev->props.power == FB_BLANK_UNBLANK)
3354 + level = dev->props.brightness;
3358 + dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
3360 + if (td->use_dsi_bl) {
3361 + if (td->enabled) {
3363 + r = taal_dcs_write_1(DCS_BRIGHTNESS, level);
3369 + if (!dssdev->set_backlight)
3372 + r = dssdev->set_backlight(dssdev, level);
3380 +static int taal_bl_get_intensity(struct backlight_device *dev)
3382 + if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
3383 + dev->props.power == FB_BLANK_UNBLANK)
3384 + return dev->props.brightness;
3389 +static struct backlight_ops taal_bl_ops = {
3390 + .get_brightness = taal_bl_get_intensity,
3391 + .update_status = taal_bl_update_status,
3394 +static void taal_get_timings(struct omap_dss_device *dssdev,
3395 + struct omap_video_timings *timings)
3397 + *timings = dssdev->panel.timings;
3400 +static void taal_get_resolution(struct omap_dss_device *dssdev,
3401 + u16 *xres, u16 *yres)
3403 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3405 + if (td->rotate == 0 || td->rotate == 2) {
3406 + *xres = dssdev->panel.timings.x_res;
3407 + *yres = dssdev->panel.timings.y_res;
3409 + *yres = dssdev->panel.timings.x_res;
3410 + *xres = dssdev->panel.timings.y_res;
3414 +static irqreturn_t taal_te_isr(int irq, void *data)
3416 + struct omap_dss_device *dssdev = data;
3417 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3419 + complete_all(&td->te_completion);
3421 + return IRQ_HANDLED;
3424 +static ssize_t taal_num_errors_show(struct device *dev,
3425 + struct device_attribute *attr, char *buf)
3427 + struct omap_dss_device *dssdev = to_dss_device(dev);
3428 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3432 + if (td->enabled) {
3434 + r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors);
3443 + return snprintf(buf, PAGE_SIZE, "%d\n", errors);
3446 +static ssize_t taal_hw_revision_show(struct device *dev,
3447 + struct device_attribute *attr, char *buf)
3449 + struct omap_dss_device *dssdev = to_dss_device(dev);
3450 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3454 + if (td->enabled) {
3456 + r = taal_get_id(&id1, &id2, &id3);
3465 + return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3);
3468 +static const char *cabc_modes[] = {
3469 + "off", /* used also always when CABC is not supported */
3475 +static ssize_t show_cabc_mode(struct device *dev,
3476 + struct device_attribute *attr,
3479 + struct omap_dss_device *dssdev = to_dss_device(dev);
3480 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3481 + const char *mode_str;
3485 + mode = td->cabc_mode;
3487 + mode_str = "unknown";
3488 + if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
3489 + mode_str = cabc_modes[mode];
3490 + len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
3492 + return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
3495 +static ssize_t store_cabc_mode(struct device *dev,
3496 + struct device_attribute *attr,
3497 + const char *buf, size_t count)
3499 + struct omap_dss_device *dssdev = to_dss_device(dev);
3500 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3503 + for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
3504 + if (sysfs_streq(cabc_modes[i], buf))
3508 + if (i == ARRAY_SIZE(cabc_modes))
3511 + if (td->enabled) {
3513 + if (!td->cabc_broken)
3514 + taal_dcs_write_1(DCS_WRITE_CABC, i);
3518 + td->cabc_mode = i;
3523 +static ssize_t show_cabc_available_modes(struct device *dev,
3524 + struct device_attribute *attr,
3530 + for (i = 0, len = 0;
3531 + len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
3532 + len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
3533 + i ? " " : "", cabc_modes[i],
3534 + i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
3536 + return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
3539 +static DEVICE_ATTR(num_dsi_errors, S_IRUGO, taal_num_errors_show, NULL);
3540 +static DEVICE_ATTR(hw_revision, S_IRUGO, taal_hw_revision_show, NULL);
3541 +static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
3542 + show_cabc_mode, store_cabc_mode);
3543 +static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
3544 + show_cabc_available_modes, NULL);
3546 +static struct attribute *taal_attrs[] = {
3547 + &dev_attr_num_dsi_errors.attr,
3548 + &dev_attr_hw_revision.attr,
3549 + &dev_attr_cabc_mode.attr,
3550 + &dev_attr_cabc_available_modes.attr,
3554 +static struct attribute_group taal_attr_group = {
3555 + .attrs = taal_attrs,
3558 +static int taal_probe(struct omap_dss_device *dssdev)
3560 + struct taal_data *td;
3561 + struct backlight_device *bldev;
3564 + const struct omap_video_timings taal_panel_timings = {
3569 + dev_dbg(&dssdev->dev, "probe\n");
3571 + dssdev->panel.config = OMAP_DSS_LCD_TFT;
3572 + dssdev->panel.timings = taal_panel_timings;
3573 + dssdev->ctrl.pixel_size = 24;
3575 + td = kzalloc(sizeof(*td), GFP_KERNEL);
3581 + dev_set_drvdata(&dssdev->dev, td);
3583 + dssdev->get_timings = taal_get_timings;
3584 + dssdev->get_resolution = taal_get_resolution;
3586 + /* if no platform set_backlight() defined, presume DSI backlight
3588 + if (!dssdev->set_backlight)
3589 + td->use_dsi_bl = true;
3591 + bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
3593 + if (IS_ERR(bldev)) {
3594 + r = PTR_ERR(bldev);
3598 + td->bldev = bldev;
3600 + bldev->props.fb_blank = FB_BLANK_UNBLANK;
3601 + bldev->props.power = FB_BLANK_UNBLANK;
3602 + if (td->use_dsi_bl) {
3603 + bldev->props.max_brightness = 255;
3604 + bldev->props.brightness = 255;
3606 + bldev->props.max_brightness = 127;
3607 + bldev->props.brightness = 127;
3610 + taal_bl_update_status(bldev);
3612 + if (dssdev->phy.dsi.ext_te) {
3613 + int gpio = dssdev->phy.dsi.ext_te_gpio;
3615 + r = gpio_request(gpio, "taal irq");
3617 + dev_err(&dssdev->dev, "GPIO request failed\n");
3621 + gpio_direction_input(gpio);
3623 + r = request_irq(gpio_to_irq(gpio), taal_te_isr,
3624 + IRQF_DISABLED | IRQF_TRIGGER_RISING,
3625 + "taal vsync", dssdev);
3628 + dev_err(&dssdev->dev, "IRQ request failed\n");
3633 + init_completion(&td->te_completion);
3635 + td->use_ext_te = true;
3638 + r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group);
3640 + dev_err(&dssdev->dev, "failed to create sysfs files\n");
3646 + if (td->use_ext_te) {
3647 + int gpio = dssdev->phy.dsi.ext_te_gpio;
3648 + free_irq(gpio_to_irq(gpio), dssdev);
3652 + backlight_device_unregister(bldev);
3659 +static void taal_remove(struct omap_dss_device *dssdev)
3661 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3662 + struct backlight_device *bldev;
3664 + dev_dbg(&dssdev->dev, "remove\n");
3666 + sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group);
3668 + if (td->use_ext_te) {
3669 + int gpio = dssdev->phy.dsi.ext_te_gpio;
3670 + free_irq(gpio_to_irq(gpio), dssdev);
3674 + bldev = td->bldev;
3675 + bldev->props.power = FB_BLANK_POWERDOWN;
3676 + taal_bl_update_status(bldev);
3677 + backlight_device_unregister(bldev);
3682 +static int taal_enable(struct omap_dss_device *dssdev)
3684 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3688 + dev_dbg(&dssdev->dev, "enable\n");
3690 + if (dssdev->platform_enable) {
3691 + r = dssdev->platform_enable(dssdev);
3696 + /* it seems we have to wait a bit until taal is ready */
3699 + r = taal_sleep_out(td);
3703 + r = taal_get_id(&id1, &id2, &id3);
3707 + /* on early revisions CABC is broken */
3708 + if (id2 == 0x00 || id2 == 0xff || id2 == 0x81)
3709 + td->cabc_broken = true;
3711 + taal_dcs_write_1(DCS_BRIGHTNESS, 0xff);
3712 + taal_dcs_write_1(DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */
3714 + taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
3716 + taal_set_addr_mode(td->rotate, td->mirror);
3717 + if (!td->cabc_broken)
3718 + taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode);
3720 + taal_dcs_write_0(DCS_DISPLAY_ON);
3724 + if (!td->intro_printed) {
3725 + dev_info(&dssdev->dev, "revision %02x.%02x.%02x\n",
3727 + if (td->cabc_broken)
3728 + dev_info(&dssdev->dev,
3729 + "old Taal version, CABC disabled\n");
3730 + td->intro_printed = true;
3736 +static void taal_disable(struct omap_dss_device *dssdev)
3738 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3740 + dev_dbg(&dssdev->dev, "disable\n");
3742 + taal_dcs_write_0(DCS_DISPLAY_OFF);
3743 + taal_sleep_in(td);
3745 + /* wait a bit so that the message goes through */
3748 + if (dssdev->platform_disable)
3749 + dssdev->platform_disable(dssdev);
3754 +static int taal_suspend(struct omap_dss_device *dssdev)
3756 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3757 + struct backlight_device *bldev = td->bldev;
3759 + bldev->props.power = FB_BLANK_POWERDOWN;
3760 + taal_bl_update_status(bldev);
3765 +static int taal_resume(struct omap_dss_device *dssdev)
3767 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3768 + struct backlight_device *bldev = td->bldev;
3770 + bldev->props.power = FB_BLANK_UNBLANK;
3771 + taal_bl_update_status(bldev);
3776 +static void taal_setup_update(struct omap_dss_device *dssdev,
3777 + u16 x, u16 y, u16 w, u16 h)
3779 + taal_set_update_window(x, y, w, h);
3782 +static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
3784 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3787 + td->te_enabled = enable;
3790 + r = taal_dcs_write_1(DCS_TEAR_ON, 0);
3792 + r = taal_dcs_write_0(DCS_TEAR_OFF);
3797 +static int taal_wait_te(struct omap_dss_device *dssdev)
3799 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3800 + long wait = msecs_to_jiffies(500);
3802 + if (!td->use_ext_te || !td->te_enabled)
3805 + INIT_COMPLETION(td->te_completion);
3806 + wait = wait_for_completion_timeout(&td->te_completion, wait);
3808 + dev_err(&dssdev->dev, "timeout waiting TE\n");
3815 +static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
3817 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3820 + dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
3822 + if (td->enabled) {
3823 + r = taal_set_addr_mode(rotate, td->mirror);
3829 + td->rotate = rotate;
3834 +static u8 taal_get_rotate(struct omap_dss_device *dssdev)
3836 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3837 + return td->rotate;
3840 +static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
3842 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3845 + dev_dbg(&dssdev->dev, "mirror %d\n", enable);
3847 + if (td->enabled) {
3848 + r = taal_set_addr_mode(td->rotate, enable);
3854 + td->mirror = enable;
3859 +static bool taal_get_mirror(struct omap_dss_device *dssdev)
3861 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3862 + return td->mirror;
3865 +static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
3870 + r = taal_dcs_read_1(DCS_GET_ID1, &id1);
3873 + r = taal_dcs_read_1(DCS_GET_ID2, &id2);
3876 + r = taal_dcs_read_1(DCS_GET_ID3, &id3);
3883 +static int taal_memory_read(struct omap_dss_device *dssdev,
3884 + void *buf, size_t size,
3885 + u16 x, u16 y, u16 w, u16 h)
3890 + unsigned buf_used = 0;
3892 + if (size < w * h * 3)
3895 + size = min(w * h * 3,
3896 + dssdev->panel.timings.x_res *
3897 + dssdev->panel.timings.y_res * 3);
3899 + /* plen 1 or 2 goes into short packet. until checksum error is fixed,
3900 + * use short packets. plen 32 works, but bigger packets seem to cause
3907 + taal_setup_update(dssdev, x, y, w, h);
3909 + r = dsi_vc_set_max_rx_packet_size(TCH, plen);
3913 + while (buf_used < size) {
3914 + u8 dcs_cmd = first ? 0x2e : 0x3e;
3917 + r = dsi_vc_dcs_read(TCH, dcs_cmd,
3918 + buf + buf_used, size - buf_used);
3921 + dev_err(&dssdev->dev, "read error\n");
3928 + dev_err(&dssdev->dev, "short read\n");
3936 + dsi_vc_set_max_rx_packet_size(TCH, 1);
3941 +static struct omap_dss_driver taal_driver = {
3942 + .probe = taal_probe,
3943 + .remove = taal_remove,
3945 + .enable = taal_enable,
3946 + .disable = taal_disable,
3947 + .suspend = taal_suspend,
3948 + .resume = taal_resume,
3950 + .setup_update = taal_setup_update,
3951 + .enable_te = taal_enable_te,
3952 + .wait_for_te = taal_wait_te,
3953 + .set_rotate = taal_rotate,
3954 + .get_rotate = taal_get_rotate,
3955 + .set_mirror = taal_mirror,
3956 + .get_mirror = taal_get_mirror,
3957 + .run_test = taal_run_test,
3958 + .memory_read = taal_memory_read,
3962 + .owner = THIS_MODULE,
3966 +static int __init taal_init(void)
3968 + omap_dss_register_driver(&taal_driver);
3973 +static void __exit taal_exit(void)
3975 + omap_dss_unregister_driver(&taal_driver);
3978 +module_init(taal_init);
3979 +module_exit(taal_exit);
3981 +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
3982 +MODULE_DESCRIPTION("Taal Driver");
3983 +MODULE_LICENSE("GPL");
3984 diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
3985 new file mode 100644
3986 index 0000000..71d8dec
3988 +++ b/drivers/video/omap2/dss/Kconfig
3990 +menuconfig OMAP2_DSS
3991 + tristate "OMAP2/3 Display Subsystem support (EXPERIMENTAL)"
3992 + depends on ARCH_OMAP2 || ARCH_OMAP3
3994 + OMAP2/3 Display Subsystem support.
3998 +config OMAP2_VRAM_SIZE
3999 + int "VRAM size (MB)"
4003 + The amount of SDRAM to reserve at boot time for video RAM use.
4004 + This VRAM will be used by omapfb and other drivers that need
4005 + large continuous RAM area for video use.
4007 + You can also set this with "vram=<bytes>" kernel argument, or
4008 + in the board file.
4010 +config OMAP2_DSS_DEBUG_SUPPORT
4011 + bool "Debug support"
4014 + This enables debug messages. You need to enable printing
4015 + with 'debug' module parameter.
4017 +config OMAP2_DSS_RFBI
4018 + bool "RFBI support"
4021 + MIPI DBI, or RFBI (Remote Framebuffer Interface), support.
4023 +config OMAP2_DSS_VENC
4024 + bool "VENC support"
4027 + OMAP Video Encoder support.
4029 +config OMAP2_DSS_SDI
4030 + bool "SDI support"
4031 + depends on ARCH_OMAP3
4034 + SDI (Serial Display Interface) support.
4036 +config OMAP2_DSS_DSI
4037 + bool "DSI support"
4038 + depends on ARCH_OMAP3
4043 +config OMAP2_DSS_USE_DSI_PLL
4044 + bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
4046 + depends on OMAP2_DSS_DSI
4048 + Use DSI PLL to generate pixel clock. Currently only for DPI output.
4049 + DSI PLL can be used to generate higher and more precise pixel clocks.
4051 +config OMAP2_DSS_FAKE_VSYNC
4052 + bool "Fake VSYNC irq from manual update displays"
4055 + If this is selected, DSI will generate a fake DISPC VSYNC interrupt
4056 + when DSI has sent a frame. This is only needed with DSI or RFBI
4057 + displays using manual mode, and you want VSYNC to, for example,
4060 +config OMAP2_DSS_MIN_FCK_PER_PCK
4061 + int "Minimum FCK/PCK ratio (for scaling)"
4065 + This can be used to adjust the minimum FCK/PCK ratio.
4067 + With this you can make sure that DISPC FCK is at least
4068 + n x PCK. Video plane scaling requires higher FCK than
4071 + If this is set to 0, there's no extra constraint on the
4072 + DISPC FCK. However, the FCK will at minimum be
4073 + 2xPCK (if active matrix) or 3xPCK (if passive matrix).
4075 + Max FCK is 173MHz, so this doesn't work if your PCK
4079 diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
4080 new file mode 100644
4081 index 0000000..980c72c
4083 +++ b/drivers/video/omap2/dss/Makefile
4085 +obj-$(CONFIG_OMAP2_DSS) += omapdss.o
4086 +omapdss-y := core.o dss.o dispc.o dpi.o display.o manager.o overlay.o
4087 +omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
4088 +omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
4089 +omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
4090 +omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
4091 diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
4092 new file mode 100644
4093 index 0000000..e8d430c
4095 +++ b/drivers/video/omap2/dss/core.c
4098 + * linux/drivers/video/omap2/dss/core.c
4100 + * Copyright (C) 2009 Nokia Corporation
4101 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
4103 + * Some code and ideas taken from drivers/video/omap/ driver
4106 + * This program is free software; you can redistribute it and/or modify it
4107 + * under the terms of the GNU General Public License version 2 as published by
4108 + * the Free Software Foundation.
4110 + * This program is distributed in the hope that it will be useful, but WITHOUT
4111 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4112 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
4115 + * You should have received a copy of the GNU General Public License along with
4116 + * this program. If not, see <http://www.gnu.org/licenses/>.
4119 +#define DSS_SUBSYS_NAME "CORE"
4121 +#include <linux/kernel.h>
4122 +#include <linux/module.h>
4123 +#include <linux/clk.h>
4124 +#include <linux/err.h>
4125 +#include <linux/platform_device.h>
4126 +#include <linux/seq_file.h>
4127 +#include <linux/debugfs.h>
4128 +#include <linux/io.h>
4129 +#include <linux/device.h>
4131 +#include <mach/display.h>
4132 +#include <mach/clock.h>
4137 + struct platform_device *pdev;
4140 + struct clk *dss_ick;
4141 + struct clk *dss1_fck;
4142 + struct clk *dss2_fck;
4143 + struct clk *dss_54m_fck;
4144 + struct clk *dss_96m_fck;
4145 + unsigned num_clks_enabled;
4148 +static void dss_clk_enable_all_no_ctx(void);
4149 +static void dss_clk_disable_all_no_ctx(void);
4150 +static void dss_clk_enable_no_ctx(enum dss_clock clks);
4151 +static void dss_clk_disable_no_ctx(enum dss_clock clks);
4153 +static char *def_disp_name;
4154 +module_param_named(def_disp, def_disp_name, charp, 0);
4155 +MODULE_PARM_DESC(def_disp_name, "default display name");
4158 +unsigned int dss_debug;
4159 +module_param_named(debug, dss_debug, bool, 0644);
4163 +static int dss_get_ctx_id(void)
4165 + struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
4168 + if (!pdata->get_last_off_on_transaction_id)
4170 + r = pdata->get_last_off_on_transaction_id(&core.pdev->dev);
4172 + dev_err(&core.pdev->dev, "getting transaction ID failed, "
4173 + "will force context restore\n");
4179 +int dss_need_ctx_restore(void)
4181 + int id = dss_get_ctx_id();
4183 + if (id < 0 || id != core.ctx_id) {
4184 + DSSDBG("ctx id %d -> id %d\n",
4193 +static void save_all_ctx(void)
4195 + DSSDBG("save context\n");
4197 + dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
4199 + dss_save_context();
4200 + dispc_save_context();
4201 +#ifdef CONFIG_OMAP2_DSS_DSI
4202 + dsi_save_context();
4205 + dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
4208 +static void restore_all_ctx(void)
4210 + DSSDBG("restore context\n");
4212 + dss_clk_enable_all_no_ctx();
4214 + dss_restore_context();
4215 + dispc_restore_context();
4216 +#ifdef CONFIG_OMAP2_DSS_DSI
4217 + dsi_restore_context();
4220 + dss_clk_disable_all_no_ctx();
4224 +void dss_dump_clocks(struct seq_file *s)
4227 + struct clk *clocks[5] = {
4235 + seq_printf(s, "- dss -\n");
4237 + seq_printf(s, "internal clk count\t%u\n", core.num_clks_enabled);
4239 + for (i = 0; i < 5; i++) {
4242 + seq_printf(s, "%-15s\t%lu\t%d\n",
4244 + clk_get_rate(clocks[i]),
4245 + clocks[i]->usecount);
4249 +static int dss_get_clock(struct clk **clock, const char *clk_name)
4253 + clk = clk_get(&core.pdev->dev, clk_name);
4255 + if (IS_ERR(clk)) {
4256 + DSSERR("can't get clock %s", clk_name);
4257 + return PTR_ERR(clk);
4262 + DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
4267 +static int dss_get_clocks(void)
4271 + core.dss_ick = NULL;
4272 + core.dss1_fck = NULL;
4273 + core.dss2_fck = NULL;
4274 + core.dss_54m_fck = NULL;
4275 + core.dss_96m_fck = NULL;
4277 + r = dss_get_clock(&core.dss_ick, "ick");
4281 + r = dss_get_clock(&core.dss1_fck, "dss1_fck");
4285 + r = dss_get_clock(&core.dss2_fck, "dss2_fck");
4289 + r = dss_get_clock(&core.dss_54m_fck, "tv_fck");
4293 + r = dss_get_clock(&core.dss_96m_fck, "video_fck");
4301 + clk_put(core.dss_ick);
4302 + if (core.dss1_fck)
4303 + clk_put(core.dss1_fck);
4304 + if (core.dss2_fck)
4305 + clk_put(core.dss2_fck);
4306 + if (core.dss_54m_fck)
4307 + clk_put(core.dss_54m_fck);
4308 + if (core.dss_96m_fck)
4309 + clk_put(core.dss_96m_fck);
4314 +static void dss_put_clocks(void)
4316 + if (core.dss_96m_fck)
4317 + clk_put(core.dss_96m_fck);
4318 + clk_put(core.dss_54m_fck);
4319 + clk_put(core.dss1_fck);
4320 + clk_put(core.dss2_fck);
4321 + clk_put(core.dss_ick);
4324 +unsigned long dss_clk_get_rate(enum dss_clock clk)
4328 + return clk_get_rate(core.dss_ick);
4329 + case DSS_CLK_FCK1:
4330 + return clk_get_rate(core.dss1_fck);
4331 + case DSS_CLK_FCK2:
4332 + return clk_get_rate(core.dss2_fck);
4334 + return clk_get_rate(core.dss_54m_fck);
4336 + return clk_get_rate(core.dss_96m_fck);
4343 +static unsigned count_clk_bits(enum dss_clock clks)
4345 + unsigned num_clks = 0;
4347 + if (clks & DSS_CLK_ICK)
4349 + if (clks & DSS_CLK_FCK1)
4351 + if (clks & DSS_CLK_FCK2)
4353 + if (clks & DSS_CLK_54M)
4355 + if (clks & DSS_CLK_96M)
4361 +static void dss_clk_enable_no_ctx(enum dss_clock clks)
4363 + unsigned num_clks = count_clk_bits(clks);
4365 + if (clks & DSS_CLK_ICK)
4366 + clk_enable(core.dss_ick);
4367 + if (clks & DSS_CLK_FCK1)
4368 + clk_enable(core.dss1_fck);
4369 + if (clks & DSS_CLK_FCK2)
4370 + clk_enable(core.dss2_fck);
4371 + if (clks & DSS_CLK_54M)
4372 + clk_enable(core.dss_54m_fck);
4373 + if (clks & DSS_CLK_96M)
4374 + clk_enable(core.dss_96m_fck);
4376 + core.num_clks_enabled += num_clks;
4379 +void dss_clk_enable(enum dss_clock clks)
4381 + dss_clk_enable_no_ctx(clks);
4383 + if (cpu_is_omap34xx() && dss_need_ctx_restore())
4384 + restore_all_ctx();
4387 +static void dss_clk_disable_no_ctx(enum dss_clock clks)
4389 + unsigned num_clks = count_clk_bits(clks);
4391 + if (clks & DSS_CLK_ICK)
4392 + clk_disable(core.dss_ick);
4393 + if (clks & DSS_CLK_FCK1)
4394 + clk_disable(core.dss1_fck);
4395 + if (clks & DSS_CLK_FCK2)
4396 + clk_disable(core.dss2_fck);
4397 + if (clks & DSS_CLK_54M)
4398 + clk_disable(core.dss_54m_fck);
4399 + if (clks & DSS_CLK_96M)
4400 + clk_disable(core.dss_96m_fck);
4402 + core.num_clks_enabled -= num_clks;
4405 +void dss_clk_disable(enum dss_clock clks)
4407 + if (cpu_is_omap34xx()) {
4408 + unsigned num_clks = count_clk_bits(clks);
4410 + BUG_ON(core.num_clks_enabled < num_clks);
4412 + if (core.num_clks_enabled == num_clks)
4416 + dss_clk_disable_no_ctx(clks);
4419 +static void dss_clk_enable_all_no_ctx(void)
4421 + enum dss_clock clks;
4423 + clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
4424 + if (cpu_is_omap34xx())
4425 + clks |= DSS_CLK_96M;
4426 + dss_clk_enable_no_ctx(clks);
4429 +static void dss_clk_disable_all_no_ctx(void)
4431 + enum dss_clock clks;
4433 + clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
4434 + if (cpu_is_omap34xx())
4435 + clks |= DSS_CLK_96M;
4436 + dss_clk_disable_no_ctx(clks);
4439 +static void dss_clk_disable_all(void)
4441 + enum dss_clock clks;
4443 + clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
4444 + if (cpu_is_omap34xx())
4445 + clks |= DSS_CLK_96M;
4446 + dss_clk_disable(clks);
4450 +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
4451 +static void dss_debug_dump_clocks(struct seq_file *s)
4453 + dss_dump_clocks(s);
4454 + dispc_dump_clocks(s);
4455 +#ifdef CONFIG_OMAP2_DSS_DSI
4456 + dsi_dump_clocks(s);
4460 +static int dss_debug_show(struct seq_file *s, void *unused)
4462 + void (*func)(struct seq_file *) = s->private;
4467 +static int dss_debug_open(struct inode *inode, struct file *file)
4469 + return single_open(file, dss_debug_show, inode->i_private);
4472 +static const struct file_operations dss_debug_fops = {
4473 + .open = dss_debug_open,
4475 + .llseek = seq_lseek,
4476 + .release = single_release,
4479 +static struct dentry *dss_debugfs_dir;
4481 +static int dss_initialize_debugfs(void)
4483 + dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
4484 + if (IS_ERR(dss_debugfs_dir)) {
4485 + int err = PTR_ERR(dss_debugfs_dir);
4486 + dss_debugfs_dir = NULL;
4490 + debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
4491 + &dss_debug_dump_clocks, &dss_debug_fops);
4493 + debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir,
4494 + &dss_dump_regs, &dss_debug_fops);
4495 + debugfs_create_file("dispc", S_IRUGO, dss_debugfs_dir,
4496 + &dispc_dump_regs, &dss_debug_fops);
4497 +#ifdef CONFIG_OMAP2_DSS_RFBI
4498 + debugfs_create_file("rfbi", S_IRUGO, dss_debugfs_dir,
4499 + &rfbi_dump_regs, &dss_debug_fops);
4501 +#ifdef CONFIG_OMAP2_DSS_DSI
4502 + debugfs_create_file("dsi", S_IRUGO, dss_debugfs_dir,
4503 + &dsi_dump_regs, &dss_debug_fops);
4505 +#ifdef CONFIG_OMAP2_DSS_VENC
4506 + debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
4507 + &venc_dump_regs, &dss_debug_fops);
4512 +static void dss_uninitialize_debugfs(void)
4514 + if (dss_debugfs_dir)
4515 + debugfs_remove_recursive(dss_debugfs_dir);
4517 +#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
4519 +/* PLATFORM DEVICE */
4520 +static int omap_dss_probe(struct platform_device *pdev)
4522 + struct omap_dss_board_info *pdata = pdev->dev.platform_data;
4523 + int skip_init = 0;
4529 + dss_init_overlay_managers(pdev);
4530 + dss_init_overlays(pdev);
4532 + r = dss_get_clocks();
4536 + dss_clk_enable_all_no_ctx();
4538 + core.ctx_id = dss_get_ctx_id();
4539 + DSSDBG("initial ctx id %u\n", core.ctx_id);
4541 +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
4542 + /* DISPC_CONTROL */
4543 + if (omap_readl(0x48050440) & 1) /* LCD enabled? */
4547 + r = dss_init(skip_init);
4549 + DSSERR("Failed to initialize DSS\n");
4553 +#ifdef CONFIG_OMAP2_DSS_RFBI
4556 + DSSERR("Failed to initialize rfbi\n");
4563 + DSSERR("Failed to initialize dpi\n");
4569 + DSSERR("Failed to initialize dispc\n");
4572 +#ifdef CONFIG_OMAP2_DSS_VENC
4573 + r = venc_init(pdev);
4575 + DSSERR("Failed to initialize venc\n");
4579 + if (cpu_is_omap34xx()) {
4580 +#ifdef CONFIG_OMAP2_DSS_SDI
4581 + r = sdi_init(skip_init);
4583 + DSSERR("Failed to initialize SDI\n");
4587 +#ifdef CONFIG_OMAP2_DSS_DSI
4588 + r = dsi_init(pdev);
4590 + DSSERR("Failed to initialize DSI\n");
4596 +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
4597 + r = dss_initialize_debugfs();
4602 + for (i = 0; i < pdata->num_devices; ++i) {
4603 + struct omap_dss_device *dssdev = pdata->devices[i];
4605 + r = omap_dss_register_device(dssdev);
4607 + DSSERR("device reg failed %d\n", i);
4609 + if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0)
4610 + pdata->default_device = dssdev;
4613 + dss_clk_disable_all();
4617 + /* XXX fail correctly */
4622 +static int omap_dss_remove(struct platform_device *pdev)
4624 + struct omap_dss_board_info *pdata = pdev->dev.platform_data;
4628 +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
4629 + dss_uninitialize_debugfs();
4632 +#ifdef CONFIG_OMAP2_DSS_VENC
4637 +#ifdef CONFIG_OMAP2_DSS_RFBI
4640 + if (cpu_is_omap34xx()) {
4641 +#ifdef CONFIG_OMAP2_DSS_DSI
4644 +#ifdef CONFIG_OMAP2_DSS_SDI
4651 + /* these should be removed at some point */
4652 + c = core.dss_ick->usecount;
4654 + DSSERR("warning: dss_ick usecount %d, disabling\n", c);
4656 + clk_disable(core.dss_ick);
4659 + c = core.dss1_fck->usecount;
4661 + DSSERR("warning: dss1_fck usecount %d, disabling\n", c);
4663 + clk_disable(core.dss1_fck);
4666 + c = core.dss2_fck->usecount;
4668 + DSSERR("warning: dss2_fck usecount %d, disabling\n", c);
4670 + clk_disable(core.dss2_fck);
4673 + c = core.dss_54m_fck->usecount;
4675 + DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c);
4677 + clk_disable(core.dss_54m_fck);
4680 + if (core.dss_96m_fck) {
4681 + c = core.dss_96m_fck->usecount;
4683 + DSSERR("warning: dss_96m_fck usecount %d, disabling\n",
4686 + clk_disable(core.dss_96m_fck);
4692 + dss_uninit_overlays(pdev);
4693 + dss_uninit_overlay_managers(pdev);
4695 + for (i = 0; i < pdata->num_devices; ++i)
4696 + omap_dss_unregister_device(pdata->devices[i]);
4701 +static void omap_dss_shutdown(struct platform_device *pdev)
4703 + DSSDBG("shutdown\n");
4706 +static int omap_dss_suspend(struct platform_device *pdev, pm_message_t state)
4708 + DSSDBG("suspend %d\n", state.event);
4710 + return dss_suspend_all_devices();
4713 +static int omap_dss_resume(struct platform_device *pdev)
4715 + DSSDBG("resume\n");
4717 + return dss_resume_all_devices();
4720 +static struct platform_driver omap_dss_driver = {
4721 + .probe = omap_dss_probe,
4722 + .remove = omap_dss_remove,
4723 + .shutdown = omap_dss_shutdown,
4724 + .suspend = omap_dss_suspend,
4725 + .resume = omap_dss_resume,
4727 + .name = "omapdss",
4728 + .owner = THIS_MODULE,
4733 +static int dss_bus_match(struct device *dev, struct device_driver *driver)
4735 + struct omap_dss_device *dssdev = to_dss_device(dev);
4737 + DSSDBG("bus_match. dev %s/%s, drv %s\n",
4738 + dev_name(dev), dssdev->driver_name, driver->name);
4740 + return strcmp(dssdev->driver_name, driver->name) == 0;
4743 +static ssize_t device_name_show(struct device *dev,
4744 + struct device_attribute *attr, char *buf)
4746 + struct omap_dss_device *dssdev = to_dss_device(dev);
4747 + return snprintf(buf, PAGE_SIZE, "%s\n",
4749 + dssdev->name : "");
4752 +static struct device_attribute default_dev_attrs[] = {
4753 + __ATTR(name, S_IRUGO, device_name_show, NULL),
4757 +static ssize_t driver_name_show(struct device_driver *drv, char *buf)
4759 + struct omap_dss_driver *dssdrv = to_dss_driver(drv);
4760 + return snprintf(buf, PAGE_SIZE, "%s\n",
4761 + dssdrv->driver.name ?
4762 + dssdrv->driver.name : "");
4764 +static struct driver_attribute default_drv_attrs[] = {
4765 + __ATTR(name, S_IRUGO, driver_name_show, NULL),
4769 +static struct bus_type dss_bus_type = {
4770 + .name = "omapdss",
4771 + .match = dss_bus_match,
4772 + .dev_attrs = default_dev_attrs,
4773 + .drv_attrs = default_drv_attrs,
4776 +static void dss_bus_release(struct device *dev)
4778 + DSSDBG("bus_release\n");
4781 +static struct device dss_bus = {
4782 + .release = dss_bus_release,
4785 +struct bus_type *dss_get_bus(void)
4787 + return &dss_bus_type;
4791 +static int dss_driver_probe(struct device *dev)
4794 + struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
4795 + struct omap_dss_device *dssdev = to_dss_device(dev);
4796 + struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
4799 + DSSDBG("driver_probe: dev %s/%s, drv %s\n",
4800 + dev_name(dev), dssdev->driver_name,
4801 + dssdrv->driver.name);
4803 + dss_init_device(core.pdev, dssdev);
4805 + /* skip this if the device is behind a ctrl */
4806 + if (!dssdev->panel.ctrl) {
4807 + force = pdata->default_device == dssdev;
4808 + dss_recheck_connections(dssdev, force);
4811 + r = dssdrv->probe(dssdev);
4814 + DSSERR("driver probe failed: %d\n", r);
4818 + DSSDBG("probe done for device %s\n", dev_name(dev));
4820 + dssdev->driver = dssdrv;
4825 +static int dss_driver_remove(struct device *dev)
4827 + struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
4828 + struct omap_dss_device *dssdev = to_dss_device(dev);
4830 + DSSDBG("driver_remove: dev %s/%s\n", dev_name(dev),
4831 + dssdev->driver_name);
4833 + dssdrv->remove(dssdev);
4835 + dss_uninit_device(core.pdev, dssdev);
4837 + dssdev->driver = NULL;
4842 +int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
4844 + dssdriver->driver.bus = &dss_bus_type;
4845 + dssdriver->driver.probe = dss_driver_probe;
4846 + dssdriver->driver.remove = dss_driver_remove;
4847 + return driver_register(&dssdriver->driver);
4849 +EXPORT_SYMBOL(omap_dss_register_driver);
4851 +void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver)
4853 + driver_unregister(&dssdriver->driver);
4855 +EXPORT_SYMBOL(omap_dss_unregister_driver);
4858 +static void reset_device(struct device *dev, int check)
4860 + u8 *dev_p = (u8 *)dev;
4861 + u8 *dev_end = dev_p + sizeof(*dev);
4862 + void *saved_pdata;
4864 + saved_pdata = dev->platform_data;
4867 + * Check if there is any other setting than platform_data
4868 + * in struct device; warn that these will be reset by our
4871 + dev->platform_data = NULL;
4872 + while (dev_p < dev_end) {
4874 + WARN("%s: struct device fields will be "
4882 + memset(dev, 0, sizeof(*dev));
4883 + dev->platform_data = saved_pdata;
4887 +static void omap_dss_dev_release(struct device *dev)
4889 + reset_device(dev, 0);
4892 +int omap_dss_register_device(struct omap_dss_device *dssdev)
4894 + static int dev_num;
4895 + static int panel_num;
4898 + WARN_ON(!dssdev->driver_name);
4900 + reset_device(&dssdev->dev, 1);
4901 + dssdev->dev.bus = &dss_bus_type;
4902 + dssdev->dev.parent = &dss_bus;
4903 + dssdev->dev.release = omap_dss_dev_release;
4904 + dev_set_name(&dssdev->dev, "display%d", dev_num++);
4905 + r = device_register(&dssdev->dev);
4909 + if (dssdev->ctrl.panel) {
4910 + struct omap_dss_device *panel = dssdev->ctrl.panel;
4912 + panel->panel.ctrl = dssdev;
4914 + reset_device(&panel->dev, 1);
4915 + panel->dev.bus = &dss_bus_type;
4916 + panel->dev.parent = &dssdev->dev;
4917 + panel->dev.release = omap_dss_dev_release;
4918 + dev_set_name(&panel->dev, "panel%d", panel_num++);
4919 + r = device_register(&panel->dev);
4927 +void omap_dss_unregister_device(struct omap_dss_device *dssdev)
4929 + device_unregister(&dssdev->dev);
4931 + if (dssdev->ctrl.panel) {
4932 + struct omap_dss_device *panel = dssdev->ctrl.panel;
4933 + device_unregister(&panel->dev);
4938 +static int omap_dss_bus_register(void)
4942 + r = bus_register(&dss_bus_type);
4944 + DSSERR("bus register failed\n");
4948 + dev_set_name(&dss_bus, "omapdss");
4949 + r = device_register(&dss_bus);
4951 + DSSERR("bus driver register failed\n");
4952 + bus_unregister(&dss_bus_type);
4961 +#ifdef CONFIG_OMAP2_DSS_MODULE
4962 +static void omap_dss_bus_unregister(void)
4964 + device_unregister(&dss_bus);
4966 + bus_unregister(&dss_bus_type);
4969 +static int __init omap_dss_init(void)
4973 + r = omap_dss_bus_register();
4977 + r = platform_driver_register(&omap_dss_driver);
4979 + omap_dss_bus_unregister();
4986 +static void __exit omap_dss_exit(void)
4988 + platform_driver_unregister(&omap_dss_driver);
4990 + omap_dss_bus_unregister();
4993 +module_init(omap_dss_init);
4994 +module_exit(omap_dss_exit);
4996 +static int __init omap_dss_init(void)
4998 + return omap_dss_bus_register();
5001 +static int __init omap_dss_init2(void)
5003 + return platform_driver_register(&omap_dss_driver);
5006 +core_initcall(omap_dss_init);
5007 +device_initcall(omap_dss_init2);
5010 +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
5011 +MODULE_DESCRIPTION("OMAP2/3 Display Subsystem");
5012 +MODULE_LICENSE("GPL v2");
5014 diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
5015 new file mode 100644
5016 index 0000000..d648475
5018 +++ b/drivers/video/omap2/dss/dispc.c
5021 + * linux/drivers/video/omap2/dss/dispc.c
5023 + * Copyright (C) 2009 Nokia Corporation
5024 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
5026 + * Some code and ideas taken from drivers/video/omap/ driver
5029 + * This program is free software; you can redistribute it and/or modify it
5030 + * under the terms of the GNU General Public License version 2 as published by
5031 + * the Free Software Foundation.
5033 + * This program is distributed in the hope that it will be useful, but WITHOUT
5034 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5035 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
5038 + * You should have received a copy of the GNU General Public License along with
5039 + * this program. If not, see <http://www.gnu.org/licenses/>.
5042 +#define DSS_SUBSYS_NAME "DISPC"
5044 +#include <linux/kernel.h>
5045 +#include <linux/dma-mapping.h>
5046 +#include <linux/vmalloc.h>
5047 +#include <linux/clk.h>
5048 +#include <linux/io.h>
5049 +#include <linux/jiffies.h>
5050 +#include <linux/seq_file.h>
5051 +#include <linux/delay.h>
5052 +#include <linux/workqueue.h>
5054 +#include <mach/sram.h>
5055 +#include <mach/board.h>
5056 +#include <mach/clock.h>
5058 +#include <mach/display.h>
5063 +#define DISPC_BASE 0x48050400
5065 +#define DISPC_SZ_REGS SZ_1K
5067 +struct dispc_reg { u16 idx; };
5069 +#define DISPC_REG(idx) ((const struct dispc_reg) { idx })
5072 +#define DISPC_REVISION DISPC_REG(0x0000)
5073 +#define DISPC_SYSCONFIG DISPC_REG(0x0010)
5074 +#define DISPC_SYSSTATUS DISPC_REG(0x0014)
5075 +#define DISPC_IRQSTATUS DISPC_REG(0x0018)
5076 +#define DISPC_IRQENABLE DISPC_REG(0x001C)
5077 +#define DISPC_CONTROL DISPC_REG(0x0040)
5078 +#define DISPC_CONFIG DISPC_REG(0x0044)
5079 +#define DISPC_CAPABLE DISPC_REG(0x0048)
5080 +#define DISPC_DEFAULT_COLOR0 DISPC_REG(0x004C)
5081 +#define DISPC_DEFAULT_COLOR1 DISPC_REG(0x0050)
5082 +#define DISPC_TRANS_COLOR0 DISPC_REG(0x0054)
5083 +#define DISPC_TRANS_COLOR1 DISPC_REG(0x0058)
5084 +#define DISPC_LINE_STATUS DISPC_REG(0x005C)
5085 +#define DISPC_LINE_NUMBER DISPC_REG(0x0060)
5086 +#define DISPC_TIMING_H DISPC_REG(0x0064)
5087 +#define DISPC_TIMING_V DISPC_REG(0x0068)
5088 +#define DISPC_POL_FREQ DISPC_REG(0x006C)
5089 +#define DISPC_DIVISOR DISPC_REG(0x0070)
5090 +#define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074)
5091 +#define DISPC_SIZE_DIG DISPC_REG(0x0078)
5092 +#define DISPC_SIZE_LCD DISPC_REG(0x007C)
5094 +/* DISPC GFX plane */
5095 +#define DISPC_GFX_BA0 DISPC_REG(0x0080)
5096 +#define DISPC_GFX_BA1 DISPC_REG(0x0084)
5097 +#define DISPC_GFX_POSITION DISPC_REG(0x0088)
5098 +#define DISPC_GFX_SIZE DISPC_REG(0x008C)
5099 +#define DISPC_GFX_ATTRIBUTES DISPC_REG(0x00A0)
5100 +#define DISPC_GFX_FIFO_THRESHOLD DISPC_REG(0x00A4)
5101 +#define DISPC_GFX_FIFO_SIZE_STATUS DISPC_REG(0x00A8)
5102 +#define DISPC_GFX_ROW_INC DISPC_REG(0x00AC)
5103 +#define DISPC_GFX_PIXEL_INC DISPC_REG(0x00B0)
5104 +#define DISPC_GFX_WINDOW_SKIP DISPC_REG(0x00B4)
5105 +#define DISPC_GFX_TABLE_BA DISPC_REG(0x00B8)
5107 +#define DISPC_DATA_CYCLE1 DISPC_REG(0x01D4)
5108 +#define DISPC_DATA_CYCLE2 DISPC_REG(0x01D8)
5109 +#define DISPC_DATA_CYCLE3 DISPC_REG(0x01DC)
5111 +#define DISPC_CPR_COEF_R DISPC_REG(0x0220)
5112 +#define DISPC_CPR_COEF_G DISPC_REG(0x0224)
5113 +#define DISPC_CPR_COEF_B DISPC_REG(0x0228)
5115 +#define DISPC_GFX_PRELOAD DISPC_REG(0x022C)
5117 +/* DISPC Video plane, n = 0 for VID1 and n = 1 for VID2 */
5118 +#define DISPC_VID_REG(n, idx) DISPC_REG(0x00BC + (n)*0x90 + idx)
5120 +#define DISPC_VID_BA0(n) DISPC_VID_REG(n, 0x0000)
5121 +#define DISPC_VID_BA1(n) DISPC_VID_REG(n, 0x0004)
5122 +#define DISPC_VID_POSITION(n) DISPC_VID_REG(n, 0x0008)
5123 +#define DISPC_VID_SIZE(n) DISPC_VID_REG(n, 0x000C)
5124 +#define DISPC_VID_ATTRIBUTES(n) DISPC_VID_REG(n, 0x0010)
5125 +#define DISPC_VID_FIFO_THRESHOLD(n) DISPC_VID_REG(n, 0x0014)
5126 +#define DISPC_VID_FIFO_SIZE_STATUS(n) DISPC_VID_REG(n, 0x0018)
5127 +#define DISPC_VID_ROW_INC(n) DISPC_VID_REG(n, 0x001C)
5128 +#define DISPC_VID_PIXEL_INC(n) DISPC_VID_REG(n, 0x0020)
5129 +#define DISPC_VID_FIR(n) DISPC_VID_REG(n, 0x0024)
5130 +#define DISPC_VID_PICTURE_SIZE(n) DISPC_VID_REG(n, 0x0028)
5131 +#define DISPC_VID_ACCU0(n) DISPC_VID_REG(n, 0x002C)
5132 +#define DISPC_VID_ACCU1(n) DISPC_VID_REG(n, 0x0030)
5134 +/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
5135 +#define DISPC_VID_FIR_COEF_H(n, i) DISPC_REG(0x00F0 + (n)*0x90 + (i)*0x8)
5136 +/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
5137 +#define DISPC_VID_FIR_COEF_HV(n, i) DISPC_REG(0x00F4 + (n)*0x90 + (i)*0x8)
5138 +/* coef index i = {0, 1, 2, 3, 4} */
5139 +#define DISPC_VID_CONV_COEF(n, i) DISPC_REG(0x0130 + (n)*0x90 + (i)*0x4)
5140 +/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
5141 +#define DISPC_VID_FIR_COEF_V(n, i) DISPC_REG(0x01E0 + (n)*0x20 + (i)*0x4)
5143 +#define DISPC_VID_PRELOAD(n) DISPC_REG(0x230 + (n)*0x04)
5146 +#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
5147 + DISPC_IRQ_OCP_ERR | \
5148 + DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
5149 + DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
5150 + DISPC_IRQ_SYNC_LOST | \
5151 + DISPC_IRQ_SYNC_LOST_DIGIT)
5153 +#define DISPC_MAX_NR_ISRS 8
5155 +struct omap_dispc_isr_data {
5156 + omap_dispc_isr_t isr;
5161 +#define REG_GET(idx, start, end) \
5162 + FLD_GET(dispc_read_reg(idx), start, end)
5164 +#define REG_FLD_MOD(idx, val, start, end) \
5165 + dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
5167 +static const struct dispc_reg dispc_reg_att[] = { DISPC_GFX_ATTRIBUTES,
5168 + DISPC_VID_ATTRIBUTES(0),
5169 + DISPC_VID_ATTRIBUTES(1) };
5172 + void __iomem *base;
5174 + struct clk *dpll4_m4_ck;
5176 + unsigned long cache_req_pck;
5177 + unsigned long cache_prate;
5178 + struct dispc_clock_info cache_cinfo;
5182 + spinlock_t irq_lock;
5183 + u32 irq_error_mask;
5184 + struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
5186 + struct work_struct error_work;
5188 + u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
5191 +static void _omap_dispc_set_irqs(void);
5193 +static inline void dispc_write_reg(const struct dispc_reg idx, u32 val)
5195 + __raw_writel(val, dispc.base + idx.idx);
5198 +static inline u32 dispc_read_reg(const struct dispc_reg idx)
5200 + return __raw_readl(dispc.base + idx.idx);
5204 + dispc.ctx[(DISPC_##reg).idx / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
5206 + dispc_write_reg(DISPC_##reg, dispc.ctx[(DISPC_##reg).idx / sizeof(u32)])
5208 +void dispc_save_context(void)
5210 + if (cpu_is_omap24xx())
5217 + SR(DEFAULT_COLOR0);
5218 + SR(DEFAULT_COLOR1);
5234 + SR(GFX_ATTRIBUTES);
5235 + SR(GFX_FIFO_THRESHOLD);
5237 + SR(GFX_PIXEL_INC);
5238 + SR(GFX_WINDOW_SKIP);
5254 + SR(VID_POSITION(0));
5256 + SR(VID_ATTRIBUTES(0));
5257 + SR(VID_FIFO_THRESHOLD(0));
5258 + SR(VID_ROW_INC(0));
5259 + SR(VID_PIXEL_INC(0));
5261 + SR(VID_PICTURE_SIZE(0));
5265 + SR(VID_FIR_COEF_H(0, 0));
5266 + SR(VID_FIR_COEF_H(0, 1));
5267 + SR(VID_FIR_COEF_H(0, 2));
5268 + SR(VID_FIR_COEF_H(0, 3));
5269 + SR(VID_FIR_COEF_H(0, 4));
5270 + SR(VID_FIR_COEF_H(0, 5));
5271 + SR(VID_FIR_COEF_H(0, 6));
5272 + SR(VID_FIR_COEF_H(0, 7));
5274 + SR(VID_FIR_COEF_HV(0, 0));
5275 + SR(VID_FIR_COEF_HV(0, 1));
5276 + SR(VID_FIR_COEF_HV(0, 2));
5277 + SR(VID_FIR_COEF_HV(0, 3));
5278 + SR(VID_FIR_COEF_HV(0, 4));
5279 + SR(VID_FIR_COEF_HV(0, 5));
5280 + SR(VID_FIR_COEF_HV(0, 6));
5281 + SR(VID_FIR_COEF_HV(0, 7));
5283 + SR(VID_CONV_COEF(0, 0));
5284 + SR(VID_CONV_COEF(0, 1));
5285 + SR(VID_CONV_COEF(0, 2));
5286 + SR(VID_CONV_COEF(0, 3));
5287 + SR(VID_CONV_COEF(0, 4));
5289 + SR(VID_FIR_COEF_V(0, 0));
5290 + SR(VID_FIR_COEF_V(0, 1));
5291 + SR(VID_FIR_COEF_V(0, 2));
5292 + SR(VID_FIR_COEF_V(0, 3));
5293 + SR(VID_FIR_COEF_V(0, 4));
5294 + SR(VID_FIR_COEF_V(0, 5));
5295 + SR(VID_FIR_COEF_V(0, 6));
5296 + SR(VID_FIR_COEF_V(0, 7));
5298 + SR(VID_PRELOAD(0));
5303 + SR(VID_POSITION(1));
5305 + SR(VID_ATTRIBUTES(1));
5306 + SR(VID_FIFO_THRESHOLD(1));
5307 + SR(VID_ROW_INC(1));
5308 + SR(VID_PIXEL_INC(1));
5310 + SR(VID_PICTURE_SIZE(1));
5314 + SR(VID_FIR_COEF_H(1, 0));
5315 + SR(VID_FIR_COEF_H(1, 1));
5316 + SR(VID_FIR_COEF_H(1, 2));
5317 + SR(VID_FIR_COEF_H(1, 3));
5318 + SR(VID_FIR_COEF_H(1, 4));
5319 + SR(VID_FIR_COEF_H(1, 5));
5320 + SR(VID_FIR_COEF_H(1, 6));
5321 + SR(VID_FIR_COEF_H(1, 7));
5323 + SR(VID_FIR_COEF_HV(1, 0));
5324 + SR(VID_FIR_COEF_HV(1, 1));
5325 + SR(VID_FIR_COEF_HV(1, 2));
5326 + SR(VID_FIR_COEF_HV(1, 3));
5327 + SR(VID_FIR_COEF_HV(1, 4));
5328 + SR(VID_FIR_COEF_HV(1, 5));
5329 + SR(VID_FIR_COEF_HV(1, 6));
5330 + SR(VID_FIR_COEF_HV(1, 7));
5332 + SR(VID_CONV_COEF(1, 0));
5333 + SR(VID_CONV_COEF(1, 1));
5334 + SR(VID_CONV_COEF(1, 2));
5335 + SR(VID_CONV_COEF(1, 3));
5336 + SR(VID_CONV_COEF(1, 4));
5338 + SR(VID_FIR_COEF_V(1, 0));
5339 + SR(VID_FIR_COEF_V(1, 1));
5340 + SR(VID_FIR_COEF_V(1, 2));
5341 + SR(VID_FIR_COEF_V(1, 3));
5342 + SR(VID_FIR_COEF_V(1, 4));
5343 + SR(VID_FIR_COEF_V(1, 5));
5344 + SR(VID_FIR_COEF_V(1, 6));
5345 + SR(VID_FIR_COEF_V(1, 7));
5347 + SR(VID_PRELOAD(1));
5350 +void dispc_restore_context(void)
5356 + RR(DEFAULT_COLOR0);
5357 + RR(DEFAULT_COLOR1);
5373 + RR(GFX_ATTRIBUTES);
5374 + RR(GFX_FIFO_THRESHOLD);
5376 + RR(GFX_PIXEL_INC);
5377 + RR(GFX_WINDOW_SKIP);
5393 + RR(VID_POSITION(0));
5395 + RR(VID_ATTRIBUTES(0));
5396 + RR(VID_FIFO_THRESHOLD(0));
5397 + RR(VID_ROW_INC(0));
5398 + RR(VID_PIXEL_INC(0));
5400 + RR(VID_PICTURE_SIZE(0));
5404 + RR(VID_FIR_COEF_H(0, 0));
5405 + RR(VID_FIR_COEF_H(0, 1));
5406 + RR(VID_FIR_COEF_H(0, 2));
5407 + RR(VID_FIR_COEF_H(0, 3));
5408 + RR(VID_FIR_COEF_H(0, 4));
5409 + RR(VID_FIR_COEF_H(0, 5));
5410 + RR(VID_FIR_COEF_H(0, 6));
5411 + RR(VID_FIR_COEF_H(0, 7));
5413 + RR(VID_FIR_COEF_HV(0, 0));
5414 + RR(VID_FIR_COEF_HV(0, 1));
5415 + RR(VID_FIR_COEF_HV(0, 2));
5416 + RR(VID_FIR_COEF_HV(0, 3));
5417 + RR(VID_FIR_COEF_HV(0, 4));
5418 + RR(VID_FIR_COEF_HV(0, 5));
5419 + RR(VID_FIR_COEF_HV(0, 6));
5420 + RR(VID_FIR_COEF_HV(0, 7));
5422 + RR(VID_CONV_COEF(0, 0));
5423 + RR(VID_CONV_COEF(0, 1));
5424 + RR(VID_CONV_COEF(0, 2));
5425 + RR(VID_CONV_COEF(0, 3));
5426 + RR(VID_CONV_COEF(0, 4));
5428 + RR(VID_FIR_COEF_V(0, 0));
5429 + RR(VID_FIR_COEF_V(0, 1));
5430 + RR(VID_FIR_COEF_V(0, 2));
5431 + RR(VID_FIR_COEF_V(0, 3));
5432 + RR(VID_FIR_COEF_V(0, 4));
5433 + RR(VID_FIR_COEF_V(0, 5));
5434 + RR(VID_FIR_COEF_V(0, 6));
5435 + RR(VID_FIR_COEF_V(0, 7));
5437 + RR(VID_PRELOAD(0));
5442 + RR(VID_POSITION(1));
5444 + RR(VID_ATTRIBUTES(1));
5445 + RR(VID_FIFO_THRESHOLD(1));
5446 + RR(VID_ROW_INC(1));
5447 + RR(VID_PIXEL_INC(1));
5449 + RR(VID_PICTURE_SIZE(1));
5453 + RR(VID_FIR_COEF_H(1, 0));
5454 + RR(VID_FIR_COEF_H(1, 1));
5455 + RR(VID_FIR_COEF_H(1, 2));
5456 + RR(VID_FIR_COEF_H(1, 3));
5457 + RR(VID_FIR_COEF_H(1, 4));
5458 + RR(VID_FIR_COEF_H(1, 5));
5459 + RR(VID_FIR_COEF_H(1, 6));
5460 + RR(VID_FIR_COEF_H(1, 7));
5462 + RR(VID_FIR_COEF_HV(1, 0));
5463 + RR(VID_FIR_COEF_HV(1, 1));
5464 + RR(VID_FIR_COEF_HV(1, 2));
5465 + RR(VID_FIR_COEF_HV(1, 3));
5466 + RR(VID_FIR_COEF_HV(1, 4));
5467 + RR(VID_FIR_COEF_HV(1, 5));
5468 + RR(VID_FIR_COEF_HV(1, 6));
5469 + RR(VID_FIR_COEF_HV(1, 7));
5471 + RR(VID_CONV_COEF(1, 0));
5472 + RR(VID_CONV_COEF(1, 1));
5473 + RR(VID_CONV_COEF(1, 2));
5474 + RR(VID_CONV_COEF(1, 3));
5475 + RR(VID_CONV_COEF(1, 4));
5477 + RR(VID_FIR_COEF_V(1, 0));
5478 + RR(VID_FIR_COEF_V(1, 1));
5479 + RR(VID_FIR_COEF_V(1, 2));
5480 + RR(VID_FIR_COEF_V(1, 3));
5481 + RR(VID_FIR_COEF_V(1, 4));
5482 + RR(VID_FIR_COEF_V(1, 5));
5483 + RR(VID_FIR_COEF_V(1, 6));
5484 + RR(VID_FIR_COEF_V(1, 7));
5486 + RR(VID_PRELOAD(1));
5488 + /* enable last, because LCD & DIGIT enable are here */
5495 +static inline void enable_clocks(bool enable)
5498 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
5500 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
5503 +bool dispc_go_busy(enum omap_channel channel)
5507 + if (channel == OMAP_DSS_CHANNEL_LCD)
5508 + bit = 5; /* GOLCD */
5510 + bit = 6; /* GODIGIT */
5512 + return REG_GET(DISPC_CONTROL, bit, bit) == 1;
5515 +void dispc_go(enum omap_channel channel)
5521 + if (channel == OMAP_DSS_CHANNEL_LCD)
5522 + bit = 0; /* LCDENABLE */
5524 + bit = 1; /* DIGITALENABLE */
5526 + /* if the channel is not enabled, we don't need GO */
5527 + if (REG_GET(DISPC_CONTROL, bit, bit) == 0)
5530 + if (channel == OMAP_DSS_CHANNEL_LCD)
5531 + bit = 5; /* GOLCD */
5533 + bit = 6; /* GODIGIT */
5535 + if (REG_GET(DISPC_CONTROL, bit, bit) == 1) {
5536 + DSSERR("GO bit not down for channel %d\n", channel);
5540 + DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT");
5542 + REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
5547 +static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
5549 + BUG_ON(plane == OMAP_DSS_GFX);
5551 + dispc_write_reg(DISPC_VID_FIR_COEF_H(plane-1, reg), value);
5554 +static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
5556 + BUG_ON(plane == OMAP_DSS_GFX);
5558 + dispc_write_reg(DISPC_VID_FIR_COEF_HV(plane-1, reg), value);
5561 +static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
5563 + BUG_ON(plane == OMAP_DSS_GFX);
5565 + dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
5568 +static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
5569 + int vscaleup, int five_taps)
5571 + /* Coefficients for horizontal up-sampling */
5572 + static const u32 coef_hup[8] = {
5583 + /* Coefficients for horizontal down-sampling */
5584 + static const u32 coef_hdown[8] = {
5595 + /* Coefficients for horizontal and vertical up-sampling */
5596 + static const u32 coef_hvup[2][8] = {
5619 + /* Coefficients for horizontal and vertical down-sampling */
5620 + static const u32 coef_hvdown[2][8] = {
5643 + /* Coefficients for vertical up-sampling */
5644 + static const u32 coef_vup[8] = {
5656 + /* Coefficients for vertical down-sampling */
5657 + static const u32 coef_vdown[8] = {
5668 + const u32 *h_coef;
5669 + const u32 *hv_coef;
5670 + const u32 *hv_coef_mod;
5671 + const u32 *v_coef;
5675 + h_coef = coef_hup;
5677 + h_coef = coef_hdown;
5680 + hv_coef = coef_hvup[five_taps];
5681 + v_coef = coef_vup;
5684 + hv_coef_mod = NULL;
5686 + hv_coef_mod = coef_hvdown[five_taps];
5688 + hv_coef = coef_hvdown[five_taps];
5689 + v_coef = coef_vdown;
5692 + hv_coef_mod = coef_hvup[five_taps];
5694 + hv_coef_mod = NULL;
5697 + for (i = 0; i < 8; i++) {
5704 + if (hv_coef_mod) {
5706 + hv |= (hv_coef_mod[i] & 0xff);
5709 + _dispc_write_firh_reg(plane, i, h);
5710 + _dispc_write_firhv_reg(plane, i, hv);
5716 + for (i = 0; i < 8; i++) {
5719 + _dispc_write_firv_reg(plane, i, v);
5723 +static void _dispc_setup_color_conv_coef(void)
5725 + const struct color_conv_coef {
5726 + int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
5728 + } ctbl_bt601_5 = {
5729 + 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
5732 + const struct color_conv_coef *ct;
5734 +#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
5736 + ct = &ctbl_bt601_5;
5738 + dispc_write_reg(DISPC_VID_CONV_COEF(0, 0), CVAL(ct->rcr, ct->ry));
5739 + dispc_write_reg(DISPC_VID_CONV_COEF(0, 1), CVAL(ct->gy, ct->rcb));
5740 + dispc_write_reg(DISPC_VID_CONV_COEF(0, 2), CVAL(ct->gcb, ct->gcr));
5741 + dispc_write_reg(DISPC_VID_CONV_COEF(0, 3), CVAL(ct->bcr, ct->by));
5742 + dispc_write_reg(DISPC_VID_CONV_COEF(0, 4), CVAL(0, ct->bcb));
5744 + dispc_write_reg(DISPC_VID_CONV_COEF(1, 0), CVAL(ct->rcr, ct->ry));
5745 + dispc_write_reg(DISPC_VID_CONV_COEF(1, 1), CVAL(ct->gy, ct->rcb));
5746 + dispc_write_reg(DISPC_VID_CONV_COEF(1, 2), CVAL(ct->gcb, ct->gcr));
5747 + dispc_write_reg(DISPC_VID_CONV_COEF(1, 3), CVAL(ct->bcr, ct->by));
5748 + dispc_write_reg(DISPC_VID_CONV_COEF(1, 4), CVAL(0, ct->bcb));
5752 + REG_FLD_MOD(DISPC_VID_ATTRIBUTES(0), ct->full_range, 11, 11);
5753 + REG_FLD_MOD(DISPC_VID_ATTRIBUTES(1), ct->full_range, 11, 11);
5757 +static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
5759 + const struct dispc_reg ba0_reg[] = { DISPC_GFX_BA0,
5761 + DISPC_VID_BA0(1) };
5763 + dispc_write_reg(ba0_reg[plane], paddr);
5766 +static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr)
5768 + const struct dispc_reg ba1_reg[] = { DISPC_GFX_BA1,
5770 + DISPC_VID_BA1(1) };
5772 + dispc_write_reg(ba1_reg[plane], paddr);
5775 +static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
5777 + const struct dispc_reg pos_reg[] = { DISPC_GFX_POSITION,
5778 + DISPC_VID_POSITION(0),
5779 + DISPC_VID_POSITION(1) };
5781 + u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
5782 + dispc_write_reg(pos_reg[plane], val);
5785 +static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
5787 + const struct dispc_reg siz_reg[] = { DISPC_GFX_SIZE,
5788 + DISPC_VID_PICTURE_SIZE(0),
5789 + DISPC_VID_PICTURE_SIZE(1) };
5790 + u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
5791 + dispc_write_reg(siz_reg[plane], val);
5794 +static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
5797 + const struct dispc_reg vsi_reg[] = { DISPC_VID_SIZE(0),
5798 + DISPC_VID_SIZE(1) };
5800 + BUG_ON(plane == OMAP_DSS_GFX);
5802 + val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
5803 + dispc_write_reg(vsi_reg[plane-1], val);
5806 +static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
5809 + BUG_ON(plane == OMAP_DSS_VIDEO1);
5811 + if (plane == OMAP_DSS_GFX)
5812 + REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
5813 + else if (plane == OMAP_DSS_VIDEO2)
5814 + REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16);
5817 +static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
5819 + const struct dispc_reg ri_reg[] = { DISPC_GFX_PIXEL_INC,
5820 + DISPC_VID_PIXEL_INC(0),
5821 + DISPC_VID_PIXEL_INC(1) };
5823 + dispc_write_reg(ri_reg[plane], inc);
5826 +static void _dispc_set_row_inc(enum omap_plane plane, s32 inc)
5828 + const struct dispc_reg ri_reg[] = { DISPC_GFX_ROW_INC,
5829 + DISPC_VID_ROW_INC(0),
5830 + DISPC_VID_ROW_INC(1) };
5832 + dispc_write_reg(ri_reg[plane], inc);
5835 +static void _dispc_set_color_mode(enum omap_plane plane,
5836 + enum omap_color_mode color_mode)
5840 + switch (color_mode) {
5841 + case OMAP_DSS_COLOR_CLUT1:
5843 + case OMAP_DSS_COLOR_CLUT2:
5845 + case OMAP_DSS_COLOR_CLUT4:
5847 + case OMAP_DSS_COLOR_CLUT8:
5849 + case OMAP_DSS_COLOR_RGB12U:
5851 + case OMAP_DSS_COLOR_ARGB16:
5853 + case OMAP_DSS_COLOR_RGB16:
5855 + case OMAP_DSS_COLOR_RGB24U:
5857 + case OMAP_DSS_COLOR_RGB24P:
5859 + case OMAP_DSS_COLOR_YUV2:
5861 + case OMAP_DSS_COLOR_UYVY:
5863 + case OMAP_DSS_COLOR_ARGB32:
5865 + case OMAP_DSS_COLOR_RGBA32:
5867 + case OMAP_DSS_COLOR_RGBX32:
5873 + REG_FLD_MOD(dispc_reg_att[plane], m, 4, 1);
5876 +static void _dispc_set_channel_out(enum omap_plane plane,
5877 + enum omap_channel channel)
5883 + case OMAP_DSS_GFX:
5886 + case OMAP_DSS_VIDEO1:
5887 + case OMAP_DSS_VIDEO2:
5895 + val = dispc_read_reg(dispc_reg_att[plane]);
5896 + val = FLD_MOD(val, channel, shift, shift);
5897 + dispc_write_reg(dispc_reg_att[plane], val);
5900 +void dispc_set_burst_size(enum omap_plane plane,
5901 + enum omap_burst_size burst_size)
5909 + case OMAP_DSS_GFX:
5912 + case OMAP_DSS_VIDEO1:
5913 + case OMAP_DSS_VIDEO2:
5921 + val = dispc_read_reg(dispc_reg_att[plane]);
5922 + val = FLD_MOD(val, burst_size, shift+1, shift);
5923 + dispc_write_reg(dispc_reg_att[plane], val);
5928 +static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
5932 + BUG_ON(plane == OMAP_DSS_GFX);
5934 + val = dispc_read_reg(dispc_reg_att[plane]);
5935 + val = FLD_MOD(val, enable, 9, 9);
5936 + dispc_write_reg(dispc_reg_att[plane], val);
5939 +void dispc_enable_replication(enum omap_plane plane, bool enable)
5943 + if (plane == OMAP_DSS_GFX)
5949 + REG_FLD_MOD(dispc_reg_att[plane], enable, bit, bit);
5953 +void dispc_set_lcd_size(u16 width, u16 height)
5956 + BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
5957 + val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
5959 + dispc_write_reg(DISPC_SIZE_LCD, val);
5963 +void dispc_set_digit_size(u16 width, u16 height)
5966 + BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
5967 + val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
5969 + dispc_write_reg(DISPC_SIZE_DIG, val);
5973 +static void dispc_read_plane_fifo_sizes(void)
5975 + const struct dispc_reg fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
5976 + DISPC_VID_FIFO_SIZE_STATUS(0),
5977 + DISPC_VID_FIFO_SIZE_STATUS(1) };
5983 + for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
5984 + if (cpu_is_omap24xx())
5985 + size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 8, 0);
5986 + else if (cpu_is_omap34xx())
5987 + size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 10, 0);
5991 + dispc.fifo_size[plane] = size;
5997 +u32 dispc_get_plane_fifo_size(enum omap_plane plane)
5999 + return dispc.fifo_size[plane];
6002 +void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
6004 + const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
6005 + DISPC_VID_FIFO_THRESHOLD(0),
6006 + DISPC_VID_FIFO_THRESHOLD(1) };
6009 + DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
6011 + REG_GET(ftrs_reg[plane], 11, 0),
6012 + REG_GET(ftrs_reg[plane], 27, 16),
6015 + if (cpu_is_omap24xx())
6016 + dispc_write_reg(ftrs_reg[plane],
6017 + FLD_VAL(high, 24, 16) | FLD_VAL(low, 8, 0));
6019 + dispc_write_reg(ftrs_reg[plane],
6020 + FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0));
6025 +void dispc_enable_fifomerge(bool enable)
6029 + DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
6030 + REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
6035 +static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
6038 + const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0),
6039 + DISPC_VID_FIR(1) };
6041 + BUG_ON(plane == OMAP_DSS_GFX);
6043 + if (cpu_is_omap24xx())
6044 + val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0);
6046 + val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
6047 + dispc_write_reg(fir_reg[plane-1], val);
6050 +static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
6053 + const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
6054 + DISPC_VID_ACCU0(1) };
6056 + BUG_ON(plane == OMAP_DSS_GFX);
6058 + val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
6059 + dispc_write_reg(ac0_reg[plane-1], val);
6062 +static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
6065 + const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
6066 + DISPC_VID_ACCU1(1) };
6068 + BUG_ON(plane == OMAP_DSS_GFX);
6070 + val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
6071 + dispc_write_reg(ac1_reg[plane-1], val);
6075 +static void _dispc_set_scaling(enum omap_plane plane,
6076 + u16 orig_width, u16 orig_height,
6077 + u16 out_width, u16 out_height,
6078 + bool ilace, bool five_taps,
6083 + int hscaleup, vscaleup;
6088 + BUG_ON(plane == OMAP_DSS_GFX);
6090 + hscaleup = orig_width <= out_width;
6091 + vscaleup = orig_height <= out_height;
6093 + _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps);
6095 + if (!orig_width || orig_width == out_width)
6098 + fir_hinc = 1024 * orig_width / out_width;
6100 + if (!orig_height || orig_height == out_height)
6103 + fir_vinc = 1024 * orig_height / out_height;
6105 + _dispc_set_fir(plane, fir_hinc, fir_vinc);
6107 + l = dispc_read_reg(dispc_reg_att[plane]);
6108 + l &= ~((0x0f << 5) | (0x3 << 21));
6110 + l |= fir_hinc ? (1 << 5) : 0;
6111 + l |= fir_vinc ? (1 << 6) : 0;
6113 + l |= hscaleup ? 0 : (1 << 7);
6114 + l |= vscaleup ? 0 : (1 << 8);
6116 + l |= five_taps ? (1 << 21) : 0;
6117 + l |= five_taps ? (1 << 22) : 0;
6119 + dispc_write_reg(dispc_reg_att[plane], l);
6122 + * field 0 = even field = bottom field
6123 + * field 1 = odd field = top field
6125 + if (ilace && !fieldmode) {
6127 + accu0 = (fir_vinc / 2) & 0x3ff;
6128 + if (accu0 >= 1024/2) {
6134 + _dispc_set_vid_accu0(plane, 0, accu0);
6135 + _dispc_set_vid_accu1(plane, 0, accu1);
6138 +static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
6139 + bool mirroring, enum omap_color_mode color_mode)
6141 + if (color_mode == OMAP_DSS_COLOR_YUV2 ||
6142 + color_mode == OMAP_DSS_COLOR_UYVY) {
6146 + switch (rotation) {
6161 + switch (rotation) {
6177 + REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
6179 + if (rotation == 1 || rotation == 3)
6180 + REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
6182 + REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
6184 + REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
6185 + REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
6189 +static s32 pixinc(int pixels, u8 ps)
6193 + else if (pixels > 1)
6194 + return 1 + (pixels - 1) * ps;
6195 + else if (pixels < 0)
6196 + return 1 - (-pixels + 1) * ps;
6201 +static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
6203 + u16 width, u16 height,
6204 + enum omap_color_mode color_mode, bool fieldmode,
6205 + unsigned int field_offset,
6206 + unsigned *offset0, unsigned *offset1,
6207 + s32 *row_inc, s32 *pix_inc)
6211 + switch (color_mode) {
6212 + case OMAP_DSS_COLOR_RGB16:
6213 + case OMAP_DSS_COLOR_ARGB16:
6217 + case OMAP_DSS_COLOR_RGB24P:
6221 + case OMAP_DSS_COLOR_RGB24U:
6222 + case OMAP_DSS_COLOR_ARGB32:
6223 + case OMAP_DSS_COLOR_RGBA32:
6224 + case OMAP_DSS_COLOR_RGBX32:
6225 + case OMAP_DSS_COLOR_YUV2:
6226 + case OMAP_DSS_COLOR_UYVY:
6235 + DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
6239 + * field 0 = even field = bottom field
6240 + * field 1 = odd field = top field
6242 + switch (rotation + mirror * 4) {
6246 + * If the pixel format is YUV or UYVY divide the width
6247 + * of the image by 2 for 0 and 180 degree rotation.
6249 + if (color_mode == OMAP_DSS_COLOR_YUV2 ||
6250 + color_mode == OMAP_DSS_COLOR_UYVY)
6251 + width = width >> 1;
6256 + *offset0 = field_offset * screen_width * ps;
6260 + *row_inc = pixinc(1 + (screen_width - width) +
6261 + (fieldmode ? screen_width : 0),
6263 + *pix_inc = pixinc(1, ps);
6268 + /* If the pixel format is YUV or UYVY divide the width
6269 + * of the image by 2 for 0 degree and 180 degree
6271 + if (color_mode == OMAP_DSS_COLOR_YUV2 ||
6272 + color_mode == OMAP_DSS_COLOR_UYVY)
6273 + width = width >> 1;
6278 + *offset0 = field_offset * screen_width * ps;
6281 + *row_inc = pixinc(1 - (screen_width + width) -
6282 + (fieldmode ? screen_width : 0),
6284 + *pix_inc = pixinc(1, ps);
6292 +static void calc_dma_rotation_offset(u8 rotation, bool mirror,
6294 + u16 width, u16 height,
6295 + enum omap_color_mode color_mode, bool fieldmode,
6296 + unsigned int field_offset,
6297 + unsigned *offset0, unsigned *offset1,
6298 + s32 *row_inc, s32 *pix_inc)
6303 + switch (color_mode) {
6304 + case OMAP_DSS_COLOR_RGB16:
6305 + case OMAP_DSS_COLOR_ARGB16:
6309 + case OMAP_DSS_COLOR_RGB24P:
6313 + case OMAP_DSS_COLOR_RGB24U:
6314 + case OMAP_DSS_COLOR_ARGB32:
6315 + case OMAP_DSS_COLOR_RGBA32:
6316 + case OMAP_DSS_COLOR_RGBX32:
6320 + case OMAP_DSS_COLOR_YUV2:
6321 + case OMAP_DSS_COLOR_UYVY:
6329 + DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
6332 + /* width & height are overlay sizes, convert to fb sizes */
6334 + if (rotation == 0 || rotation == 2) {
6343 + * field 0 = even field = bottom field
6344 + * field 1 = odd field = top field
6346 + switch (rotation + mirror * 4) {
6350 + *offset0 = *offset1 + field_offset * screen_width * ps;
6352 + *offset0 = *offset1;
6353 + *row_inc = pixinc(1 + (screen_width - fbw) +
6354 + (fieldmode ? screen_width : 0),
6356 + *pix_inc = pixinc(1, ps);
6359 + *offset1 = screen_width * (fbh - 1) * ps;
6361 + *offset0 = *offset1 + field_offset * ps;
6363 + *offset0 = *offset1;
6364 + *row_inc = pixinc(screen_width * (fbh - 1) + 1 +
6365 + (fieldmode ? 1 : 0), ps);
6366 + *pix_inc = pixinc(-screen_width, ps);
6369 + *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
6371 + *offset0 = *offset1 - field_offset * screen_width * ps;
6373 + *offset0 = *offset1;
6374 + *row_inc = pixinc(-1 -
6375 + (screen_width - fbw) -
6376 + (fieldmode ? screen_width : 0),
6378 + *pix_inc = pixinc(-1, ps);
6381 + *offset1 = (fbw - 1) * ps;
6383 + *offset0 = *offset1 - field_offset * ps;
6385 + *offset0 = *offset1;
6386 + *row_inc = pixinc(-screen_width * (fbh - 1) - 1 -
6387 + (fieldmode ? 1 : 0), ps);
6388 + *pix_inc = pixinc(screen_width, ps);
6393 + *offset1 = (fbw - 1) * ps;
6395 + *offset0 = *offset1 + field_offset * screen_width * ps;
6397 + *offset0 = *offset1;
6398 + *row_inc = pixinc(screen_width * 2 - 1 +
6399 + (fieldmode ? screen_width : 0),
6401 + *pix_inc = pixinc(-1, ps);
6407 + *offset0 = *offset1 + field_offset * ps;
6409 + *offset0 = *offset1;
6410 + *row_inc = pixinc(-screen_width * (fbh - 1) + 1 +
6411 + (fieldmode ? 1 : 0),
6413 + *pix_inc = pixinc(screen_width, ps);
6417 + *offset1 = screen_width * (fbh - 1) * ps;
6419 + *offset0 = *offset1 - field_offset * screen_width * ps;
6421 + *offset0 = *offset1;
6422 + *row_inc = pixinc(1 - screen_width * 2 -
6423 + (fieldmode ? screen_width : 0),
6425 + *pix_inc = pixinc(1, ps);
6429 + *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
6431 + *offset0 = *offset1 - field_offset * ps;
6433 + *offset0 = *offset1;
6434 + *row_inc = pixinc(screen_width * (fbh - 1) - 1 -
6435 + (fieldmode ? 1 : 0),
6437 + *pix_inc = pixinc(-screen_width, ps);
6445 +static unsigned long calc_fclk_five_taps(u16 width, u16 height,
6446 + u16 out_width, u16 out_height, enum omap_color_mode color_mode)
6449 + /* FIXME venc pclk? */
6450 + u64 tmp, pclk = dispc_pclk_rate();
6452 + if (height > out_height) {
6453 + /* FIXME get real display PPL */
6454 + unsigned int ppl = 800;
6456 + tmp = pclk * height * out_width;
6457 + do_div(tmp, 2 * out_height * ppl);
6460 + if (height > 2 * out_height && ppl != out_width) {
6461 + tmp = pclk * (height - 2 * out_height) * out_width;
6462 + do_div(tmp, 2 * out_height * (ppl - out_width));
6463 + fclk = max(fclk, (u32) tmp);
6467 + if (width > out_width) {
6468 + tmp = pclk * width;
6469 + do_div(tmp, out_width);
6470 + fclk = max(fclk, (u32) tmp);
6472 + if (color_mode == OMAP_DSS_COLOR_RGB24U)
6479 +static unsigned long calc_fclk(u16 width, u16 height,
6480 + u16 out_width, u16 out_height)
6482 + unsigned int hf, vf;
6485 + * FIXME how to determine the 'A' factor
6486 + * for the no downscaling case ?
6489 + if (width > 3 * out_width)
6491 + else if (width > 2 * out_width)
6493 + else if (width > out_width)
6498 + if (height > out_height)
6503 + /* FIXME venc pclk? */
6504 + return dispc_pclk_rate() * vf * hf;
6507 +void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
6510 + _dispc_set_channel_out(plane, channel_out);
6514 +static int _dispc_setup_plane(enum omap_plane plane,
6515 + u32 paddr, u16 screen_width,
6516 + u16 pos_x, u16 pos_y,
6517 + u16 width, u16 height,
6518 + u16 out_width, u16 out_height,
6519 + enum omap_color_mode color_mode,
6521 + enum omap_dss_rotation_type rotation_type,
6522 + u8 rotation, int mirror,
6525 + const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
6526 + bool five_taps = 0;
6527 + bool fieldmode = 0;
6529 + unsigned offset0, offset1;
6532 + u16 frame_height = height;
6533 + unsigned int field_offset = 0;
6538 + if (ilace && height == out_height)
6547 + DSSDBG("adjusting for ilace: height %d, pos_y %d, "
6548 + "out_height %d\n",
6549 + height, pos_y, out_height);
6552 + if (plane == OMAP_DSS_GFX) {
6553 + if (width != out_width || height != out_height)
6556 + switch (color_mode) {
6557 + case OMAP_DSS_COLOR_ARGB16:
6558 + case OMAP_DSS_COLOR_RGB16:
6559 + case OMAP_DSS_COLOR_RGB24P:
6560 + case OMAP_DSS_COLOR_RGB24U:
6561 + case OMAP_DSS_COLOR_ARGB32:
6562 + case OMAP_DSS_COLOR_RGBA32:
6563 + case OMAP_DSS_COLOR_RGBX32:
6572 + unsigned long fclk = 0;
6574 + if (out_width < width / maxdownscale ||
6575 + out_width > width * 8)
6578 + if (out_height < height / maxdownscale ||
6579 + out_height > height * 8)
6582 + switch (color_mode) {
6583 + case OMAP_DSS_COLOR_RGB16:
6584 + case OMAP_DSS_COLOR_RGB24P:
6585 + case OMAP_DSS_COLOR_RGB24U:
6586 + case OMAP_DSS_COLOR_RGBX32:
6589 + case OMAP_DSS_COLOR_ARGB16:
6590 + case OMAP_DSS_COLOR_ARGB32:
6591 + case OMAP_DSS_COLOR_RGBA32:
6592 + if (plane == OMAP_DSS_VIDEO1)
6596 + case OMAP_DSS_COLOR_YUV2:
6597 + case OMAP_DSS_COLOR_UYVY:
6605 + /* Must use 5-tap filter? */
6606 + five_taps = height > out_height * 2;
6609 + fclk = calc_fclk(width, height,
6610 + out_width, out_height);
6612 + /* Try 5-tap filter if 3-tap fclk is too high */
6613 + if (cpu_is_omap34xx() && height > out_height &&
6614 + fclk > dispc_fclk_rate())
6618 + if (width > (2048 >> five_taps))
6622 + fclk = calc_fclk_five_taps(width, height,
6623 + out_width, out_height, color_mode);
6625 + DSSDBG("required fclk rate = %lu Hz\n", fclk);
6626 + DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
6628 + if (fclk > dispc_fclk_rate()) {
6629 + DSSERR("failed to set up scaling, "
6630 + "required fclk rate = %lu Hz, "
6631 + "current fclk rate = %lu Hz\n",
6632 + fclk, dispc_fclk_rate());
6637 + if (ilace && !fieldmode) {
6639 + * when downscaling the bottom field may have to start several
6640 + * source lines below the top field. Unfortunately ACCUI
6641 + * registers will only hold the fractional part of the offset
6642 + * so the integer part must be added to the base address of the
6645 + if (!height || height == out_height)
6648 + field_offset = height / out_height / 2;
6651 + /* Fields are independent but interleaved in memory. */
6655 + if (rotation_type == OMAP_DSS_ROT_DMA)
6656 + calc_dma_rotation_offset(rotation, mirror,
6657 + screen_width, width, frame_height, color_mode,
6658 + fieldmode, field_offset,
6659 + &offset0, &offset1, &row_inc, &pix_inc);
6661 + calc_vrfb_rotation_offset(rotation, mirror,
6662 + screen_width, width, frame_height, color_mode,
6663 + fieldmode, field_offset,
6664 + &offset0, &offset1, &row_inc, &pix_inc);
6666 + DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
6667 + offset0, offset1, row_inc, pix_inc);
6669 + _dispc_set_color_mode(plane, color_mode);
6671 + _dispc_set_plane_ba0(plane, paddr + offset0);
6672 + _dispc_set_plane_ba1(plane, paddr + offset1);
6674 + _dispc_set_row_inc(plane, row_inc);
6675 + _dispc_set_pix_inc(plane, pix_inc);
6677 + DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height,
6678 + out_width, out_height);
6680 + _dispc_set_plane_pos(plane, pos_x, pos_y);
6682 + _dispc_set_pic_size(plane, width, height);
6684 + if (plane != OMAP_DSS_GFX) {
6685 + _dispc_set_scaling(plane, width, height,
6686 + out_width, out_height,
6687 + ilace, five_taps, fieldmode);
6688 + _dispc_set_vid_size(plane, out_width, out_height);
6689 + _dispc_set_vid_color_conv(plane, cconv);
6692 + _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
6694 + if (plane != OMAP_DSS_VIDEO1)
6695 + _dispc_setup_global_alpha(plane, global_alpha);
6700 +static void _dispc_enable_plane(enum omap_plane plane, bool enable)
6702 + REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 0, 0);
6705 +static void dispc_disable_isr(void *data, u32 mask)
6707 + struct completion *compl = data;
6711 +static void _enable_lcd_out(bool enable)
6713 + REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
6716 +void dispc_enable_lcd_out(bool enable)
6718 + struct completion frame_done_completion;
6724 + /* When we disable LCD output, we need to wait until frame is done.
6725 + * Otherwise the DSS is still working, and turning off the clocks
6726 + * prevents DSS from going to OFF mode */
6727 + is_on = REG_GET(DISPC_CONTROL, 0, 0);
6729 + if (!enable && is_on) {
6730 + init_completion(&frame_done_completion);
6732 + r = omap_dispc_register_isr(dispc_disable_isr,
6733 + &frame_done_completion,
6734 + DISPC_IRQ_FRAMEDONE);
6737 + DSSERR("failed to register FRAMEDONE isr\n");
6740 + _enable_lcd_out(enable);
6742 + if (!enable && is_on) {
6743 + if (!wait_for_completion_timeout(&frame_done_completion,
6744 + msecs_to_jiffies(100)))
6745 + DSSERR("timeout waiting for FRAME DONE\n");
6747 + r = omap_dispc_unregister_isr(dispc_disable_isr,
6748 + &frame_done_completion,
6749 + DISPC_IRQ_FRAMEDONE);
6752 + DSSERR("failed to unregister FRAMEDONE isr\n");
6758 +static void _enable_digit_out(bool enable)
6760 + REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
6763 +void dispc_enable_digit_out(bool enable)
6765 + struct completion frame_done_completion;
6770 + if (REG_GET(DISPC_CONTROL, 1, 1) == enable) {
6776 + unsigned long flags;
6777 + /* When we enable digit output, we'll get an extra digit
6778 + * sync lost interrupt, that we need to ignore */
6779 + spin_lock_irqsave(&dispc.irq_lock, flags);
6780 + dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
6781 + _omap_dispc_set_irqs();
6782 + spin_unlock_irqrestore(&dispc.irq_lock, flags);
6785 + /* When we disable digit output, we need to wait until fields are done.
6786 + * Otherwise the DSS is still working, and turning off the clocks
6787 + * prevents DSS from going to OFF mode. And when enabling, we need to
6788 + * wait for the extra sync losts */
6789 + init_completion(&frame_done_completion);
6791 + r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion,
6792 + DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
6794 + DSSERR("failed to register EVSYNC isr\n");
6796 + _enable_digit_out(enable);
6798 + /* XXX I understand from TRM that we should only wait for the
6799 + * current field to complete. But it seems we have to wait
6800 + * for both fields */
6801 + if (!wait_for_completion_timeout(&frame_done_completion,
6802 + msecs_to_jiffies(100)))
6803 + DSSERR("timeout waiting for EVSYNC\n");
6805 + if (!wait_for_completion_timeout(&frame_done_completion,
6806 + msecs_to_jiffies(100)))
6807 + DSSERR("timeout waiting for EVSYNC\n");
6809 + r = omap_dispc_unregister_isr(dispc_disable_isr,
6810 + &frame_done_completion,
6811 + DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
6813 + DSSERR("failed to unregister EVSYNC isr\n");
6816 + unsigned long flags;
6817 + spin_lock_irqsave(&dispc.irq_lock, flags);
6818 + dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
6819 + dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
6820 + _omap_dispc_set_irqs();
6821 + spin_unlock_irqrestore(&dispc.irq_lock, flags);
6827 +void dispc_lcd_enable_signal_polarity(bool act_high)
6830 + REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
6834 +void dispc_lcd_enable_signal(bool enable)
6837 + REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
6841 +void dispc_pck_free_enable(bool enable)
6844 + REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
6848 +void dispc_enable_fifohandcheck(bool enable)
6851 + REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
6856 +void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
6861 + case OMAP_DSS_LCD_DISPLAY_STN:
6865 + case OMAP_DSS_LCD_DISPLAY_TFT:
6875 + REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
6879 +void dispc_set_loadmode(enum omap_dss_load_mode mode)
6882 + REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
6887 +void dispc_set_default_color(enum omap_channel channel, u32 color)
6889 + const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
6890 + DISPC_DEFAULT_COLOR1 };
6893 + dispc_write_reg(def_reg[channel], color);
6897 +u32 dispc_get_default_color(enum omap_channel channel)
6899 + const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
6900 + DISPC_DEFAULT_COLOR1 };
6903 + BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
6904 + channel != OMAP_DSS_CHANNEL_LCD);
6907 + l = dispc_read_reg(def_reg[channel]);
6913 +void dispc_set_trans_key(enum omap_channel ch,
6914 + enum omap_dss_trans_key_type type,
6917 + const struct dispc_reg tr_reg[] = {
6918 + DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
6921 + if (ch == OMAP_DSS_CHANNEL_LCD)
6922 + REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
6923 + else /* OMAP_DSS_CHANNEL_DIGIT */
6924 + REG_FLD_MOD(DISPC_CONFIG, type, 13, 13);
6926 + dispc_write_reg(tr_reg[ch], trans_key);
6930 +void dispc_get_trans_key(enum omap_channel ch,
6931 + enum omap_dss_trans_key_type *type,
6934 + const struct dispc_reg tr_reg[] = {
6935 + DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
6939 + if (ch == OMAP_DSS_CHANNEL_LCD)
6940 + *type = REG_GET(DISPC_CONFIG, 11, 11);
6941 + else if (ch == OMAP_DSS_CHANNEL_DIGIT)
6942 + *type = REG_GET(DISPC_CONFIG, 13, 13);
6948 + *trans_key = dispc_read_reg(tr_reg[ch]);
6952 +void dispc_enable_trans_key(enum omap_channel ch, bool enable)
6955 + if (ch == OMAP_DSS_CHANNEL_LCD)
6956 + REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
6957 + else /* OMAP_DSS_CHANNEL_DIGIT */
6958 + REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
6961 +void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
6964 + if (ch == OMAP_DSS_CHANNEL_LCD)
6965 + REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
6966 + else /* OMAP_DSS_CHANNEL_DIGIT */
6967 + REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
6970 +bool dispc_alpha_blending_enabled(enum omap_channel ch)
6975 + if (ch == OMAP_DSS_CHANNEL_LCD)
6976 + enabled = REG_GET(DISPC_CONFIG, 18, 18);
6977 + else if (ch == OMAP_DSS_CHANNEL_DIGIT)
6978 + enabled = REG_GET(DISPC_CONFIG, 18, 18);
6988 +bool dispc_trans_key_enabled(enum omap_channel ch)
6993 + if (ch == OMAP_DSS_CHANNEL_LCD)
6994 + enabled = REG_GET(DISPC_CONFIG, 10, 10);
6995 + else if (ch == OMAP_DSS_CHANNEL_DIGIT)
6996 + enabled = REG_GET(DISPC_CONFIG, 12, 12);
7005 +void dispc_set_tft_data_lines(u8 data_lines)
7009 + switch (data_lines) {
7028 + REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
7032 +void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
7040 + case OMAP_DSS_PARALLELMODE_BYPASS:
7045 + case OMAP_DSS_PARALLELMODE_RFBI:
7050 + case OMAP_DSS_PARALLELMODE_DSI:
7062 + l = dispc_read_reg(DISPC_CONTROL);
7064 + l = FLD_MOD(l, stallmode, 11, 11);
7065 + l = FLD_MOD(l, gpout0, 15, 15);
7066 + l = FLD_MOD(l, gpout1, 16, 16);
7068 + dispc_write_reg(DISPC_CONTROL, l);
7073 +static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
7074 + int vsw, int vfp, int vbp)
7076 + if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
7077 + if (hsw < 1 || hsw > 64 ||
7078 + hfp < 1 || hfp > 256 ||
7079 + hbp < 1 || hbp > 256 ||
7080 + vsw < 1 || vsw > 64 ||
7081 + vfp < 0 || vfp > 255 ||
7082 + vbp < 0 || vbp > 255)
7085 + if (hsw < 1 || hsw > 256 ||
7086 + hfp < 1 || hfp > 4096 ||
7087 + hbp < 1 || hbp > 4096 ||
7088 + vsw < 1 || vsw > 256 ||
7089 + vfp < 0 || vfp > 4095 ||
7090 + vbp < 0 || vbp > 4095)
7097 +bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
7099 + return _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
7100 + timings->hbp, timings->vsw,
7101 + timings->vfp, timings->vbp);
7104 +static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
7105 + int vsw, int vfp, int vbp)
7107 + u32 timing_h, timing_v;
7109 + if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
7110 + timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
7111 + FLD_VAL(hbp-1, 27, 20);
7113 + timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
7114 + FLD_VAL(vbp, 27, 20);
7116 + timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
7117 + FLD_VAL(hbp-1, 31, 20);
7119 + timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
7120 + FLD_VAL(vbp, 31, 20);
7124 + dispc_write_reg(DISPC_TIMING_H, timing_h);
7125 + dispc_write_reg(DISPC_TIMING_V, timing_v);
7129 +/* change name to mode? */
7130 +void dispc_set_lcd_timings(struct omap_video_timings *timings)
7132 + unsigned xtot, ytot;
7133 + unsigned long ht, vt;
7135 + if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp,
7136 + timings->hbp, timings->vsw,
7137 + timings->vfp, timings->vbp))
7140 + _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp,
7141 + timings->vsw, timings->vfp, timings->vbp);
7143 + dispc_set_lcd_size(timings->x_res, timings->y_res);
7145 + xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
7146 + ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
7148 + ht = (timings->pixel_clock * 1000) / xtot;
7149 + vt = (timings->pixel_clock * 1000) / xtot / ytot;
7151 + DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res);
7152 + DSSDBG("pck %u\n", timings->pixel_clock);
7153 + DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
7154 + timings->hsw, timings->hfp, timings->hbp,
7155 + timings->vsw, timings->vfp, timings->vbp);
7157 + DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
7160 +void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div)
7162 + BUG_ON(lck_div < 1);
7163 + BUG_ON(pck_div < 2);
7166 + dispc_write_reg(DISPC_DIVISOR,
7167 + FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
7171 +static void dispc_get_lcd_divisor(int *lck_div, int *pck_div)
7174 + l = dispc_read_reg(DISPC_DIVISOR);
7175 + *lck_div = FLD_GET(l, 23, 16);
7176 + *pck_div = FLD_GET(l, 7, 0);
7179 +unsigned long dispc_fclk_rate(void)
7181 + unsigned long r = 0;
7183 + if (dss_get_dispc_clk_source() == 0)
7184 + r = dss_clk_get_rate(DSS_CLK_FCK1);
7186 +#ifdef CONFIG_OMAP2_DSS_DSI
7187 + r = dsi_get_dsi1_pll_rate();
7194 +unsigned long dispc_lclk_rate(void)
7200 + l = dispc_read_reg(DISPC_DIVISOR);
7202 + lcd = FLD_GET(l, 23, 16);
7204 + r = dispc_fclk_rate();
7209 +unsigned long dispc_pclk_rate(void)
7215 + l = dispc_read_reg(DISPC_DIVISOR);
7217 + lcd = FLD_GET(l, 23, 16);
7218 + pcd = FLD_GET(l, 7, 0);
7220 + r = dispc_fclk_rate();
7222 + return r / lcd / pcd;
7225 +void dispc_dump_clocks(struct seq_file *s)
7231 + dispc_get_lcd_divisor(&lcd, &pcd);
7233 + seq_printf(s, "- dispc -\n");
7235 + seq_printf(s, "dispc fclk source = %s\n",
7236 + dss_get_dispc_clk_source() == 0 ?
7237 + "dss1_alwon_fclk" : "dsi1_pll_fclk");
7239 + seq_printf(s, "pixel clk = %lu / %d / %d = %lu\n",
7240 + dispc_fclk_rate(),
7242 + dispc_pclk_rate());
7247 +void dispc_dump_regs(struct seq_file *s)
7249 +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
7251 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
7253 + DUMPREG(DISPC_REVISION);
7254 + DUMPREG(DISPC_SYSCONFIG);
7255 + DUMPREG(DISPC_SYSSTATUS);
7256 + DUMPREG(DISPC_IRQSTATUS);
7257 + DUMPREG(DISPC_IRQENABLE);
7258 + DUMPREG(DISPC_CONTROL);
7259 + DUMPREG(DISPC_CONFIG);
7260 + DUMPREG(DISPC_CAPABLE);
7261 + DUMPREG(DISPC_DEFAULT_COLOR0);
7262 + DUMPREG(DISPC_DEFAULT_COLOR1);
7263 + DUMPREG(DISPC_TRANS_COLOR0);
7264 + DUMPREG(DISPC_TRANS_COLOR1);
7265 + DUMPREG(DISPC_LINE_STATUS);
7266 + DUMPREG(DISPC_LINE_NUMBER);
7267 + DUMPREG(DISPC_TIMING_H);
7268 + DUMPREG(DISPC_TIMING_V);
7269 + DUMPREG(DISPC_POL_FREQ);
7270 + DUMPREG(DISPC_DIVISOR);
7271 + DUMPREG(DISPC_GLOBAL_ALPHA);
7272 + DUMPREG(DISPC_SIZE_DIG);
7273 + DUMPREG(DISPC_SIZE_LCD);
7275 + DUMPREG(DISPC_GFX_BA0);
7276 + DUMPREG(DISPC_GFX_BA1);
7277 + DUMPREG(DISPC_GFX_POSITION);
7278 + DUMPREG(DISPC_GFX_SIZE);
7279 + DUMPREG(DISPC_GFX_ATTRIBUTES);
7280 + DUMPREG(DISPC_GFX_FIFO_THRESHOLD);
7281 + DUMPREG(DISPC_GFX_FIFO_SIZE_STATUS);
7282 + DUMPREG(DISPC_GFX_ROW_INC);
7283 + DUMPREG(DISPC_GFX_PIXEL_INC);
7284 + DUMPREG(DISPC_GFX_WINDOW_SKIP);
7285 + DUMPREG(DISPC_GFX_TABLE_BA);
7287 + DUMPREG(DISPC_DATA_CYCLE1);
7288 + DUMPREG(DISPC_DATA_CYCLE2);
7289 + DUMPREG(DISPC_DATA_CYCLE3);
7291 + DUMPREG(DISPC_CPR_COEF_R);
7292 + DUMPREG(DISPC_CPR_COEF_G);
7293 + DUMPREG(DISPC_CPR_COEF_B);
7295 + DUMPREG(DISPC_GFX_PRELOAD);
7297 + DUMPREG(DISPC_VID_BA0(0));
7298 + DUMPREG(DISPC_VID_BA1(0));
7299 + DUMPREG(DISPC_VID_POSITION(0));
7300 + DUMPREG(DISPC_VID_SIZE(0));
7301 + DUMPREG(DISPC_VID_ATTRIBUTES(0));
7302 + DUMPREG(DISPC_VID_FIFO_THRESHOLD(0));
7303 + DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(0));
7304 + DUMPREG(DISPC_VID_ROW_INC(0));
7305 + DUMPREG(DISPC_VID_PIXEL_INC(0));
7306 + DUMPREG(DISPC_VID_FIR(0));
7307 + DUMPREG(DISPC_VID_PICTURE_SIZE(0));
7308 + DUMPREG(DISPC_VID_ACCU0(0));
7309 + DUMPREG(DISPC_VID_ACCU1(0));
7311 + DUMPREG(DISPC_VID_BA0(1));
7312 + DUMPREG(DISPC_VID_BA1(1));
7313 + DUMPREG(DISPC_VID_POSITION(1));
7314 + DUMPREG(DISPC_VID_SIZE(1));
7315 + DUMPREG(DISPC_VID_ATTRIBUTES(1));
7316 + DUMPREG(DISPC_VID_FIFO_THRESHOLD(1));
7317 + DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(1));
7318 + DUMPREG(DISPC_VID_ROW_INC(1));
7319 + DUMPREG(DISPC_VID_PIXEL_INC(1));
7320 + DUMPREG(DISPC_VID_FIR(1));
7321 + DUMPREG(DISPC_VID_PICTURE_SIZE(1));
7322 + DUMPREG(DISPC_VID_ACCU0(1));
7323 + DUMPREG(DISPC_VID_ACCU1(1));
7325 + DUMPREG(DISPC_VID_FIR_COEF_H(0, 0));
7326 + DUMPREG(DISPC_VID_FIR_COEF_H(0, 1));
7327 + DUMPREG(DISPC_VID_FIR_COEF_H(0, 2));
7328 + DUMPREG(DISPC_VID_FIR_COEF_H(0, 3));
7329 + DUMPREG(DISPC_VID_FIR_COEF_H(0, 4));
7330 + DUMPREG(DISPC_VID_FIR_COEF_H(0, 5));
7331 + DUMPREG(DISPC_VID_FIR_COEF_H(0, 6));
7332 + DUMPREG(DISPC_VID_FIR_COEF_H(0, 7));
7333 + DUMPREG(DISPC_VID_FIR_COEF_HV(0, 0));
7334 + DUMPREG(DISPC_VID_FIR_COEF_HV(0, 1));
7335 + DUMPREG(DISPC_VID_FIR_COEF_HV(0, 2));
7336 + DUMPREG(DISPC_VID_FIR_COEF_HV(0, 3));
7337 + DUMPREG(DISPC_VID_FIR_COEF_HV(0, 4));
7338 + DUMPREG(DISPC_VID_FIR_COEF_HV(0, 5));
7339 + DUMPREG(DISPC_VID_FIR_COEF_HV(0, 6));
7340 + DUMPREG(DISPC_VID_FIR_COEF_HV(0, 7));
7341 + DUMPREG(DISPC_VID_CONV_COEF(0, 0));
7342 + DUMPREG(DISPC_VID_CONV_COEF(0, 1));
7343 + DUMPREG(DISPC_VID_CONV_COEF(0, 2));
7344 + DUMPREG(DISPC_VID_CONV_COEF(0, 3));
7345 + DUMPREG(DISPC_VID_CONV_COEF(0, 4));
7346 + DUMPREG(DISPC_VID_FIR_COEF_V(0, 0));
7347 + DUMPREG(DISPC_VID_FIR_COEF_V(0, 1));
7348 + DUMPREG(DISPC_VID_FIR_COEF_V(0, 2));
7349 + DUMPREG(DISPC_VID_FIR_COEF_V(0, 3));
7350 + DUMPREG(DISPC_VID_FIR_COEF_V(0, 4));
7351 + DUMPREG(DISPC_VID_FIR_COEF_V(0, 5));
7352 + DUMPREG(DISPC_VID_FIR_COEF_V(0, 6));
7353 + DUMPREG(DISPC_VID_FIR_COEF_V(0, 7));
7355 + DUMPREG(DISPC_VID_FIR_COEF_H(1, 0));
7356 + DUMPREG(DISPC_VID_FIR_COEF_H(1, 1));
7357 + DUMPREG(DISPC_VID_FIR_COEF_H(1, 2));
7358 + DUMPREG(DISPC_VID_FIR_COEF_H(1, 3));
7359 + DUMPREG(DISPC_VID_FIR_COEF_H(1, 4));
7360 + DUMPREG(DISPC_VID_FIR_COEF_H(1, 5));
7361 + DUMPREG(DISPC_VID_FIR_COEF_H(1, 6));
7362 + DUMPREG(DISPC_VID_FIR_COEF_H(1, 7));
7363 + DUMPREG(DISPC_VID_FIR_COEF_HV(1, 0));
7364 + DUMPREG(DISPC_VID_FIR_COEF_HV(1, 1));
7365 + DUMPREG(DISPC_VID_FIR_COEF_HV(1, 2));
7366 + DUMPREG(DISPC_VID_FIR_COEF_HV(1, 3));
7367 + DUMPREG(DISPC_VID_FIR_COEF_HV(1, 4));
7368 + DUMPREG(DISPC_VID_FIR_COEF_HV(1, 5));
7369 + DUMPREG(DISPC_VID_FIR_COEF_HV(1, 6));
7370 + DUMPREG(DISPC_VID_FIR_COEF_HV(1, 7));
7371 + DUMPREG(DISPC_VID_CONV_COEF(1, 0));
7372 + DUMPREG(DISPC_VID_CONV_COEF(1, 1));
7373 + DUMPREG(DISPC_VID_CONV_COEF(1, 2));
7374 + DUMPREG(DISPC_VID_CONV_COEF(1, 3));
7375 + DUMPREG(DISPC_VID_CONV_COEF(1, 4));
7376 + DUMPREG(DISPC_VID_FIR_COEF_V(1, 0));
7377 + DUMPREG(DISPC_VID_FIR_COEF_V(1, 1));
7378 + DUMPREG(DISPC_VID_FIR_COEF_V(1, 2));
7379 + DUMPREG(DISPC_VID_FIR_COEF_V(1, 3));
7380 + DUMPREG(DISPC_VID_FIR_COEF_V(1, 4));
7381 + DUMPREG(DISPC_VID_FIR_COEF_V(1, 5));
7382 + DUMPREG(DISPC_VID_FIR_COEF_V(1, 6));
7383 + DUMPREG(DISPC_VID_FIR_COEF_V(1, 7));
7385 + DUMPREG(DISPC_VID_PRELOAD(0));
7386 + DUMPREG(DISPC_VID_PRELOAD(1));
7388 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
7392 +static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
7393 + bool ihs, bool ivs, u8 acbi, u8 acb)
7397 + DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n",
7398 + onoff, rf, ieo, ipc, ihs, ivs, acbi, acb);
7400 + l |= FLD_VAL(onoff, 17, 17);
7401 + l |= FLD_VAL(rf, 16, 16);
7402 + l |= FLD_VAL(ieo, 15, 15);
7403 + l |= FLD_VAL(ipc, 14, 14);
7404 + l |= FLD_VAL(ihs, 13, 13);
7405 + l |= FLD_VAL(ivs, 12, 12);
7406 + l |= FLD_VAL(acbi, 11, 8);
7407 + l |= FLD_VAL(acb, 7, 0);
7410 + dispc_write_reg(DISPC_POL_FREQ, l);
7414 +void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb)
7416 + _dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0,
7417 + (config & OMAP_DSS_LCD_RF) != 0,
7418 + (config & OMAP_DSS_LCD_IEO) != 0,
7419 + (config & OMAP_DSS_LCD_IPC) != 0,
7420 + (config & OMAP_DSS_LCD_IHS) != 0,
7421 + (config & OMAP_DSS_LCD_IVS) != 0,
7425 +void find_lck_pck_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
7426 + u16 *lck_div, u16 *pck_div)
7428 + u16 pcd_min = is_tft ? 2 : 3;
7429 + unsigned long best_pck;
7430 + u16 best_ld, cur_ld;
7431 + u16 best_pd, cur_pd;
7437 + for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
7438 + unsigned long lck = fck / cur_ld;
7440 + for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) {
7441 + unsigned long pck = lck / cur_pd;
7442 + long old_delta = abs(best_pck - req_pck);
7443 + long new_delta = abs(pck - req_pck);
7445 + if (best_pck == 0 || new_delta < old_delta) {
7450 + if (pck == req_pck)
7454 + if (pck < req_pck)
7458 + if (lck / pcd_min < req_pck)
7463 + *lck_div = best_ld;
7464 + *pck_div = best_pd;
7467 +int dispc_calc_clock_div(bool is_tft, unsigned long req_pck,
7468 + struct dispc_clock_info *cinfo)
7470 + unsigned long prate;
7471 + struct dispc_clock_info cur, best;
7473 + int min_fck_per_pck;
7474 + unsigned long fck_rate = dss_clk_get_rate(DSS_CLK_FCK1);
7476 + if (cpu_is_omap34xx())
7477 + prate = clk_get_rate(clk_get_parent(dispc.dpll4_m4_ck));
7481 + if (req_pck == dispc.cache_req_pck &&
7482 + ((cpu_is_omap34xx() && prate == dispc.cache_prate) ||
7483 + dispc.cache_cinfo.fck == fck_rate)) {
7484 + DSSDBG("dispc clock info found from cache.\n");
7485 + *cinfo = dispc.cache_cinfo;
7489 + min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
7491 + if (min_fck_per_pck &&
7492 + req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
7493 + DSSERR("Requested pixel clock not possible with the current "
7494 + "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
7495 + "the constraint off.\n");
7496 + min_fck_per_pck = 0;
7500 + memset(&cur, 0, sizeof(cur));
7501 + memset(&best, 0, sizeof(best));
7503 + if (cpu_is_omap24xx()) {
7504 + /* XXX can we change the clock on omap2? */
7505 + cur.fck = dss_clk_get_rate(DSS_CLK_FCK1);
7510 + find_lck_pck_divs(is_tft, req_pck, cur.fck,
7511 + &cur.lck_div, &cur.pck_div);
7513 + cur.lck = cur.fck / cur.lck_div;
7514 + cur.pck = cur.lck / cur.pck_div;
7519 + } else if (cpu_is_omap34xx()) {
7520 + for (cur.fck_div = 16; cur.fck_div > 0; --cur.fck_div) {
7521 + cur.fck = prate / cur.fck_div * 2;
7523 + if (cur.fck > DISPC_MAX_FCK)
7526 + if (min_fck_per_pck &&
7527 + cur.fck < req_pck * min_fck_per_pck)
7532 + find_lck_pck_divs(is_tft, req_pck, cur.fck,
7533 + &cur.lck_div, &cur.pck_div);
7535 + cur.lck = cur.fck / cur.lck_div;
7536 + cur.pck = cur.lck / cur.pck_div;
7538 + if (abs(cur.pck - req_pck) < abs(best.pck - req_pck)) {
7541 + if (cur.pck == req_pck)
7551 + if (min_fck_per_pck) {
7552 + DSSERR("Could not find suitable clock settings.\n"
7553 + "Turning FCK/PCK constraint off and"
7554 + "trying again.\n");
7555 + min_fck_per_pck = 0;
7559 + DSSERR("Could not find suitable clock settings.\n");
7567 + dispc.cache_req_pck = req_pck;
7568 + dispc.cache_prate = prate;
7569 + dispc.cache_cinfo = best;
7574 +int dispc_set_clock_div(struct dispc_clock_info *cinfo)
7576 + unsigned long prate;
7579 + if (cpu_is_omap34xx()) {
7580 + prate = clk_get_rate(clk_get_parent(dispc.dpll4_m4_ck));
7581 + DSSDBG("dpll4_m4 = %ld\n", prate);
7584 + DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
7585 + DSSDBG("lck = %ld (%d)\n", cinfo->lck, cinfo->lck_div);
7586 + DSSDBG("pck = %ld (%d)\n", cinfo->pck, cinfo->pck_div);
7588 + if (cpu_is_omap34xx()) {
7589 + r = clk_set_rate(dispc.dpll4_m4_ck, prate / cinfo->fck_div);
7594 + dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div);
7599 +int dispc_get_clock_div(struct dispc_clock_info *cinfo)
7601 + cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK1);
7603 + if (cpu_is_omap34xx()) {
7604 + unsigned long prate;
7605 + prate = clk_get_rate(clk_get_parent(dispc.dpll4_m4_ck));
7606 + cinfo->fck_div = prate / (cinfo->fck / 2);
7608 + cinfo->fck_div = 0;
7611 + cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
7612 + cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
7614 + cinfo->lck = cinfo->fck / cinfo->lck_div;
7615 + cinfo->pck = cinfo->lck / cinfo->pck_div;
7620 +/* dispc.irq_lock has to be locked by the caller */
7621 +static void _omap_dispc_set_irqs(void)
7626 + struct omap_dispc_isr_data *isr_data;
7628 + mask = dispc.irq_error_mask;
7630 + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
7631 + isr_data = &dispc.registered_isr[i];
7633 + if (isr_data->isr == NULL)
7636 + mask |= isr_data->mask;
7641 + old_mask = dispc_read_reg(DISPC_IRQENABLE);
7642 + /* clear the irqstatus for newly enabled irqs */
7643 + dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
7645 + dispc_write_reg(DISPC_IRQENABLE, mask);
7650 +int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
7654 + unsigned long flags;
7655 + struct omap_dispc_isr_data *isr_data;
7660 + spin_lock_irqsave(&dispc.irq_lock, flags);
7662 + /* check for duplicate entry */
7663 + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
7664 + isr_data = &dispc.registered_isr[i];
7665 + if (isr_data->isr == isr && isr_data->arg == arg &&
7666 + isr_data->mask == mask) {
7675 + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
7676 + isr_data = &dispc.registered_isr[i];
7678 + if (isr_data->isr != NULL)
7681 + isr_data->isr = isr;
7682 + isr_data->arg = arg;
7683 + isr_data->mask = mask;
7689 + _omap_dispc_set_irqs();
7691 + spin_unlock_irqrestore(&dispc.irq_lock, flags);
7695 + spin_unlock_irqrestore(&dispc.irq_lock, flags);
7699 +EXPORT_SYMBOL(omap_dispc_register_isr);
7701 +int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
7704 + unsigned long flags;
7705 + int ret = -EINVAL;
7706 + struct omap_dispc_isr_data *isr_data;
7708 + spin_lock_irqsave(&dispc.irq_lock, flags);
7710 + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
7711 + isr_data = &dispc.registered_isr[i];
7712 + if (isr_data->isr != isr || isr_data->arg != arg ||
7713 + isr_data->mask != mask)
7716 + /* found the correct isr */
7718 + isr_data->isr = NULL;
7719 + isr_data->arg = NULL;
7720 + isr_data->mask = 0;
7727 + _omap_dispc_set_irqs();
7729 + spin_unlock_irqrestore(&dispc.irq_lock, flags);
7733 +EXPORT_SYMBOL(omap_dispc_unregister_isr);
7736 +static void print_irq_status(u32 status)
7738 + if ((status & dispc.irq_error_mask) == 0)
7741 + printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status);
7744 + if (status & DISPC_IRQ_##x) \
7746 + PIS(GFX_FIFO_UNDERFLOW);
7748 + PIS(VID1_FIFO_UNDERFLOW);
7749 + PIS(VID2_FIFO_UNDERFLOW);
7751 + PIS(SYNC_LOST_DIGIT);
7758 +/* Called from dss.c. Note that we don't touch clocks here,
7759 + * but we presume they are on because we got an IRQ. However,
7760 + * an irq handler may turn the clocks off, so we may not have
7761 + * clock later in the function. */
7762 +void dispc_irq_handler(void)
7766 + u32 handledirqs = 0;
7767 + u32 unhandled_errors;
7768 + struct omap_dispc_isr_data *isr_data;
7769 + struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
7771 + spin_lock(&dispc.irq_lock);
7773 + irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
7777 + print_irq_status(irqstatus);
7779 + /* Ack the interrupt. Do it here before clocks are possibly turned
7781 + dispc_write_reg(DISPC_IRQSTATUS, irqstatus);
7783 + /* make a copy and unlock, so that isrs can unregister
7785 + memcpy(registered_isr, dispc.registered_isr,
7786 + sizeof(registered_isr));
7788 + spin_unlock(&dispc.irq_lock);
7790 + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
7791 + isr_data = ®istered_isr[i];
7793 + if (!isr_data->isr)
7796 + if (isr_data->mask & irqstatus) {
7797 + isr_data->isr(isr_data->arg, irqstatus);
7798 + handledirqs |= isr_data->mask;
7802 + spin_lock(&dispc.irq_lock);
7804 + unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
7806 + if (unhandled_errors) {
7807 + dispc.error_irqs |= unhandled_errors;
7809 + dispc.irq_error_mask &= ~unhandled_errors;
7810 + _omap_dispc_set_irqs();
7812 + schedule_work(&dispc.error_work);
7815 + spin_unlock(&dispc.irq_lock);
7818 +static void dispc_error_worker(struct work_struct *work)
7822 + unsigned long flags;
7824 + spin_lock_irqsave(&dispc.irq_lock, flags);
7825 + errors = dispc.error_irqs;
7826 + dispc.error_irqs = 0;
7827 + spin_unlock_irqrestore(&dispc.irq_lock, flags);
7829 + if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) {
7830 + DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n");
7831 + for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
7832 + struct omap_overlay *ovl;
7833 + ovl = omap_dss_get_overlay(i);
7835 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
7838 + if (ovl->id == 0) {
7839 + dispc_enable_plane(ovl->id, 0);
7840 + dispc_go(ovl->manager->id);
7847 + if (errors & DISPC_IRQ_VID1_FIFO_UNDERFLOW) {
7848 + DSSERR("VID1_FIFO_UNDERFLOW, disabling VID1\n");
7849 + for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
7850 + struct omap_overlay *ovl;
7851 + ovl = omap_dss_get_overlay(i);
7853 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
7856 + if (ovl->id == 1) {
7857 + dispc_enable_plane(ovl->id, 0);
7858 + dispc_go(ovl->manager->id);
7865 + if (errors & DISPC_IRQ_VID2_FIFO_UNDERFLOW) {
7866 + DSSERR("VID2_FIFO_UNDERFLOW, disabling VID2\n");
7867 + for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
7868 + struct omap_overlay *ovl;
7869 + ovl = omap_dss_get_overlay(i);
7871 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
7874 + if (ovl->id == 2) {
7875 + dispc_enable_plane(ovl->id, 0);
7876 + dispc_go(ovl->manager->id);
7883 + if (errors & DISPC_IRQ_SYNC_LOST) {
7884 + struct omap_overlay_manager *manager = NULL;
7885 + bool enable = false;
7887 + DSSERR("SYNC_LOST, disabling LCD\n");
7889 + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
7890 + struct omap_overlay_manager *mgr;
7891 + mgr = omap_dss_get_overlay_manager(i);
7893 + if (mgr->id == OMAP_DSS_CHANNEL_LCD) {
7895 + enable = mgr->device->state ==
7896 + OMAP_DSS_DISPLAY_ACTIVE;
7897 + mgr->device->disable(mgr->device);
7903 + for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
7904 + struct omap_overlay *ovl;
7905 + ovl = omap_dss_get_overlay(i);
7907 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
7910 + if (ovl->id != 0 && ovl->manager == manager)
7911 + dispc_enable_plane(ovl->id, 0);
7914 + dispc_go(manager->id);
7917 + manager->device->enable(manager->device);
7921 + if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) {
7922 + struct omap_overlay_manager *manager = NULL;
7923 + bool enable = false;
7925 + DSSERR("SYNC_LOST_DIGIT, disabling TV\n");
7927 + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
7928 + struct omap_overlay_manager *mgr;
7929 + mgr = omap_dss_get_overlay_manager(i);
7931 + if (mgr->id == OMAP_DSS_CHANNEL_DIGIT) {
7933 + enable = mgr->device->state ==
7934 + OMAP_DSS_DISPLAY_ACTIVE;
7935 + mgr->device->disable(mgr->device);
7941 + for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
7942 + struct omap_overlay *ovl;
7943 + ovl = omap_dss_get_overlay(i);
7945 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
7948 + if (ovl->id != 0 && ovl->manager == manager)
7949 + dispc_enable_plane(ovl->id, 0);
7952 + dispc_go(manager->id);
7955 + manager->device->enable(manager->device);
7959 + if (errors & DISPC_IRQ_OCP_ERR) {
7960 + DSSERR("OCP_ERR\n");
7961 + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
7962 + struct omap_overlay_manager *mgr;
7963 + mgr = omap_dss_get_overlay_manager(i);
7965 + if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC)
7966 + mgr->device->disable(mgr->device);
7970 + spin_lock_irqsave(&dispc.irq_lock, flags);
7971 + dispc.irq_error_mask |= errors;
7972 + _omap_dispc_set_irqs();
7973 + spin_unlock_irqrestore(&dispc.irq_lock, flags);
7976 +int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
7978 + void dispc_irq_wait_handler(void *data, u32 mask)
7980 + complete((struct completion *)data);
7984 + DECLARE_COMPLETION_ONSTACK(completion);
7986 + r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
7992 + timeout = wait_for_completion_timeout(&completion, timeout);
7994 + omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
7997 + return -ETIMEDOUT;
7999 + if (timeout == -ERESTARTSYS)
8000 + return -ERESTARTSYS;
8005 +int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
8006 + unsigned long timeout)
8008 + void dispc_irq_wait_handler(void *data, u32 mask)
8010 + complete((struct completion *)data);
8014 + DECLARE_COMPLETION_ONSTACK(completion);
8016 + r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
8022 + timeout = wait_for_completion_interruptible_timeout(&completion,
8025 + omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
8028 + return -ETIMEDOUT;
8030 + if (timeout == -ERESTARTSYS)
8031 + return -ERESTARTSYS;
8036 +#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
8037 +void dispc_fake_vsync_irq(void)
8039 + u32 irqstatus = DISPC_IRQ_VSYNC;
8042 + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
8043 + struct omap_dispc_isr_data *isr_data;
8044 + isr_data = &dispc.registered_isr[i];
8046 + if (!isr_data->isr)
8049 + if (isr_data->mask & irqstatus)
8050 + isr_data->isr(isr_data->arg, irqstatus);
8055 +static void _omap_dispc_initialize_irq(void)
8057 + unsigned long flags;
8059 + spin_lock_irqsave(&dispc.irq_lock, flags);
8061 + memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
8063 + dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
8065 + /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
8067 + dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS));
8069 + _omap_dispc_set_irqs();
8071 + spin_unlock_irqrestore(&dispc.irq_lock, flags);
8074 +void dispc_enable_sidle(void)
8076 + REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
8079 +void dispc_disable_sidle(void)
8081 + REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
8084 +static void _omap_dispc_initial_config(void)
8088 + l = dispc_read_reg(DISPC_SYSCONFIG);
8089 + l = FLD_MOD(l, 2, 13, 12); /* MIDLEMODE: smart standby */
8090 + l = FLD_MOD(l, 2, 4, 3); /* SIDLEMODE: smart idle */
8091 + l = FLD_MOD(l, 1, 2, 2); /* ENWAKEUP */
8092 + l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */
8093 + dispc_write_reg(DISPC_SYSCONFIG, l);
8096 + REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
8098 + /* L3 firewall setting: enable access to OCM RAM */
8099 + if (cpu_is_omap24xx())
8100 + __raw_writel(0x402000b0, OMAP2_IO_ADDRESS(0x680050a0));
8102 + _dispc_setup_color_conv_coef();
8104 + dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
8106 + dispc_read_plane_fifo_sizes();
8109 +int dispc_init(void)
8113 + spin_lock_init(&dispc.irq_lock);
8115 + INIT_WORK(&dispc.error_work, dispc_error_worker);
8117 + dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
8118 + if (!dispc.base) {
8119 + DSSERR("can't ioremap DISPC\n");
8123 + if (cpu_is_omap34xx()) {
8124 + dispc.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
8125 + if (IS_ERR(dispc.dpll4_m4_ck)) {
8126 + DSSERR("Failed to get dpll4_m4_ck\n");
8133 + _omap_dispc_initial_config();
8135 + _omap_dispc_initialize_irq();
8137 + dispc_save_context();
8139 + rev = dispc_read_reg(DISPC_REVISION);
8140 + printk(KERN_INFO "OMAP DISPC rev %d.%d\n",
8141 + FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
8148 +void dispc_exit(void)
8150 + if (cpu_is_omap34xx())
8151 + clk_put(dispc.dpll4_m4_ck);
8152 + iounmap(dispc.base);
8155 +int dispc_enable_plane(enum omap_plane plane, bool enable)
8157 + DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
8160 + _dispc_enable_plane(plane, enable);
8166 +int dispc_setup_plane(enum omap_plane plane,
8167 + u32 paddr, u16 screen_width,
8168 + u16 pos_x, u16 pos_y,
8169 + u16 width, u16 height,
8170 + u16 out_width, u16 out_height,
8171 + enum omap_color_mode color_mode,
8173 + enum omap_dss_rotation_type rotation_type,
8174 + u8 rotation, bool mirror, u8 global_alpha)
8178 + DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
8179 + "%dx%d, ilace %d, cmode %x, rot %d, mir %d\n",
8180 + plane, paddr, screen_width, pos_x, pos_y,
8182 + out_width, out_height,
8183 + ilace, color_mode,
8184 + rotation, mirror);
8188 + r = _dispc_setup_plane(plane,
8189 + paddr, screen_width,
8192 + out_width, out_height,
8193 + color_mode, ilace,
8202 diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
8203 new file mode 100644
8204 index 0000000..6b5d0cf
8206 +++ b/drivers/video/omap2/dss/display.c
8209 + * linux/drivers/video/omap2/dss/display.c
8211 + * Copyright (C) 2009 Nokia Corporation
8212 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
8214 + * Some code and ideas taken from drivers/video/omap/ driver
8217 + * This program is free software; you can redistribute it and/or modify it
8218 + * under the terms of the GNU General Public License version 2 as published by
8219 + * the Free Software Foundation.
8221 + * This program is distributed in the hope that it will be useful, but WITHOUT
8222 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
8223 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
8226 + * You should have received a copy of the GNU General Public License along with
8227 + * this program. If not, see <http://www.gnu.org/licenses/>.
8230 +#define DSS_SUBSYS_NAME "DISPLAY"
8232 +#include <linux/kernel.h>
8233 +#include <linux/module.h>
8234 +#include <linux/jiffies.h>
8235 +#include <linux/list.h>
8236 +#include <linux/platform_device.h>
8238 +#include <mach/display.h>
8241 +static LIST_HEAD(display_list);
8243 +static ssize_t display_enabled_show(struct device *dev,
8244 + struct device_attribute *attr, char *buf)
8246 + struct omap_dss_device *dssdev = to_dss_device(dev);
8247 + bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED;
8249 + return snprintf(buf, PAGE_SIZE, "%d\n", enabled);
8252 +static ssize_t display_enabled_store(struct device *dev,
8253 + struct device_attribute *attr,
8254 + const char *buf, size_t size)
8256 + struct omap_dss_device *dssdev = to_dss_device(dev);
8259 + enabled = simple_strtoul(buf, NULL, 10);
8261 + if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
8263 + r = dssdev->enable(dssdev);
8267 + dssdev->disable(dssdev);
8274 +static ssize_t display_upd_mode_show(struct device *dev,
8275 + struct device_attribute *attr, char *buf)
8277 + struct omap_dss_device *dssdev = to_dss_device(dev);
8278 + enum omap_dss_update_mode mode = OMAP_DSS_UPDATE_AUTO;
8279 + if (dssdev->get_update_mode)
8280 + mode = dssdev->get_update_mode(dssdev);
8281 + return snprintf(buf, PAGE_SIZE, "%d\n", mode);
8284 +static ssize_t display_upd_mode_store(struct device *dev,
8285 + struct device_attribute *attr,
8286 + const char *buf, size_t size)
8288 + struct omap_dss_device *dssdev = to_dss_device(dev);
8290 + enum omap_dss_update_mode mode;
8292 + val = simple_strtoul(buf, NULL, 10);
8295 + case OMAP_DSS_UPDATE_DISABLED:
8296 + case OMAP_DSS_UPDATE_AUTO:
8297 + case OMAP_DSS_UPDATE_MANUAL:
8298 + mode = (enum omap_dss_update_mode)val;
8304 + r = dssdev->set_update_mode(dssdev, mode);
8311 +static ssize_t display_tear_show(struct device *dev,
8312 + struct device_attribute *attr, char *buf)
8314 + struct omap_dss_device *dssdev = to_dss_device(dev);
8315 + return snprintf(buf, PAGE_SIZE, "%d\n",
8316 + dssdev->get_te ? dssdev->get_te(dssdev) : 0);
8319 +static ssize_t display_tear_store(struct device *dev,
8320 + struct device_attribute *attr, const char *buf, size_t size)
8322 + struct omap_dss_device *dssdev = to_dss_device(dev);
8326 + if (!dssdev->enable_te || !dssdev->get_te)
8329 + te = simple_strtoul(buf, NULL, 0);
8331 + r = dssdev->enable_te(dssdev, te);
8338 +static ssize_t display_timings_show(struct device *dev,
8339 + struct device_attribute *attr, char *buf)
8341 + struct omap_dss_device *dssdev = to_dss_device(dev);
8342 + struct omap_video_timings t;
8344 + if (!dssdev->get_timings)
8347 + dssdev->get_timings(dssdev, &t);
8349 + return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
8351 + t.x_res, t.hfp, t.hbp, t.hsw,
8352 + t.y_res, t.vfp, t.vbp, t.vsw);
8355 +static ssize_t display_timings_store(struct device *dev,
8356 + struct device_attribute *attr, const char *buf, size_t size)
8358 + struct omap_dss_device *dssdev = to_dss_device(dev);
8359 + struct omap_video_timings t;
8362 + if (!dssdev->set_timings || !dssdev->check_timings)
8366 +#ifdef CONFIG_OMAP2_DSS_VENC
8367 + if (strncmp("pal", buf, 3) == 0) {
8368 + t = omap_dss_pal_timings;
8370 + } else if (strncmp("ntsc", buf, 4) == 0) {
8371 + t = omap_dss_ntsc_timings;
8375 + if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
8377 + &t.x_res, &t.hfp, &t.hbp, &t.hsw,
8378 + &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
8381 + r = dssdev->check_timings(dssdev, &t);
8385 + dssdev->set_timings(dssdev, &t);
8390 +static ssize_t display_rotate_show(struct device *dev,
8391 + struct device_attribute *attr, char *buf)
8393 + struct omap_dss_device *dssdev = to_dss_device(dev);
8395 + if (!dssdev->get_rotate)
8397 + rotate = dssdev->get_rotate(dssdev);
8398 + return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
8401 +static ssize_t display_rotate_store(struct device *dev,
8402 + struct device_attribute *attr, const char *buf, size_t size)
8404 + struct omap_dss_device *dssdev = to_dss_device(dev);
8405 + unsigned long rot;
8408 + if (!dssdev->set_rotate || !dssdev->get_rotate)
8411 + rot = simple_strtoul(buf, NULL, 0);
8413 + r = dssdev->set_rotate(dssdev, rot);
8420 +static ssize_t display_mirror_show(struct device *dev,
8421 + struct device_attribute *attr, char *buf)
8423 + struct omap_dss_device *dssdev = to_dss_device(dev);
8425 + if (!dssdev->get_mirror)
8427 + mirror = dssdev->get_mirror(dssdev);
8428 + return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
8431 +static ssize_t display_mirror_store(struct device *dev,
8432 + struct device_attribute *attr, const char *buf, size_t size)
8434 + struct omap_dss_device *dssdev = to_dss_device(dev);
8435 + unsigned long mirror;
8438 + if (!dssdev->set_mirror || !dssdev->get_mirror)
8441 + mirror = simple_strtoul(buf, NULL, 0);
8443 + r = dssdev->set_mirror(dssdev, mirror);
8450 +static ssize_t display_wss_show(struct device *dev,
8451 + struct device_attribute *attr, char *buf)
8453 + struct omap_dss_device *dssdev = to_dss_device(dev);
8456 + if (!dssdev->get_wss)
8459 + wss = dssdev->get_wss(dssdev);
8461 + return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
8464 +static ssize_t display_wss_store(struct device *dev,
8465 + struct device_attribute *attr, const char *buf, size_t size)
8467 + struct omap_dss_device *dssdev = to_dss_device(dev);
8468 + unsigned long wss;
8471 + if (!dssdev->get_wss || !dssdev->set_wss)
8474 + if (strict_strtoul(buf, 0, &wss))
8477 + if (wss > 0xfffff)
8480 + r = dssdev->set_wss(dssdev, wss);
8487 +static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
8488 + display_enabled_show, display_enabled_store);
8489 +static DEVICE_ATTR(update_mode, S_IRUGO|S_IWUSR,
8490 + display_upd_mode_show, display_upd_mode_store);
8491 +static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
8492 + display_tear_show, display_tear_store);
8493 +static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
8494 + display_timings_show, display_timings_store);
8495 +static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
8496 + display_rotate_show, display_rotate_store);
8497 +static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
8498 + display_mirror_show, display_mirror_store);
8499 +static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
8500 + display_wss_show, display_wss_store);
8502 +static struct device_attribute *display_sysfs_attrs[] = {
8503 + &dev_attr_enabled,
8504 + &dev_attr_update_mode,
8505 + &dev_attr_tear_elim,
8506 + &dev_attr_timings,
8513 +static void default_get_resolution(struct omap_dss_device *dssdev,
8514 + u16 *xres, u16 *yres)
8516 + *xres = dssdev->panel.timings.x_res;
8517 + *yres = dssdev->panel.timings.y_res;
8520 +void default_get_overlay_fifo_thresholds(enum omap_plane plane,
8521 + u32 fifo_size, enum omap_burst_size *burst_size,
8522 + u32 *fifo_low, u32 *fifo_high)
8524 + unsigned burst_size_bytes;
8526 + *burst_size = OMAP_DSS_BURST_16x32;
8527 + burst_size_bytes = 16 * 32 / 8;
8529 + *fifo_high = fifo_size - 1;
8530 + *fifo_low = fifo_size - burst_size_bytes;
8533 +static int default_wait_vsync(struct omap_dss_device *dssdev)
8535 + unsigned long timeout = msecs_to_jiffies(500);
8538 + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
8539 + irq = DISPC_IRQ_EVSYNC_ODD;
8541 + irq = DISPC_IRQ_VSYNC;
8543 + return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
8546 +static int default_get_recommended_bpp(struct omap_dss_device *dssdev)
8548 + if (dssdev->panel.recommended_bpp)
8549 + return dssdev->panel.recommended_bpp;
8551 + switch (dssdev->type) {
8552 + case OMAP_DISPLAY_TYPE_DPI:
8553 + if (dssdev->phy.dpi.data_lines == 24)
8558 + case OMAP_DISPLAY_TYPE_DBI:
8559 + case OMAP_DISPLAY_TYPE_DSI:
8560 + if (dssdev->ctrl.pixel_size == 24)
8564 + case OMAP_DISPLAY_TYPE_VENC:
8565 + case OMAP_DISPLAY_TYPE_SDI:
8573 +/* Checks if replication logic should be used. Only use for active matrix,
8574 + * when overlay is in RGB12U or RGB16 mode, and LCD interface is
8575 + * 18bpp or 24bpp */
8576 +bool dss_use_replication(struct omap_dss_device *dssdev,
8577 + enum omap_color_mode mode)
8581 + if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
8584 + if (dssdev->type == OMAP_DISPLAY_TYPE_DPI &&
8585 + (dssdev->panel.config & OMAP_DSS_LCD_TFT) == 0)
8588 + switch (dssdev->type) {
8589 + case OMAP_DISPLAY_TYPE_DPI:
8590 + bpp = dssdev->phy.dpi.data_lines;
8592 + case OMAP_DISPLAY_TYPE_VENC:
8593 + case OMAP_DISPLAY_TYPE_SDI:
8596 + case OMAP_DISPLAY_TYPE_DBI:
8597 + case OMAP_DISPLAY_TYPE_DSI:
8598 + bpp = dssdev->ctrl.pixel_size;
8607 +void dss_init_device(struct platform_device *pdev,
8608 + struct omap_dss_device *dssdev)
8610 + struct device_attribute *attr;
8614 + switch (dssdev->type) {
8615 + case OMAP_DISPLAY_TYPE_DPI:
8616 +#ifdef CONFIG_OMAP2_DSS_RFBI
8617 + case OMAP_DISPLAY_TYPE_DBI:
8619 +#ifdef CONFIG_OMAP2_DSS_SDI
8620 + case OMAP_DISPLAY_TYPE_SDI:
8622 +#ifdef CONFIG_OMAP2_DSS_DSI
8623 + case OMAP_DISPLAY_TYPE_DSI:
8625 +#ifdef CONFIG_OMAP2_DSS_VENC
8626 + case OMAP_DISPLAY_TYPE_VENC:
8630 + DSSERR("Support for display '%s' not compiled in.\n",
8635 + dssdev->get_resolution = default_get_resolution;
8636 + dssdev->get_recommended_bpp = default_get_recommended_bpp;
8637 + dssdev->wait_vsync = default_wait_vsync;
8639 + switch (dssdev->type) {
8640 + case OMAP_DISPLAY_TYPE_DPI:
8641 + r = dpi_init_display(dssdev);
8643 +#ifdef CONFIG_OMAP2_DSS_RFBI
8644 + case OMAP_DISPLAY_TYPE_DBI:
8645 + r = rfbi_init_display(dssdev);
8648 +#ifdef CONFIG_OMAP2_DSS_VENC
8649 + case OMAP_DISPLAY_TYPE_VENC:
8650 + r = venc_init_display(dssdev);
8653 +#ifdef CONFIG_OMAP2_DSS_SDI
8654 + case OMAP_DISPLAY_TYPE_SDI:
8655 + r = sdi_init_display(dssdev);
8658 +#ifdef CONFIG_OMAP2_DSS_DSI
8659 + case OMAP_DISPLAY_TYPE_DSI:
8660 + r = dsi_init_display(dssdev);
8668 + DSSERR("failed to init display %s\n", dssdev->name);
8672 + /* create device sysfs files */
8674 + while ((attr = display_sysfs_attrs[i++]) != NULL) {
8675 + r = device_create_file(&dssdev->dev, attr);
8677 + DSSERR("failed to create sysfs file\n");
8680 + /* create display? sysfs links */
8681 + r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
8682 + dev_name(&dssdev->dev));
8684 + DSSERR("failed to create sysfs display link\n");
8687 +void dss_uninit_device(struct platform_device *pdev,
8688 + struct omap_dss_device *dssdev)
8690 + struct device_attribute *attr;
8693 + sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev));
8695 + while ((attr = display_sysfs_attrs[i++]) != NULL)
8696 + device_remove_file(&dssdev->dev, attr);
8698 + if (dssdev->manager)
8699 + dssdev->manager->unset_device(dssdev->manager);
8702 +static int dss_suspend_device(struct device *dev, void *data)
8705 + struct omap_dss_device *dssdev = to_dss_device(dev);
8707 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
8708 + dssdev->activate_after_resume = false;
8712 + if (!dssdev->suspend) {
8713 + DSSERR("display '%s' doesn't implement suspend\n",
8718 + r = dssdev->suspend(dssdev);
8722 + dssdev->activate_after_resume = true;
8727 +int dss_suspend_all_devices(void)
8730 + struct bus_type *bus = dss_get_bus();
8732 + r = bus_for_each_dev(bus, NULL, NULL, dss_suspend_device);
8734 + /* resume all displays that were suspended */
8735 + dss_resume_all_devices();
8742 +static int dss_resume_device(struct device *dev, void *data)
8745 + struct omap_dss_device *dssdev = to_dss_device(dev);
8747 + if (dssdev->activate_after_resume && dssdev->resume) {
8748 + r = dssdev->resume(dssdev);
8753 + dssdev->activate_after_resume = false;
8758 +int dss_resume_all_devices(void)
8760 + struct bus_type *bus = dss_get_bus();
8762 + return bus_for_each_dev(bus, NULL, NULL, dss_resume_device);
8766 +void omap_dss_get_device(struct omap_dss_device *dssdev)
8768 + get_device(&dssdev->dev);
8770 +EXPORT_SYMBOL(omap_dss_get_device);
8772 +void omap_dss_put_device(struct omap_dss_device *dssdev)
8774 + put_device(&dssdev->dev);
8776 +EXPORT_SYMBOL(omap_dss_put_device);
8778 +/* ref count of the found device is incremented. ref count
8779 + * of from-device is decremented. */
8780 +struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
8782 + struct device *dev;
8783 + struct device *dev_start = NULL;
8784 + struct omap_dss_device *dssdev = NULL;
8786 + int match(struct device *dev, void *data)
8788 + /* skip panels connected to controllers */
8789 + if (to_dss_device(dev)->panel.ctrl)
8796 + dev_start = &from->dev;
8797 + dev = bus_find_device(dss_get_bus(), dev_start, NULL, match);
8799 + dssdev = to_dss_device(dev);
8801 + put_device(&from->dev);
8805 +EXPORT_SYMBOL(omap_dss_get_next_device);
8807 +struct omap_dss_device *omap_dss_find_device(void *data,
8808 + int (*match)(struct omap_dss_device *dssdev, void *data))
8810 + struct omap_dss_device *dssdev = NULL;
8812 + while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
8813 + if (match(dssdev, data))
8819 +EXPORT_SYMBOL(omap_dss_find_device);
8821 +int omap_dss_start_device(struct omap_dss_device *dssdev)
8825 + if (!dssdev->driver) {
8826 + DSSDBG("no driver\n");
8831 + if (dssdev->ctrl.panel && !dssdev->ctrl.panel->driver) {
8832 + DSSDBG("no panel driver\n");
8837 + if (!try_module_get(dssdev->dev.driver->owner)) {
8842 + if (dssdev->ctrl.panel) {
8843 + if (!try_module_get(dssdev->ctrl.panel->dev.driver->owner)) {
8851 + module_put(dssdev->dev.driver->owner);
8855 +EXPORT_SYMBOL(omap_dss_start_device);
8857 +void omap_dss_stop_device(struct omap_dss_device *dssdev)
8859 + if (dssdev->ctrl.panel)
8860 + module_put(dssdev->ctrl.panel->dev.driver->owner);
8862 + module_put(dssdev->dev.driver->owner);
8864 +EXPORT_SYMBOL(omap_dss_stop_device);
8866 diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
8867 new file mode 100644
8868 index 0000000..b6543c8
8870 +++ b/drivers/video/omap2/dss/dpi.c
8873 + * linux/drivers/video/omap2/dss/dpi.c
8875 + * Copyright (C) 2009 Nokia Corporation
8876 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
8878 + * Some code and ideas taken from drivers/video/omap/ driver
8881 + * This program is free software; you can redistribute it and/or modify it
8882 + * under the terms of the GNU General Public License version 2 as published by
8883 + * the Free Software Foundation.
8885 + * This program is distributed in the hope that it will be useful, but WITHOUT
8886 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
8887 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
8890 + * You should have received a copy of the GNU General Public License along with
8891 + * this program. If not, see <http://www.gnu.org/licenses/>.
8894 +#define DSS_SUBSYS_NAME "DPI"
8896 +#include <linux/kernel.h>
8897 +#include <linux/clk.h>
8898 +#include <linux/delay.h>
8899 +#include <linux/errno.h>
8901 +#include <mach/board.h>
8902 +#include <mach/display.h>
8903 +#include <mach/cpu.h>
8908 + int update_enabled;
8911 +#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
8912 +static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
8913 + unsigned long *fck, int *lck_div, int *pck_div)
8915 + struct dsi_clock_info cinfo;
8918 + r = dsi_pll_calc_pck(is_tft, pck_req, &cinfo);
8922 + r = dsi_pll_program(&cinfo);
8926 + dss_select_clk_source(0, 1);
8928 + dispc_set_lcd_divisor(cinfo.lck_div, cinfo.pck_div);
8930 + *fck = cinfo.dsi1_pll_fclk;
8931 + *lck_div = cinfo.lck_div;
8932 + *pck_div = cinfo.pck_div;
8937 +static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
8938 + unsigned long *fck, int *lck_div, int *pck_div)
8940 + struct dispc_clock_info cinfo;
8943 + r = dispc_calc_clock_div(is_tft, pck_req, &cinfo);
8947 + r = dispc_set_clock_div(&cinfo);
8952 + *lck_div = cinfo.lck_div;
8953 + *pck_div = cinfo.pck_div;
8959 +static int dpi_set_mode(struct omap_dss_device *dssdev)
8961 + struct omap_video_timings *t = &dssdev->panel.timings;
8962 + int lck_div, pck_div;
8963 + unsigned long fck;
8964 + unsigned long pck;
8968 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
8970 + dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
8971 + dssdev->panel.acb);
8973 + is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
8975 +#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
8976 + r = dpi_set_dsi_clk(is_tft, t->pixel_clock * 1000,
8977 + &fck, &lck_div, &pck_div);
8979 + r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000,
8980 + &fck, &lck_div, &pck_div);
8985 + pck = fck / lck_div / pck_div / 1000;
8987 + if (pck != t->pixel_clock) {
8988 + DSSWARN("Could not find exact pixel clock. "
8989 + "Requested %d kHz, got %lu kHz\n",
8990 + t->pixel_clock, pck);
8992 + t->pixel_clock = pck;
8995 + dispc_set_lcd_timings(t);
8998 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
9002 +static int dpi_basic_init(struct omap_dss_device *dssdev)
9006 + is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
9008 + dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
9009 + dispc_set_lcd_display_type(is_tft ? OMAP_DSS_LCD_DISPLAY_TFT :
9010 + OMAP_DSS_LCD_DISPLAY_STN);
9011 + dispc_set_tft_data_lines(dssdev->phy.dpi.data_lines);
9016 +static int dpi_display_enable(struct omap_dss_device *dssdev)
9020 + r = omap_dss_start_device(dssdev);
9022 + DSSERR("failed to start device\n");
9026 + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
9027 + DSSERR("display already enabled\n");
9032 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
9034 + r = dpi_basic_init(dssdev);
9038 +#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
9039 + dss_clk_enable(DSS_CLK_FCK2);
9040 + r = dsi_pll_init(0, 1);
9044 + r = dpi_set_mode(dssdev);
9050 + dispc_enable_lcd_out(1);
9052 + r = dssdev->driver->enable(dssdev);
9056 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
9061 + dispc_enable_lcd_out(0);
9063 +#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
9066 + dss_clk_disable(DSS_CLK_FCK2);
9069 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
9071 + omap_dss_stop_device(dssdev);
9076 +static int dpi_display_resume(struct omap_dss_device *dssdev);
9078 +static void dpi_display_disable(struct omap_dss_device *dssdev)
9080 + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
9083 + if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
9084 + dpi_display_resume(dssdev);
9086 + dssdev->driver->disable(dssdev);
9088 + dispc_enable_lcd_out(0);
9090 +#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
9091 + dss_select_clk_source(0, 0);
9093 + dss_clk_disable(DSS_CLK_FCK2);
9096 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
9098 + dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
9100 + omap_dss_stop_device(dssdev);
9103 +static int dpi_display_suspend(struct omap_dss_device *dssdev)
9105 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
9108 + DSSDBG("dpi_display_suspend\n");
9110 + if (dssdev->driver->suspend)
9111 + dssdev->driver->suspend(dssdev);
9113 + dispc_enable_lcd_out(0);
9115 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
9117 + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
9122 +static int dpi_display_resume(struct omap_dss_device *dssdev)
9124 + if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
9127 + DSSDBG("dpi_display_resume\n");
9129 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
9131 + dispc_enable_lcd_out(1);
9133 + if (dssdev->driver->resume)
9134 + dssdev->driver->resume(dssdev);
9136 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
9141 +static void dpi_set_timings(struct omap_dss_device *dssdev,
9142 + struct omap_video_timings *timings)
9144 + DSSDBG("dpi_set_timings\n");
9145 + dssdev->panel.timings = *timings;
9146 + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
9147 + dpi_set_mode(dssdev);
9148 + dispc_go(OMAP_DSS_CHANNEL_LCD);
9152 +static int dpi_check_timings(struct omap_dss_device *dssdev,
9153 + struct omap_video_timings *timings)
9157 + int lck_div, pck_div;
9158 + unsigned long fck;
9159 + unsigned long pck;
9161 + if (!dispc_lcd_timings_ok(timings))
9164 + if (timings->pixel_clock == 0)
9167 + is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
9169 +#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
9171 + struct dsi_clock_info cinfo;
9172 + r = dsi_pll_calc_pck(is_tft, timings->pixel_clock * 1000,
9178 + fck = cinfo.dsi1_pll_fclk;
9179 + lck_div = cinfo.lck_div;
9180 + pck_div = cinfo.pck_div;
9184 + struct dispc_clock_info cinfo;
9185 + r = dispc_calc_clock_div(is_tft, timings->pixel_clock * 1000,
9192 + lck_div = cinfo.lck_div;
9193 + pck_div = cinfo.pck_div;
9197 + pck = fck / lck_div / pck_div / 1000;
9199 + timings->pixel_clock = pck;
9204 +static void dpi_get_timings(struct omap_dss_device *dssdev,
9205 + struct omap_video_timings *timings)
9207 + *timings = dssdev->panel.timings;
9210 +static int dpi_display_set_update_mode(struct omap_dss_device *dssdev,
9211 + enum omap_dss_update_mode mode)
9213 + if (mode == OMAP_DSS_UPDATE_MANUAL)
9216 + if (mode == OMAP_DSS_UPDATE_DISABLED) {
9217 + dispc_enable_lcd_out(0);
9218 + dpi.update_enabled = 0;
9220 + dispc_enable_lcd_out(1);
9221 + dpi.update_enabled = 1;
9227 +static enum omap_dss_update_mode dpi_display_get_update_mode(
9228 + struct omap_dss_device *dssdev)
9230 + return dpi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
9231 + OMAP_DSS_UPDATE_DISABLED;
9234 +int dpi_init_display(struct omap_dss_device *dssdev)
9236 + DSSDBG("init_display\n");
9238 + dssdev->enable = dpi_display_enable;
9239 + dssdev->disable = dpi_display_disable;
9240 + dssdev->suspend = dpi_display_suspend;
9241 + dssdev->resume = dpi_display_resume;
9242 + dssdev->set_timings = dpi_set_timings;
9243 + dssdev->check_timings = dpi_check_timings;
9244 + dssdev->get_timings = dpi_get_timings;
9245 + dssdev->set_update_mode = dpi_display_set_update_mode;
9246 + dssdev->get_update_mode = dpi_display_get_update_mode;
9256 +void dpi_exit(void)
9260 diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
9261 new file mode 100644
9262 index 0000000..d43b9ce
9264 +++ b/drivers/video/omap2/dss/dsi.c
9267 + * linux/drivers/video/omap2/dss/dsi.c
9269 + * Copyright (C) 2009 Nokia Corporation
9270 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
9272 + * This program is free software; you can redistribute it and/or modify it
9273 + * under the terms of the GNU General Public License version 2 as published by
9274 + * the Free Software Foundation.
9276 + * This program is distributed in the hope that it will be useful, but WITHOUT
9277 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9278 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
9281 + * You should have received a copy of the GNU General Public License along with
9282 + * this program. If not, see <http://www.gnu.org/licenses/>.
9285 +#define DSS_SUBSYS_NAME "DSI"
9287 +#include <linux/kernel.h>
9288 +#include <linux/io.h>
9289 +#include <linux/clk.h>
9290 +#include <linux/device.h>
9291 +#include <linux/err.h>
9292 +#include <linux/interrupt.h>
9293 +#include <linux/delay.h>
9294 +#include <linux/mutex.h>
9295 +#include <linux/seq_file.h>
9296 +#include <linux/platform_device.h>
9297 +#include <linux/regulator/consumer.h>
9298 +#include <linux/kthread.h>
9299 +#include <linux/wait.h>
9301 +#include <mach/board.h>
9302 +#include <mach/display.h>
9303 +#include <mach/clock.h>
9307 +/*#define VERBOSE_IRQ*/
9309 +#define DSI_BASE 0x4804FC00
9311 +struct dsi_reg { u16 idx; };
9313 +#define DSI_REG(idx) ((const struct dsi_reg) { idx })
9315 +#define DSI_SZ_REGS SZ_1K
9316 +/* DSI Protocol Engine */
9318 +#define DSI_REVISION DSI_REG(0x0000)
9319 +#define DSI_SYSCONFIG DSI_REG(0x0010)
9320 +#define DSI_SYSSTATUS DSI_REG(0x0014)
9321 +#define DSI_IRQSTATUS DSI_REG(0x0018)
9322 +#define DSI_IRQENABLE DSI_REG(0x001C)
9323 +#define DSI_CTRL DSI_REG(0x0040)
9324 +#define DSI_COMPLEXIO_CFG1 DSI_REG(0x0048)
9325 +#define DSI_COMPLEXIO_IRQ_STATUS DSI_REG(0x004C)
9326 +#define DSI_COMPLEXIO_IRQ_ENABLE DSI_REG(0x0050)
9327 +#define DSI_CLK_CTRL DSI_REG(0x0054)
9328 +#define DSI_TIMING1 DSI_REG(0x0058)
9329 +#define DSI_TIMING2 DSI_REG(0x005C)
9330 +#define DSI_VM_TIMING1 DSI_REG(0x0060)
9331 +#define DSI_VM_TIMING2 DSI_REG(0x0064)
9332 +#define DSI_VM_TIMING3 DSI_REG(0x0068)
9333 +#define DSI_CLK_TIMING DSI_REG(0x006C)
9334 +#define DSI_TX_FIFO_VC_SIZE DSI_REG(0x0070)
9335 +#define DSI_RX_FIFO_VC_SIZE DSI_REG(0x0074)
9336 +#define DSI_COMPLEXIO_CFG2 DSI_REG(0x0078)
9337 +#define DSI_RX_FIFO_VC_FULLNESS DSI_REG(0x007C)
9338 +#define DSI_VM_TIMING4 DSI_REG(0x0080)
9339 +#define DSI_TX_FIFO_VC_EMPTINESS DSI_REG(0x0084)
9340 +#define DSI_VM_TIMING5 DSI_REG(0x0088)
9341 +#define DSI_VM_TIMING6 DSI_REG(0x008C)
9342 +#define DSI_VM_TIMING7 DSI_REG(0x0090)
9343 +#define DSI_STOPCLK_TIMING DSI_REG(0x0094)
9344 +#define DSI_VC_CTRL(n) DSI_REG(0x0100 + (n * 0x20))
9345 +#define DSI_VC_TE(n) DSI_REG(0x0104 + (n * 0x20))
9346 +#define DSI_VC_LONG_PACKET_HEADER(n) DSI_REG(0x0108 + (n * 0x20))
9347 +#define DSI_VC_LONG_PACKET_PAYLOAD(n) DSI_REG(0x010C + (n * 0x20))
9348 +#define DSI_VC_SHORT_PACKET_HEADER(n) DSI_REG(0x0110 + (n * 0x20))
9349 +#define DSI_VC_IRQSTATUS(n) DSI_REG(0x0118 + (n * 0x20))
9350 +#define DSI_VC_IRQENABLE(n) DSI_REG(0x011C + (n * 0x20))
9354 +#define DSI_DSIPHY_CFG0 DSI_REG(0x200 + 0x0000)
9355 +#define DSI_DSIPHY_CFG1 DSI_REG(0x200 + 0x0004)
9356 +#define DSI_DSIPHY_CFG2 DSI_REG(0x200 + 0x0008)
9357 +#define DSI_DSIPHY_CFG5 DSI_REG(0x200 + 0x0014)
9359 +/* DSI_PLL_CTRL_SCP */
9361 +#define DSI_PLL_CONTROL DSI_REG(0x300 + 0x0000)
9362 +#define DSI_PLL_STATUS DSI_REG(0x300 + 0x0004)
9363 +#define DSI_PLL_GO DSI_REG(0x300 + 0x0008)
9364 +#define DSI_PLL_CONFIGURATION1 DSI_REG(0x300 + 0x000C)
9365 +#define DSI_PLL_CONFIGURATION2 DSI_REG(0x300 + 0x0010)
9367 +#define REG_GET(idx, start, end) \
9368 + FLD_GET(dsi_read_reg(idx), start, end)
9370 +#define REG_FLD_MOD(idx, val, start, end) \
9371 + dsi_write_reg(idx, FLD_MOD(dsi_read_reg(idx), val, start, end))
9373 +/* Global interrupts */
9374 +#define DSI_IRQ_VC0 (1 << 0)
9375 +#define DSI_IRQ_VC1 (1 << 1)
9376 +#define DSI_IRQ_VC2 (1 << 2)
9377 +#define DSI_IRQ_VC3 (1 << 3)
9378 +#define DSI_IRQ_WAKEUP (1 << 4)
9379 +#define DSI_IRQ_RESYNC (1 << 5)
9380 +#define DSI_IRQ_PLL_LOCK (1 << 7)
9381 +#define DSI_IRQ_PLL_UNLOCK (1 << 8)
9382 +#define DSI_IRQ_PLL_RECALL (1 << 9)
9383 +#define DSI_IRQ_COMPLEXIO_ERR (1 << 10)
9384 +#define DSI_IRQ_HS_TX_TIMEOUT (1 << 14)
9385 +#define DSI_IRQ_LP_RX_TIMEOUT (1 << 15)
9386 +#define DSI_IRQ_TE_TRIGGER (1 << 16)
9387 +#define DSI_IRQ_ACK_TRIGGER (1 << 17)
9388 +#define DSI_IRQ_SYNC_LOST (1 << 18)
9389 +#define DSI_IRQ_LDO_POWER_GOOD (1 << 19)
9390 +#define DSI_IRQ_TA_TIMEOUT (1 << 20)
9391 +#define DSI_IRQ_ERROR_MASK \
9392 + (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \
9393 + DSI_IRQ_TA_TIMEOUT)
9394 +#define DSI_IRQ_CHANNEL_MASK 0xf
9396 +/* Virtual channel interrupts */
9397 +#define DSI_VC_IRQ_CS (1 << 0)
9398 +#define DSI_VC_IRQ_ECC_CORR (1 << 1)
9399 +#define DSI_VC_IRQ_PACKET_SENT (1 << 2)
9400 +#define DSI_VC_IRQ_FIFO_TX_OVF (1 << 3)
9401 +#define DSI_VC_IRQ_FIFO_RX_OVF (1 << 4)
9402 +#define DSI_VC_IRQ_BTA (1 << 5)
9403 +#define DSI_VC_IRQ_ECC_NO_CORR (1 << 6)
9404 +#define DSI_VC_IRQ_FIFO_TX_UDF (1 << 7)
9405 +#define DSI_VC_IRQ_PP_BUSY_CHANGE (1 << 8)
9406 +#define DSI_VC_IRQ_ERROR_MASK \
9407 + (DSI_VC_IRQ_CS | DSI_VC_IRQ_ECC_CORR | DSI_VC_IRQ_FIFO_TX_OVF | \
9408 + DSI_VC_IRQ_FIFO_RX_OVF | DSI_VC_IRQ_ECC_NO_CORR | \
9409 + DSI_VC_IRQ_FIFO_TX_UDF)
9411 +/* ComplexIO interrupts */
9412 +#define DSI_CIO_IRQ_ERRSYNCESC1 (1 << 0)
9413 +#define DSI_CIO_IRQ_ERRSYNCESC2 (1 << 1)
9414 +#define DSI_CIO_IRQ_ERRSYNCESC3 (1 << 2)
9415 +#define DSI_CIO_IRQ_ERRESC1 (1 << 5)
9416 +#define DSI_CIO_IRQ_ERRESC2 (1 << 6)
9417 +#define DSI_CIO_IRQ_ERRESC3 (1 << 7)
9418 +#define DSI_CIO_IRQ_ERRCONTROL1 (1 << 10)
9419 +#define DSI_CIO_IRQ_ERRCONTROL2 (1 << 11)
9420 +#define DSI_CIO_IRQ_ERRCONTROL3 (1 << 12)
9421 +#define DSI_CIO_IRQ_STATEULPS1 (1 << 15)
9422 +#define DSI_CIO_IRQ_STATEULPS2 (1 << 16)
9423 +#define DSI_CIO_IRQ_STATEULPS3 (1 << 17)
9424 +#define DSI_CIO_IRQ_ERRCONTENTIONLP0_1 (1 << 20)
9425 +#define DSI_CIO_IRQ_ERRCONTENTIONLP1_1 (1 << 21)
9426 +#define DSI_CIO_IRQ_ERRCONTENTIONLP0_2 (1 << 22)
9427 +#define DSI_CIO_IRQ_ERRCONTENTIONLP1_2 (1 << 23)
9428 +#define DSI_CIO_IRQ_ERRCONTENTIONLP0_3 (1 << 24)
9429 +#define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25)
9430 +#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30)
9431 +#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31)
9433 +#define DSI_DT_DCS_SHORT_WRITE_0 0x05
9434 +#define DSI_DT_DCS_SHORT_WRITE_1 0x15
9435 +#define DSI_DT_DCS_READ 0x06
9436 +#define DSI_DT_SET_MAX_RET_PKG_SIZE 0x37
9437 +#define DSI_DT_NULL_PACKET 0x09
9438 +#define DSI_DT_DCS_LONG_WRITE 0x39
9440 +#define DSI_DT_RX_ACK_WITH_ERR 0x02
9441 +#define DSI_DT_RX_DCS_LONG_READ 0x1c
9442 +#define DSI_DT_RX_SHORT_READ_1 0x21
9443 +#define DSI_DT_RX_SHORT_READ_2 0x22
9445 +#define FINT_MAX 2100000
9446 +#define FINT_MIN 750000
9447 +#define REGN_MAX (1 << 7)
9448 +#define REGM_MAX ((1 << 11) - 1)
9449 +#define REGM3_MAX (1 << 4)
9450 +#define REGM4_MAX (1 << 4)
9453 + DSI_FIFO_SIZE_0 = 0,
9454 + DSI_FIFO_SIZE_32 = 1,
9455 + DSI_FIFO_SIZE_64 = 2,
9456 + DSI_FIFO_SIZE_96 = 3,
9457 + DSI_FIFO_SIZE_128 = 4,
9461 + DSI_VC_MODE_L4 = 0,
9465 +struct dsi_update_region {
9468 + struct omap_dss_device *device;
9473 + void __iomem *base;
9475 + unsigned long dsi1_pll_fclk; /* Hz */
9476 + unsigned long dsi2_pll_fclk; /* Hz */
9477 + unsigned long dsiphy; /* Hz */
9478 + unsigned long ddr_clk; /* Hz */
9480 + struct regulator *vdds_dsi_reg;
9483 + enum dsi_vc_mode mode;
9484 + struct omap_dss_device *dssdev;
9485 + enum fifo_size fifo_size;
9486 + int dest_per; /* destination peripheral 0-3 */
9489 + struct mutex lock;
9490 + struct mutex bus_lock;
9492 + unsigned pll_locked;
9494 + struct completion bta_completion;
9496 + struct task_struct *thread;
9497 + wait_queue_head_t waitqueue;
9499 + spinlock_t update_lock;
9500 + bool framedone_received;
9501 + struct dsi_update_region update_region;
9502 + struct dsi_update_region active_update_region;
9503 + struct completion update_completion;
9505 + enum omap_dss_update_mode user_update_mode;
9506 + enum omap_dss_update_mode update_mode;
9510 + unsigned long cache_req_pck;
9511 + unsigned long cache_clk_freq;
9512 + struct dsi_clock_info cache_cinfo;
9515 + spinlock_t errors_lock;
9517 + ktime_t perf_setup_time;
9518 + ktime_t perf_start_time;
9519 + ktime_t perf_start_time_auto;
9520 + int perf_measure_frames;
9527 +static unsigned int dsi_perf;
9528 +module_param_named(dsi_perf, dsi_perf, bool, 0644);
9531 +static inline void dsi_write_reg(const struct dsi_reg idx, u32 val)
9533 + __raw_writel(val, dsi.base + idx.idx);
9536 +static inline u32 dsi_read_reg(const struct dsi_reg idx)
9538 + return __raw_readl(dsi.base + idx.idx);
9542 +void dsi_save_context(void)
9546 +void dsi_restore_context(void)
9550 +void dsi_bus_lock(void)
9552 + mutex_lock(&dsi.bus_lock);
9554 +EXPORT_SYMBOL(dsi_bus_lock);
9556 +void dsi_bus_unlock(void)
9558 + mutex_unlock(&dsi.bus_lock);
9560 +EXPORT_SYMBOL(dsi_bus_unlock);
9562 +static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
9567 + while (REG_GET(idx, bitnum, bitnum) != value) {
9576 +static void dsi_perf_mark_setup(void)
9578 + dsi.perf_setup_time = ktime_get();
9581 +static void dsi_perf_mark_start(void)
9583 + dsi.perf_start_time = ktime_get();
9586 +static void dsi_perf_mark_start_auto(void)
9588 + dsi.perf_measure_frames = 0;
9589 + dsi.perf_start_time_auto = ktime_get();
9592 +static void dsi_perf_show(const char *name)
9594 + ktime_t t, setup_time, trans_time;
9596 + u32 setup_us, trans_us, total_us;
9601 + if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED)
9606 + setup_time = ktime_sub(dsi.perf_start_time, dsi.perf_setup_time);
9607 + setup_us = (u32)ktime_to_us(setup_time);
9608 + if (setup_us == 0)
9611 + trans_time = ktime_sub(t, dsi.perf_start_time);
9612 + trans_us = (u32)ktime_to_us(trans_time);
9613 + if (trans_us == 0)
9616 + total_us = setup_us + trans_us;
9618 + total_bytes = dsi.active_update_region.w *
9619 + dsi.active_update_region.h *
9620 + dsi.active_update_region.device->ctrl.pixel_size / 8;
9622 + if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) {
9623 + static u32 s_total_trans_us, s_total_setup_us;
9624 + static u32 s_min_trans_us = 0xffffffff, s_min_setup_us;
9625 + static u32 s_max_trans_us, s_max_setup_us;
9626 + const int numframes = 100;
9627 + ktime_t total_time_auto;
9628 + u32 total_time_auto_us;
9630 + dsi.perf_measure_frames++;
9632 + if (setup_us < s_min_setup_us)
9633 + s_min_setup_us = setup_us;
9635 + if (setup_us > s_max_setup_us)
9636 + s_max_setup_us = setup_us;
9638 + s_total_setup_us += setup_us;
9640 + if (trans_us < s_min_trans_us)
9641 + s_min_trans_us = trans_us;
9643 + if (trans_us > s_max_trans_us)
9644 + s_max_trans_us = trans_us;
9646 + s_total_trans_us += trans_us;
9648 + if (dsi.perf_measure_frames < numframes)
9651 + total_time_auto = ktime_sub(t, dsi.perf_start_time_auto);
9652 + total_time_auto_us = (u32)ktime_to_us(total_time_auto);
9654 + printk(KERN_INFO "DSI(%s): %u fps, setup %u/%u/%u, "
9655 + "trans %u/%u/%u\n",
9657 + 1000 * 1000 * numframes / total_time_auto_us,
9660 + s_total_setup_us / numframes,
9663 + s_total_trans_us / numframes);
9665 + s_total_setup_us = 0;
9666 + s_min_setup_us = 0xffffffff;
9667 + s_max_setup_us = 0;
9668 + s_total_trans_us = 0;
9669 + s_min_trans_us = 0xffffffff;
9670 + s_max_trans_us = 0;
9671 + dsi_perf_mark_start_auto();
9673 + printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
9674 + "%u bytes, %u kbytes/sec\n",
9679 + 1000*1000 / total_us,
9681 + total_bytes * 1000 / total_us);
9685 +#define dsi_perf_mark_setup()
9686 +#define dsi_perf_mark_start()
9687 +#define dsi_perf_mark_start_auto()
9688 +#define dsi_perf_show(x)
9691 +static void print_irq_status(u32 status)
9693 +#ifndef VERBOSE_IRQ
9694 + if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0)
9697 + printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status);
9700 + if (status & DSI_IRQ_##x) \
9713 + PIS(COMPLEXIO_ERR);
9714 + PIS(HS_TX_TIMEOUT);
9715 + PIS(LP_RX_TIMEOUT);
9719 + PIS(LDO_POWER_GOOD);
9726 +static void print_irq_status_vc(int channel, u32 status)
9728 +#ifndef VERBOSE_IRQ
9729 + if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
9732 + printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status);
9735 + if (status & DSI_VC_IRQ_##x) \
9747 + PIS(PP_BUSY_CHANGE);
9752 +static void print_irq_status_cio(u32 status)
9754 + printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status);
9757 + if (status & DSI_CIO_IRQ_##x) \
9771 + PIS(ERRCONTENTIONLP0_1);
9772 + PIS(ERRCONTENTIONLP1_1);
9773 + PIS(ERRCONTENTIONLP0_2);
9774 + PIS(ERRCONTENTIONLP1_2);
9775 + PIS(ERRCONTENTIONLP0_3);
9776 + PIS(ERRCONTENTIONLP1_3);
9777 + PIS(ULPSACTIVENOT_ALL0);
9778 + PIS(ULPSACTIVENOT_ALL1);
9784 +static int debug_irq;
9786 +/* called from dss */
9787 +void dsi_irq_handler(void)
9789 + u32 irqstatus, vcstatus, ciostatus;
9792 + irqstatus = dsi_read_reg(DSI_IRQSTATUS);
9794 + if (irqstatus & DSI_IRQ_ERROR_MASK) {
9795 + DSSERR("DSI error, irqstatus %x\n", irqstatus);
9796 + print_irq_status(irqstatus);
9797 + spin_lock(&dsi.errors_lock);
9798 + dsi.errors |= irqstatus & DSI_IRQ_ERROR_MASK;
9799 + spin_unlock(&dsi.errors_lock);
9800 + } else if (debug_irq) {
9801 + print_irq_status(irqstatus);
9804 + for (i = 0; i < 4; ++i) {
9805 + if ((irqstatus & (1<<i)) == 0)
9808 + vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i));
9810 + if (vcstatus & DSI_VC_IRQ_BTA)
9811 + complete(&dsi.bta_completion);
9813 + if (vcstatus & DSI_VC_IRQ_ERROR_MASK) {
9814 + DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
9816 + print_irq_status_vc(i, vcstatus);
9817 + } else if (debug_irq) {
9818 + print_irq_status_vc(i, vcstatus);
9821 + dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus);
9824 + if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
9825 + ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
9827 + dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
9829 + DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
9830 + print_irq_status_cio(ciostatus);
9833 + dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
9837 +static void _dsi_initialize_irq(void)
9842 + /* disable all interrupts */
9843 + dsi_write_reg(DSI_IRQENABLE, 0);
9844 + for (i = 0; i < 4; ++i)
9845 + dsi_write_reg(DSI_VC_IRQENABLE(i), 0);
9846 + dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0);
9848 + /* clear interrupt status */
9849 + l = dsi_read_reg(DSI_IRQSTATUS);
9850 + dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK);
9852 + for (i = 0; i < 4; ++i) {
9853 + l = dsi_read_reg(DSI_VC_IRQSTATUS(i));
9854 + dsi_write_reg(DSI_VC_IRQSTATUS(i), l);
9857 + l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
9858 + dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l);
9860 + /* enable error irqs */
9861 + l = DSI_IRQ_ERROR_MASK;
9862 + dsi_write_reg(DSI_IRQENABLE, l);
9864 + l = DSI_VC_IRQ_ERROR_MASK;
9865 + for (i = 0; i < 4; ++i)
9866 + dsi_write_reg(DSI_VC_IRQENABLE(i), l);
9868 + /* XXX zonda responds incorrectly, causing control error:
9869 + Exit from LP-ESC mode to LP11 uses wrong transition states on the
9870 + data lines LP0 and LN0. */
9871 + dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE,
9872 + -1 & (~DSI_CIO_IRQ_ERRCONTROL2));
9875 +static u32 dsi_get_errors(void)
9877 + unsigned long flags;
9879 + spin_lock_irqsave(&dsi.errors_lock, flags);
9882 + spin_unlock_irqrestore(&dsi.errors_lock, flags);
9886 +static void dsi_vc_enable_bta_irq(int channel)
9890 + dsi_write_reg(DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA);
9892 + l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
9893 + l |= DSI_VC_IRQ_BTA;
9894 + dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
9897 +static void dsi_vc_disable_bta_irq(int channel)
9901 + l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
9902 + l &= ~DSI_VC_IRQ_BTA;
9903 + dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
9906 +/* DSI func clock. this could also be DSI2_PLL_FCLK */
9907 +static inline void enable_clocks(bool enable)
9910 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
9912 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
9915 +/* source clock for DSI PLL. this could also be PCLKFREE */
9916 +static inline void dsi_enable_pll_clock(bool enable)
9919 + dss_clk_enable(DSS_CLK_FCK2);
9921 + dss_clk_disable(DSS_CLK_FCK2);
9923 + if (enable && dsi.pll_locked) {
9924 + if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1)
9925 + DSSERR("cannot lock PLL when enabling clocks\n");
9930 +static void _dsi_print_reset_status(void)
9937 + /* A dummy read using the SCP interface to any DSIPHY register is
9938 + * required after DSIPHY reset to complete the reset of the DSI complex
9940 + l = dsi_read_reg(DSI_DSIPHY_CFG5);
9942 + printk(KERN_DEBUG "DSI resets: ");
9944 + l = dsi_read_reg(DSI_PLL_STATUS);
9945 + printk("PLL (%d) ", FLD_GET(l, 0, 0));
9947 + l = dsi_read_reg(DSI_COMPLEXIO_CFG1);
9948 + printk("CIO (%d) ", FLD_GET(l, 29, 29));
9950 + l = dsi_read_reg(DSI_DSIPHY_CFG5);
9951 + printk("PHY (%x, %d, %d, %d)\n",
9952 + FLD_GET(l, 28, 26),
9953 + FLD_GET(l, 29, 29),
9954 + FLD_GET(l, 30, 30),
9955 + FLD_GET(l, 31, 31));
9958 +#define _dsi_print_reset_status()
9961 +static inline int dsi_if_enable(bool enable)
9963 + DSSDBG("dsi_if_enable(%d)\n", enable);
9965 + enable = enable ? 1 : 0;
9966 + REG_FLD_MOD(DSI_CTRL, enable, 0, 0); /* IF_EN */
9968 + if (wait_for_bit_change(DSI_CTRL, 0, enable) != enable) {
9969 + DSSERR("Failed to set dsi_if_enable to %d\n", enable);
9976 +static unsigned long dsi_fclk_rate(void)
9980 + if (dss_get_dsi_clk_source() == 0) {
9981 + /* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */
9982 + r = dss_clk_get_rate(DSS_CLK_FCK1);
9984 + /* DSI FCLK source is DSI2_PLL_FCLK */
9985 + r = dsi.dsi2_pll_fclk;
9991 +static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
9994 + unsigned long dsi_fclk;
9995 + unsigned long lp_clk, lp_clk_req;
9997 + dsi_fclk = dsi_fclk_rate();
9999 + lp_clk_req = dssdev->phy.dsi.lp_clk_hz;
10001 + for (n = 1; n < (1 << 13) - 1; ++n) {
10002 + lp_clk = dsi_fclk / 2 / n;
10003 + if (lp_clk <= lp_clk_req)
10007 + if (n == (1 << 13) - 1) {
10008 + DSSERR("Failed to find LP_CLK_DIVISOR\n");
10012 + DSSDBG("LP_CLK_DIV %u, LP_CLK %lu (req %lu)\n", n, lp_clk, lp_clk_req);
10014 + REG_FLD_MOD(DSI_CLK_CTRL, n, 12, 0); /* LP_CLK_DIVISOR */
10015 + if (dsi_fclk > 30*1000*1000)
10016 + REG_FLD_MOD(DSI_CLK_CTRL, 1, 21, 21); /* LP_RX_SYNCHRO_ENABLE */
10022 +enum dsi_pll_power_state {
10023 + DSI_PLL_POWER_OFF = 0x0,
10024 + DSI_PLL_POWER_ON_HSCLK = 0x1,
10025 + DSI_PLL_POWER_ON_ALL = 0x2,
10026 + DSI_PLL_POWER_ON_DIV = 0x3,
10029 +static int dsi_pll_power(enum dsi_pll_power_state state)
10033 + REG_FLD_MOD(DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_CMD */
10035 + /* PLL_PWR_STATUS */
10036 + while (FLD_GET(dsi_read_reg(DSI_CLK_CTRL), 29, 28) != state) {
10038 + if (t++ > 1000) {
10039 + DSSERR("Failed to set DSI PLL power mode to %d\n",
10048 +int dsi_pll_calc_pck(bool is_tft, unsigned long req_pck,
10049 + struct dsi_clock_info *cinfo)
10051 + struct dsi_clock_info cur, best;
10052 + int min_fck_per_pck;
10054 + unsigned long dss_clk_fck2;
10056 + dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_FCK2);
10058 + if (req_pck == dsi.cache_req_pck &&
10059 + dsi.cache_cinfo.clkin == dss_clk_fck2) {
10060 + DSSDBG("DSI clock info found from cache\n");
10061 + *cinfo = dsi.cache_cinfo;
10065 + min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
10067 + if (min_fck_per_pck &&
10068 + req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
10069 + DSSERR("Requested pixel clock not possible with the current "
10070 + "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
10071 + "the constraint off.\n");
10072 + min_fck_per_pck = 0;
10075 + DSSDBG("dsi_pll_calc\n");
10078 + memset(&best, 0, sizeof(best));
10080 + memset(&cur, 0, sizeof(cur));
10081 + cur.clkin = dss_clk_fck2;
10082 + cur.use_dss2_fck = 1;
10083 + cur.highfreq = 0;
10085 + /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
10086 + /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
10087 + /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
10088 + for (cur.regn = 1; cur.regn < REGN_MAX; ++cur.regn) {
10089 + if (cur.highfreq == 0)
10090 + cur.fint = cur.clkin / cur.regn;
10092 + cur.fint = cur.clkin / (2 * cur.regn);
10094 + if (cur.fint > FINT_MAX || cur.fint < FINT_MIN)
10097 + /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
10098 + for (cur.regm = 1; cur.regm < REGM_MAX; ++cur.regm) {
10099 + unsigned long a, b;
10101 + a = 2 * cur.regm * (cur.clkin/1000);
10102 + b = cur.regn * (cur.highfreq + 1);
10103 + cur.dsiphy = a / b * 1000;
10105 + if (cur.dsiphy > 1800 * 1000 * 1000)
10108 + /* DSI1_PLL_FCLK(MHz) = DSIPHY(MHz) / regm3 < 173MHz */
10109 + for (cur.regm3 = 1; cur.regm3 < REGM3_MAX;
10111 + cur.dsi1_pll_fclk = cur.dsiphy / cur.regm3;
10113 + /* this will narrow down the search a bit,
10114 + * but still give pixclocks below what was
10116 + if (cur.dsi1_pll_fclk < req_pck)
10119 + if (cur.dsi1_pll_fclk > DISPC_MAX_FCK)
10122 + if (min_fck_per_pck &&
10123 + cur.dsi1_pll_fclk <
10124 + req_pck * min_fck_per_pck)
10129 + find_lck_pck_divs(is_tft, req_pck,
10130 + cur.dsi1_pll_fclk,
10134 + cur.lck = cur.dsi1_pll_fclk / cur.lck_div;
10135 + cur.pck = cur.lck / cur.pck_div;
10137 + if (abs(cur.pck - req_pck) <
10138 + abs(best.pck - req_pck)) {
10141 + if (cur.pck == req_pck)
10149 + if (min_fck_per_pck) {
10150 + DSSERR("Could not find suitable clock settings.\n"
10151 + "Turning FCK/PCK constraint off and"
10152 + "trying again.\n");
10153 + min_fck_per_pck = 0;
10157 + DSSERR("Could not find suitable clock settings.\n");
10162 + /* DSI2_PLL_FCLK (regm4) is not used. Set it to something sane. */
10163 + best.regm4 = best.dsiphy / 48000000;
10164 + if (best.regm4 > REGM4_MAX)
10165 + best.regm4 = REGM4_MAX;
10166 + else if (best.regm4 == 0)
10168 + best.dsi2_pll_fclk = best.dsiphy / best.regm4;
10173 + dsi.cache_req_pck = req_pck;
10174 + dsi.cache_clk_freq = 0;
10175 + dsi.cache_cinfo = best;
10180 +static int dsi_pll_calc_ddrfreq(unsigned long clk_freq,
10181 + struct dsi_clock_info *cinfo)
10183 + struct dsi_clock_info cur, best;
10184 + const bool use_dss2_fck = 1;
10185 + unsigned long datafreq;
10186 + unsigned long dss_clk_fck2;
10188 + DSSDBG("dsi_pll_calc_ddrfreq\n");
10190 + dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_FCK2);
10192 + if (clk_freq == dsi.cache_clk_freq &&
10193 + dsi.cache_cinfo.clkin == dss_clk_fck2) {
10194 + DSSDBG("DSI clock info found from cache\n");
10195 + *cinfo = dsi.cache_cinfo;
10199 + datafreq = clk_freq * 4;
10201 + memset(&best, 0, sizeof(best));
10203 + memset(&cur, 0, sizeof(cur));
10204 + cur.use_dss2_fck = use_dss2_fck;
10205 + if (use_dss2_fck) {
10206 + cur.clkin = dss_clk_fck2;
10207 + cur.highfreq = 0;
10209 + cur.clkin = dispc_pclk_rate();
10210 + if (cur.clkin < 32000000)
10211 + cur.highfreq = 0;
10213 + cur.highfreq = 1;
10216 + /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
10217 + /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
10218 + /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
10219 + for (cur.regn = 1; cur.regn < REGN_MAX; ++cur.regn) {
10220 + if (cur.highfreq == 0)
10221 + cur.fint = cur.clkin / cur.regn;
10223 + cur.fint = cur.clkin / (2 * cur.regn);
10225 + if (cur.fint > FINT_MAX || cur.fint < FINT_MIN)
10228 + /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
10229 + for (cur.regm = 1; cur.regm < REGM_MAX; ++cur.regm) {
10230 + unsigned long a, b;
10232 + a = 2 * cur.regm * (cur.clkin/1000);
10233 + b = cur.regn * (cur.highfreq + 1);
10234 + cur.dsiphy = a / b * 1000;
10236 + if (cur.dsiphy > 1800 * 1000 * 1000)
10239 + if (abs(cur.dsiphy - datafreq) <
10240 + abs(best.dsiphy - datafreq)) {
10242 + /* DSSDBG("best %ld\n", best.dsiphy); */
10245 + if (cur.dsiphy == datafreq)
10250 + /* DSI1_PLL_FCLK (regm3) is not used. Set it to something sane. */
10251 + best.regm3 = best.dsiphy / 48000000;
10252 + if (best.regm3 > REGM3_MAX)
10253 + best.regm3 = REGM3_MAX;
10254 + else if (best.regm3 == 0)
10256 + best.dsi1_pll_fclk = best.dsiphy / best.regm3;
10258 + /* DSI2_PLL_FCLK (regm4) is not used. Set it to something sane. */
10259 + best.regm4 = best.dsiphy / 48000000;
10260 + if (best.regm4 > REGM4_MAX)
10261 + best.regm4 = REGM4_MAX;
10262 + else if (best.regm4 == 0)
10264 + best.dsi2_pll_fclk = best.dsiphy / best.regm4;
10269 + dsi.cache_clk_freq = clk_freq;
10270 + dsi.cache_req_pck = 0;
10271 + dsi.cache_cinfo = best;
10276 +int dsi_pll_program(struct dsi_clock_info *cinfo)
10281 + DSSDBG("dsi_pll_program\n");
10283 + dsi.dsiphy = cinfo->dsiphy;
10284 + dsi.ddr_clk = dsi.dsiphy / 4;
10285 + dsi.dsi1_pll_fclk = cinfo->dsi1_pll_fclk;
10286 + dsi.dsi2_pll_fclk = cinfo->dsi2_pll_fclk;
10288 + DSSDBG("DSI Fint %ld\n", cinfo->fint);
10290 + DSSDBG("clkin (%s) rate %ld, highfreq %d\n",
10291 + cinfo->use_dss2_fck ? "dss2_fck" : "pclkfree",
10293 + cinfo->highfreq);
10295 + /* DSIPHY == CLKIN4DDR */
10296 + DSSDBG("DSIPHY = 2 * %d / %d * %lu / %d = %lu\n",
10300 + cinfo->highfreq + 1,
10303 + DSSDBG("Data rate on 1 DSI lane %ld Mbps\n",
10304 + dsi.dsiphy / 1000 / 1000 / 2);
10306 + DSSDBG("Clock lane freq %ld Hz\n", dsi.ddr_clk);
10308 + DSSDBG("regm3 = %d, dsi1_pll_fclk = %lu\n",
10309 + cinfo->regm3, cinfo->dsi1_pll_fclk);
10310 + DSSDBG("regm4 = %d, dsi2_pll_fclk = %lu\n",
10311 + cinfo->regm4, cinfo->dsi2_pll_fclk);
10313 + REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */
10315 + l = dsi_read_reg(DSI_PLL_CONFIGURATION1);
10316 + l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */
10317 + l = FLD_MOD(l, cinfo->regn - 1, 7, 1); /* DSI_PLL_REGN */
10318 + l = FLD_MOD(l, cinfo->regm, 18, 8); /* DSI_PLL_REGM */
10319 + l = FLD_MOD(l, cinfo->regm3 - 1, 22, 19); /* DSI_CLOCK_DIV */
10320 + l = FLD_MOD(l, cinfo->regm4 - 1, 26, 23); /* DSIPROTO_CLOCK_DIV */
10321 + dsi_write_reg(DSI_PLL_CONFIGURATION1, l);
10323 + l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
10324 + l = FLD_MOD(l, 7, 4, 1); /* DSI_PLL_FREQSEL */
10325 + /* DSI_PLL_CLKSEL */
10326 + l = FLD_MOD(l, cinfo->use_dss2_fck ? 0 : 1, 11, 11);
10327 + l = FLD_MOD(l, cinfo->highfreq, 12, 12); /* DSI_PLL_HIGHFREQ */
10328 + l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
10329 + l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */
10330 + l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */
10331 + dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
10333 + REG_FLD_MOD(DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
10335 + if (wait_for_bit_change(DSI_PLL_GO, 0, 0) != 0) {
10336 + DSSERR("dsi pll go bit not going down.\n");
10341 + if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1) {
10342 + DSSERR("cannot lock PLL\n");
10347 + dsi.pll_locked = 1;
10349 + l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
10350 + l = FLD_MOD(l, 0, 0, 0); /* DSI_PLL_IDLE */
10351 + l = FLD_MOD(l, 0, 5, 5); /* DSI_PLL_PLLLPMODE */
10352 + l = FLD_MOD(l, 0, 6, 6); /* DSI_PLL_LOWCURRSTBY */
10353 + l = FLD_MOD(l, 0, 7, 7); /* DSI_PLL_TIGHTPHASELOCK */
10354 + l = FLD_MOD(l, 0, 8, 8); /* DSI_PLL_DRIFTGUARDEN */
10355 + l = FLD_MOD(l, 0, 10, 9); /* DSI_PLL_LOCKSEL */
10356 + l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
10357 + l = FLD_MOD(l, 1, 14, 14); /* DSIPHY_CLKINEN */
10358 + l = FLD_MOD(l, 0, 15, 15); /* DSI_BYPASSEN */
10359 + l = FLD_MOD(l, 1, 16, 16); /* DSS_CLOCK_EN */
10360 + l = FLD_MOD(l, 0, 17, 17); /* DSS_CLOCK_PWDN */
10361 + l = FLD_MOD(l, 1, 18, 18); /* DSI_PROTO_CLOCK_EN */
10362 + l = FLD_MOD(l, 0, 19, 19); /* DSI_PROTO_CLOCK_PWDN */
10363 + l = FLD_MOD(l, 0, 20, 20); /* DSI_HSDIVBYPASS */
10364 + dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
10366 + DSSDBG("PLL config done\n");
10371 +int dsi_pll_init(bool enable_hsclk, bool enable_hsdiv)
10374 + enum dsi_pll_power_state pwstate;
10375 + struct dispc_clock_info cinfo;
10377 + DSSDBG("PLL init\n");
10379 + enable_clocks(1);
10380 + dsi_enable_pll_clock(1);
10382 + /* XXX this should be calculated depending on the screen size,
10383 + * required framerate and DSI speed.
10384 + * For now 48MHz is enough for 864x480@60 with 360Mbps/lane
10385 + * with two lanes */
10386 + r = dispc_calc_clock_div(1, 48 * 1000 * 1000, &cinfo);
10390 + r = dispc_set_clock_div(&cinfo);
10392 + DSSERR("Failed to set basic clocks\n");
10396 + r = regulator_enable(dsi.vdds_dsi_reg);
10400 + /* XXX PLL does not come out of reset without this... */
10401 + dispc_pck_free_enable(1);
10403 + if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) {
10404 + DSSERR("PLL not coming out of reset.\n");
10409 + /* XXX ... but if left on, we get problems when planes do not
10410 + * fill the whole display. No idea about this */
10411 + dispc_pck_free_enable(0);
10413 + if (enable_hsclk && enable_hsdiv)
10414 + pwstate = DSI_PLL_POWER_ON_ALL;
10415 + else if (enable_hsclk)
10416 + pwstate = DSI_PLL_POWER_ON_HSCLK;
10417 + else if (enable_hsdiv)
10418 + pwstate = DSI_PLL_POWER_ON_DIV;
10420 + pwstate = DSI_PLL_POWER_OFF;
10422 + r = dsi_pll_power(pwstate);
10427 + DSSDBG("PLL init done\n");
10431 + regulator_disable(dsi.vdds_dsi_reg);
10433 + enable_clocks(0);
10434 + dsi_enable_pll_clock(0);
10438 +void dsi_pll_uninit(void)
10440 + enable_clocks(0);
10441 + dsi_enable_pll_clock(0);
10443 + dsi.pll_locked = 0;
10444 + dsi_pll_power(DSI_PLL_POWER_OFF);
10445 + regulator_disable(dsi.vdds_dsi_reg);
10446 + DSSDBG("PLL uninit done\n");
10449 +unsigned long dsi_get_dsi1_pll_rate(void)
10451 + return dsi.dsi1_pll_fclk;
10454 +unsigned long dsi_get_dsi2_pll_rate(void)
10456 + return dsi.dsi2_pll_fclk;
10459 +void dsi_dump_clocks(struct seq_file *s)
10463 + enable_clocks(1);
10465 + clksel = REG_GET(DSI_PLL_CONFIGURATION2, 11, 11);
10467 + seq_printf(s, "- dsi -\n");
10469 + seq_printf(s, "dsi fclk source = %s\n",
10470 + dss_get_dsi_clk_source() == 0 ?
10471 + "dss1_alwon_fclk" : "dsi2_pll_fclk");
10473 + seq_printf(s, "dsi pll source = %s\n",
10475 + "dss2_alwon_fclk" : "pclkfree");
10477 + seq_printf(s, "DSIPHY\t\t%lu\nDDR_CLK\t\t%lu\n",
10478 + dsi.dsiphy, dsi.ddr_clk);
10480 + seq_printf(s, "dsi1_pll_fck\t%lu (%s)\n"
10481 + "dsi2_pll_fck\t%lu (%s)\n",
10482 + dsi.dsi1_pll_fclk,
10483 + dss_get_dispc_clk_source() == 0 ? "off" : "on",
10484 + dsi.dsi2_pll_fclk,
10485 + dss_get_dsi_clk_source() == 0 ? "off" : "on");
10487 + enable_clocks(0);
10490 +void dsi_dump_regs(struct seq_file *s)
10492 +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r))
10494 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
10496 + DUMPREG(DSI_REVISION);
10497 + DUMPREG(DSI_SYSCONFIG);
10498 + DUMPREG(DSI_SYSSTATUS);
10499 + DUMPREG(DSI_IRQSTATUS);
10500 + DUMPREG(DSI_IRQENABLE);
10501 + DUMPREG(DSI_CTRL);
10502 + DUMPREG(DSI_COMPLEXIO_CFG1);
10503 + DUMPREG(DSI_COMPLEXIO_IRQ_STATUS);
10504 + DUMPREG(DSI_COMPLEXIO_IRQ_ENABLE);
10505 + DUMPREG(DSI_CLK_CTRL);
10506 + DUMPREG(DSI_TIMING1);
10507 + DUMPREG(DSI_TIMING2);
10508 + DUMPREG(DSI_VM_TIMING1);
10509 + DUMPREG(DSI_VM_TIMING2);
10510 + DUMPREG(DSI_VM_TIMING3);
10511 + DUMPREG(DSI_CLK_TIMING);
10512 + DUMPREG(DSI_TX_FIFO_VC_SIZE);
10513 + DUMPREG(DSI_RX_FIFO_VC_SIZE);
10514 + DUMPREG(DSI_COMPLEXIO_CFG2);
10515 + DUMPREG(DSI_RX_FIFO_VC_FULLNESS);
10516 + DUMPREG(DSI_VM_TIMING4);
10517 + DUMPREG(DSI_TX_FIFO_VC_EMPTINESS);
10518 + DUMPREG(DSI_VM_TIMING5);
10519 + DUMPREG(DSI_VM_TIMING6);
10520 + DUMPREG(DSI_VM_TIMING7);
10521 + DUMPREG(DSI_STOPCLK_TIMING);
10523 + DUMPREG(DSI_VC_CTRL(0));
10524 + DUMPREG(DSI_VC_TE(0));
10525 + DUMPREG(DSI_VC_LONG_PACKET_HEADER(0));
10526 + DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(0));
10527 + DUMPREG(DSI_VC_SHORT_PACKET_HEADER(0));
10528 + DUMPREG(DSI_VC_IRQSTATUS(0));
10529 + DUMPREG(DSI_VC_IRQENABLE(0));
10531 + DUMPREG(DSI_VC_CTRL(1));
10532 + DUMPREG(DSI_VC_TE(1));
10533 + DUMPREG(DSI_VC_LONG_PACKET_HEADER(1));
10534 + DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(1));
10535 + DUMPREG(DSI_VC_SHORT_PACKET_HEADER(1));
10536 + DUMPREG(DSI_VC_IRQSTATUS(1));
10537 + DUMPREG(DSI_VC_IRQENABLE(1));
10539 + DUMPREG(DSI_VC_CTRL(2));
10540 + DUMPREG(DSI_VC_TE(2));
10541 + DUMPREG(DSI_VC_LONG_PACKET_HEADER(2));
10542 + DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(2));
10543 + DUMPREG(DSI_VC_SHORT_PACKET_HEADER(2));
10544 + DUMPREG(DSI_VC_IRQSTATUS(2));
10545 + DUMPREG(DSI_VC_IRQENABLE(2));
10547 + DUMPREG(DSI_VC_CTRL(3));
10548 + DUMPREG(DSI_VC_TE(3));
10549 + DUMPREG(DSI_VC_LONG_PACKET_HEADER(3));
10550 + DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(3));
10551 + DUMPREG(DSI_VC_SHORT_PACKET_HEADER(3));
10552 + DUMPREG(DSI_VC_IRQSTATUS(3));
10553 + DUMPREG(DSI_VC_IRQENABLE(3));
10555 + DUMPREG(DSI_DSIPHY_CFG0);
10556 + DUMPREG(DSI_DSIPHY_CFG1);
10557 + DUMPREG(DSI_DSIPHY_CFG2);
10558 + DUMPREG(DSI_DSIPHY_CFG5);
10560 + DUMPREG(DSI_PLL_CONTROL);
10561 + DUMPREG(DSI_PLL_STATUS);
10562 + DUMPREG(DSI_PLL_GO);
10563 + DUMPREG(DSI_PLL_CONFIGURATION1);
10564 + DUMPREG(DSI_PLL_CONFIGURATION2);
10566 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
10570 +enum dsi_complexio_power_state {
10571 + DSI_COMPLEXIO_POWER_OFF = 0x0,
10572 + DSI_COMPLEXIO_POWER_ON = 0x1,
10573 + DSI_COMPLEXIO_POWER_ULPS = 0x2,
10576 +static int dsi_complexio_power(enum dsi_complexio_power_state state)
10581 + REG_FLD_MOD(DSI_COMPLEXIO_CFG1, state, 28, 27);
10584 + while (FLD_GET(dsi_read_reg(DSI_COMPLEXIO_CFG1), 26, 25) != state) {
10586 + if (t++ > 1000) {
10587 + DSSERR("failed to set complexio power state to "
10596 +static void dsi_complexio_config(struct omap_dss_device *dssdev)
10600 + int clk_lane = dssdev->phy.dsi.clk_lane;
10601 + int data1_lane = dssdev->phy.dsi.data1_lane;
10602 + int data2_lane = dssdev->phy.dsi.data2_lane;
10603 + int clk_pol = dssdev->phy.dsi.clk_pol;
10604 + int data1_pol = dssdev->phy.dsi.data1_pol;
10605 + int data2_pol = dssdev->phy.dsi.data2_pol;
10607 + r = dsi_read_reg(DSI_COMPLEXIO_CFG1);
10608 + r = FLD_MOD(r, clk_lane, 2, 0);
10609 + r = FLD_MOD(r, clk_pol, 3, 3);
10610 + r = FLD_MOD(r, data1_lane, 6, 4);
10611 + r = FLD_MOD(r, data1_pol, 7, 7);
10612 + r = FLD_MOD(r, data2_lane, 10, 8);
10613 + r = FLD_MOD(r, data2_pol, 11, 11);
10614 + dsi_write_reg(DSI_COMPLEXIO_CFG1, r);
10616 + /* The configuration of the DSI complex I/O (number of data lanes,
10617 + position, differential order) should not be changed while
10618 + DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for
10619 + the hardware to take into account a new configuration of the complex
10620 + I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to
10621 + follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1,
10622 + then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set
10623 + DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the
10624 + DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the
10625 + DSI complex I/O configuration is unknown. */
10628 + REG_FLD_MOD(DSI_CTRL, 1, 0, 0);
10629 + REG_FLD_MOD(DSI_CTRL, 0, 0, 0);
10630 + REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20);
10631 + REG_FLD_MOD(DSI_CTRL, 1, 0, 0);
10635 +static inline unsigned ns2ddr(unsigned ns)
10637 + /* convert time in ns to ddr ticks, rounding up */
10638 + return (ns * (dsi.ddr_clk/1000/1000) + 999) / 1000;
10641 +static inline unsigned ddr2ns(unsigned ddr)
10643 + return ddr * 1000 * 1000 / (dsi.ddr_clk / 1000);
10646 +static void dsi_complexio_timings(void)
10649 + u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
10650 + u32 tlpx_half, tclk_trail, tclk_zero;
10651 + u32 tclk_prepare;
10653 + /* calculate timings */
10655 + /* 1 * DDR_CLK = 2 * UI */
10657 + /* min 40ns + 4*UI max 85ns + 6*UI */
10658 + ths_prepare = ns2ddr(70) + 2;
10660 + /* min 145ns + 10*UI */
10661 + ths_prepare_ths_zero = ns2ddr(175) + 2;
10663 + /* min max(8*UI, 60ns+4*UI) */
10664 + ths_trail = ns2ddr(60) + 5;
10667 + ths_exit = ns2ddr(145);
10669 + /* tlpx min 50n */
10670 + tlpx_half = ns2ddr(25);
10673 + tclk_trail = ns2ddr(60) + 2;
10675 + /* min 38ns, max 95ns */
10676 + tclk_prepare = ns2ddr(65);
10678 + /* min tclk-prepare + tclk-zero = 300ns */
10679 + tclk_zero = ns2ddr(260);
10681 + DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
10682 + ths_prepare, ddr2ns(ths_prepare),
10683 + ths_prepare_ths_zero, ddr2ns(ths_prepare_ths_zero));
10684 + DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
10685 + ths_trail, ddr2ns(ths_trail),
10686 + ths_exit, ddr2ns(ths_exit));
10688 + DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
10689 + "tclk_zero %u (%uns)\n",
10690 + tlpx_half, ddr2ns(tlpx_half),
10691 + tclk_trail, ddr2ns(tclk_trail),
10692 + tclk_zero, ddr2ns(tclk_zero));
10693 + DSSDBG("tclk_prepare %u (%uns)\n",
10694 + tclk_prepare, ddr2ns(tclk_prepare));
10696 + /* program timings */
10698 + r = dsi_read_reg(DSI_DSIPHY_CFG0);
10699 + r = FLD_MOD(r, ths_prepare, 31, 24);
10700 + r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
10701 + r = FLD_MOD(r, ths_trail, 15, 8);
10702 + r = FLD_MOD(r, ths_exit, 7, 0);
10703 + dsi_write_reg(DSI_DSIPHY_CFG0, r);
10705 + r = dsi_read_reg(DSI_DSIPHY_CFG1);
10706 + r = FLD_MOD(r, tlpx_half, 22, 16);
10707 + r = FLD_MOD(r, tclk_trail, 15, 8);
10708 + r = FLD_MOD(r, tclk_zero, 7, 0);
10709 + dsi_write_reg(DSI_DSIPHY_CFG1, r);
10711 + r = dsi_read_reg(DSI_DSIPHY_CFG2);
10712 + r = FLD_MOD(r, tclk_prepare, 7, 0);
10713 + dsi_write_reg(DSI_DSIPHY_CFG2, r);
10717 +static int dsi_complexio_init(struct omap_dss_device *dssdev)
10721 + DSSDBG("dsi_complexio_init\n");
10723 + /* CIO_CLK_ICG, enable L3 clk to CIO */
10724 + REG_FLD_MOD(DSI_CLK_CTRL, 1, 14, 14);
10726 + /* A dummy read using the SCP interface to any DSIPHY register is
10727 + * required after DSIPHY reset to complete the reset of the DSI complex
10729 + dsi_read_reg(DSI_DSIPHY_CFG5);
10731 + if (wait_for_bit_change(DSI_DSIPHY_CFG5, 30, 1) != 1) {
10732 + DSSERR("ComplexIO PHY not coming out of reset.\n");
10737 + dsi_complexio_config(dssdev);
10739 + r = dsi_complexio_power(DSI_COMPLEXIO_POWER_ON);
10744 + if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
10745 + DSSERR("ComplexIO not coming out of reset.\n");
10750 + if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 21, 1) != 1) {
10751 + DSSERR("ComplexIO LDO power down.\n");
10756 + dsi_complexio_timings();
10759 + The configuration of the DSI complex I/O (number of data lanes,
10760 + position, differential order) should not be changed while
10761 + DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. For the
10762 + hardware to recognize a new configuration of the complex I/O (done
10763 + in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to follow
10764 + this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, next
10765 + reset the DSS.DSI_CTRL[0] IF_EN to 0, then set DSS.DSI_CLK_CTRL[20]
10766 + LP_CLK_ENABLE to 1, and finally, set again the DSS.DSI_CTRL[0] IF_EN
10767 + bit to 1. If the sequence is not followed, the DSi complex I/O
10768 + configuration is undetermined.
10770 + dsi_if_enable(1);
10771 + dsi_if_enable(0);
10772 + REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
10773 + dsi_if_enable(1);
10774 + dsi_if_enable(0);
10776 + DSSDBG("CIO init done\n");
10781 +static void dsi_complexio_uninit(void)
10783 + dsi_complexio_power(DSI_COMPLEXIO_POWER_OFF);
10786 +static int _dsi_wait_reset(void)
10790 + while (REG_GET(DSI_SYSSTATUS, 0, 0) == 0) {
10792 + DSSERR("soft reset failed\n");
10801 +static int _dsi_reset(void)
10804 + REG_FLD_MOD(DSI_SYSCONFIG, 1, 1, 1);
10805 + return _dsi_wait_reset();
10809 +static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
10810 + enum fifo_size size3, enum fifo_size size4)
10816 + dsi.vc[0].fifo_size = size1;
10817 + dsi.vc[1].fifo_size = size2;
10818 + dsi.vc[2].fifo_size = size3;
10819 + dsi.vc[3].fifo_size = size4;
10821 + for (i = 0; i < 4; i++) {
10823 + int size = dsi.vc[i].fifo_size;
10825 + if (add + size > 4) {
10826 + DSSERR("Illegal FIFO configuration\n");
10830 + v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
10831 + r |= v << (8 * i);
10832 + /*DSSDBG("TX FIFO vc %d: size %d, add %d\n", i, size, add); */
10836 + dsi_write_reg(DSI_TX_FIFO_VC_SIZE, r);
10839 +static void dsi_config_rx_fifo(enum fifo_size size1, enum fifo_size size2,
10840 + enum fifo_size size3, enum fifo_size size4)
10846 + dsi.vc[0].fifo_size = size1;
10847 + dsi.vc[1].fifo_size = size2;
10848 + dsi.vc[2].fifo_size = size3;
10849 + dsi.vc[3].fifo_size = size4;
10851 + for (i = 0; i < 4; i++) {
10853 + int size = dsi.vc[i].fifo_size;
10855 + if (add + size > 4) {
10856 + DSSERR("Illegal FIFO configuration\n");
10860 + v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
10861 + r |= v << (8 * i);
10862 + /*DSSDBG("RX FIFO vc %d: size %d, add %d\n", i, size, add); */
10866 + dsi_write_reg(DSI_RX_FIFO_VC_SIZE, r);
10869 +static int dsi_force_tx_stop_mode_io(void)
10873 + r = dsi_read_reg(DSI_TIMING1);
10874 + r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
10875 + dsi_write_reg(DSI_TIMING1, r);
10877 + if (wait_for_bit_change(DSI_TIMING1, 15, 0) != 0) {
10878 + DSSERR("TX_STOP bit not going down\n");
10885 +static void dsi_vc_print_status(int channel)
10889 + r = dsi_read_reg(DSI_VC_CTRL(channel));
10890 + DSSDBG("vc %d: TX_FIFO_NOT_EMPTY %d, BTA_EN %d, VC_BUSY %d, "
10891 + "TX_FIFO_FULL %d, RX_FIFO_NOT_EMPTY %d, ",
10893 + FLD_GET(r, 5, 5),
10894 + FLD_GET(r, 6, 6),
10895 + FLD_GET(r, 15, 15),
10896 + FLD_GET(r, 16, 16),
10897 + FLD_GET(r, 20, 20));
10899 + r = dsi_read_reg(DSI_TX_FIFO_VC_EMPTINESS);
10900 + DSSDBG("EMPTINESS %d\n", (r >> (8 * channel)) & 0xff);
10903 +static int dsi_vc_enable(int channel, bool enable)
10905 + if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
10906 + DSSDBG("dsi_vc_enable channel %d, enable %d\n",
10907 + channel, enable);
10909 + enable = enable ? 1 : 0;
10911 + REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 0, 0);
10913 + if (wait_for_bit_change(DSI_VC_CTRL(channel), 0, enable) != enable) {
10914 + DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
10921 +static void dsi_vc_initial_config(int channel)
10925 + DSSDBGF("%d", channel);
10927 + r = dsi_read_reg(DSI_VC_CTRL(channel));
10929 + if (FLD_GET(r, 15, 15)) /* VC_BUSY */
10930 + DSSERR("VC(%d) busy when trying to configure it!\n",
10933 + r = FLD_MOD(r, 0, 1, 1); /* SOURCE, 0 = L4 */
10934 + r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN */
10935 + r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */
10936 + r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */
10937 + r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
10938 + r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
10939 + r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
10941 + r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
10942 + r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
10944 + dsi_write_reg(DSI_VC_CTRL(channel), r);
10946 + dsi.vc[channel].mode = DSI_VC_MODE_L4;
10949 +static void dsi_vc_config_l4(int channel)
10951 + if (dsi.vc[channel].mode == DSI_VC_MODE_L4)
10954 + DSSDBGF("%d", channel);
10956 + dsi_vc_enable(channel, 0);
10958 + if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
10959 + DSSERR("vc(%d) busy when trying to config for L4\n", channel);
10961 + REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
10963 + dsi_vc_enable(channel, 1);
10965 + dsi.vc[channel].mode = DSI_VC_MODE_L4;
10968 +static void dsi_vc_config_vp(int channel)
10970 + if (dsi.vc[channel].mode == DSI_VC_MODE_VP)
10973 + DSSDBGF("%d", channel);
10975 + dsi_vc_enable(channel, 0);
10977 + if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
10978 + DSSERR("vc(%d) busy when trying to config for VP\n", channel);
10980 + REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */
10982 + dsi_vc_enable(channel, 1);
10984 + dsi.vc[channel].mode = DSI_VC_MODE_VP;
10988 +static void dsi_vc_enable_hs(int channel, bool enable)
10990 + DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
10992 + dsi_vc_enable(channel, 0);
10993 + dsi_if_enable(0);
10995 + REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 9, 9);
10997 + dsi_vc_enable(channel, 1);
10998 + dsi_if_enable(1);
11000 + dsi_force_tx_stop_mode_io();
11003 +static void dsi_vc_flush_long_data(int channel)
11005 + while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
11007 + val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
11008 + DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
11009 + (val >> 0) & 0xff,
11010 + (val >> 8) & 0xff,
11011 + (val >> 16) & 0xff,
11012 + (val >> 24) & 0xff);
11016 +static void dsi_show_rx_ack_with_err(u16 err)
11018 + DSSERR("\tACK with ERROR (%#x):\n", err);
11019 + if (err & (1 << 0))
11020 + DSSERR("\t\tSoT Error\n");
11021 + if (err & (1 << 1))
11022 + DSSERR("\t\tSoT Sync Error\n");
11023 + if (err & (1 << 2))
11024 + DSSERR("\t\tEoT Sync Error\n");
11025 + if (err & (1 << 3))
11026 + DSSERR("\t\tEscape Mode Entry Command Error\n");
11027 + if (err & (1 << 4))
11028 + DSSERR("\t\tLP Transmit Sync Error\n");
11029 + if (err & (1 << 5))
11030 + DSSERR("\t\tHS Receive Timeout Error\n");
11031 + if (err & (1 << 6))
11032 + DSSERR("\t\tFalse Control Error\n");
11033 + if (err & (1 << 7))
11034 + DSSERR("\t\t(reserved7)\n");
11035 + if (err & (1 << 8))
11036 + DSSERR("\t\tECC Error, single-bit (corrected)\n");
11037 + if (err & (1 << 9))
11038 + DSSERR("\t\tECC Error, multi-bit (not corrected)\n");
11039 + if (err & (1 << 10))
11040 + DSSERR("\t\tChecksum Error\n");
11041 + if (err & (1 << 11))
11042 + DSSERR("\t\tData type not recognized\n");
11043 + if (err & (1 << 12))
11044 + DSSERR("\t\tInvalid VC ID\n");
11045 + if (err & (1 << 13))
11046 + DSSERR("\t\tInvalid Transmission Length\n");
11047 + if (err & (1 << 14))
11048 + DSSERR("\t\t(reserved14)\n");
11049 + if (err & (1 << 15))
11050 + DSSERR("\t\tDSI Protocol Violation\n");
11053 +static u16 dsi_vc_flush_receive_data(int channel)
11055 + /* RX_FIFO_NOT_EMPTY */
11056 + while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
11059 + val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
11060 + DSSDBG("\trawval %#08x\n", val);
11061 + dt = FLD_GET(val, 5, 0);
11062 + if (dt == DSI_DT_RX_ACK_WITH_ERR) {
11063 + u16 err = FLD_GET(val, 23, 8);
11064 + dsi_show_rx_ack_with_err(err);
11065 + } else if (dt == DSI_DT_RX_SHORT_READ_1) {
11066 + DSSDBG("\tDCS short response, 1 byte: %#x\n",
11067 + FLD_GET(val, 23, 8));
11068 + } else if (dt == DSI_DT_RX_SHORT_READ_2) {
11069 + DSSDBG("\tDCS short response, 2 byte: %#x\n",
11070 + FLD_GET(val, 23, 8));
11071 + } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
11072 + DSSDBG("\tDCS long response, len %d\n",
11073 + FLD_GET(val, 23, 8));
11074 + dsi_vc_flush_long_data(channel);
11076 + DSSERR("\tunknown datatype 0x%02x\n", dt);
11082 +static int dsi_vc_send_bta(int channel)
11084 + if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO &&
11085 + (dsi.debug_write || dsi.debug_read))
11086 + DSSDBG("dsi_vc_send_bta %d\n", channel);
11088 + WARN_ON(!mutex_is_locked(&dsi.bus_lock));
11090 + if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */
11091 + DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
11092 + dsi_vc_flush_receive_data(channel);
11095 + REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
11100 +int dsi_vc_send_bta_sync(int channel)
11105 + INIT_COMPLETION(dsi.bta_completion);
11107 + dsi_vc_enable_bta_irq(channel);
11109 + r = dsi_vc_send_bta(channel);
11113 + if (wait_for_completion_timeout(&dsi.bta_completion,
11114 + msecs_to_jiffies(500)) == 0) {
11115 + DSSERR("Failed to receive BTA\n");
11120 + err = dsi_get_errors();
11122 + DSSERR("Error while sending BTA: %x\n", err);
11127 + dsi_vc_disable_bta_irq(channel);
11131 +EXPORT_SYMBOL(dsi_vc_send_bta_sync);
11133 +static inline void dsi_vc_write_long_header(int channel, u8 data_type,
11139 + WARN_ON(!mutex_is_locked(&dsi.bus_lock));
11141 + /*data_id = data_type | channel << 6; */
11142 + data_id = data_type | dsi.vc[channel].dest_per << 6;
11144 + val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
11145 + FLD_VAL(ecc, 31, 24);
11147 + dsi_write_reg(DSI_VC_LONG_PACKET_HEADER(channel), val);
11150 +static inline void dsi_vc_write_long_payload(int channel,
11151 + u8 b1, u8 b2, u8 b3, u8 b4)
11155 + val = b4 << 24 | b3 << 16 | b2 << 8 | b1 << 0;
11157 +/* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
11158 + b1, b2, b3, b4, val); */
11160 + dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
11163 +static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
11170 + u8 b1, b2, b3, b4;
11172 + if (dsi.debug_write)
11173 + DSSDBG("dsi_vc_send_long, %d bytes\n", len);
11175 + /* len + header */
11176 + if (dsi.vc[channel].fifo_size * 32 * 4 < len + 4) {
11177 + DSSERR("unable to send long packet: packet too long.\n");
11181 + dsi_vc_config_l4(channel);
11183 + dsi_vc_write_long_header(channel, data_type, len, ecc);
11185 + /*dsi_vc_print_status(0); */
11188 + for (i = 0; i < len >> 2; i++) {
11189 + if (dsi.debug_write)
11190 + DSSDBG("\tsending full packet %d\n", i);
11191 + /*dsi_vc_print_status(0); */
11198 + dsi_vc_write_long_payload(channel, b1, b2, b3, b4);
11203 + b1 = 0; b2 = 0; b3 = 0;
11205 + if (dsi.debug_write)
11206 + DSSDBG("\tsending remainder bytes %d\n", i);
11223 + dsi_vc_write_long_payload(channel, b1, b2, b3, 0);
11229 +static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
11234 + WARN_ON(!mutex_is_locked(&dsi.bus_lock));
11236 + if (dsi.debug_write)
11237 + DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
11239 + data_type, data & 0xff, (data >> 8) & 0xff);
11241 + dsi_vc_config_l4(channel);
11243 + if (FLD_GET(dsi_read_reg(DSI_VC_CTRL(channel)), 16, 16)) {
11244 + DSSERR("ERROR FIFO FULL, aborting transfer\n");
11248 + data_id = data_type | channel << 6;
11250 + r = (data_id << 0) | (data << 8) | (ecc << 24);
11252 + dsi_write_reg(DSI_VC_SHORT_PACKET_HEADER(channel), r);
11257 +int dsi_vc_send_null(int channel)
11259 + u8 nullpkg[] = {0, 0, 0, 0};
11260 + return dsi_vc_send_long(0, DSI_DT_NULL_PACKET, nullpkg, 4, 0);
11262 +EXPORT_SYMBOL(dsi_vc_send_null);
11264 +int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len)
11268 + BUG_ON(len == 0);
11271 + r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_0,
11273 + } else if (len == 2) {
11274 + r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_1,
11275 + data[0] | (data[1] << 8), 0);
11277 + /* 0x39 = DCS Long Write */
11278 + r = dsi_vc_send_long(channel, DSI_DT_DCS_LONG_WRITE,
11284 +EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
11286 +int dsi_vc_dcs_write(int channel, u8 *data, int len)
11290 + r = dsi_vc_dcs_write_nosync(channel, data, len);
11294 + r = dsi_vc_send_bta_sync(channel);
11298 +EXPORT_SYMBOL(dsi_vc_dcs_write);
11300 +int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
11306 + if (dsi.debug_read)
11307 + DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %u)\n", channel, dcs_cmd);
11309 + r = dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0);
11313 + r = dsi_vc_send_bta_sync(channel);
11317 + /* RX_FIFO_NOT_EMPTY */
11318 + if (REG_GET(DSI_VC_CTRL(channel), 20, 20) == 0) {
11319 + DSSERR("RX fifo empty when trying to read.\n");
11323 + val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
11324 + if (dsi.debug_read)
11325 + DSSDBG("\theader: %08x\n", val);
11326 + dt = FLD_GET(val, 5, 0);
11327 + if (dt == DSI_DT_RX_ACK_WITH_ERR) {
11328 + u16 err = FLD_GET(val, 23, 8);
11329 + dsi_show_rx_ack_with_err(err);
11332 + } else if (dt == DSI_DT_RX_SHORT_READ_1) {
11333 + u8 data = FLD_GET(val, 15, 8);
11334 + if (dsi.debug_read)
11335 + DSSDBG("\tDCS short response, 1 byte: %02x\n", data);
11343 + } else if (dt == DSI_DT_RX_SHORT_READ_2) {
11344 + u16 data = FLD_GET(val, 23, 8);
11345 + if (dsi.debug_read)
11346 + DSSDBG("\tDCS short response, 2 byte: %04x\n", data);
11351 + buf[0] = data & 0xff;
11352 + buf[1] = (data >> 8) & 0xff;
11355 + } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
11357 + int len = FLD_GET(val, 23, 8);
11358 + if (dsi.debug_read)
11359 + DSSDBG("\tDCS long response, len %d\n", len);
11361 + if (len > buflen)
11364 + /* two byte checksum ends the packet, not included in len */
11365 + for (w = 0; w < len + 2;) {
11367 + val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
11368 + if (dsi.debug_read)
11369 + DSSDBG("\t\t%02x %02x %02x %02x\n",
11370 + (val >> 0) & 0xff,
11371 + (val >> 8) & 0xff,
11372 + (val >> 16) & 0xff,
11373 + (val >> 24) & 0xff);
11375 + for (b = 0; b < 4; ++b) {
11377 + buf[w] = (val >> (b * 8)) & 0xff;
11378 + /* we discard the 2 byte checksum */
11386 + DSSERR("\tunknown datatype 0x%02x\n", dt);
11390 +EXPORT_SYMBOL(dsi_vc_dcs_read);
11393 +int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
11395 + return dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
11398 +EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
11401 +static int dsi_set_lp_rx_timeout(int ns, int x4, int x16)
11404 + unsigned long fck;
11407 + /* ticks in DSI_FCK */
11409 + fck = dsi_fclk_rate();
11410 + ticks = (fck / 1000 / 1000) * ns / 1000;
11412 + if (ticks > 0x1fff) {
11413 + DSSERR("LP_TX_TO too high\n");
11417 + r = dsi_read_reg(DSI_TIMING2);
11418 + r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */
11419 + r = FLD_MOD(r, x16, 14, 14); /* LP_RX_TO_X16 */
11420 + r = FLD_MOD(r, x4, 13, 13); /* LP_RX_TO_X4 */
11421 + r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */
11422 + dsi_write_reg(DSI_TIMING2, r);
11424 + DSSDBG("LP_RX_TO %ld ns (%#x ticks)\n",
11425 + (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
11426 + (fck / 1000 / 1000),
11432 +static int dsi_set_ta_timeout(int ns, int x8, int x16)
11435 + unsigned long fck;
11438 + /* ticks in DSI_FCK */
11440 + fck = dsi_fclk_rate();
11441 + ticks = (fck / 1000 / 1000) * ns / 1000;
11443 + if (ticks > 0x1fff) {
11444 + DSSERR("TA_TO too high\n");
11448 + r = dsi_read_reg(DSI_TIMING1);
11449 + r = FLD_MOD(r, 1, 31, 31); /* TA_TO */
11450 + r = FLD_MOD(r, x16, 30, 30); /* TA_TO_X16 */
11451 + r = FLD_MOD(r, x8, 29, 29); /* TA_TO_X8 */
11452 + r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */
11453 + dsi_write_reg(DSI_TIMING1, r);
11455 + DSSDBG("TA_TO %ld ns (%#x ticks)\n",
11456 + (ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1) * 1000) /
11457 + (fck / 1000 / 1000),
11463 +static int dsi_set_stop_state_counter(int ns, int x4, int x16)
11466 + unsigned long fck;
11469 + /* ticks in DSI_FCK */
11471 + fck = dsi_fclk_rate();
11472 + ticks = (fck / 1000 / 1000) * ns / 1000;
11474 + if (ticks > 0x1fff) {
11475 + DSSERR("STOP_STATE_COUNTER_IO too high\n");
11479 + r = dsi_read_reg(DSI_TIMING1);
11480 + r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
11481 + r = FLD_MOD(r, x16, 14, 14); /* STOP_STATE_X16_IO */
11482 + r = FLD_MOD(r, x4, 13, 13); /* STOP_STATE_X4_IO */
11483 + r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */
11484 + dsi_write_reg(DSI_TIMING1, r);
11486 + DSSDBG("STOP_STATE_COUNTER %ld ns (%#x ticks)\n",
11487 + (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
11488 + (fck / 1000 / 1000),
11494 +static int dsi_set_hs_tx_timeout(int ns, int x4, int x16)
11497 + unsigned long fck;
11500 + /* ticks in TxByteClkHS */
11502 + fck = dsi.ddr_clk / 4;
11503 + ticks = (fck / 1000 / 1000) * ns / 1000;
11505 + if (ticks > 0x1fff) {
11506 + DSSERR("HS_TX_TO too high\n");
11510 + r = dsi_read_reg(DSI_TIMING2);
11511 + r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */
11512 + r = FLD_MOD(r, x16, 30, 30); /* HS_TX_TO_X16 */
11513 + r = FLD_MOD(r, x4, 29, 29); /* HS_TX_TO_X8 (4 really) */
11514 + r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */
11515 + dsi_write_reg(DSI_TIMING2, r);
11517 + DSSDBG("HS_TX_TO %ld ns (%#x ticks)\n",
11518 + (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
11519 + (fck / 1000 / 1000),
11524 +static int dsi_proto_config(struct omap_dss_device *dssdev)
11527 + int buswidth = 0;
11530 + dsi_config_tx_fifo(DSI_FIFO_SIZE_128,
11533 + DSI_FIFO_SIZE_0);
11535 + dsi_config_rx_fifo(DSI_FIFO_SIZE_128,
11538 + DSI_FIFO_SIZE_0);
11540 + /* XXX what values for the timeouts? */
11541 + dsi_set_stop_state_counter(1000, 0, 0);
11543 + dsi_set_ta_timeout(50000, 1, 1);
11545 + /* 3000ns * 16 */
11546 + dsi_set_lp_rx_timeout(3000, 0, 1);
11548 + /* 10000ns * 4 */
11549 + dsi_set_hs_tx_timeout(10000, 1, 0);
11551 + switch (dssdev->ctrl.pixel_size) {
11565 + r = dsi_read_reg(DSI_CTRL);
11566 + r = FLD_MOD(r, 1, 1, 1); /* CS_RX_EN */
11567 + r = FLD_MOD(r, 1, 2, 2); /* ECC_RX_EN */
11568 + r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */
11570 + div = dispc_lclk_rate() / dispc_pclk_rate();
11571 + r = FLD_MOD(r, div == 2 ? 0 : 1, 4, 4); /* VP_CLK_RATIO */
11572 + r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */
11573 + r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */
11574 + r = FLD_MOD(r, 2, 13, 12); /* LINE_BUFFER, 2 lines */
11575 + r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */
11576 + r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */
11577 + r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
11578 + r = FLD_MOD(r, 0, 25, 25); /* DCS_CMD_CODE, 1=start, 0=continue */
11580 + dsi_write_reg(DSI_CTRL, r);
11582 + dsi_vc_initial_config(0);
11584 + /* set all vc targets to peripheral 0 */
11585 + dsi.vc[0].dest_per = 0;
11586 + dsi.vc[1].dest_per = 0;
11587 + dsi.vc[2].dest_per = 0;
11588 + dsi.vc[3].dest_per = 0;
11593 +static void dsi_proto_timings(struct omap_dss_device *dssdev)
11595 + unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
11596 + unsigned tclk_pre, tclk_post;
11597 + unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
11598 + unsigned ths_trail, ths_exit;
11599 + unsigned ddr_clk_pre, ddr_clk_post;
11600 + unsigned enter_hs_mode_lat, exit_hs_mode_lat;
11601 + unsigned ths_eot;
11604 + r = dsi_read_reg(DSI_DSIPHY_CFG0);
11605 + ths_prepare = FLD_GET(r, 31, 24);
11606 + ths_prepare_ths_zero = FLD_GET(r, 23, 16);
11607 + ths_zero = ths_prepare_ths_zero - ths_prepare;
11608 + ths_trail = FLD_GET(r, 15, 8);
11609 + ths_exit = FLD_GET(r, 7, 0);
11611 + r = dsi_read_reg(DSI_DSIPHY_CFG1);
11612 + tlpx = FLD_GET(r, 22, 16) * 2;
11613 + tclk_trail = FLD_GET(r, 15, 8);
11614 + tclk_zero = FLD_GET(r, 7, 0);
11616 + r = dsi_read_reg(DSI_DSIPHY_CFG2);
11617 + tclk_prepare = FLD_GET(r, 7, 0);
11621 + /* min 60ns + 52*UI */
11622 + tclk_post = ns2ddr(60) + 26;
11624 + /* ths_eot is 2 for 2 datalanes and 4 for 1 datalane */
11625 + if (dssdev->phy.dsi.data1_lane != 0 &&
11626 + dssdev->phy.dsi.data2_lane != 0)
11631 + ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
11633 + ddr_clk_post = DIV_ROUND_UP(tclk_post + tclk_trail, 4) + ths_eot;
11635 + BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
11636 + BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);
11638 + r = dsi_read_reg(DSI_CLK_TIMING);
11639 + r = FLD_MOD(r, ddr_clk_pre, 15, 8);
11640 + r = FLD_MOD(r, ddr_clk_post, 7, 0);
11641 + dsi_write_reg(DSI_CLK_TIMING, r);
11643 + DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
11647 + enter_hs_mode_lat = 1 + DIV_ROUND_UP(tlpx, 4) +
11648 + DIV_ROUND_UP(ths_prepare, 4) +
11649 + DIV_ROUND_UP(ths_zero + 3, 4);
11651 + exit_hs_mode_lat = DIV_ROUND_UP(ths_trail + ths_exit, 4) + 1 + ths_eot;
11653 + r = FLD_VAL(enter_hs_mode_lat, 31, 16) |
11654 + FLD_VAL(exit_hs_mode_lat, 15, 0);
11655 + dsi_write_reg(DSI_VM_TIMING7, r);
11657 + DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
11658 + enter_hs_mode_lat, exit_hs_mode_lat);
11662 +#define DSI_DECL_VARS \
11663 + int __dsi_cb = 0; u32 __dsi_cv = 0;
11665 +#define DSI_FLUSH(ch) \
11666 + if (__dsi_cb > 0) { \
11667 + /*DSSDBG("sending long packet %#010x\n", __dsi_cv);*/ \
11668 + dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \
11669 + __dsi_cb = __dsi_cv = 0; \
11672 +#define DSI_PUSH(ch, data) \
11674 + __dsi_cv |= (data) << (__dsi_cb * 8); \
11675 + /*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \
11676 + if (++__dsi_cb > 3) \
11680 +static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
11681 + int x, int y, int w, int h)
11683 + /* Note: supports only 24bit colors in 32bit container */
11685 + int fifo_stalls = 0;
11686 + int max_dsi_packet_size;
11687 + int max_data_per_packet;
11688 + int max_pixels_per_packet;
11690 + int bytespp = dssdev->ctrl.pixel_size / 8;
11692 + u32 __iomem *data;
11693 + int start_offset;
11696 + struct omap_overlay *ovl;
11700 + DSSDBG("dsi_update_screen_l4 (%d,%d %dx%d)\n",
11703 + ovl = dssdev->manager->overlays[0];
11705 + if (ovl->info.color_mode != OMAP_DSS_COLOR_RGB24U)
11708 + if (dssdev->ctrl.pixel_size != 24)
11711 + scr_width = ovl->info.screen_width;
11712 + data = ovl->info.vaddr;
11714 + start_offset = scr_width * y + x;
11715 + horiz_inc = scr_width - w;
11718 + /* We need header(4) + DCSCMD(1) + pixels(numpix*bytespp) bytes
11721 + /* When using CPU, max long packet size is TX buffer size */
11722 + max_dsi_packet_size = dsi.vc[0].fifo_size * 32 * 4;
11724 + /* we seem to get better perf if we divide the tx fifo to half,
11725 + and while the other half is being sent, we fill the other half
11726 + max_dsi_packet_size /= 2; */
11728 + max_data_per_packet = max_dsi_packet_size - 4 - 1;
11730 + max_pixels_per_packet = max_data_per_packet / bytespp;
11732 + DSSDBG("max_pixels_per_packet %d\n", max_pixels_per_packet);
11734 + pixels_left = w * h;
11736 + DSSDBG("total pixels %d\n", pixels_left);
11738 + data += start_offset;
11740 + while (pixels_left > 0) {
11741 + /* 0x2c = write_memory_start */
11742 + /* 0x3c = write_memory_continue */
11743 + u8 dcs_cmd = first ? 0x2c : 0x3c;
11749 + /* using fifo not empty */
11750 + /* TX_FIFO_NOT_EMPTY */
11751 + while (FLD_GET(dsi_read_reg(DSI_VC_CTRL(0)), 5, 5)) {
11754 + if (fifo_stalls > 0xfffff) {
11755 + DSSERR("fifo stalls overflow, pixels left %d\n",
11757 + dsi_if_enable(0);
11762 + /* using fifo emptiness */
11763 + while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 <
11764 + max_dsi_packet_size) {
11766 + if (fifo_stalls > 0xfffff) {
11767 + DSSERR("fifo stalls overflow, pixels left %d\n",
11769 + dsi_if_enable(0);
11774 + while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 == 0) {
11776 + if (fifo_stalls > 0xfffff) {
11777 + DSSERR("fifo stalls overflow, pixels left %d\n",
11779 + dsi_if_enable(0);
11784 + pixels = min(max_pixels_per_packet, pixels_left);
11786 + pixels_left -= pixels;
11788 + dsi_vc_write_long_header(0, DSI_DT_DCS_LONG_WRITE,
11789 + 1 + pixels * bytespp, 0);
11791 + DSI_PUSH(0, dcs_cmd);
11793 + while (pixels-- > 0) {
11794 + u32 pix = __raw_readl(data++);
11796 + DSI_PUSH(0, (pix >> 16) & 0xff);
11797 + DSI_PUSH(0, (pix >> 8) & 0xff);
11798 + DSI_PUSH(0, (pix >> 0) & 0xff);
11801 + if (current_x == x+w) {
11803 + data += horiz_inc;
11813 +static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
11814 + u16 x, u16 y, u16 w, u16 h)
11816 + int bytespp = dssdev->ctrl.pixel_size / 8;
11819 + int packet_payload;
11822 + bool use_te_trigger;
11823 + const int channel = 0;
11825 + use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;
11827 + if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
11828 + DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
11831 + len = w * h * bytespp;
11833 + /* XXX: one packet could be longer, I think? Line buffer is
11834 + * 1024 x 24bits, but we have to put DCS cmd there also.
11835 + * 1023 * 3 should work, but causes strange color effects. */
11836 + packet_payload = min(w, (u16)1020) * bytespp;
11838 + packet_len = packet_payload + 1; /* 1 byte for DCS cmd */
11839 + total_len = (len / packet_payload) * packet_len;
11841 + if (len % packet_payload)
11842 + total_len += (len % packet_payload) + 1;
11845 + dsi_vc_print_status(1);
11847 + l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
11848 + dsi_write_reg(DSI_VC_TE(channel), l);
11850 + dsi_vc_write_long_header(channel, DSI_DT_DCS_LONG_WRITE, packet_len, 0);
11852 + if (use_te_trigger)
11853 + l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
11855 + l = FLD_MOD(l, 1, 31, 31); /* TE_START */
11856 + dsi_write_reg(DSI_VC_TE(channel), l);
11858 + /* We put SIDLEMODE to no-idle for the duration of the transfer,
11859 + * because DSS interrupts are not capable of waking up the CPU and the
11860 + * framedone interrupt could be delayed for quite a long time. I think
11861 + * the same goes for any DSS interrupts, but for some reason I have not
11862 + * seen the problem anywhere else than here.
11864 + dispc_disable_sidle();
11866 + dss_start_update(dssdev);
11868 + if (use_te_trigger) {
11869 + /* disable LP_RX_TO, so that we can receive TE. Time to wait
11870 + * for TE is longer than the timer allows */
11871 + REG_FLD_MOD(DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
11873 + dsi_vc_send_bta(channel);
11877 +static void dsi_framedone_irq_callback(void *data, u32 mask)
11879 + /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
11880 + * turns itself off. However, DSI still has the pixels in its buffers,
11881 + * and is sending the data.
11884 + /* SIDLEMODE back to smart-idle */
11885 + dispc_enable_sidle();
11887 + dsi.framedone_received = true;
11888 + wake_up(&dsi.waitqueue);
11891 +static void dsi_set_update_region(struct omap_dss_device *dssdev,
11892 + u16 x, u16 y, u16 w, u16 h)
11894 + spin_lock(&dsi.update_lock);
11895 + if (dsi.update_region.dirty) {
11896 + dsi.update_region.x = min(x, dsi.update_region.x);
11897 + dsi.update_region.y = min(y, dsi.update_region.y);
11898 + dsi.update_region.w = max(w, dsi.update_region.w);
11899 + dsi.update_region.h = max(h, dsi.update_region.h);
11901 + dsi.update_region.x = x;
11902 + dsi.update_region.y = y;
11903 + dsi.update_region.w = w;
11904 + dsi.update_region.h = h;
11907 + dsi.update_region.device = dssdev;
11908 + dsi.update_region.dirty = true;
11910 + spin_unlock(&dsi.update_lock);
11914 +static void dsi_start_auto_update(struct omap_dss_device *dssdev)
11919 + DSSDBG("starting auto update\n");
11921 + /* In automatic mode the overlay settings are applied like on DPI/SDI.
11922 + * Mark the overlays dirty, so that we get the overlays configured, as
11923 + * manual mode has left them in bad shape after config partia planes */
11924 + for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
11925 + struct omap_overlay *ovl;
11926 + ovl = omap_dss_get_overlay(i);
11927 + if (ovl->manager == dssdev->manager)
11928 + ovl->info_dirty = true;
11930 + dssdev->manager->apply(dssdev->manager);
11932 + dssdev->get_resolution(dssdev, &w, &h);
11934 + dsi_set_update_region(dssdev, 0, 0, w, h);
11936 + dsi_perf_mark_start_auto();
11938 + wake_up(&dsi.waitqueue);
11941 +static int dsi_set_te(struct omap_dss_device *dssdev, bool enable)
11944 + r = dssdev->driver->enable_te(dssdev, enable);
11945 + /* XXX for some reason, DSI TE breaks if we don't wait here.
11946 + * Panel bug? Needs more studying */
11951 +static void dsi_handle_framedone(void)
11954 + const int channel = 0;
11955 + bool use_te_trigger;
11957 + use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;
11959 + if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
11960 + DSSDBG("FRAMEDONE\n");
11962 + if (use_te_trigger) {
11963 + /* enable LP_RX_TO again after the TE */
11964 + REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
11967 + /* Send BTA after the frame. We need this for the TE to work, as TE
11968 + * trigger is only sent for BTAs without preceding packet. Thus we need
11969 + * to BTA after the pixel packets so that next BTA will cause TE
11972 + * This is not needed when TE is not in use, but we do it anyway to
11973 + * make sure that the transfer has been completed. It would be more
11974 + * optimal, but more complex, to wait only just before starting next
11976 + r = dsi_vc_send_bta_sync(channel);
11978 + DSSERR("BTA after framedone failed\n");
11980 +#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
11981 + dispc_fake_vsync_irq();
11985 +static int dsi_update_thread(void *data)
11987 + unsigned long timeout;
11988 + struct omap_dss_device *device;
11994 + wait_event_interruptible(dsi.waitqueue,
11995 + dsi.update_mode == OMAP_DSS_UPDATE_AUTO ||
11996 + (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL &&
11997 + dsi.update_region.dirty == true) ||
11998 + kthread_should_stop());
12000 + if (kthread_should_stop())
12005 + if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED ||
12006 + kthread_should_stop()) {
12007 + dsi_bus_unlock();
12011 + dsi_perf_mark_setup();
12013 + if (dsi.update_region.dirty) {
12014 + spin_lock(&dsi.update_lock);
12015 + dsi.active_update_region = dsi.update_region;
12016 + dsi.update_region.dirty = false;
12017 + spin_unlock(&dsi.update_lock);
12020 + device = dsi.active_update_region.device;
12021 + x = dsi.active_update_region.x;
12022 + y = dsi.active_update_region.y;
12023 + w = dsi.active_update_region.w;
12024 + h = dsi.active_update_region.h;
12026 + if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
12028 + if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL) {
12029 + dss_setup_partial_planes(device,
12032 + /* XXX there seems to be a bug in this driver
12033 + * or OMAP hardware. Some updates with certain
12034 + * widths and x coordinates fail. These widths
12035 + * are always odd, so "fix" it here for now */
12038 + device->get_resolution(device,
12044 + dss_setup_partial_planes(device,
12050 + dispc_set_lcd_size(w, h);
12053 + if (dsi.active_update_region.dirty) {
12054 + dsi.active_update_region.dirty = false;
12055 + /* XXX TODO we don't need to send the coords, if they
12056 + * are the same that are already programmed to the
12057 + * panel. That should speed up manual update a bit */
12058 + device->driver->setup_update(device, x, y, w, h);
12061 + dsi_perf_mark_start();
12063 + if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
12064 + dsi_vc_config_vp(0);
12066 + if (dsi.te_enabled && dsi.use_ext_te)
12067 + device->driver->wait_for_te(device);
12069 + dsi.framedone_received = false;
12071 + dsi_update_screen_dispc(device, x, y, w, h);
12073 + /* wait for framedone */
12074 + timeout = msecs_to_jiffies(1000);
12075 + timeout = wait_event_timeout(dsi.waitqueue,
12076 + dsi.framedone_received == true,
12079 + if (timeout == 0) {
12080 + DSSERR("framedone timeout\n");
12081 + DSSERR("failed update %d,%d %dx%d\n",
12084 + dispc_enable_sidle();
12085 + dispc_enable_lcd_out(0);
12087 + dsi_handle_framedone();
12088 + dsi_perf_show("DISPC");
12091 + dsi_update_screen_l4(device, x, y, w, h);
12092 + dsi_perf_show("L4");
12095 + sched = atomic_read(&dsi.bus_lock.count) < 0;
12097 + complete_all(&dsi.update_completion);
12099 + dsi_bus_unlock();
12101 + /* XXX We need to give others chance to get the bus lock. Is
12102 + * there a better way for this? */
12103 + if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO && sched)
12104 + schedule_timeout_interruptible(1);
12107 + DSSDBG("update thread exiting\n");
12114 +/* Display funcs */
12116 +static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
12120 + r = omap_dispc_register_isr(dsi_framedone_irq_callback, NULL,
12121 + DISPC_IRQ_FRAMEDONE);
12123 + DSSERR("can't get FRAMEDONE irq\n");
12127 + dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
12129 + dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_DSI);
12130 + dispc_enable_fifohandcheck(1);
12132 + dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
12135 + struct omap_video_timings timings = {
12144 + dispc_set_lcd_timings(&timings);
12150 +static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
12152 + omap_dispc_unregister_isr(dsi_framedone_irq_callback, NULL,
12153 + DISPC_IRQ_FRAMEDONE);
12156 +static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
12158 + struct dsi_clock_info cinfo;
12161 + _dsi_print_reset_status();
12163 + r = dsi_pll_init(1, 0);
12167 + r = dsi_pll_calc_ddrfreq(dssdev->phy.dsi.ddr_clk_hz, &cinfo);
12171 + r = dsi_pll_program(&cinfo);
12175 + DSSDBG("PLL OK\n");
12177 + r = dsi_complexio_init(dssdev);
12181 + _dsi_print_reset_status();
12183 + dsi_proto_timings(dssdev);
12184 + dsi_set_lp_clk_divisor(dssdev);
12187 + _dsi_print_reset_status();
12189 + r = dsi_proto_config(dssdev);
12193 + /* enable interface */
12194 + dsi_vc_enable(0, 1);
12195 + dsi_if_enable(1);
12196 + dsi_force_tx_stop_mode_io();
12198 + if (dssdev->driver->enable) {
12199 + r = dssdev->driver->enable(dssdev);
12204 + /* enable high-speed after initial config */
12205 + dsi_vc_enable_hs(0, 1);
12209 + dsi_if_enable(0);
12211 + dsi_complexio_uninit();
12213 + dsi_pll_uninit();
12218 +static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
12220 + if (dssdev->driver->disable)
12221 + dssdev->driver->disable(dssdev);
12223 + dsi_complexio_uninit();
12224 + dsi_pll_uninit();
12227 +static int dsi_core_init(void)
12230 + REG_FLD_MOD(DSI_SYSCONFIG, 1, 0, 0);
12233 + REG_FLD_MOD(DSI_SYSCONFIG, 1, 2, 2);
12235 + /* SIDLEMODE smart-idle */
12236 + REG_FLD_MOD(DSI_SYSCONFIG, 2, 4, 3);
12238 + _dsi_initialize_irq();
12243 +static int dsi_display_enable(struct omap_dss_device *dssdev)
12247 + DSSDBG("dsi_display_enable\n");
12249 + mutex_lock(&dsi.lock);
12252 + r = omap_dss_start_device(dssdev);
12254 + DSSERR("failed to start device\n");
12258 + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
12259 + DSSERR("dssdev already enabled\n");
12264 + enable_clocks(1);
12265 + dsi_enable_pll_clock(1);
12267 + r = _dsi_reset();
12273 + r = dsi_display_init_dispc(dssdev);
12277 + r = dsi_display_init_dsi(dssdev);
12281 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
12283 + dsi.use_ext_te = dssdev->phy.dsi.ext_te;
12284 + r = dsi_set_te(dssdev, dsi.te_enabled);
12288 + dsi.update_mode = dsi.user_update_mode;
12289 + if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO)
12290 + dsi_start_auto_update(dssdev);
12292 + dsi_bus_unlock();
12293 + mutex_unlock(&dsi.lock);
12298 + dsi_display_uninit_dispc(dssdev);
12300 + enable_clocks(0);
12301 + dsi_enable_pll_clock(0);
12303 + omap_dss_stop_device(dssdev);
12305 + dsi_bus_unlock();
12306 + mutex_unlock(&dsi.lock);
12307 + DSSDBG("dsi_display_enable FAILED\n");
12311 +static void dsi_display_disable(struct omap_dss_device *dssdev)
12313 + DSSDBG("dsi_display_disable\n");
12315 + mutex_lock(&dsi.lock);
12318 + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
12319 + dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
12322 + dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
12323 + dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
12325 + dsi_display_uninit_dispc(dssdev);
12327 + dsi_display_uninit_dsi(dssdev);
12329 + enable_clocks(0);
12330 + dsi_enable_pll_clock(0);
12332 + omap_dss_stop_device(dssdev);
12334 + dsi_bus_unlock();
12335 + mutex_unlock(&dsi.lock);
12338 +static int dsi_display_suspend(struct omap_dss_device *dssdev)
12340 + DSSDBG("dsi_display_suspend\n");
12342 + mutex_lock(&dsi.lock);
12345 + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
12346 + dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
12349 + dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
12350 + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
12352 + dsi_display_uninit_dispc(dssdev);
12354 + dsi_display_uninit_dsi(dssdev);
12356 + enable_clocks(0);
12357 + dsi_enable_pll_clock(0);
12359 + dsi_bus_unlock();
12360 + mutex_unlock(&dsi.lock);
12365 +static int dsi_display_resume(struct omap_dss_device *dssdev)
12369 + DSSDBG("dsi_display_resume\n");
12371 + mutex_lock(&dsi.lock);
12374 + if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
12375 + DSSERR("dssdev not suspended\n");
12380 + enable_clocks(1);
12381 + dsi_enable_pll_clock(1);
12383 + r = _dsi_reset();
12389 + r = dsi_display_init_dispc(dssdev);
12393 + r = dsi_display_init_dsi(dssdev);
12397 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
12399 + r = dsi_set_te(dssdev, dsi.te_enabled);
12403 + dsi.update_mode = dsi.user_update_mode;
12404 + if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO)
12405 + dsi_start_auto_update(dssdev);
12407 + dsi_bus_unlock();
12408 + mutex_unlock(&dsi.lock);
12413 + dsi_display_uninit_dispc(dssdev);
12415 + enable_clocks(0);
12416 + dsi_enable_pll_clock(0);
12418 + dsi_bus_unlock();
12419 + mutex_unlock(&dsi.lock);
12420 + DSSDBG("dsi_display_resume FAILED\n");
12424 +static int dsi_display_update(struct omap_dss_device *dssdev,
12425 + u16 x, u16 y, u16 w, u16 h)
12430 + DSSDBG("dsi_display_update(%d,%d %dx%d)\n", x, y, w, h);
12432 + mutex_lock(&dsi.lock);
12434 + if (dsi.update_mode != OMAP_DSS_UPDATE_MANUAL)
12437 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
12440 + dssdev->get_resolution(dssdev, &dw, &dh);
12442 + if (x > dw || y > dh)
12451 + if (w == 0 || h == 0)
12454 + dsi_set_update_region(dssdev, x, y, w, h);
12456 + wake_up(&dsi.waitqueue);
12459 + mutex_unlock(&dsi.lock);
12464 +static int dsi_display_sync(struct omap_dss_device *dssdev)
12468 + DSSDBG("dsi_display_sync()\n");
12470 + mutex_lock(&dsi.lock);
12473 + if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL &&
12474 + dsi.update_region.dirty) {
12475 + INIT_COMPLETION(dsi.update_completion);
12481 + dsi_bus_unlock();
12482 + mutex_unlock(&dsi.lock);
12485 + wait_for_completion_interruptible(&dsi.update_completion);
12487 + DSSDBG("dsi_display_sync() done\n");
12491 +static int dsi_display_set_update_mode(struct omap_dss_device *dssdev,
12492 + enum omap_dss_update_mode mode)
12494 + DSSDBGF("%d", mode);
12496 + mutex_lock(&dsi.lock);
12499 + if (dsi.update_mode != mode) {
12500 + dsi.user_update_mode = mode;
12501 + dsi.update_mode = mode;
12503 + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE &&
12504 + mode == OMAP_DSS_UPDATE_AUTO)
12505 + dsi_start_auto_update(dssdev);
12508 + dsi_bus_unlock();
12509 + mutex_unlock(&dsi.lock);
12514 +static enum omap_dss_update_mode dsi_display_get_update_mode(
12515 + struct omap_dss_device *dssdev)
12517 + return dsi.update_mode;
12521 +static int dsi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
12525 + DSSDBGF("%d", enable);
12527 + if (!dssdev->driver->enable_te)
12532 + dsi.te_enabled = enable;
12534 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
12537 + r = dsi_set_te(dssdev, enable);
12539 + dsi_bus_unlock();
12544 +static int dsi_display_get_te(struct omap_dss_device *dssdev)
12546 + return dsi.te_enabled;
12549 +static int dsi_display_set_rotate(struct omap_dss_device *dssdev, u8 rotate)
12552 + DSSDBGF("%d", rotate);
12554 + if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
12558 + dssdev->driver->set_rotate(dssdev, rotate);
12559 + if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) {
12561 + /* the display dimensions may have changed, so set a new
12562 + * update region */
12563 + dssdev->get_resolution(dssdev, &w, &h);
12564 + dsi_set_update_region(dssdev, 0, 0, w, h);
12566 + dsi_bus_unlock();
12571 +static u8 dsi_display_get_rotate(struct omap_dss_device *dssdev)
12573 + if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
12576 + return dssdev->driver->get_rotate(dssdev);
12579 +static int dsi_display_set_mirror(struct omap_dss_device *dssdev, bool mirror)
12581 + DSSDBGF("%d", mirror);
12583 + if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
12587 + dssdev->driver->set_mirror(dssdev, mirror);
12588 + dsi_bus_unlock();
12593 +static bool dsi_display_get_mirror(struct omap_dss_device *dssdev)
12595 + if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
12598 + return dssdev->driver->get_mirror(dssdev);
12601 +static int dsi_display_run_test(struct omap_dss_device *dssdev, int test_num)
12605 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
12608 + DSSDBGF("%d", test_num);
12612 + /* run test first in low speed mode */
12613 + dsi_vc_enable_hs(0, 0);
12615 + if (dssdev->driver->run_test) {
12616 + r = dssdev->driver->run_test(dssdev, test_num);
12621 + /* then in high speed */
12622 + dsi_vc_enable_hs(0, 1);
12624 + if (dssdev->driver->run_test) {
12625 + r = dssdev->driver->run_test(dssdev, test_num);
12631 + dsi_vc_enable_hs(0, 1);
12633 + dsi_bus_unlock();
12638 +static int dsi_display_memory_read(struct omap_dss_device *dssdev,
12639 + void *buf, size_t size,
12640 + u16 x, u16 y, u16 w, u16 h)
12646 + if (!dssdev->driver->memory_read)
12649 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
12654 + r = dssdev->driver->memory_read(dssdev, buf, size,
12657 + dsi_bus_unlock();
12662 +void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
12663 + u32 fifo_size, enum omap_burst_size *burst_size,
12664 + u32 *fifo_low, u32 *fifo_high)
12666 + unsigned burst_size_bytes;
12668 + *burst_size = OMAP_DSS_BURST_16x32;
12669 + burst_size_bytes = 16 * 32 / 8;
12671 + *fifo_high = fifo_size - burst_size_bytes;
12675 +int dsi_init_display(struct omap_dss_device *dssdev)
12677 + DSSDBG("DSI init\n");
12679 + dssdev->enable = dsi_display_enable;
12680 + dssdev->disable = dsi_display_disable;
12681 + dssdev->suspend = dsi_display_suspend;
12682 + dssdev->resume = dsi_display_resume;
12683 + dssdev->update = dsi_display_update;
12684 + dssdev->sync = dsi_display_sync;
12685 + dssdev->set_update_mode = dsi_display_set_update_mode;
12686 + dssdev->get_update_mode = dsi_display_get_update_mode;
12687 + dssdev->enable_te = dsi_display_enable_te;
12688 + dssdev->get_te = dsi_display_get_te;
12690 + dssdev->get_rotate = dsi_display_get_rotate;
12691 + dssdev->set_rotate = dsi_display_set_rotate;
12693 + dssdev->get_mirror = dsi_display_get_mirror;
12694 + dssdev->set_mirror = dsi_display_set_mirror;
12696 + dssdev->run_test = dsi_display_run_test;
12697 + dssdev->memory_read = dsi_display_memory_read;
12699 + dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
12701 + dsi.vc[0].dssdev = dssdev;
12702 + dsi.vc[1].dssdev = dssdev;
12707 +int dsi_init(struct platform_device *pdev)
12710 + struct sched_param param = {
12711 + .sched_priority = MAX_USER_RT_PRIO-1
12714 + spin_lock_init(&dsi.errors_lock);
12717 + /* XXX fail properly */
12719 + init_completion(&dsi.bta_completion);
12720 + init_completion(&dsi.update_completion);
12722 + dsi.thread = kthread_create(dsi_update_thread, NULL, "dsi");
12723 + if (IS_ERR(dsi.thread)) {
12724 + DSSERR("cannot create kthread\n");
12725 + return PTR_ERR(dsi.thread);
12727 + sched_setscheduler(dsi.thread, SCHED_FIFO, ¶m);
12729 + init_waitqueue_head(&dsi.waitqueue);
12730 + spin_lock_init(&dsi.update_lock);
12732 + mutex_init(&dsi.lock);
12733 + mutex_init(&dsi.bus_lock);
12735 + dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
12736 + dsi.user_update_mode = OMAP_DSS_UPDATE_DISABLED;
12738 + dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS);
12740 + DSSERR("can't ioremap DSI\n");
12744 + dsi.vdds_dsi_reg = regulator_get(&pdev->dev, "vdds_dsi");
12745 + if (IS_ERR(dsi.vdds_dsi_reg)) {
12746 + iounmap(dsi.base);
12747 + DSSERR("can't get VDDS_DSI regulator\n");
12748 + return PTR_ERR(dsi.vdds_dsi_reg);
12751 + enable_clocks(1);
12753 + rev = dsi_read_reg(DSI_REVISION);
12754 + printk(KERN_INFO "OMAP DSI rev %d.%d\n",
12755 + FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
12757 + enable_clocks(0);
12759 + wake_up_process(dsi.thread);
12764 +void dsi_exit(void)
12766 + kthread_stop(dsi.thread);
12768 + regulator_put(dsi.vdds_dsi_reg);
12770 + iounmap(dsi.base);
12772 + DSSDBG("omap_dsi_exit\n");
12775 diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
12776 new file mode 100644
12777 index 0000000..aab9758
12779 +++ b/drivers/video/omap2/dss/dss.c
12782 + * linux/drivers/video/omap2/dss/dss.c
12784 + * Copyright (C) 2009 Nokia Corporation
12785 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
12787 + * Some code and ideas taken from drivers/video/omap/ driver
12790 + * This program is free software; you can redistribute it and/or modify it
12791 + * under the terms of the GNU General Public License version 2 as published by
12792 + * the Free Software Foundation.
12794 + * This program is distributed in the hope that it will be useful, but WITHOUT
12795 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12796 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12799 + * You should have received a copy of the GNU General Public License along with
12800 + * this program. If not, see <http://www.gnu.org/licenses/>.
12803 +#define DSS_SUBSYS_NAME "DSS"
12805 +#include <linux/kernel.h>
12806 +#include <linux/io.h>
12807 +#include <linux/err.h>
12808 +#include <linux/delay.h>
12809 +#include <linux/interrupt.h>
12810 +#include <linux/seq_file.h>
12812 +#include <mach/display.h>
12815 +#define DSS_BASE 0x48050000
12817 +#define DSS_SZ_REGS SZ_512
12823 +#define DSS_REG(idx) ((const struct dss_reg) { idx })
12825 +#define DSS_REVISION DSS_REG(0x0000)
12826 +#define DSS_SYSCONFIG DSS_REG(0x0010)
12827 +#define DSS_SYSSTATUS DSS_REG(0x0014)
12828 +#define DSS_IRQSTATUS DSS_REG(0x0018)
12829 +#define DSS_CONTROL DSS_REG(0x0040)
12830 +#define DSS_SDI_CONTROL DSS_REG(0x0044)
12831 +#define DSS_PLL_CONTROL DSS_REG(0x0048)
12832 +#define DSS_SDI_STATUS DSS_REG(0x005C)
12834 +#define REG_GET(idx, start, end) \
12835 + FLD_GET(dss_read_reg(idx), start, end)
12837 +#define REG_FLD_MOD(idx, val, start, end) \
12838 + dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
12841 + void __iomem *base;
12843 + u32 ctx[DSS_SZ_REGS / sizeof(u32)];
12846 +static int _omap_dss_wait_reset(void);
12848 +static inline void dss_write_reg(const struct dss_reg idx, u32 val)
12850 + __raw_writel(val, dss.base + idx.idx);
12853 +static inline u32 dss_read_reg(const struct dss_reg idx)
12855 + return __raw_readl(dss.base + idx.idx);
12859 + dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
12861 + dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
12863 +void dss_save_context(void)
12865 + if (cpu_is_omap24xx())
12871 +#ifdef CONFIG_OMAP2_DSS_SDI
12877 +void dss_restore_context(void)
12879 + if (_omap_dss_wait_reset())
12880 + DSSERR("DSS not coming out of reset after sleep\n");
12885 +#ifdef CONFIG_OMAP2_DSS_SDI
12894 +void dss_sdi_init(u8 datapairs)
12898 + BUG_ON(datapairs > 3 || datapairs < 1);
12900 + l = dss_read_reg(DSS_SDI_CONTROL);
12901 + l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */
12902 + l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */
12903 + l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */
12904 + dss_write_reg(DSS_SDI_CONTROL, l);
12906 + l = dss_read_reg(DSS_PLL_CONTROL);
12907 + l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */
12908 + l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */
12909 + l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */
12910 + dss_write_reg(DSS_PLL_CONTROL, l);
12913 +void dss_sdi_enable(void)
12915 + dispc_pck_free_enable(1);
12917 + /* Reset SDI PLL */
12918 + REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
12919 + udelay(1); /* wait 2x PCLK */
12921 + /* Lock SDI PLL */
12922 + REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
12924 + /* Waiting for PLL lock request to complete */
12925 + while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6))
12928 + /* Clearing PLL_GO bit */
12929 + REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
12931 + /* Waiting for PLL to lock */
12932 + while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5)))
12935 + dispc_lcd_enable_signal(1);
12937 + /* Waiting for SDI reset to complete */
12938 + while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2)))
12942 +void dss_sdi_disable(void)
12944 + dispc_lcd_enable_signal(0);
12946 + dispc_pck_free_enable(0);
12948 + /* Reset SDI PLL */
12949 + REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
12952 +void dss_dump_regs(struct seq_file *s)
12954 +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
12956 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
12958 + DUMPREG(DSS_REVISION);
12959 + DUMPREG(DSS_SYSCONFIG);
12960 + DUMPREG(DSS_SYSSTATUS);
12961 + DUMPREG(DSS_IRQSTATUS);
12962 + DUMPREG(DSS_CONTROL);
12963 + DUMPREG(DSS_SDI_CONTROL);
12964 + DUMPREG(DSS_PLL_CONTROL);
12965 + DUMPREG(DSS_SDI_STATUS);
12967 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
12971 +void dss_select_clk_source(bool dsi, bool dispc)
12974 + r = dss_read_reg(DSS_CONTROL);
12975 + r = FLD_MOD(r, dsi, 1, 1); /* DSI_CLK_SWITCH */
12976 + r = FLD_MOD(r, dispc, 0, 0); /* DISPC_CLK_SWITCH */
12977 + dss_write_reg(DSS_CONTROL, r);
12980 +int dss_get_dsi_clk_source(void)
12982 + return FLD_GET(dss_read_reg(DSS_CONTROL), 1, 1);
12985 +int dss_get_dispc_clk_source(void)
12987 + return FLD_GET(dss_read_reg(DSS_CONTROL), 0, 0);
12990 +static irqreturn_t dss_irq_handler_omap2(int irq, void *arg)
12992 + dispc_irq_handler();
12994 + return IRQ_HANDLED;
12997 +static irqreturn_t dss_irq_handler_omap3(int irq, void *arg)
13001 + irqstatus = dss_read_reg(DSS_IRQSTATUS);
13003 + if (irqstatus & (1<<0)) /* DISPC_IRQ */
13004 + dispc_irq_handler();
13005 +#ifdef CONFIG_OMAP2_DSS_DSI
13006 + if (irqstatus & (1<<1)) /* DSI_IRQ */
13007 + dsi_irq_handler();
13010 + return IRQ_HANDLED;
13013 +static int _omap_dss_wait_reset(void)
13015 + unsigned timeout = 1000;
13017 + while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) {
13019 + if (!--timeout) {
13020 + DSSERR("soft reset failed\n");
13028 +static int _omap_dss_reset(void)
13031 + REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1);
13032 + return _omap_dss_wait_reset();
13035 +void dss_set_venc_output(enum omap_dss_venc_type type)
13039 + if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
13041 + else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
13046 + /* venc out selection. 0 = comp, 1 = svideo */
13047 + REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
13050 +void dss_set_dac_pwrdn_bgz(bool enable)
13052 + REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
13055 +int dss_init(bool skip_init)
13060 + dss.base = ioremap(DSS_BASE, DSS_SZ_REGS);
13062 + DSSERR("can't ioremap DSS\n");
13067 + if (!skip_init) {
13068 + /* disable LCD and DIGIT output. This seems to fix the synclost
13069 + * problem that we get, if the bootloader starts the DSS and
13070 + * the kernel resets it */
13071 + omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
13073 + /* We need to wait here a bit, otherwise we sometimes start to
13074 + * get synclost errors, and after that only power cycle will
13075 + * restore DSS functionality. I have no idea why this happens.
13076 + * And we have to wait _before_ resetting the DSS, but after
13077 + * enabling clocks.
13081 + _omap_dss_reset();
13085 + REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
13087 + /* Select DPLL */
13088 + REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
13090 +#ifdef CONFIG_OMAP2_DSS_VENC
13091 + REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
13092 + REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
13093 + REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
13096 + r = request_irq(INT_24XX_DSS_IRQ,
13097 + cpu_is_omap24xx()
13098 + ? dss_irq_handler_omap2
13099 + : dss_irq_handler_omap3,
13100 + 0, "OMAP DSS", NULL);
13103 + DSSERR("omap2 dss: request_irq failed\n");
13107 + dss_save_context();
13109 + rev = dss_read_reg(DSS_REVISION);
13110 + printk(KERN_INFO "OMAP DSS rev %d.%d\n",
13111 + FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
13116 + iounmap(dss.base);
13121 +void dss_exit(void)
13123 + free_irq(INT_24XX_DSS_IRQ, NULL);
13125 + iounmap(dss.base);
13128 diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
13129 new file mode 100644
13130 index 0000000..50f7f5f
13132 +++ b/drivers/video/omap2/dss/dss.h
13135 + * linux/drivers/video/omap2/dss/dss.h
13137 + * Copyright (C) 2009 Nokia Corporation
13138 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
13140 + * Some code and ideas taken from drivers/video/omap/ driver
13143 + * This program is free software; you can redistribute it and/or modify it
13144 + * under the terms of the GNU General Public License version 2 as published by
13145 + * the Free Software Foundation.
13147 + * This program is distributed in the hope that it will be useful, but WITHOUT
13148 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13149 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13152 + * You should have received a copy of the GNU General Public License along with
13153 + * this program. If not, see <http://www.gnu.org/licenses/>.
13156 +#ifndef __OMAP2_DSS_H
13157 +#define __OMAP2_DSS_H
13159 +#ifdef CONFIG_OMAP2_DSS_DEBUG_SUPPORT
13164 +extern unsigned int dss_debug;
13165 +#ifdef DSS_SUBSYS_NAME
13166 +#define DSSDBG(format, ...) \
13168 + printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME ": " format, \
13171 +#define DSSDBG(format, ...) \
13173 + printk(KERN_DEBUG "omapdss: " format, ## __VA_ARGS__)
13176 +#ifdef DSS_SUBSYS_NAME
13177 +#define DSSDBGF(format, ...) \
13179 + printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME \
13180 + ": %s(" format ")\n", \
13184 +#define DSSDBGF(format, ...) \
13186 + printk(KERN_DEBUG "omapdss: " \
13187 + ": %s(" format ")\n", \
13193 +#define DSSDBG(format, ...)
13194 +#define DSSDBGF(format, ...)
13198 +#ifdef DSS_SUBSYS_NAME
13199 +#define DSSERR(format, ...) \
13200 + printk(KERN_ERR "omapdss " DSS_SUBSYS_NAME " error: " format, \
13203 +#define DSSERR(format, ...) \
13204 + printk(KERN_ERR "omapdss error: " format, ## __VA_ARGS__)
13207 +#ifdef DSS_SUBSYS_NAME
13208 +#define DSSINFO(format, ...) \
13209 + printk(KERN_INFO "omapdss " DSS_SUBSYS_NAME ": " format, \
13212 +#define DSSINFO(format, ...) \
13213 + printk(KERN_INFO "omapdss: " format, ## __VA_ARGS__)
13216 +#ifdef DSS_SUBSYS_NAME
13217 +#define DSSWARN(format, ...) \
13218 + printk(KERN_WARNING "omapdss " DSS_SUBSYS_NAME ": " format, \
13221 +#define DSSWARN(format, ...) \
13222 + printk(KERN_WARNING "omapdss: " format, ## __VA_ARGS__)
13225 +/* OMAP TRM gives bitfields as start:end, where start is the higher bit
13226 + number. For example 7:0 */
13227 +#define FLD_MASK(start, end) (((1 << (start - end + 1)) - 1) << (end))
13228 +#define FLD_VAL(val, start, end) (((val) << end) & FLD_MASK(start, end))
13229 +#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
13230 +#define FLD_MOD(orig, val, start, end) \
13231 + (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
13233 +#define DISPC_MAX_FCK 173000000
13235 +enum omap_burst_size {
13236 + OMAP_DSS_BURST_4x32 = 0,
13237 + OMAP_DSS_BURST_8x32 = 1,
13238 + OMAP_DSS_BURST_16x32 = 2,
13241 +enum omap_parallel_interface_mode {
13242 + OMAP_DSS_PARALLELMODE_BYPASS, /* MIPI DPI */
13243 + OMAP_DSS_PARALLELMODE_RFBI, /* MIPI DBI */
13244 + OMAP_DSS_PARALLELMODE_DSI,
13248 + DSS_CLK_ICK = 1 << 0,
13249 + DSS_CLK_FCK1 = 1 << 1,
13250 + DSS_CLK_FCK2 = 1 << 2,
13251 + DSS_CLK_54M = 1 << 3,
13252 + DSS_CLK_96M = 1 << 4,
13255 +struct dispc_clock_info {
13256 + /* rates that we get with dividers below */
13257 + unsigned long fck;
13258 + unsigned long lck;
13259 + unsigned long pck;
13267 +struct dsi_clock_info {
13268 + /* rates that we get with dividers below */
13269 + unsigned long fint;
13270 + unsigned long dsiphy;
13271 + unsigned long clkin;
13272 + unsigned long dsi1_pll_fclk;
13273 + unsigned long dsi2_pll_fclk;
13274 + unsigned long lck;
13275 + unsigned long pck;
13287 + bool use_dss2_fck;
13291 +struct platform_device;
13294 +void dss_clk_enable(enum dss_clock clks);
13295 +void dss_clk_disable(enum dss_clock clks);
13296 +unsigned long dss_clk_get_rate(enum dss_clock clk);
13297 +int dss_need_ctx_restore(void);
13298 +void dss_dump_clocks(struct seq_file *s);
13299 +struct bus_type *dss_get_bus(void);
13302 +int dss_suspend_all_devices(void);
13303 +int dss_resume_all_devices(void);
13305 +void dss_init_device(struct platform_device *pdev,
13306 + struct omap_dss_device *dssdev);
13307 +void dss_uninit_device(struct platform_device *pdev,
13308 + struct omap_dss_device *dssdev);
13309 +bool dss_use_replication(struct omap_dss_device *dssdev,
13310 + enum omap_color_mode mode);
13311 +void default_get_overlay_fifo_thresholds(enum omap_plane plane,
13312 + u32 fifo_size, enum omap_burst_size *burst_size,
13313 + u32 *fifo_low, u32 *fifo_high);
13316 +int dss_init_overlay_managers(struct platform_device *pdev);
13317 +void dss_uninit_overlay_managers(struct platform_device *pdev);
13318 +int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
13319 +void dss_setup_partial_planes(struct omap_dss_device *dssdev,
13320 + u16 *x, u16 *y, u16 *w, u16 *h);
13321 +void dss_start_update(struct omap_dss_device *dssdev);
13324 +void dss_init_overlays(struct platform_device *pdev);
13325 +void dss_uninit_overlays(struct platform_device *pdev);
13326 +int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev);
13327 +void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
13329 +void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr);
13331 +void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
13334 +int dss_init(bool skip_init);
13335 +void dss_exit(void);
13337 +void dss_save_context(void);
13338 +void dss_restore_context(void);
13340 +void dss_dump_regs(struct seq_file *s);
13342 +void dss_sdi_init(u8 datapairs);
13343 +void dss_sdi_enable(void);
13344 +void dss_sdi_disable(void);
13346 +void dss_select_clk_source(bool dsi, bool dispc);
13347 +int dss_get_dsi_clk_source(void);
13348 +int dss_get_dispc_clk_source(void);
13349 +void dss_set_venc_output(enum omap_dss_venc_type type);
13350 +void dss_set_dac_pwrdn_bgz(bool enable);
13353 +int sdi_init(bool skip_init);
13354 +void sdi_exit(void);
13355 +int sdi_init_display(struct omap_dss_device *display);
13358 +int dsi_init(struct platform_device *pdev);
13359 +void dsi_exit(void);
13361 +void dsi_dump_clocks(struct seq_file *s);
13362 +void dsi_dump_regs(struct seq_file *s);
13364 +void dsi_save_context(void);
13365 +void dsi_restore_context(void);
13367 +int dsi_init_display(struct omap_dss_device *display);
13368 +void dsi_irq_handler(void);
13369 +unsigned long dsi_get_dsi1_pll_rate(void);
13370 +unsigned long dsi_get_dsi2_pll_rate(void);
13371 +int dsi_pll_calc_pck(bool is_tft, unsigned long req_pck,
13372 + struct dsi_clock_info *cinfo);
13373 +int dsi_pll_program(struct dsi_clock_info *cinfo);
13374 +int dsi_pll_init(bool enable_hsclk, bool enable_hsdiv);
13375 +void dsi_pll_uninit(void);
13376 +void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
13377 + u32 fifo_size, enum omap_burst_size *burst_size,
13378 + u32 *fifo_low, u32 *fifo_high);
13381 +int dpi_init(void);
13382 +void dpi_exit(void);
13383 +int dpi_init_display(struct omap_dss_device *dssdev);
13386 +int dispc_init(void);
13387 +void dispc_exit(void);
13388 +void dispc_dump_clocks(struct seq_file *s);
13389 +void dispc_dump_regs(struct seq_file *s);
13390 +void dispc_irq_handler(void);
13391 +void dispc_fake_vsync_irq(void);
13393 +void dispc_save_context(void);
13394 +void dispc_restore_context(void);
13396 +void dispc_enable_sidle(void);
13397 +void dispc_disable_sidle(void);
13399 +void dispc_lcd_enable_signal_polarity(bool act_high);
13400 +void dispc_lcd_enable_signal(bool enable);
13401 +void dispc_pck_free_enable(bool enable);
13402 +void dispc_enable_fifohandcheck(bool enable);
13404 +void dispc_set_lcd_size(u16 width, u16 height);
13405 +void dispc_set_digit_size(u16 width, u16 height);
13406 +u32 dispc_get_plane_fifo_size(enum omap_plane plane);
13407 +void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
13408 +void dispc_enable_fifomerge(bool enable);
13409 +void dispc_set_burst_size(enum omap_plane plane,
13410 + enum omap_burst_size burst_size);
13412 +void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr);
13413 +void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
13414 +void dispc_set_plane_pos(enum omap_plane plane, u16 x, u16 y);
13415 +void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height);
13416 +void dispc_set_channel_out(enum omap_plane plane,
13417 + enum omap_channel channel_out);
13419 +int dispc_setup_plane(enum omap_plane plane,
13420 + u32 paddr, u16 screen_width,
13421 + u16 pos_x, u16 pos_y,
13422 + u16 width, u16 height,
13423 + u16 out_width, u16 out_height,
13424 + enum omap_color_mode color_mode,
13426 + enum omap_dss_rotation_type rotation_type,
13427 + u8 rotation, bool mirror,
13428 + u8 global_alpha);
13430 +bool dispc_go_busy(enum omap_channel channel);
13431 +void dispc_go(enum omap_channel channel);
13432 +void dispc_enable_lcd_out(bool enable);
13433 +void dispc_enable_digit_out(bool enable);
13434 +int dispc_enable_plane(enum omap_plane plane, bool enable);
13435 +void dispc_enable_replication(enum omap_plane plane, bool enable);
13437 +void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode);
13438 +void dispc_set_tft_data_lines(u8 data_lines);
13439 +void dispc_set_lcd_display_type(enum omap_lcd_display_type type);
13440 +void dispc_set_loadmode(enum omap_dss_load_mode mode);
13442 +void dispc_set_default_color(enum omap_channel channel, u32 color);
13443 +u32 dispc_get_default_color(enum omap_channel channel);
13444 +void dispc_set_trans_key(enum omap_channel ch,
13445 + enum omap_dss_trans_key_type type,
13447 +void dispc_get_trans_key(enum omap_channel ch,
13448 + enum omap_dss_trans_key_type *type,
13450 +void dispc_enable_trans_key(enum omap_channel ch, bool enable);
13451 +void dispc_enable_alpha_blending(enum omap_channel ch, bool enable);
13452 +bool dispc_trans_key_enabled(enum omap_channel ch);
13453 +bool dispc_alpha_blending_enabled(enum omap_channel ch);
13455 +bool dispc_lcd_timings_ok(struct omap_video_timings *timings);
13456 +void dispc_set_lcd_timings(struct omap_video_timings *timings);
13457 +unsigned long dispc_fclk_rate(void);
13458 +unsigned long dispc_lclk_rate(void);
13459 +unsigned long dispc_pclk_rate(void);
13460 +void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb);
13461 +void find_lck_pck_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
13462 + u16 *lck_div, u16 *pck_div);
13463 +int dispc_calc_clock_div(bool is_tft, unsigned long req_pck,
13464 + struct dispc_clock_info *cinfo);
13465 +int dispc_set_clock_div(struct dispc_clock_info *cinfo);
13466 +int dispc_get_clock_div(struct dispc_clock_info *cinfo);
13467 +void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div);
13471 +int venc_init(struct platform_device *pdev);
13472 +void venc_exit(void);
13473 +void venc_dump_regs(struct seq_file *s);
13474 +int venc_init_display(struct omap_dss_device *display);
13477 +int rfbi_init(void);
13478 +void rfbi_exit(void);
13479 +void rfbi_dump_regs(struct seq_file *s);
13481 +int rfbi_configure(int rfbi_module, int bpp, int lines);
13482 +void rfbi_enable_rfbi(bool enable);
13483 +void rfbi_transfer_area(u16 width, u16 height,
13484 + void (callback)(void *data), void *data);
13485 +void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
13486 +unsigned long rfbi_get_max_tx_rate(void);
13487 +int rfbi_init_display(struct omap_dss_device *display);
13490 diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
13491 new file mode 100644
13492 index 0000000..7ee0b2b
13494 +++ b/drivers/video/omap2/dss/manager.c
13497 + * linux/drivers/video/omap2/dss/manager.c
13499 + * Copyright (C) 2009 Nokia Corporation
13500 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
13502 + * Some code and ideas taken from drivers/video/omap/ driver
13505 + * This program is free software; you can redistribute it and/or modify it
13506 + * under the terms of the GNU General Public License version 2 as published by
13507 + * the Free Software Foundation.
13509 + * This program is distributed in the hope that it will be useful, but WITHOUT
13510 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13511 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13514 + * You should have received a copy of the GNU General Public License along with
13515 + * this program. If not, see <http://www.gnu.org/licenses/>.
13518 +#define DSS_SUBSYS_NAME "MANAGER"
13520 +#include <linux/kernel.h>
13521 +#include <linux/module.h>
13522 +#include <linux/platform_device.h>
13523 +#include <linux/spinlock.h>
13524 +#include <linux/jiffies.h>
13526 +#include <mach/display.h>
13527 +#include <mach/cpu.h>
13531 +static int num_managers;
13532 +static struct list_head manager_list;
13534 +static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
13536 + return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
13539 +static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
13541 + return snprintf(buf, PAGE_SIZE, "%s\n",
13542 + mgr->device ? mgr->device->name : "<none>");
13545 +static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
13546 + const char *buf, size_t size)
13549 + size_t len = size;
13550 + struct omap_dss_device *dssdev = NULL;
13552 + int match(struct omap_dss_device *dssdev, void *data)
13554 + const char *str = data;
13555 + return sysfs_streq(dssdev->name, str);
13558 + if (buf[size-1] == '\n')
13562 + dssdev = omap_dss_find_device((void *)buf, match);
13564 + if (len > 0 && dssdev == NULL)
13568 + DSSDBG("display %s found\n", dssdev->name);
13570 + if (mgr->device) {
13571 + r = mgr->unset_device(mgr);
13573 + DSSERR("failed to unset display\n");
13579 + r = mgr->set_device(mgr, dssdev);
13581 + DSSERR("failed to set manager\n");
13585 + r = mgr->apply(mgr);
13587 + DSSERR("failed to apply dispc config\n");
13594 + omap_dss_put_device(dssdev);
13596 + return r ? r : size;
13599 +static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
13602 + return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.default_color);
13605 +static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
13606 + const char *buf, size_t size)
13608 + struct omap_overlay_manager_info info;
13612 + if (sscanf(buf, "%d", &color) != 1)
13615 + mgr->get_manager_info(mgr, &info);
13617 + info.default_color = color;
13619 + r = mgr->set_manager_info(mgr, &info);
13623 + r = mgr->apply(mgr);
13630 +static const char *trans_key_type_str[] = {
13631 + "gfx-destination",
13635 +static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
13638 + enum omap_dss_trans_key_type key_type;
13640 + key_type = mgr->info.trans_key_type;
13641 + BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
13643 + return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
13646 +static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
13647 + const char *buf, size_t size)
13649 + enum omap_dss_trans_key_type key_type;
13650 + struct omap_overlay_manager_info info;
13653 + for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
13654 + key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
13655 + if (sysfs_streq(buf, trans_key_type_str[key_type]))
13659 + if (key_type == ARRAY_SIZE(trans_key_type_str))
13662 + mgr->get_manager_info(mgr, &info);
13664 + info.trans_key_type = key_type;
13666 + r = mgr->set_manager_info(mgr, &info);
13670 + r = mgr->apply(mgr);
13677 +static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
13680 + return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_key);
13683 +static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
13684 + const char *buf, size_t size)
13686 + struct omap_overlay_manager_info info;
13690 + if (sscanf(buf, "%d", &key_value) != 1)
13693 + mgr->get_manager_info(mgr, &info);
13695 + info.trans_key = key_value;
13697 + r = mgr->set_manager_info(mgr, &info);
13701 + r = mgr->apply(mgr);
13708 +static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
13711 + return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled);
13714 +static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
13715 + const char *buf, size_t size)
13717 + struct omap_overlay_manager_info info;
13721 + if (sscanf(buf, "%d", &enable) != 1)
13724 + mgr->get_manager_info(mgr, &info);
13726 + info.trans_enabled = enable ? true : false;
13728 + r = mgr->set_manager_info(mgr, &info);
13732 + r = mgr->apply(mgr);
13739 +static ssize_t manager_alpha_blending_enabled_show(
13740 + struct omap_overlay_manager *mgr, char *buf)
13742 + return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.alpha_enabled);
13745 +static ssize_t manager_alpha_blending_enabled_store(
13746 + struct omap_overlay_manager *mgr,
13747 + const char *buf, size_t size)
13749 + struct omap_overlay_manager_info info;
13753 + if (sscanf(buf, "%d", &enable) != 1)
13756 + mgr->get_manager_info(mgr, &info);
13758 + info.alpha_enabled = enable ? true : false;
13760 + r = mgr->set_manager_info(mgr, &info);
13764 + r = mgr->apply(mgr);
13771 +struct manager_attribute {
13772 + struct attribute attr;
13773 + ssize_t (*show)(struct omap_overlay_manager *, char *);
13774 + ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
13777 +#define MANAGER_ATTR(_name, _mode, _show, _store) \
13778 + struct manager_attribute manager_attr_##_name = \
13779 + __ATTR(_name, _mode, _show, _store)
13781 +static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
13782 +static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
13783 + manager_display_show, manager_display_store);
13784 +static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
13785 + manager_default_color_show, manager_default_color_store);
13786 +static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
13787 + manager_trans_key_type_show, manager_trans_key_type_store);
13788 +static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
13789 + manager_trans_key_value_show, manager_trans_key_value_store);
13790 +static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
13791 + manager_trans_key_enabled_show,
13792 + manager_trans_key_enabled_store);
13793 +static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
13794 + manager_alpha_blending_enabled_show,
13795 + manager_alpha_blending_enabled_store);
13798 +static struct attribute *manager_sysfs_attrs[] = {
13799 + &manager_attr_name.attr,
13800 + &manager_attr_display.attr,
13801 + &manager_attr_default_color.attr,
13802 + &manager_attr_trans_key_type.attr,
13803 + &manager_attr_trans_key_value.attr,
13804 + &manager_attr_trans_key_enabled.attr,
13805 + &manager_attr_alpha_blending_enabled.attr,
13809 +static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
13812 + struct omap_overlay_manager *manager;
13813 + struct manager_attribute *manager_attr;
13815 + manager = container_of(kobj, struct omap_overlay_manager, kobj);
13816 + manager_attr = container_of(attr, struct manager_attribute, attr);
13818 + if (!manager_attr->show)
13821 + return manager_attr->show(manager, buf);
13824 +static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
13825 + const char *buf, size_t size)
13827 + struct omap_overlay_manager *manager;
13828 + struct manager_attribute *manager_attr;
13830 + manager = container_of(kobj, struct omap_overlay_manager, kobj);
13831 + manager_attr = container_of(attr, struct manager_attribute, attr);
13833 + if (!manager_attr->store)
13836 + return manager_attr->store(manager, buf, size);
13839 +static struct sysfs_ops manager_sysfs_ops = {
13840 + .show = manager_attr_show,
13841 + .store = manager_attr_store,
13844 +static struct kobj_type manager_ktype = {
13845 + .sysfs_ops = &manager_sysfs_ops,
13846 + .default_attrs = manager_sysfs_attrs,
13850 + * We have 4 levels of cache for the dispc settings. First two are in SW and
13851 + * the latter two in HW.
13853 + * +--------------------+
13854 + * |overlay/manager_info|
13855 + * +--------------------+
13859 + * +--------------------+
13861 + * +--------------------+
13865 + * +--------------------+
13866 + * | shadow registers |
13867 + * +--------------------+
13869 + * VFP or lcd/digit_enable
13871 + * +--------------------+
13873 + * +--------------------+
13876 +struct overlay_cache_data {
13877 + /* If true, cache changed, but not written to shadow registers. Set
13878 + * in apply(), cleared when registers written. */
13880 + /* If true, shadow registers contain changed values not yet in real
13881 + * registers. Set when writing to shadow registers, cleared at
13882 + * VSYNC/EVSYNC */
13883 + bool shadow_dirty;
13888 + void __iomem *vaddr;
13889 + u16 screen_width;
13892 + enum omap_color_mode color_mode;
13894 + enum omap_dss_rotation_type rotation_type;
13899 + u16 out_width; /* if 0, out_width == width */
13900 + u16 out_height; /* if 0, out_height == height */
13903 + enum omap_channel channel;
13904 + bool replication;
13907 + enum omap_burst_size burst_size;
13911 + bool manual_update;
13914 +struct manager_cache_data {
13915 + /* If true, cache changed, but not written to shadow registers. Set
13916 + * in apply(), cleared when registers written. */
13918 + /* If true, shadow registers contain changed values not yet in real
13919 + * registers. Set when writing to shadow registers, cleared at
13920 + * VSYNC/EVSYNC */
13921 + bool shadow_dirty;
13923 + u32 default_color;
13925 + enum omap_dss_trans_key_type trans_key_type;
13927 + bool trans_enabled;
13929 + bool alpha_enabled;
13931 + bool manual_upd_display;
13932 + bool manual_update;
13933 + bool do_manual_update;
13935 + /* manual update region */
13941 + struct overlay_cache_data overlay_cache[3];
13942 + struct manager_cache_data manager_cache[2];
13944 + bool irq_enabled;
13949 +static int omap_dss_set_device(struct omap_overlay_manager *mgr,
13950 + struct omap_dss_device *dssdev)
13955 + if (dssdev->manager) {
13956 + DSSERR("display '%s' already has a manager '%s'\n",
13957 + dssdev->name, dssdev->manager->name);
13961 + if ((mgr->supported_displays & dssdev->type) == 0) {
13962 + DSSERR("display '%s' does not support manager '%s'\n",
13963 + dssdev->name, mgr->name);
13967 + for (i = 0; i < mgr->num_overlays; i++) {
13968 + struct omap_overlay *ovl = mgr->overlays[i];
13970 + if (ovl->manager != mgr || !ovl->info.enabled)
13973 + r = dss_check_overlay(ovl, dssdev);
13978 + dssdev->manager = mgr;
13979 + mgr->device = dssdev;
13980 + mgr->device_changed = true;
13985 +static int omap_dss_unset_device(struct omap_overlay_manager *mgr)
13987 + if (!mgr->device) {
13988 + DSSERR("failed to unset display, display not set.\n");
13992 + mgr->device->manager = NULL;
13993 + mgr->device = NULL;
13994 + mgr->device_changed = true;
13999 +static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
14001 + unsigned long timeout = msecs_to_jiffies(500);
14002 + struct manager_cache_data *mc;
14003 + enum omap_channel channel;
14008 + if (!mgr->device)
14011 + if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
14012 + irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
14013 + channel = OMAP_DSS_CHANNEL_DIGIT;
14015 + if (mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
14016 + enum omap_dss_update_mode mode;
14017 + mode = mgr->device->get_update_mode(mgr->device);
14018 + if (mode != OMAP_DSS_UPDATE_AUTO)
14021 + irq = DISPC_IRQ_FRAMEDONE;
14023 + irq = DISPC_IRQ_VSYNC;
14025 + channel = OMAP_DSS_CHANNEL_LCD;
14028 + mc = &dss_cache.manager_cache[mgr->id];
14031 + unsigned long flags;
14032 + bool shadow_dirty, dirty;
14034 + spin_lock_irqsave(&dss_cache.lock, flags);
14035 + dirty = mc->dirty;
14036 + shadow_dirty = mc->shadow_dirty;
14037 + spin_unlock_irqrestore(&dss_cache.lock, flags);
14039 + if (!dirty && !shadow_dirty) {
14044 + /* 4 iterations is the worst case:
14045 + * 1 - initial iteration, dirty = true (between VFP and VSYNC)
14046 + * 2 - first VSYNC, dirty = true
14047 + * 3 - dirty = false, shadow_dirty = true
14048 + * 4 - shadow_dirty = false */
14050 + DSSERR("mgr(%d)->wait_for_go() not finishing\n",
14056 + r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
14057 + if (r == -ERESTARTSYS)
14061 + DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
14069 +int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
14071 + unsigned long timeout = msecs_to_jiffies(500);
14072 + enum omap_channel channel;
14073 + struct overlay_cache_data *oc;
14074 + struct omap_dss_device *dssdev;
14079 + if (!ovl->manager || !ovl->manager->device)
14082 + dssdev = ovl->manager->device;
14084 + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
14085 + irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
14086 + channel = OMAP_DSS_CHANNEL_DIGIT;
14088 + if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
14089 + enum omap_dss_update_mode mode;
14090 + mode = dssdev->get_update_mode(dssdev);
14091 + if (mode != OMAP_DSS_UPDATE_AUTO)
14094 + irq = DISPC_IRQ_FRAMEDONE;
14096 + irq = DISPC_IRQ_VSYNC;
14098 + channel = OMAP_DSS_CHANNEL_LCD;
14101 + oc = &dss_cache.overlay_cache[ovl->id];
14104 + unsigned long flags;
14105 + bool shadow_dirty, dirty;
14107 + spin_lock_irqsave(&dss_cache.lock, flags);
14108 + dirty = oc->dirty;
14109 + shadow_dirty = oc->shadow_dirty;
14110 + spin_unlock_irqrestore(&dss_cache.lock, flags);
14112 + if (!dirty && !shadow_dirty) {
14117 + /* 4 iterations is the worst case:
14118 + * 1 - initial iteration, dirty = true (between VFP and VSYNC)
14119 + * 2 - first VSYNC, dirty = true
14120 + * 3 - dirty = false, shadow_dirty = true
14121 + * 4 - shadow_dirty = false */
14123 + DSSERR("ovl(%d)->wait_for_go() not finishing\n",
14129 + r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
14130 + if (r == -ERESTARTSYS)
14134 + DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
14142 +static int overlay_enabled(struct omap_overlay *ovl)
14144 + return ovl->info.enabled && ovl->manager && ovl->manager->device;
14147 +/* Is rect1 a subset of rect2? */
14148 +static bool rectangle_subset(int x1, int y1, int w1, int h1,
14149 + int x2, int y2, int w2, int h2)
14151 + if (x1 < x2 || y1 < y2)
14154 + if (x1 + w1 > x2 + w2)
14157 + if (y1 + h1 > y2 + h2)
14163 +/* Do rect1 and rect2 overlap? */
14164 +static bool rectangle_intersects(int x1, int y1, int w1, int h1,
14165 + int x2, int y2, int w2, int h2)
14167 + if (x1 >= x2 + w2)
14170 + if (x2 >= x1 + w1)
14173 + if (y1 >= y2 + h2)
14176 + if (y2 >= y1 + h1)
14182 +static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
14184 + if (oc->out_width != 0 && oc->width != oc->out_width)
14187 + if (oc->out_height != 0 && oc->height != oc->out_height)
14193 +static int configure_overlay(enum omap_plane plane)
14195 + struct overlay_cache_data *c;
14196 + struct manager_cache_data *mc;
14202 + DSSDBGF("%d", plane);
14204 + c = &dss_cache.overlay_cache[plane];
14206 + if (!c->enabled) {
14207 + dispc_enable_plane(plane, 0);
14211 + mc = &dss_cache.manager_cache[c->channel];
14217 + outw = c->out_width == 0 ? c->width : c->out_width;
14218 + outh = c->out_height == 0 ? c->height : c->out_height;
14219 + paddr = c->paddr;
14221 + if (c->manual_update && mc->do_manual_update) {
14223 + /* If the overlay is outside the update region, disable it */
14224 + if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
14225 + x, y, outw, outh)) {
14226 + dispc_enable_plane(plane, 0);
14230 + switch (c->color_mode) {
14231 + case OMAP_DSS_COLOR_RGB16:
14232 + case OMAP_DSS_COLOR_ARGB16:
14233 + case OMAP_DSS_COLOR_YUV2:
14234 + case OMAP_DSS_COLOR_UYVY:
14238 + case OMAP_DSS_COLOR_RGB24P:
14242 + case OMAP_DSS_COLOR_RGB24U:
14243 + case OMAP_DSS_COLOR_ARGB32:
14244 + case OMAP_DSS_COLOR_RGBA32:
14245 + case OMAP_DSS_COLOR_RGBX32:
14253 + if (dispc_is_overlay_scaled(c)) {
14254 + /* If the overlay is scaled, the update area has
14255 + * already been enlarged to cover the whole overlay. We
14256 + * only need to adjust x/y here */
14257 + x = c->pos_x - mc->x;
14258 + y = c->pos_y - mc->y;
14260 + if (mc->x > c->pos_x) {
14262 + w -= (mc->x - c->pos_x);
14263 + paddr += (mc->x - c->pos_x) * bpp / 8;
14265 + x = c->pos_x - mc->x;
14268 + if (mc->y > c->pos_y) {
14270 + h -= (mc->y - c->pos_y);
14271 + paddr += (mc->y - c->pos_y) * c->screen_width *
14274 + y = c->pos_y - mc->y;
14277 + if (mc->w < (x+w))
14278 + w -= (x+w) - (mc->w);
14280 + if (mc->h < (y+h))
14281 + h -= (y+h) - (mc->h);
14288 + r = dispc_setup_plane(plane,
14296 + c->rotation_type,
14299 + c->global_alpha);
14302 + /* this shouldn't happen */
14303 + DSSERR("dispc_setup_plane failed for ovl %d\n", plane);
14304 + dispc_enable_plane(plane, 0);
14308 + dispc_enable_replication(plane, c->replication);
14310 + dispc_set_burst_size(plane, c->burst_size);
14311 + dispc_setup_plane_fifo(plane, c->fifo_low, c->fifo_high);
14313 + dispc_enable_plane(plane, 1);
14318 +static void configure_manager(enum omap_channel channel)
14320 + struct manager_cache_data *c;
14322 + DSSDBGF("%d", channel);
14324 + c = &dss_cache.manager_cache[channel];
14326 + dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
14327 + dispc_enable_trans_key(channel, c->trans_enabled);
14328 + dispc_enable_alpha_blending(channel, c->alpha_enabled);
14331 +/* configure_dispc() tries to write values from cache to shadow registers.
14332 + * It writes only to those managers/overlays that are not busy.
14333 + * returns 0 if everything could be written to shadow registers.
14334 + * returns 1 if not everything could be written to shadow registers. */
14335 +static int configure_dispc(void)
14337 + struct overlay_cache_data *oc;
14338 + struct manager_cache_data *mc;
14339 + const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
14340 + const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
14343 + bool mgr_busy[2];
14350 + mgr_busy[0] = dispc_go_busy(0);
14351 + mgr_busy[1] = dispc_go_busy(1);
14352 + mgr_go[0] = false;
14353 + mgr_go[1] = false;
14355 + /* Commit overlay settings */
14356 + for (i = 0; i < num_ovls; ++i) {
14357 + oc = &dss_cache.overlay_cache[i];
14358 + mc = &dss_cache.manager_cache[oc->channel];
14363 + if (oc->manual_update && !mc->do_manual_update)
14366 + if (mgr_busy[oc->channel]) {
14371 + r = configure_overlay(i);
14373 + DSSERR("configure_overlay %d failed\n", i);
14375 + oc->dirty = false;
14376 + oc->shadow_dirty = true;
14377 + mgr_go[oc->channel] = true;
14380 + /* Commit manager settings */
14381 + for (i = 0; i < num_mgrs; ++i) {
14382 + mc = &dss_cache.manager_cache[i];
14387 + if (mc->manual_update && !mc->do_manual_update)
14390 + if (mgr_busy[i]) {
14395 + configure_manager(i);
14396 + mc->dirty = false;
14397 + mc->shadow_dirty = true;
14398 + mgr_go[i] = true;
14402 + for (i = 0; i < num_mgrs; ++i) {
14403 + mc = &dss_cache.manager_cache[i];
14408 + /* We don't need GO with manual update display. LCD iface will
14409 + * always be turned off after frame, and new settings will be
14410 + * taken in to use at next update */
14411 + if (!mc->manual_upd_display)
14423 +/* Configure dispc for partial update. Return possibly modified update
14425 +void dss_setup_partial_planes(struct omap_dss_device *dssdev,
14426 + u16 *xi, u16 *yi, u16 *wi, u16 *hi)
14428 + struct overlay_cache_data *oc;
14429 + struct manager_cache_data *mc;
14430 + const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
14431 + struct omap_overlay_manager *mgr;
14434 + unsigned long flags;
14441 + DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n",
14442 + *xi, *yi, *wi, *hi);
14444 + mgr = dssdev->manager;
14447 + DSSDBG("no manager\n");
14451 + spin_lock_irqsave(&dss_cache.lock, flags);
14453 + /* We need to show the whole overlay if it is scaled. So look for
14454 + * those, and make the update area larger if found.
14455 + * Also mark the overlay cache dirty */
14456 + for (i = 0; i < num_ovls; ++i) {
14457 + unsigned x1, y1, x2, y2;
14458 + unsigned outw, outh;
14460 + oc = &dss_cache.overlay_cache[i];
14462 + if (oc->channel != mgr->id)
14465 + oc->dirty = true;
14467 + if (!oc->enabled)
14470 + if (!dispc_is_overlay_scaled(oc))
14473 + outw = oc->out_width == 0 ? oc->width : oc->out_width;
14474 + outh = oc->out_height == 0 ? oc->height : oc->out_height;
14476 + /* is the overlay outside the update region? */
14477 + if (!rectangle_intersects(x, y, w, h,
14478 + oc->pos_x, oc->pos_y,
14482 + /* if the overlay totally inside the update region? */
14483 + if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
14487 + if (x > oc->pos_x)
14492 + if (y > oc->pos_y)
14497 + if ((x + w) < (oc->pos_x + outw))
14498 + x2 = oc->pos_x + outw;
14502 + if ((y + h) < (oc->pos_y + outh))
14503 + y2 = oc->pos_y + outh;
14512 + DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n",
14516 + mc = &dss_cache.manager_cache[mgr->id];
14517 + mc->do_manual_update = true;
14523 + configure_dispc();
14525 + mc->do_manual_update = false;
14527 + spin_unlock_irqrestore(&dss_cache.lock, flags);
14535 +void dss_start_update(struct omap_dss_device *dssdev)
14537 + struct manager_cache_data *mc;
14538 + struct overlay_cache_data *oc;
14539 + const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
14540 + const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
14541 + struct omap_overlay_manager *mgr;
14544 + mgr = dssdev->manager;
14546 + for (i = 0; i < num_ovls; ++i) {
14547 + oc = &dss_cache.overlay_cache[i];
14548 + if (oc->channel != mgr->id)
14551 + oc->shadow_dirty = false;
14554 + for (i = 0; i < num_mgrs; ++i) {
14555 + mc = &dss_cache.manager_cache[i];
14556 + if (mgr->id != i)
14559 + mc->shadow_dirty = false;
14562 + dispc_enable_lcd_out(1);
14565 +static void dss_apply_irq_handler(void *data, u32 mask)
14567 + struct manager_cache_data *mc;
14568 + struct overlay_cache_data *oc;
14569 + const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
14570 + const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
14572 + bool mgr_busy[2];
14574 + mgr_busy[0] = dispc_go_busy(0);
14575 + mgr_busy[1] = dispc_go_busy(1);
14577 + spin_lock(&dss_cache.lock);
14579 + for (i = 0; i < num_ovls; ++i) {
14580 + oc = &dss_cache.overlay_cache[i];
14581 + if (!mgr_busy[oc->channel])
14582 + oc->shadow_dirty = false;
14585 + for (i = 0; i < num_mgrs; ++i) {
14586 + mc = &dss_cache.manager_cache[i];
14587 + if (!mgr_busy[i])
14588 + mc->shadow_dirty = false;
14591 + r = configure_dispc();
14595 + /* re-read busy flags */
14596 + mgr_busy[0] = dispc_go_busy(0);
14597 + mgr_busy[1] = dispc_go_busy(1);
14599 + /* keep running as long as there are busy managers, so that
14600 + * we can collect overlay-applied information */
14601 + for (i = 0; i < num_mgrs; ++i) {
14606 + omap_dispc_unregister_isr(dss_apply_irq_handler, NULL,
14607 + DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
14608 + DISPC_IRQ_EVSYNC_EVEN);
14609 + dss_cache.irq_enabled = false;
14612 + spin_unlock(&dss_cache.lock);
14615 +static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
14617 + struct overlay_cache_data *oc;
14618 + struct manager_cache_data *mc;
14620 + struct omap_overlay *ovl;
14621 + int num_planes_enabled = 0;
14622 + bool use_fifomerge;
14623 + unsigned long flags;
14626 + DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
14628 + spin_lock_irqsave(&dss_cache.lock, flags);
14630 + /* Configure overlays */
14631 + for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
14632 + struct omap_dss_device *dssdev;
14634 + ovl = omap_dss_get_overlay(i);
14636 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
14639 + oc = &dss_cache.overlay_cache[ovl->id];
14641 + if (!overlay_enabled(ovl)) {
14642 + if (oc->enabled) {
14643 + oc->enabled = false;
14644 + oc->dirty = true;
14649 + if (!ovl->info_dirty) {
14651 + ++num_planes_enabled;
14655 + dssdev = ovl->manager->device;
14657 + if (dss_check_overlay(ovl, dssdev)) {
14658 + if (oc->enabled) {
14659 + oc->enabled = false;
14660 + oc->dirty = true;
14665 + ovl->info_dirty = false;
14666 + oc->dirty = true;
14668 + oc->paddr = ovl->info.paddr;
14669 + oc->vaddr = ovl->info.vaddr;
14670 + oc->screen_width = ovl->info.screen_width;
14671 + oc->width = ovl->info.width;
14672 + oc->height = ovl->info.height;
14673 + oc->color_mode = ovl->info.color_mode;
14674 + oc->rotation = ovl->info.rotation;
14675 + oc->rotation_type = ovl->info.rotation_type;
14676 + oc->mirror = ovl->info.mirror;
14677 + oc->pos_x = ovl->info.pos_x;
14678 + oc->pos_y = ovl->info.pos_y;
14679 + oc->out_width = ovl->info.out_width;
14680 + oc->out_height = ovl->info.out_height;
14681 + oc->global_alpha = ovl->info.global_alpha;
14683 + oc->replication =
14684 + dss_use_replication(dssdev, ovl->info.color_mode);
14686 + oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
14688 + oc->channel = ovl->manager->id;
14690 + oc->enabled = true;
14692 + oc->manual_update =
14693 + dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
14694 + dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
14696 + ++num_planes_enabled;
14699 + /* Configure managers */
14700 + list_for_each_entry(mgr, &manager_list, list) {
14701 + struct omap_dss_device *dssdev;
14703 + if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC))
14706 + mc = &dss_cache.manager_cache[mgr->id];
14708 + if (mgr->device_changed) {
14709 + mgr->device_changed = false;
14710 + mgr->info_dirty = true;
14713 + if (!mgr->info_dirty)
14716 + if (!mgr->device)
14719 + dssdev = mgr->device;
14721 + mgr->info_dirty = false;
14722 + mc->dirty = true;
14724 + mc->default_color = mgr->info.default_color;
14725 + mc->trans_key_type = mgr->info.trans_key_type;
14726 + mc->trans_key = mgr->info.trans_key;
14727 + mc->trans_enabled = mgr->info.trans_enabled;
14728 + mc->alpha_enabled = mgr->info.alpha_enabled;
14730 + mc->manual_upd_display =
14731 + dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
14733 + mc->manual_update =
14734 + dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
14735 + dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
14738 + /* XXX TODO: Try to get fifomerge working. The problem is that it
14739 + * affects both managers, not individually but at the same time. This
14740 + * means the change has to be well synchronized. I guess the proper way
14741 + * is to have a two step process for fifo merge:
14742 + * fifomerge enable:
14743 + * 1. disable other planes, leaving one plane enabled
14744 + * 2. wait until the planes are disabled on HW
14745 + * 3. config merged fifo thresholds, enable fifomerge
14746 + * fifomerge disable:
14747 + * 1. config unmerged fifo thresholds, disable fifomerge
14748 + * 2. wait until fifo changes are in HW
14749 + * 3. enable planes
14751 + use_fifomerge = false;
14753 + /* Configure overlay fifos */
14754 + for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
14755 + struct omap_dss_device *dssdev;
14758 + ovl = omap_dss_get_overlay(i);
14760 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
14763 + oc = &dss_cache.overlay_cache[ovl->id];
14765 + if (!oc->enabled)
14768 + dssdev = ovl->manager->device;
14770 + size = dispc_get_plane_fifo_size(ovl->id);
14771 + if (use_fifomerge)
14774 + switch (dssdev->type) {
14775 + case OMAP_DISPLAY_TYPE_DPI:
14776 + case OMAP_DISPLAY_TYPE_DBI:
14777 + case OMAP_DISPLAY_TYPE_SDI:
14778 + case OMAP_DISPLAY_TYPE_VENC:
14779 + default_get_overlay_fifo_thresholds(ovl->id, size,
14780 + &oc->burst_size, &oc->fifo_low,
14783 +#ifdef CONFIG_OMAP2_DSS_DSI
14784 + case OMAP_DISPLAY_TYPE_DSI:
14785 + dsi_get_overlay_fifo_thresholds(ovl->id, size,
14786 + &oc->burst_size, &oc->fifo_low,
14796 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
14797 + if (!dss_cache.irq_enabled) {
14798 + r = omap_dispc_register_isr(dss_apply_irq_handler, NULL,
14799 + DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
14800 + DISPC_IRQ_EVSYNC_EVEN);
14801 + dss_cache.irq_enabled = true;
14803 + configure_dispc();
14804 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
14806 + spin_unlock_irqrestore(&dss_cache.lock, flags);
14811 +static int dss_check_manager(struct omap_overlay_manager *mgr)
14813 + /* OMAP supports only graphics source transparency color key and alpha
14814 + * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */
14816 + if (mgr->info.alpha_enabled && mgr->info.trans_enabled &&
14817 + mgr->info.trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST)
14823 +static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
14824 + struct omap_overlay_manager_info *info)
14827 + struct omap_overlay_manager_info old_info;
14829 + old_info = mgr->info;
14830 + mgr->info = *info;
14832 + r = dss_check_manager(mgr);
14834 + mgr->info = old_info;
14838 + mgr->info_dirty = true;
14843 +static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
14844 + struct omap_overlay_manager_info *info)
14846 + *info = mgr->info;
14849 +static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
14852 + list_add_tail(&manager->list, &manager_list);
14855 +int dss_init_overlay_managers(struct platform_device *pdev)
14859 + spin_lock_init(&dss_cache.lock);
14861 + INIT_LIST_HEAD(&manager_list);
14863 + num_managers = 0;
14865 + for (i = 0; i < 2; ++i) {
14866 + struct omap_overlay_manager *mgr;
14867 + mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
14869 + BUG_ON(mgr == NULL);
14873 + mgr->name = "lcd";
14874 + mgr->id = OMAP_DSS_CHANNEL_LCD;
14875 + mgr->supported_displays =
14876 + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
14877 + OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI;
14880 + mgr->name = "tv";
14881 + mgr->id = OMAP_DSS_CHANNEL_DIGIT;
14882 + mgr->supported_displays = OMAP_DISPLAY_TYPE_VENC;
14886 + mgr->set_device = &omap_dss_set_device;
14887 + mgr->unset_device = &omap_dss_unset_device;
14888 + mgr->apply = &omap_dss_mgr_apply;
14889 + mgr->set_manager_info = &omap_dss_mgr_set_info;
14890 + mgr->get_manager_info = &omap_dss_mgr_get_info;
14891 + mgr->wait_for_go = &dss_mgr_wait_for_go;
14893 + mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
14895 + dss_overlay_setup_dispc_manager(mgr);
14897 + omap_dss_add_overlay_manager(mgr);
14899 + r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
14900 + &pdev->dev.kobj, "manager%d", i);
14903 + DSSERR("failed to create sysfs file\n");
14910 + int omap_dss_mgr_apply_l4(struct omap_overlay_manager *mgr)
14912 + DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name);
14917 + struct omap_overlay_manager *mgr;
14918 + mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
14920 + BUG_ON(mgr == NULL);
14922 + mgr->name = "l4";
14923 + mgr->supported_displays =
14924 + OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI;
14926 + mgr->set_device = &omap_dss_set_device;
14927 + mgr->unset_device = &omap_dss_unset_device;
14928 + mgr->apply = &omap_dss_mgr_apply_l4;
14929 + mgr->set_manager_info = &omap_dss_mgr_set_info;
14930 + mgr->get_manager_info = &omap_dss_mgr_get_info;
14932 + dss_overlay_setup_l4_manager(mgr);
14934 + omap_dss_add_overlay_manager(mgr);
14936 + r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
14937 + &pdev->dev.kobj, "managerl4");
14940 + DSSERR("failed to create sysfs file\n");
14947 +void dss_uninit_overlay_managers(struct platform_device *pdev)
14949 + struct omap_overlay_manager *mgr;
14951 + while (!list_empty(&manager_list)) {
14952 + mgr = list_first_entry(&manager_list,
14953 + struct omap_overlay_manager, list);
14954 + list_del(&mgr->list);
14955 + kobject_del(&mgr->kobj);
14956 + kobject_put(&mgr->kobj);
14960 + num_managers = 0;
14963 +int omap_dss_get_num_overlay_managers(void)
14965 + return num_managers;
14967 +EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
14969 +struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
14972 + struct omap_overlay_manager *mgr;
14974 + list_for_each_entry(mgr, &manager_list, list) {
14981 +EXPORT_SYMBOL(omap_dss_get_overlay_manager);
14983 diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
14984 new file mode 100644
14985 index 0000000..c7cb81b
14987 +++ b/drivers/video/omap2/dss/overlay.c
14990 + * linux/drivers/video/omap2/dss/overlay.c
14992 + * Copyright (C) 2009 Nokia Corporation
14993 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
14995 + * Some code and ideas taken from drivers/video/omap/ driver
14998 + * This program is free software; you can redistribute it and/or modify it
14999 + * under the terms of the GNU General Public License version 2 as published by
15000 + * the Free Software Foundation.
15002 + * This program is distributed in the hope that it will be useful, but WITHOUT
15003 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15004 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15007 + * You should have received a copy of the GNU General Public License along with
15008 + * this program. If not, see <http://www.gnu.org/licenses/>.
15011 +#define DSS_SUBSYS_NAME "OVERLAY"
15013 +#include <linux/kernel.h>
15014 +#include <linux/module.h>
15015 +#include <linux/err.h>
15016 +#include <linux/sysfs.h>
15017 +#include <linux/kobject.h>
15018 +#include <linux/platform_device.h>
15019 +#include <linux/delay.h>
15021 +#include <mach/display.h>
15025 +static int num_overlays;
15026 +static struct list_head overlay_list;
15028 +static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
15030 + return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
15033 +static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
15035 + return snprintf(buf, PAGE_SIZE, "%s\n",
15036 + ovl->manager ? ovl->manager->name : "<none>");
15039 +static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
15043 + struct omap_overlay_manager *mgr = NULL;
15044 + struct omap_overlay_manager *old_mgr;
15047 + if (buf[size-1] == '\n')
15051 + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
15052 + mgr = omap_dss_get_overlay_manager(i);
15054 + if (strncmp(buf, mgr->name, len) == 0)
15061 + if (len > 0 && mgr == NULL)
15065 + DSSDBG("manager %s found\n", mgr->name);
15067 + if (mgr == ovl->manager)
15070 + old_mgr = ovl->manager;
15072 + /* detach old manager */
15074 + r = ovl->unset_manager(ovl);
15076 + DSSERR("detach failed\n");
15080 + r = old_mgr->apply(old_mgr);
15086 + r = ovl->set_manager(ovl, mgr);
15088 + DSSERR("Failed to attach overlay\n");
15092 + r = mgr->apply(mgr);
15100 +static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
15102 + return snprintf(buf, PAGE_SIZE, "%d,%d\n",
15103 + ovl->info.width, ovl->info.height);
15106 +static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
15108 + return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width);
15111 +static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
15113 + return snprintf(buf, PAGE_SIZE, "%d,%d\n",
15114 + ovl->info.pos_x, ovl->info.pos_y);
15117 +static ssize_t overlay_position_store(struct omap_overlay *ovl,
15118 + const char *buf, size_t size)
15122 + struct omap_overlay_info info;
15124 + ovl->get_overlay_info(ovl, &info);
15126 + info.pos_x = simple_strtoul(buf, &last, 10);
15128 + if (last - buf >= size)
15131 + info.pos_y = simple_strtoul(last, &last, 10);
15133 + r = ovl->set_overlay_info(ovl, &info);
15137 + if (ovl->manager) {
15138 + r = ovl->manager->apply(ovl->manager);
15146 +static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
15148 + return snprintf(buf, PAGE_SIZE, "%d,%d\n",
15149 + ovl->info.out_width, ovl->info.out_height);
15152 +static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
15153 + const char *buf, size_t size)
15157 + struct omap_overlay_info info;
15159 + ovl->get_overlay_info(ovl, &info);
15161 + info.out_width = simple_strtoul(buf, &last, 10);
15163 + if (last - buf >= size)
15166 + info.out_height = simple_strtoul(last, &last, 10);
15168 + r = ovl->set_overlay_info(ovl, &info);
15172 + if (ovl->manager) {
15173 + r = ovl->manager->apply(ovl->manager);
15181 +static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
15183 + return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled);
15186 +static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
15190 + struct omap_overlay_info info;
15192 + ovl->get_overlay_info(ovl, &info);
15194 + info.enabled = simple_strtoul(buf, NULL, 10);
15196 + r = ovl->set_overlay_info(ovl, &info);
15200 + if (ovl->manager) {
15201 + r = ovl->manager->apply(ovl->manager);
15209 +static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
15211 + return snprintf(buf, PAGE_SIZE, "%d\n",
15212 + ovl->info.global_alpha);
15215 +static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
15216 + const char *buf, size_t size)
15219 + struct omap_overlay_info info;
15221 + ovl->get_overlay_info(ovl, &info);
15223 + /* Video1 plane does not support global alpha
15224 + * to always make it 255 completely opaque
15226 + if (ovl->id == OMAP_DSS_VIDEO1)
15227 + info.global_alpha = 255;
15229 + info.global_alpha = simple_strtoul(buf, NULL, 10);
15231 + r = ovl->set_overlay_info(ovl, &info);
15235 + if (ovl->manager) {
15236 + r = ovl->manager->apply(ovl->manager);
15244 +struct overlay_attribute {
15245 + struct attribute attr;
15246 + ssize_t (*show)(struct omap_overlay *, char *);
15247 + ssize_t (*store)(struct omap_overlay *, const char *, size_t);
15250 +#define OVERLAY_ATTR(_name, _mode, _show, _store) \
15251 + struct overlay_attribute overlay_attr_##_name = \
15252 + __ATTR(_name, _mode, _show, _store)
15254 +static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
15255 +static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
15256 + overlay_manager_show, overlay_manager_store);
15257 +static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
15258 +static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
15259 +static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
15260 + overlay_position_show, overlay_position_store);
15261 +static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
15262 + overlay_output_size_show, overlay_output_size_store);
15263 +static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
15264 + overlay_enabled_show, overlay_enabled_store);
15265 +static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
15266 + overlay_global_alpha_show, overlay_global_alpha_store);
15268 +static struct attribute *overlay_sysfs_attrs[] = {
15269 + &overlay_attr_name.attr,
15270 + &overlay_attr_manager.attr,
15271 + &overlay_attr_input_size.attr,
15272 + &overlay_attr_screen_width.attr,
15273 + &overlay_attr_position.attr,
15274 + &overlay_attr_output_size.attr,
15275 + &overlay_attr_enabled.attr,
15276 + &overlay_attr_global_alpha.attr,
15280 +static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
15283 + struct omap_overlay *overlay;
15284 + struct overlay_attribute *overlay_attr;
15286 + overlay = container_of(kobj, struct omap_overlay, kobj);
15287 + overlay_attr = container_of(attr, struct overlay_attribute, attr);
15289 + if (!overlay_attr->show)
15292 + return overlay_attr->show(overlay, buf);
15295 +static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
15296 + const char *buf, size_t size)
15298 + struct omap_overlay *overlay;
15299 + struct overlay_attribute *overlay_attr;
15301 + overlay = container_of(kobj, struct omap_overlay, kobj);
15302 + overlay_attr = container_of(attr, struct overlay_attribute, attr);
15304 + if (!overlay_attr->store)
15307 + return overlay_attr->store(overlay, buf, size);
15310 +static struct sysfs_ops overlay_sysfs_ops = {
15311 + .show = overlay_attr_show,
15312 + .store = overlay_attr_store,
15315 +static struct kobj_type overlay_ktype = {
15316 + .sysfs_ops = &overlay_sysfs_ops,
15317 + .default_attrs = overlay_sysfs_attrs,
15320 +/* Check if overlay parameters are compatible with display */
15321 +int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
15323 + struct omap_overlay_info *info;
15330 + if (!ovl->info.enabled)
15333 + info = &ovl->info;
15335 + if (info->paddr == 0) {
15336 + DSSDBG("check_overlay failed: paddr 0\n");
15340 + dssdev->get_resolution(dssdev, &dw, &dh);
15342 + DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n",
15344 + info->pos_x, info->pos_y,
15345 + info->width, info->height,
15346 + info->out_width, info->out_height,
15349 + if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
15350 + outw = info->width;
15351 + outh = info->height;
15353 + if (info->out_width == 0)
15354 + outw = info->width;
15356 + outw = info->out_width;
15358 + if (info->out_height == 0)
15359 + outh = info->height;
15361 + outh = info->out_height;
15364 + if (dw < info->pos_x + outw) {
15365 + DSSDBG("check_overlay failed 1: %d < %d + %d\n",
15366 + dw, info->pos_x, outw);
15370 + if (dh < info->pos_y + outh) {
15371 + DSSDBG("check_overlay failed 2: %d < %d + %d\n",
15372 + dh, info->pos_y, outh);
15376 + if ((ovl->supported_modes & info->color_mode) == 0) {
15377 + DSSERR("overlay doesn't support mode %d\n", info->color_mode);
15384 +static int dss_ovl_set_overlay_info(struct omap_overlay *ovl,
15385 + struct omap_overlay_info *info)
15388 + struct omap_overlay_info old_info;
15390 + old_info = ovl->info;
15391 + ovl->info = *info;
15393 + if (ovl->manager) {
15394 + r = dss_check_overlay(ovl, ovl->manager->device);
15396 + ovl->info = old_info;
15401 + ovl->info_dirty = true;
15406 +static void dss_ovl_get_overlay_info(struct omap_overlay *ovl,
15407 + struct omap_overlay_info *info)
15409 + *info = ovl->info;
15412 +static int dss_ovl_wait_for_go(struct omap_overlay *ovl)
15414 + return dss_mgr_wait_for_go_ovl(ovl);
15417 +static int omap_dss_set_manager(struct omap_overlay *ovl,
15418 + struct omap_overlay_manager *mgr)
15423 + if (ovl->manager) {
15424 + DSSERR("overlay '%s' already has a manager '%s'\n",
15425 + ovl->name, ovl->manager->name);
15429 + if (ovl->info.enabled) {
15430 + DSSERR("overlay has to be disabled to change the manager\n");
15434 + ovl->manager = mgr;
15436 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
15437 + /* XXX: on manual update display, in auto update mode, a bug happens
15438 + * here. When an overlay is first enabled on LCD, then it's disabled,
15439 + * and the manager is changed to TV, we sometimes get SYNC_LOST_DIGIT
15440 + * errors. Waiting before changing the channel_out fixes it. I'm
15441 + * guessing that the overlay is still somehow being used for the LCD,
15442 + * but I don't understand how or why. */
15444 + dispc_set_channel_out(ovl->id, mgr->id);
15445 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
15450 +static int omap_dss_unset_manager(struct omap_overlay *ovl)
15454 + if (!ovl->manager) {
15455 + DSSERR("failed to detach overlay: manager not set\n");
15459 + if (ovl->info.enabled) {
15460 + DSSERR("overlay has to be disabled to unset the manager\n");
15464 + r = ovl->wait_for_go(ovl);
15468 + ovl->manager = NULL;
15473 +int omap_dss_get_num_overlays(void)
15475 + return num_overlays;
15477 +EXPORT_SYMBOL(omap_dss_get_num_overlays);
15479 +struct omap_overlay *omap_dss_get_overlay(int num)
15482 + struct omap_overlay *ovl;
15484 + list_for_each_entry(ovl, &overlay_list, list) {
15491 +EXPORT_SYMBOL(omap_dss_get_overlay);
15493 +static void omap_dss_add_overlay(struct omap_overlay *overlay)
15496 + list_add_tail(&overlay->list, &overlay_list);
15499 +static struct omap_overlay *dispc_overlays[3];
15501 +void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr)
15503 + mgr->num_overlays = 3;
15504 + mgr->overlays = dispc_overlays;
15508 +static struct omap_overlay *l4_overlays[1];
15509 +void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr)
15511 + mgr->num_overlays = 1;
15512 + mgr->overlays = l4_overlays;
15516 +void dss_init_overlays(struct platform_device *pdev)
15520 + INIT_LIST_HEAD(&overlay_list);
15522 + num_overlays = 0;
15524 + for (i = 0; i < 3; ++i) {
15525 + struct omap_overlay *ovl;
15526 + ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
15528 + BUG_ON(ovl == NULL);
15532 + ovl->name = "gfx";
15533 + ovl->id = OMAP_DSS_GFX;
15534 + ovl->supported_modes = OMAP_DSS_COLOR_GFX_OMAP3;
15535 + ovl->caps = OMAP_DSS_OVL_CAP_DISPC;
15536 + ovl->info.global_alpha = 255;
15539 + ovl->name = "vid1";
15540 + ovl->id = OMAP_DSS_VIDEO1;
15541 + ovl->supported_modes = OMAP_DSS_COLOR_VID_OMAP3;
15542 + ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
15543 + OMAP_DSS_OVL_CAP_DISPC;
15544 + ovl->info.global_alpha = 255;
15547 + ovl->name = "vid2";
15548 + ovl->id = OMAP_DSS_VIDEO2;
15549 + ovl->supported_modes = OMAP_DSS_COLOR_VID_OMAP3;
15550 + ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
15551 + OMAP_DSS_OVL_CAP_DISPC;
15552 + ovl->info.global_alpha = 255;
15556 + ovl->set_manager = &omap_dss_set_manager;
15557 + ovl->unset_manager = &omap_dss_unset_manager;
15558 + ovl->set_overlay_info = &dss_ovl_set_overlay_info;
15559 + ovl->get_overlay_info = &dss_ovl_get_overlay_info;
15560 + ovl->wait_for_go = &dss_ovl_wait_for_go;
15562 + omap_dss_add_overlay(ovl);
15564 + r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
15565 + &pdev->dev.kobj, "overlay%d", i);
15568 + DSSERR("failed to create sysfs file\n");
15572 + dispc_overlays[i] = ovl;
15577 + struct omap_overlay *ovl;
15578 + ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
15580 + BUG_ON(ovl == NULL);
15582 + ovl->name = "l4";
15583 + ovl->supported_modes = OMAP_DSS_COLOR_RGB24U;
15585 + ovl->set_manager = &omap_dss_set_manager;
15586 + ovl->unset_manager = &omap_dss_unset_manager;
15587 + ovl->set_overlay_info = &dss_ovl_set_overlay_info;
15588 + ovl->get_overlay_info = &dss_ovl_get_overlay_info;
15590 + omap_dss_add_overlay(ovl);
15592 + r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
15593 + &pdev->dev.kobj, "overlayl4");
15596 + DSSERR("failed to create sysfs file\n");
15598 + l4_overlays[0] = ovl;
15603 +/* connect overlays to the new device, if not already connected. if force
15604 + * selected, connect always. */
15605 +void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
15608 + struct omap_overlay_manager *lcd_mgr;
15609 + struct omap_overlay_manager *tv_mgr;
15610 + struct omap_overlay_manager *mgr = NULL;
15612 + lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD);
15613 + tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV);
15615 + if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
15616 + if (!lcd_mgr->device || force) {
15617 + if (lcd_mgr->device)
15618 + lcd_mgr->unset_device(lcd_mgr);
15619 + lcd_mgr->set_device(lcd_mgr, dssdev);
15624 + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
15625 + if (!tv_mgr->device || force) {
15626 + if (tv_mgr->device)
15627 + tv_mgr->unset_device(tv_mgr);
15628 + tv_mgr->set_device(tv_mgr, dssdev);
15634 + for (i = 0; i < 3; i++) {
15635 + struct omap_overlay *ovl;
15636 + ovl = omap_dss_get_overlay(i);
15637 + if (!ovl->manager || force) {
15638 + if (ovl->manager)
15639 + omap_dss_unset_manager(ovl);
15640 + omap_dss_set_manager(ovl, mgr);
15646 +void dss_uninit_overlays(struct platform_device *pdev)
15648 + struct omap_overlay *ovl;
15650 + while (!list_empty(&overlay_list)) {
15651 + ovl = list_first_entry(&overlay_list,
15652 + struct omap_overlay, list);
15653 + list_del(&ovl->list);
15654 + kobject_del(&ovl->kobj);
15655 + kobject_put(&ovl->kobj);
15659 + num_overlays = 0;
15662 diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
15663 new file mode 100644
15664 index 0000000..9dd2349
15666 +++ b/drivers/video/omap2/dss/rfbi.c
15669 + * linux/drivers/video/omap2/dss/rfbi.c
15671 + * Copyright (C) 2009 Nokia Corporation
15672 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
15674 + * Some code and ideas taken from drivers/video/omap/ driver
15677 + * This program is free software; you can redistribute it and/or modify it
15678 + * under the terms of the GNU General Public License version 2 as published by
15679 + * the Free Software Foundation.
15681 + * This program is distributed in the hope that it will be useful, but WITHOUT
15682 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15683 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15686 + * You should have received a copy of the GNU General Public License along with
15687 + * this program. If not, see <http://www.gnu.org/licenses/>.
15690 +#define DSS_SUBSYS_NAME "RFBI"
15692 +#include <linux/kernel.h>
15693 +#include <linux/dma-mapping.h>
15694 +#include <linux/vmalloc.h>
15695 +#include <linux/clk.h>
15696 +#include <linux/io.h>
15697 +#include <linux/delay.h>
15698 +#include <linux/kfifo.h>
15699 +#include <linux/ktime.h>
15700 +#include <linux/hrtimer.h>
15701 +#include <linux/seq_file.h>
15703 +#include <mach/board.h>
15704 +#include <mach/display.h>
15707 +/*#define MEASURE_PERF*/
15709 +#define RFBI_BASE 0x48050800
15711 +struct rfbi_reg { u16 idx; };
15713 +#define RFBI_REG(idx) ((const struct rfbi_reg) { idx })
15715 +#define RFBI_REVISION RFBI_REG(0x0000)
15716 +#define RFBI_SYSCONFIG RFBI_REG(0x0010)
15717 +#define RFBI_SYSSTATUS RFBI_REG(0x0014)
15718 +#define RFBI_CONTROL RFBI_REG(0x0040)
15719 +#define RFBI_PIXEL_CNT RFBI_REG(0x0044)
15720 +#define RFBI_LINE_NUMBER RFBI_REG(0x0048)
15721 +#define RFBI_CMD RFBI_REG(0x004c)
15722 +#define RFBI_PARAM RFBI_REG(0x0050)
15723 +#define RFBI_DATA RFBI_REG(0x0054)
15724 +#define RFBI_READ RFBI_REG(0x0058)
15725 +#define RFBI_STATUS RFBI_REG(0x005c)
15727 +#define RFBI_CONFIG(n) RFBI_REG(0x0060 + (n)*0x18)
15728 +#define RFBI_ONOFF_TIME(n) RFBI_REG(0x0064 + (n)*0x18)
15729 +#define RFBI_CYCLE_TIME(n) RFBI_REG(0x0068 + (n)*0x18)
15730 +#define RFBI_DATA_CYCLE1(n) RFBI_REG(0x006c + (n)*0x18)
15731 +#define RFBI_DATA_CYCLE2(n) RFBI_REG(0x0070 + (n)*0x18)
15732 +#define RFBI_DATA_CYCLE3(n) RFBI_REG(0x0074 + (n)*0x18)
15734 +#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090)
15735 +#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094)
15737 +#define RFBI_CMD_FIFO_LEN_BYTES (16 * sizeof(struct update_param))
15739 +#define REG_FLD_MOD(idx, val, start, end) \
15740 + rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
15742 +/* To work around an RFBI transfer rate limitation */
15743 +#define OMAP_RFBI_RATE_LIMIT 1
15745 +enum omap_rfbi_cycleformat {
15746 + OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0,
15747 + OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1,
15748 + OMAP_DSS_RFBI_CYCLEFORMAT_3_1 = 2,
15749 + OMAP_DSS_RFBI_CYCLEFORMAT_3_2 = 3,
15752 +enum omap_rfbi_datatype {
15753 + OMAP_DSS_RFBI_DATATYPE_12 = 0,
15754 + OMAP_DSS_RFBI_DATATYPE_16 = 1,
15755 + OMAP_DSS_RFBI_DATATYPE_18 = 2,
15756 + OMAP_DSS_RFBI_DATATYPE_24 = 3,
15759 +enum omap_rfbi_parallelmode {
15760 + OMAP_DSS_RFBI_PARALLELMODE_8 = 0,
15761 + OMAP_DSS_RFBI_PARALLELMODE_9 = 1,
15762 + OMAP_DSS_RFBI_PARALLELMODE_12 = 2,
15763 + OMAP_DSS_RFBI_PARALLELMODE_16 = 3,
15767 + RFBI_CMD_UPDATE = 0,
15768 + RFBI_CMD_SYNC = 1,
15771 +static int rfbi_convert_timings(struct rfbi_timings *t);
15772 +static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
15773 +static void process_cmd_fifo(void);
15776 + void __iomem *base;
15778 + unsigned long l4_khz;
15780 + enum omap_rfbi_datatype datatype;
15781 + enum omap_rfbi_parallelmode parallelmode;
15783 + enum omap_rfbi_te_mode te_mode;
15786 + void (*framedone_callback)(void *data);
15787 + void *framedone_callback_data;
15789 + struct omap_dss_device *dssdev[2];
15791 + struct kfifo *cmd_fifo;
15792 + spinlock_t cmd_lock;
15793 + struct completion cmd_done;
15794 + atomic_t cmd_fifo_full;
15795 + atomic_t cmd_pending;
15796 +#ifdef MEASURE_PERF
15797 + unsigned perf_bytes;
15798 + ktime_t perf_setup_time;
15799 + ktime_t perf_start_time;
15803 +struct update_region {
15810 +struct update_param {
15815 + struct update_region r;
15816 + struct completion *sync;
15820 +static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
15822 + __raw_writel(val, rfbi.base + idx.idx);
15825 +static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
15827 + return __raw_readl(rfbi.base + idx.idx);
15830 +static void rfbi_enable_clocks(bool enable)
15833 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
15835 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
15838 +void omap_rfbi_write_command(const void *buf, u32 len)
15840 + rfbi_enable_clocks(1);
15841 + switch (rfbi.parallelmode) {
15842 + case OMAP_DSS_RFBI_PARALLELMODE_8:
15844 + const u8 *b = buf;
15845 + for (; len; len--)
15846 + rfbi_write_reg(RFBI_CMD, *b++);
15850 + case OMAP_DSS_RFBI_PARALLELMODE_16:
15852 + const u16 *w = buf;
15854 + for (; len; len -= 2)
15855 + rfbi_write_reg(RFBI_CMD, *w++);
15859 + case OMAP_DSS_RFBI_PARALLELMODE_9:
15860 + case OMAP_DSS_RFBI_PARALLELMODE_12:
15864 + rfbi_enable_clocks(0);
15866 +EXPORT_SYMBOL(omap_rfbi_write_command);
15868 +void omap_rfbi_read_data(void *buf, u32 len)
15870 + rfbi_enable_clocks(1);
15871 + switch (rfbi.parallelmode) {
15872 + case OMAP_DSS_RFBI_PARALLELMODE_8:
15875 + for (; len; len--) {
15876 + rfbi_write_reg(RFBI_READ, 0);
15877 + *b++ = rfbi_read_reg(RFBI_READ);
15882 + case OMAP_DSS_RFBI_PARALLELMODE_16:
15885 + BUG_ON(len & ~1);
15886 + for (; len; len -= 2) {
15887 + rfbi_write_reg(RFBI_READ, 0);
15888 + *w++ = rfbi_read_reg(RFBI_READ);
15893 + case OMAP_DSS_RFBI_PARALLELMODE_9:
15894 + case OMAP_DSS_RFBI_PARALLELMODE_12:
15898 + rfbi_enable_clocks(0);
15900 +EXPORT_SYMBOL(omap_rfbi_read_data);
15902 +void omap_rfbi_write_data(const void *buf, u32 len)
15904 + rfbi_enable_clocks(1);
15905 + switch (rfbi.parallelmode) {
15906 + case OMAP_DSS_RFBI_PARALLELMODE_8:
15908 + const u8 *b = buf;
15909 + for (; len; len--)
15910 + rfbi_write_reg(RFBI_PARAM, *b++);
15914 + case OMAP_DSS_RFBI_PARALLELMODE_16:
15916 + const u16 *w = buf;
15918 + for (; len; len -= 2)
15919 + rfbi_write_reg(RFBI_PARAM, *w++);
15923 + case OMAP_DSS_RFBI_PARALLELMODE_9:
15924 + case OMAP_DSS_RFBI_PARALLELMODE_12:
15929 + rfbi_enable_clocks(0);
15931 +EXPORT_SYMBOL(omap_rfbi_write_data);
15933 +void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
15937 + int start_offset = scr_width * y + x;
15938 + int horiz_offset = scr_width - w;
15941 + rfbi_enable_clocks(1);
15943 + if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
15944 + rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
15945 + const u16 __iomem *pd = buf;
15946 + pd += start_offset;
15949 + for (i = 0; i < w; ++i) {
15950 + const u8 __iomem *b = (const u8 __iomem *)pd;
15951 + rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
15952 + rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
15955 + pd += horiz_offset;
15957 + } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_24 &&
15958 + rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
15959 + const u32 __iomem *pd = buf;
15960 + pd += start_offset;
15963 + for (i = 0; i < w; ++i) {
15964 + const u8 __iomem *b = (const u8 __iomem *)pd;
15965 + rfbi_write_reg(RFBI_PARAM, __raw_readb(b+2));
15966 + rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
15967 + rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
15970 + pd += horiz_offset;
15972 + } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
15973 + rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_16) {
15974 + const u16 __iomem *pd = buf;
15975 + pd += start_offset;
15978 + for (i = 0; i < w; ++i) {
15979 + rfbi_write_reg(RFBI_PARAM, __raw_readw(pd));
15982 + pd += horiz_offset;
15988 + rfbi_enable_clocks(0);
15990 +EXPORT_SYMBOL(omap_rfbi_write_pixels);
15992 +#ifdef MEASURE_PERF
15993 +static void perf_mark_setup(void)
15995 + rfbi.perf_setup_time = ktime_get();
15998 +static void perf_mark_start(void)
16000 + rfbi.perf_start_time = ktime_get();
16003 +static void perf_show(const char *name)
16005 + ktime_t t, setup_time, trans_time;
16007 + u32 setup_us, trans_us, total_us;
16011 + setup_time = ktime_sub(rfbi.perf_start_time, rfbi.perf_setup_time);
16012 + setup_us = (u32)ktime_to_us(setup_time);
16013 + if (setup_us == 0)
16016 + trans_time = ktime_sub(t, rfbi.perf_start_time);
16017 + trans_us = (u32)ktime_to_us(trans_time);
16018 + if (trans_us == 0)
16021 + total_us = setup_us + trans_us;
16023 + total_bytes = rfbi.perf_bytes;
16025 + DSSINFO("%s update %u us + %u us = %u us (%uHz), %u bytes, "
16026 + "%u kbytes/sec\n",
16031 + 1000*1000 / total_us,
16033 + total_bytes * 1000 / total_us);
16036 +#define perf_mark_setup()
16037 +#define perf_mark_start()
16038 +#define perf_show(x)
16041 +void rfbi_transfer_area(u16 width, u16 height,
16042 + void (callback)(void *data), void *data)
16046 + /*BUG_ON(callback == 0);*/
16047 + BUG_ON(rfbi.framedone_callback != NULL);
16049 + DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
16051 + dispc_set_lcd_size(width, height);
16053 + dispc_enable_lcd_out(1);
16055 + rfbi.framedone_callback = callback;
16056 + rfbi.framedone_callback_data = data;
16058 + rfbi_enable_clocks(1);
16060 + rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
16062 + l = rfbi_read_reg(RFBI_CONTROL);
16063 + l = FLD_MOD(l, 1, 0, 0); /* enable */
16064 + if (!rfbi.te_enabled)
16065 + l = FLD_MOD(l, 1, 4, 4); /* ITE */
16067 + perf_mark_start();
16069 + rfbi_write_reg(RFBI_CONTROL, l);
16072 +static void framedone_callback(void *data, u32 mask)
16074 + void (*callback)(void *data);
16076 + DSSDBG("FRAMEDONE\n");
16078 + perf_show("DISPC");
16080 + REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
16082 + rfbi_enable_clocks(0);
16084 + callback = rfbi.framedone_callback;
16085 + rfbi.framedone_callback = NULL;
16087 + /*callback(rfbi.framedone_callback_data);*/
16089 + atomic_set(&rfbi.cmd_pending, 0);
16091 + process_cmd_fifo();
16094 +#if 1 /* VERBOSE */
16095 +static void rfbi_print_timings(void)
16100 + l = rfbi_read_reg(RFBI_CONFIG(0));
16101 + time = 1000000000 / rfbi.l4_khz;
16102 + if (l & (1 << 4))
16105 + DSSDBG("Tick time %u ps\n", time);
16106 + l = rfbi_read_reg(RFBI_ONOFF_TIME(0));
16107 + DSSDBG("CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
16108 + "REONTIME %d, REOFFTIME %d\n",
16109 + l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
16110 + (l >> 20) & 0x0f, (l >> 24) & 0x3f);
16112 + l = rfbi_read_reg(RFBI_CYCLE_TIME(0));
16113 + DSSDBG("WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
16114 + "ACCESSTIME %d\n",
16115 + (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
16116 + (l >> 22) & 0x3f);
16119 +static void rfbi_print_timings(void) {}
16125 +static u32 extif_clk_period;
16127 +static inline unsigned long round_to_extif_ticks(unsigned long ps, int div)
16129 + int bus_tick = extif_clk_period * div;
16130 + return (ps + bus_tick - 1) / bus_tick * bus_tick;
16133 +static int calc_reg_timing(struct rfbi_timings *t, int div)
16135 + t->clk_div = div;
16137 + t->cs_on_time = round_to_extif_ticks(t->cs_on_time, div);
16139 + t->we_on_time = round_to_extif_ticks(t->we_on_time, div);
16140 + t->we_off_time = round_to_extif_ticks(t->we_off_time, div);
16141 + t->we_cycle_time = round_to_extif_ticks(t->we_cycle_time, div);
16143 + t->re_on_time = round_to_extif_ticks(t->re_on_time, div);
16144 + t->re_off_time = round_to_extif_ticks(t->re_off_time, div);
16145 + t->re_cycle_time = round_to_extif_ticks(t->re_cycle_time, div);
16147 + t->access_time = round_to_extif_ticks(t->access_time, div);
16148 + t->cs_off_time = round_to_extif_ticks(t->cs_off_time, div);
16149 + t->cs_pulse_width = round_to_extif_ticks(t->cs_pulse_width, div);
16151 + DSSDBG("[reg]cson %d csoff %d reon %d reoff %d\n",
16152 + t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
16153 + DSSDBG("[reg]weon %d weoff %d recyc %d wecyc %d\n",
16154 + t->we_on_time, t->we_off_time, t->re_cycle_time,
16155 + t->we_cycle_time);
16156 + DSSDBG("[reg]rdaccess %d cspulse %d\n",
16157 + t->access_time, t->cs_pulse_width);
16159 + return rfbi_convert_timings(t);
16162 +static int calc_extif_timings(struct rfbi_timings *t)
16167 + rfbi_get_clk_info(&extif_clk_period, &max_clk_div);
16168 + for (div = 1; div <= max_clk_div; div++) {
16169 + if (calc_reg_timing(t, div) == 0)
16173 + if (div <= max_clk_div)
16176 + DSSERR("can't setup timings\n");
16181 +void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
16185 + if (!t->converted) {
16186 + r = calc_extif_timings(t);
16188 + DSSERR("Failed to calc timings\n");
16191 + BUG_ON(!t->converted);
16193 + rfbi_enable_clocks(1);
16194 + rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]);
16195 + rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]);
16197 + /* TIMEGRANULARITY */
16198 + REG_FLD_MOD(RFBI_CONFIG(rfbi_module),
16199 + (t->tim[2] ? 1 : 0), 4, 4);
16201 + rfbi_print_timings();
16202 + rfbi_enable_clocks(0);
16205 +static int ps_to_rfbi_ticks(int time, int div)
16207 + unsigned long tick_ps;
16210 + /* Calculate in picosecs to yield more exact results */
16211 + tick_ps = 1000000000 / (rfbi.l4_khz) * div;
16213 + ret = (time + tick_ps - 1) / tick_ps;
16218 +#ifdef OMAP_RFBI_RATE_LIMIT
16219 +unsigned long rfbi_get_max_tx_rate(void)
16221 + unsigned long l4_rate, dss1_rate;
16222 + int min_l4_ticks = 0;
16225 + /* According to TI this can't be calculated so make the
16226 + * adjustments for a couple of known frequencies and warn for
16229 + static const struct {
16230 + unsigned long l4_clk; /* HZ */
16231 + unsigned long dss1_clk; /* HZ */
16232 + unsigned long min_l4_ticks;
16234 + { 55, 132, 7, }, /* 7.86 MPix/s */
16235 + { 110, 110, 12, }, /* 9.16 MPix/s */
16236 + { 110, 132, 10, }, /* 11 Mpix/s */
16237 + { 120, 120, 10, }, /* 12 Mpix/s */
16238 + { 133, 133, 10, }, /* 13.3 Mpix/s */
16241 + l4_rate = rfbi.l4_khz / 1000;
16242 + dss1_rate = dss_clk_get_rate(DSS_CLK_FCK1) / 1000000;
16244 + for (i = 0; i < ARRAY_SIZE(ftab); i++) {
16245 + /* Use a window instead of an exact match, to account
16246 + * for different DPLL multiplier / divider pairs.
16248 + if (abs(ftab[i].l4_clk - l4_rate) < 3 &&
16249 + abs(ftab[i].dss1_clk - dss1_rate) < 3) {
16250 + min_l4_ticks = ftab[i].min_l4_ticks;
16254 + if (i == ARRAY_SIZE(ftab)) {
16255 + /* Can't be sure, return anyway the maximum not
16256 + * rate-limited. This might cause a problem only for the
16257 + * tearing synchronisation.
16259 + DSSERR("can't determine maximum RFBI transfer rate\n");
16260 + return rfbi.l4_khz * 1000;
16262 + return rfbi.l4_khz * 1000 / min_l4_ticks;
16265 +int rfbi_get_max_tx_rate(void)
16267 + return rfbi.l4_khz * 1000;
16271 +static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
16273 + *clk_period = 1000000000 / rfbi.l4_khz;
16274 + *max_clk_div = 2;
16277 +static int rfbi_convert_timings(struct rfbi_timings *t)
16280 + int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
16281 + int actim, recyc, wecyc;
16282 + int div = t->clk_div;
16284 + if (div <= 0 || div > 2)
16287 + /* Make sure that after conversion it still holds that:
16288 + * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
16289 + * csoff > cson, csoff >= max(weoff, reoff), actim > reon
16291 + weon = ps_to_rfbi_ticks(t->we_on_time, div);
16292 + weoff = ps_to_rfbi_ticks(t->we_off_time, div);
16293 + if (weoff <= weon)
16294 + weoff = weon + 1;
16297 + if (weoff > 0x3f)
16300 + reon = ps_to_rfbi_ticks(t->re_on_time, div);
16301 + reoff = ps_to_rfbi_ticks(t->re_off_time, div);
16302 + if (reoff <= reon)
16303 + reoff = reon + 1;
16306 + if (reoff > 0x3f)
16309 + cson = ps_to_rfbi_ticks(t->cs_on_time, div);
16310 + csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
16311 + if (csoff <= cson)
16312 + csoff = cson + 1;
16313 + if (csoff < max(weoff, reoff))
16314 + csoff = max(weoff, reoff);
16317 + if (csoff > 0x3f)
16323 + l |= weoff << 14;
16325 + l |= reoff << 24;
16329 + actim = ps_to_rfbi_ticks(t->access_time, div);
16330 + if (actim <= reon)
16331 + actim = reon + 1;
16332 + if (actim > 0x3f)
16335 + wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
16336 + if (wecyc < weoff)
16338 + if (wecyc > 0x3f)
16341 + recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
16342 + if (recyc < reoff)
16344 + if (recyc > 0x3f)
16347 + cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
16348 + if (cs_pulse > 0x3f)
16353 + l |= cs_pulse << 12;
16354 + l |= actim << 22;
16358 + t->tim[2] = div - 1;
16360 + t->converted = 1;
16365 +/* xxx FIX module selection missing */
16366 +int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
16367 + unsigned hs_pulse_time, unsigned vs_pulse_time,
16368 + int hs_pol_inv, int vs_pol_inv, int extif_div)
16374 + hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
16375 + vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
16378 + if (mode == OMAP_DSS_RFBI_TE_MODE_2)
16380 + else /* OMAP_DSS_RFBI_TE_MODE_1 */
16386 + rfbi.te_mode = mode;
16387 + DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n",
16388 + mode, hs, vs, hs_pol_inv, vs_pol_inv);
16390 + rfbi_enable_clocks(1);
16391 + rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
16392 + rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
16394 + l = rfbi_read_reg(RFBI_CONFIG(0));
16403 + rfbi_enable_clocks(0);
16407 +EXPORT_SYMBOL(omap_rfbi_setup_te);
16409 +/* xxx FIX module selection missing */
16410 +int omap_rfbi_enable_te(bool enable, unsigned line)
16414 + DSSDBG("te %d line %d mode %d\n", enable, line, rfbi.te_mode);
16415 + if (line > (1 << 11) - 1)
16418 + rfbi_enable_clocks(1);
16419 + l = rfbi_read_reg(RFBI_CONFIG(0));
16420 + l &= ~(0x3 << 2);
16422 + rfbi.te_enabled = 1;
16423 + l |= rfbi.te_mode << 2;
16425 + rfbi.te_enabled = 0;
16426 + rfbi_write_reg(RFBI_CONFIG(0), l);
16427 + rfbi_write_reg(RFBI_LINE_NUMBER, line);
16428 + rfbi_enable_clocks(0);
16432 +EXPORT_SYMBOL(omap_rfbi_enable_te);
16435 +static void rfbi_enable_config(int enable1, int enable2)
16445 + rfbi_enable_clocks(1);
16447 + l = rfbi_read_reg(RFBI_CONTROL);
16449 + l = FLD_MOD(l, cs, 3, 2);
16450 + l = FLD_MOD(l, 0, 1, 1);
16452 + rfbi_write_reg(RFBI_CONTROL, l);
16455 + l = rfbi_read_reg(RFBI_CONFIG(0));
16456 + l = FLD_MOD(l, 0, 3, 2); /* TRIGGERMODE: ITE */
16457 + /*l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
16458 + /*l |= FLD_VAL(0, 8, 7); */ /* L4FORMAT, 1pix/L4 */
16460 + l = FLD_MOD(l, 0, 16, 16); /* A0POLARITY */
16461 + l = FLD_MOD(l, 1, 20, 20); /* TE_VSYNC_POLARITY */
16462 + l = FLD_MOD(l, 1, 21, 21); /* HSYNCPOLARITY */
16464 + l = FLD_MOD(l, OMAP_DSS_RFBI_PARALLELMODE_8, 1, 0);
16465 + rfbi_write_reg(RFBI_CONFIG(0), l);
16467 + rfbi_enable_clocks(0);
16471 +int rfbi_configure(int rfbi_module, int bpp, int lines)
16474 + int cycle1 = 0, cycle2 = 0, cycle3 = 0;
16475 + enum omap_rfbi_cycleformat cycleformat;
16476 + enum omap_rfbi_datatype datatype;
16477 + enum omap_rfbi_parallelmode parallelmode;
16481 + datatype = OMAP_DSS_RFBI_DATATYPE_12;
16484 + datatype = OMAP_DSS_RFBI_DATATYPE_16;
16487 + datatype = OMAP_DSS_RFBI_DATATYPE_18;
16490 + datatype = OMAP_DSS_RFBI_DATATYPE_24;
16496 + rfbi.datatype = datatype;
16500 + parallelmode = OMAP_DSS_RFBI_PARALLELMODE_8;
16503 + parallelmode = OMAP_DSS_RFBI_PARALLELMODE_9;
16506 + parallelmode = OMAP_DSS_RFBI_PARALLELMODE_12;
16509 + parallelmode = OMAP_DSS_RFBI_PARALLELMODE_16;
16515 + rfbi.parallelmode = parallelmode;
16517 + if ((bpp % lines) == 0) {
16518 + switch (bpp / lines) {
16520 + cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_1_1;
16523 + cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_2_1;
16526 + cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_1;
16532 + } else if ((2 * bpp % lines) == 0) {
16533 + if ((2 * bpp / lines) == 3)
16534 + cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_2;
16544 + switch (cycleformat) {
16545 + case OMAP_DSS_RFBI_CYCLEFORMAT_1_1:
16549 + case OMAP_DSS_RFBI_CYCLEFORMAT_2_1:
16554 + case OMAP_DSS_RFBI_CYCLEFORMAT_3_1:
16560 + case OMAP_DSS_RFBI_CYCLEFORMAT_3_2:
16562 + cycle2 = (lines / 2) | ((lines / 2) << 16);
16563 + cycle3 = (lines << 16);
16567 + rfbi_enable_clocks(1);
16569 + REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */
16572 + l |= FLD_VAL(parallelmode, 1, 0);
16573 + l |= FLD_VAL(0, 3, 2); /* TRIGGERMODE: ITE */
16574 + l |= FLD_VAL(0, 4, 4); /* TIMEGRANULARITY */
16575 + l |= FLD_VAL(datatype, 6, 5);
16576 + /* l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
16577 + l |= FLD_VAL(0, 8, 7); /* L4FORMAT, 1pix/L4 */
16578 + l |= FLD_VAL(cycleformat, 10, 9);
16579 + l |= FLD_VAL(0, 12, 11); /* UNUSEDBITS */
16580 + l |= FLD_VAL(0, 16, 16); /* A0POLARITY */
16581 + l |= FLD_VAL(0, 17, 17); /* REPOLARITY */
16582 + l |= FLD_VAL(0, 18, 18); /* WEPOLARITY */
16583 + l |= FLD_VAL(0, 19, 19); /* CSPOLARITY */
16584 + l |= FLD_VAL(1, 20, 20); /* TE_VSYNC_POLARITY */
16585 + l |= FLD_VAL(1, 21, 21); /* HSYNCPOLARITY */
16586 + rfbi_write_reg(RFBI_CONFIG(rfbi_module), l);
16588 + rfbi_write_reg(RFBI_DATA_CYCLE1(rfbi_module), cycle1);
16589 + rfbi_write_reg(RFBI_DATA_CYCLE2(rfbi_module), cycle2);
16590 + rfbi_write_reg(RFBI_DATA_CYCLE3(rfbi_module), cycle3);
16593 + l = rfbi_read_reg(RFBI_CONTROL);
16594 + l = FLD_MOD(l, rfbi_module+1, 3, 2); /* Select CSx */
16595 + l = FLD_MOD(l, 0, 1, 1); /* clear bypass */
16596 + rfbi_write_reg(RFBI_CONTROL, l);
16599 + DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n",
16600 + bpp, lines, cycle1, cycle2, cycle3);
16602 + rfbi_enable_clocks(0);
16606 +EXPORT_SYMBOL(rfbi_configure);
16608 +static int rfbi_find_display(struct omap_dss_device *dssdev)
16610 + if (dssdev == rfbi.dssdev[0])
16613 + if (dssdev == rfbi.dssdev[1])
16621 +static void signal_fifo_waiters(void)
16623 + if (atomic_read(&rfbi.cmd_fifo_full) > 0) {
16624 + /* DSSDBG("SIGNALING: Fifo not full for waiter!\n"); */
16625 + complete(&rfbi.cmd_done);
16626 + atomic_dec(&rfbi.cmd_fifo_full);
16630 +/* returns 1 for async op, and 0 for sync op */
16631 +static int do_update(struct omap_dss_device *dssdev, struct update_region *upd)
16638 + perf_mark_setup();
16640 + if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
16641 + /*dssdev->driver->enable_te(dssdev, 1); */
16642 + dss_setup_partial_planes(dssdev, &x, &y, &w, &h);
16645 +#ifdef MEASURE_PERF
16646 + rfbi.perf_bytes = w * h * 2; /* XXX always 16bit */
16649 + dssdev->driver->setup_update(dssdev, x, y, w, h);
16651 + if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
16652 + rfbi_transfer_area(w, h, NULL, NULL);
16655 + struct omap_overlay *ovl;
16656 + void __iomem *addr;
16659 + ovl = dssdev->manager->overlays[0];
16660 + scr_width = ovl->info.screen_width;
16661 + addr = ovl->info.vaddr;
16663 + omap_rfbi_write_pixels(addr, scr_width, x, y, w, h);
16671 +static void process_cmd_fifo(void)
16674 + struct update_param p;
16675 + struct omap_dss_device *dssdev;
16676 + unsigned long flags;
16678 + if (atomic_inc_return(&rfbi.cmd_pending) != 1)
16682 + spin_lock_irqsave(rfbi.cmd_fifo->lock, flags);
16684 + len = __kfifo_get(rfbi.cmd_fifo, (unsigned char *)&p,
16685 + sizeof(struct update_param));
16687 + DSSDBG("nothing more in fifo\n");
16688 + atomic_set(&rfbi.cmd_pending, 0);
16689 + spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags);
16693 + /* DSSDBG("fifo full %d\n", rfbi.cmd_fifo_full.counter);*/
16695 + spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags);
16697 + BUG_ON(len != sizeof(struct update_param));
16698 + BUG_ON(p.rfbi_module > 1);
16700 + dssdev = rfbi.dssdev[p.rfbi_module];
16702 + if (p.cmd == RFBI_CMD_UPDATE) {
16703 + if (do_update(dssdev, &p.par.r))
16704 + break; /* async op */
16705 + } else if (p.cmd == RFBI_CMD_SYNC) {
16706 + DSSDBG("Signaling SYNC done!\n");
16707 + complete(p.par.sync);
16712 + signal_fifo_waiters();
16715 +static void rfbi_push_cmd(struct update_param *p)
16720 + unsigned long flags;
16723 + spin_lock_irqsave(rfbi.cmd_fifo->lock, flags);
16724 + available = RFBI_CMD_FIFO_LEN_BYTES -
16725 + __kfifo_len(rfbi.cmd_fifo);
16727 +/* DSSDBG("%d bytes left in fifo\n", available); */
16728 + if (available < sizeof(struct update_param)) {
16729 + DSSDBG("Going to wait because FIFO FULL..\n");
16730 + spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags);
16731 + atomic_inc(&rfbi.cmd_fifo_full);
16732 + wait_for_completion(&rfbi.cmd_done);
16733 + /*DSSDBG("Woke up because fifo not full anymore\n");*/
16737 + ret = __kfifo_put(rfbi.cmd_fifo, (unsigned char *)p,
16738 + sizeof(struct update_param));
16739 +/* DSSDBG("pushed %d bytes\n", ret);*/
16741 + spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags);
16743 + BUG_ON(ret != sizeof(struct update_param));
16749 +static void rfbi_push_update(int rfbi_module, int x, int y, int w, int h)
16751 + struct update_param p;
16753 + p.rfbi_module = rfbi_module;
16754 + p.cmd = RFBI_CMD_UPDATE;
16761 + DSSDBG("RFBI pushed %d,%d %dx%d\n", x, y, w, h);
16763 + rfbi_push_cmd(&p);
16765 + process_cmd_fifo();
16768 +static void rfbi_push_sync(int rfbi_module, struct completion *sync_comp)
16770 + struct update_param p;
16772 + p.rfbi_module = rfbi_module;
16773 + p.cmd = RFBI_CMD_SYNC;
16774 + p.par.sync = sync_comp;
16776 + rfbi_push_cmd(&p);
16778 + DSSDBG("RFBI sync pushed to cmd fifo\n");
16780 + process_cmd_fifo();
16783 +void rfbi_dump_regs(struct seq_file *s)
16785 +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
16787 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
16789 + DUMPREG(RFBI_REVISION);
16790 + DUMPREG(RFBI_SYSCONFIG);
16791 + DUMPREG(RFBI_SYSSTATUS);
16792 + DUMPREG(RFBI_CONTROL);
16793 + DUMPREG(RFBI_PIXEL_CNT);
16794 + DUMPREG(RFBI_LINE_NUMBER);
16795 + DUMPREG(RFBI_CMD);
16796 + DUMPREG(RFBI_PARAM);
16797 + DUMPREG(RFBI_DATA);
16798 + DUMPREG(RFBI_READ);
16799 + DUMPREG(RFBI_STATUS);
16801 + DUMPREG(RFBI_CONFIG(0));
16802 + DUMPREG(RFBI_ONOFF_TIME(0));
16803 + DUMPREG(RFBI_CYCLE_TIME(0));
16804 + DUMPREG(RFBI_DATA_CYCLE1(0));
16805 + DUMPREG(RFBI_DATA_CYCLE2(0));
16806 + DUMPREG(RFBI_DATA_CYCLE3(0));
16808 + DUMPREG(RFBI_CONFIG(1));
16809 + DUMPREG(RFBI_ONOFF_TIME(1));
16810 + DUMPREG(RFBI_CYCLE_TIME(1));
16811 + DUMPREG(RFBI_DATA_CYCLE1(1));
16812 + DUMPREG(RFBI_DATA_CYCLE2(1));
16813 + DUMPREG(RFBI_DATA_CYCLE3(1));
16815 + DUMPREG(RFBI_VSYNC_WIDTH);
16816 + DUMPREG(RFBI_HSYNC_WIDTH);
16818 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
16822 +int rfbi_init(void)
16827 + spin_lock_init(&rfbi.cmd_lock);
16828 + rfbi.cmd_fifo = kfifo_alloc(RFBI_CMD_FIFO_LEN_BYTES, GFP_KERNEL,
16830 + if (IS_ERR(rfbi.cmd_fifo))
16833 + init_completion(&rfbi.cmd_done);
16834 + atomic_set(&rfbi.cmd_fifo_full, 0);
16835 + atomic_set(&rfbi.cmd_pending, 0);
16837 + rfbi.base = ioremap(RFBI_BASE, SZ_256);
16838 + if (!rfbi.base) {
16839 + DSSERR("can't ioremap RFBI\n");
16843 + rfbi_enable_clocks(1);
16847 + rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
16849 + /* Enable autoidle and smart-idle */
16850 + l = rfbi_read_reg(RFBI_SYSCONFIG);
16851 + l |= (1 << 0) | (2 << 3);
16852 + rfbi_write_reg(RFBI_SYSCONFIG, l);
16854 + rev = rfbi_read_reg(RFBI_REVISION);
16855 + printk(KERN_INFO "OMAP RFBI rev %d.%d\n",
16856 + FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
16858 + rfbi_enable_clocks(0);
16863 +void rfbi_exit(void)
16865 + DSSDBG("rfbi_exit\n");
16867 + kfifo_free(rfbi.cmd_fifo);
16869 + iounmap(rfbi.base);
16872 +/* struct omap_display support */
16873 +static int rfbi_display_update(struct omap_dss_device *dssdev,
16874 + u16 x, u16 y, u16 w, u16 h)
16878 + if (w == 0 || h == 0)
16881 + rfbi_module = rfbi_find_display(dssdev);
16883 + rfbi_push_update(rfbi_module, x, y, w, h);
16888 +static int rfbi_display_sync(struct omap_dss_device *dssdev)
16890 + struct completion sync_comp;
16893 + rfbi_module = rfbi_find_display(dssdev);
16895 + init_completion(&sync_comp);
16896 + rfbi_push_sync(rfbi_module, &sync_comp);
16897 + DSSDBG("Waiting for SYNC to happen...\n");
16898 + wait_for_completion(&sync_comp);
16899 + DSSDBG("Released from SYNC\n");
16903 +static int rfbi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
16905 + dssdev->driver->enable_te(dssdev, enable);
16909 +static int rfbi_display_enable(struct omap_dss_device *dssdev)
16913 + r = omap_dss_start_device(dssdev);
16915 + DSSERR("failed to start device\n");
16919 + r = omap_dispc_register_isr(framedone_callback, NULL,
16920 + DISPC_IRQ_FRAMEDONE);
16922 + DSSERR("can't get FRAMEDONE irq\n");
16926 + dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
16928 + dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_RFBI);
16930 + dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
16932 + rfbi_configure(dssdev->phy.rfbi.channel,
16933 + dssdev->ctrl.pixel_size,
16934 + dssdev->phy.rfbi.data_lines);
16936 + rfbi_set_timings(dssdev->phy.rfbi.channel,
16937 + &dssdev->ctrl.rfbi_timings);
16940 + if (dssdev->driver->enable) {
16941 + r = dssdev->driver->enable(dssdev);
16948 + omap_dispc_unregister_isr(framedone_callback, NULL,
16949 + DISPC_IRQ_FRAMEDONE);
16951 + omap_dss_stop_device(dssdev);
16956 +static void rfbi_display_disable(struct omap_dss_device *dssdev)
16958 + dssdev->driver->disable(dssdev);
16959 + omap_dispc_unregister_isr(framedone_callback, NULL,
16960 + DISPC_IRQ_FRAMEDONE);
16961 + omap_dss_stop_device(dssdev);
16964 +int rfbi_init_display(struct omap_dss_device *dssdev)
16966 + dssdev->enable = rfbi_display_enable;
16967 + dssdev->disable = rfbi_display_disable;
16968 + dssdev->update = rfbi_display_update;
16969 + dssdev->sync = rfbi_display_sync;
16970 + dssdev->enable_te = rfbi_display_enable_te;
16972 + rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
16974 + dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
16978 diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
16979 new file mode 100644
16980 index 0000000..a9c727e
16982 +++ b/drivers/video/omap2/dss/sdi.c
16985 + * linux/drivers/video/omap2/dss/sdi.c
16987 + * Copyright (C) 2009 Nokia Corporation
16988 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
16990 + * This program is free software; you can redistribute it and/or modify it
16991 + * under the terms of the GNU General Public License version 2 as published by
16992 + * the Free Software Foundation.
16994 + * This program is distributed in the hope that it will be useful, but WITHOUT
16995 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16996 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16999 + * You should have received a copy of the GNU General Public License along with
17000 + * this program. If not, see <http://www.gnu.org/licenses/>.
17003 +#define DSS_SUBSYS_NAME "SDI"
17005 +#include <linux/kernel.h>
17006 +#include <linux/clk.h>
17007 +#include <linux/delay.h>
17008 +#include <linux/err.h>
17010 +#include <mach/board.h>
17011 +#include <mach/display.h>
17016 + bool update_enabled;
17019 +static void sdi_basic_init(void)
17021 + dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
17023 + dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
17024 + dispc_set_tft_data_lines(24);
17025 + dispc_lcd_enable_signal_polarity(1);
17028 +static int sdi_display_enable(struct omap_dss_device *dssdev)
17030 + struct omap_video_timings *t = &dssdev->panel.timings;
17031 + struct dispc_clock_info cinfo;
17032 + u16 lck_div, pck_div;
17033 + unsigned long fck;
17034 + unsigned long pck;
17037 + r = omap_dss_start_device(dssdev);
17039 + DSSERR("failed to start device\n");
17043 + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
17044 + DSSERR("dssdev already enabled\n");
17049 + /* In case of skip_init sdi_init has already enabled the clocks */
17050 + if (!sdi.skip_init)
17051 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
17053 + sdi_basic_init();
17056 + dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF;
17058 + dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
17059 + dssdev->panel.acb);
17061 + if (!sdi.skip_init)
17062 + r = dispc_calc_clock_div(1, t->pixel_clock * 1000,
17065 + r = dispc_get_clock_div(&cinfo);
17071 + lck_div = cinfo.lck_div;
17072 + pck_div = cinfo.pck_div;
17074 + pck = fck / lck_div / pck_div / 1000;
17076 + if (pck != t->pixel_clock) {
17077 + DSSWARN("Could not find exact pixel clock. Requested %d kHz, "
17079 + t->pixel_clock, pck);
17081 + t->pixel_clock = pck;
17085 + dispc_set_lcd_timings(t);
17087 + r = dispc_set_clock_div(&cinfo);
17091 + if (!sdi.skip_init) {
17092 + dss_sdi_init(dssdev->phy.sdi.datapairs);
17093 + dss_sdi_enable();
17097 + dispc_enable_lcd_out(1);
17099 + if (dssdev->driver->enable) {
17100 + r = dssdev->driver->enable(dssdev);
17105 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
17107 + sdi.skip_init = 0;
17111 + dispc_enable_lcd_out(0);
17113 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
17115 + omap_dss_stop_device(dssdev);
17120 +static int sdi_display_resume(struct omap_dss_device *dssdev);
17122 +static void sdi_display_disable(struct omap_dss_device *dssdev)
17124 + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
17127 + if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
17128 + sdi_display_resume(dssdev);
17130 + if (dssdev->driver->disable)
17131 + dssdev->driver->disable(dssdev);
17133 + dispc_enable_lcd_out(0);
17135 + dss_sdi_disable();
17137 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
17139 + dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
17141 + omap_dss_stop_device(dssdev);
17144 +static int sdi_display_suspend(struct omap_dss_device *dssdev)
17146 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
17149 + if (dssdev->driver->suspend)
17150 + dssdev->driver->suspend(dssdev);
17152 + dispc_enable_lcd_out(0);
17154 + dss_sdi_disable();
17156 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
17158 + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
17163 +static int sdi_display_resume(struct omap_dss_device *dssdev)
17165 + if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
17168 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
17170 + dss_sdi_enable();
17173 + dispc_enable_lcd_out(1);
17175 + if (dssdev->driver->resume)
17176 + dssdev->driver->resume(dssdev);
17178 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
17183 +static int sdi_display_set_update_mode(struct omap_dss_device *dssdev,
17184 + enum omap_dss_update_mode mode)
17186 + if (mode == OMAP_DSS_UPDATE_MANUAL)
17189 + if (mode == OMAP_DSS_UPDATE_DISABLED) {
17190 + dispc_enable_lcd_out(0);
17191 + sdi.update_enabled = 0;
17193 + dispc_enable_lcd_out(1);
17194 + sdi.update_enabled = 1;
17200 +static enum omap_dss_update_mode sdi_display_get_update_mode(
17201 + struct omap_dss_device *dssdev)
17203 + return sdi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
17204 + OMAP_DSS_UPDATE_DISABLED;
17207 +static void sdi_get_timings(struct omap_dss_device *dssdev,
17208 + struct omap_video_timings *timings)
17210 + *timings = dssdev->panel.timings;
17213 +int sdi_init_display(struct omap_dss_device *dssdev)
17215 + DSSDBG("SDI init\n");
17217 + dssdev->enable = sdi_display_enable;
17218 + dssdev->disable = sdi_display_disable;
17219 + dssdev->suspend = sdi_display_suspend;
17220 + dssdev->resume = sdi_display_resume;
17221 + dssdev->set_update_mode = sdi_display_set_update_mode;
17222 + dssdev->get_update_mode = sdi_display_get_update_mode;
17223 + dssdev->get_timings = sdi_get_timings;
17228 +int sdi_init(bool skip_init)
17230 + /* we store this for first display enable, then clear it */
17231 + sdi.skip_init = skip_init;
17234 + * Enable clocks already here, otherwise there would be a toggle
17235 + * of them until sdi_display_enable is called.
17238 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
17242 +void sdi_exit(void)
17245 diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
17246 new file mode 100644
17247 index 0000000..cf7827e
17249 +++ b/drivers/video/omap2/dss/venc.c
17252 + * linux/drivers/video/omap2/dss/venc.c
17254 + * Copyright (C) 2009 Nokia Corporation
17255 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
17257 + * VENC settings from TI's DSS driver
17259 + * This program is free software; you can redistribute it and/or modify it
17260 + * under the terms of the GNU General Public License version 2 as published by
17261 + * the Free Software Foundation.
17263 + * This program is distributed in the hope that it will be useful, but WITHOUT
17264 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17265 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17268 + * You should have received a copy of the GNU General Public License along with
17269 + * this program. If not, see <http://www.gnu.org/licenses/>.
17272 +#define DSS_SUBSYS_NAME "VENC"
17274 +#include <linux/kernel.h>
17275 +#include <linux/module.h>
17276 +#include <linux/clk.h>
17277 +#include <linux/err.h>
17278 +#include <linux/io.h>
17279 +#include <linux/mutex.h>
17280 +#include <linux/completion.h>
17281 +#include <linux/delay.h>
17282 +#include <linux/string.h>
17283 +#include <linux/seq_file.h>
17284 +#include <linux/platform_device.h>
17285 +#include <linux/regulator/consumer.h>
17287 +#include <mach/display.h>
17288 +#include <mach/cpu.h>
17292 +#define VENC_BASE 0x48050C00
17294 +/* Venc registers */
17295 +#define VENC_REV_ID 0x00
17296 +#define VENC_STATUS 0x04
17297 +#define VENC_F_CONTROL 0x08
17298 +#define VENC_VIDOUT_CTRL 0x10
17299 +#define VENC_SYNC_CTRL 0x14
17300 +#define VENC_LLEN 0x1C
17301 +#define VENC_FLENS 0x20
17302 +#define VENC_HFLTR_CTRL 0x24
17303 +#define VENC_CC_CARR_WSS_CARR 0x28
17304 +#define VENC_C_PHASE 0x2C
17305 +#define VENC_GAIN_U 0x30
17306 +#define VENC_GAIN_V 0x34
17307 +#define VENC_GAIN_Y 0x38
17308 +#define VENC_BLACK_LEVEL 0x3C
17309 +#define VENC_BLANK_LEVEL 0x40
17310 +#define VENC_X_COLOR 0x44
17311 +#define VENC_M_CONTROL 0x48
17312 +#define VENC_BSTAMP_WSS_DATA 0x4C
17313 +#define VENC_S_CARR 0x50
17314 +#define VENC_LINE21 0x54
17315 +#define VENC_LN_SEL 0x58
17316 +#define VENC_L21__WC_CTL 0x5C
17317 +#define VENC_HTRIGGER_VTRIGGER 0x60
17318 +#define VENC_SAVID__EAVID 0x64
17319 +#define VENC_FLEN__FAL 0x68
17320 +#define VENC_LAL__PHASE_RESET 0x6C
17321 +#define VENC_HS_INT_START_STOP_X 0x70
17322 +#define VENC_HS_EXT_START_STOP_X 0x74
17323 +#define VENC_VS_INT_START_X 0x78
17324 +#define VENC_VS_INT_STOP_X__VS_INT_START_Y 0x7C
17325 +#define VENC_VS_INT_STOP_Y__VS_EXT_START_X 0x80
17326 +#define VENC_VS_EXT_STOP_X__VS_EXT_START_Y 0x84
17327 +#define VENC_VS_EXT_STOP_Y 0x88
17328 +#define VENC_AVID_START_STOP_X 0x90
17329 +#define VENC_AVID_START_STOP_Y 0x94
17330 +#define VENC_FID_INT_START_X__FID_INT_START_Y 0xA0
17331 +#define VENC_FID_INT_OFFSET_Y__FID_EXT_START_X 0xA4
17332 +#define VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y 0xA8
17333 +#define VENC_TVDETGP_INT_START_STOP_X 0xB0
17334 +#define VENC_TVDETGP_INT_START_STOP_Y 0xB4
17335 +#define VENC_GEN_CTRL 0xB8
17336 +#define VENC_OUTPUT_CONTROL 0xC4
17337 +#define VENC_OUTPUT_TEST 0xC8
17338 +#define VENC_DAC_B__DAC_C 0xC8
17340 +struct venc_config {
17347 + u32 cc_carr_wss_carr;
17356 + u32 bstamp_wss_data;
17361 + u32 htrigger_vtrigger;
17362 + u32 savid__eavid;
17364 + u32 lal__phase_reset;
17365 + u32 hs_int_start_stop_x;
17366 + u32 hs_ext_start_stop_x;
17367 + u32 vs_int_start_x;
17368 + u32 vs_int_stop_x__vs_int_start_y;
17369 + u32 vs_int_stop_y__vs_ext_start_x;
17370 + u32 vs_ext_stop_x__vs_ext_start_y;
17371 + u32 vs_ext_stop_y;
17372 + u32 avid_start_stop_x;
17373 + u32 avid_start_stop_y;
17374 + u32 fid_int_start_x__fid_int_start_y;
17375 + u32 fid_int_offset_y__fid_ext_start_x;
17376 + u32 fid_ext_start_y__fid_ext_offset_y;
17377 + u32 tvdetgp_int_start_stop_x;
17378 + u32 tvdetgp_int_start_stop_y;
17383 +static const struct venc_config venc_config_pal_trm = {
17385 + .vidout_ctrl = 1,
17386 + .sync_ctrl = 0x40,
17387 + .llen = 0x35F, /* 863 */
17388 + .flens = 0x270, /* 624 */
17390 + .cc_carr_wss_carr = 0x2F7225ED,
17395 + .black_level = 0x3B,
17396 + .blank_level = 0x3B,
17398 + .m_control = 0x2,
17399 + .bstamp_wss_data = 0x3F,
17400 + .s_carr = 0x2A098ACB,
17402 + .ln_sel = 0x01290015,
17403 + .l21__wc_ctl = 0x0000F603,
17404 + .htrigger_vtrigger = 0,
17406 + .savid__eavid = 0x06A70108,
17407 + .flen__fal = 0x00180270,
17408 + .lal__phase_reset = 0x00040135,
17409 + .hs_int_start_stop_x = 0x00880358,
17410 + .hs_ext_start_stop_x = 0x000F035F,
17411 + .vs_int_start_x = 0x01A70000,
17412 + .vs_int_stop_x__vs_int_start_y = 0x000001A7,
17413 + .vs_int_stop_y__vs_ext_start_x = 0x01AF0000,
17414 + .vs_ext_stop_x__vs_ext_start_y = 0x000101AF,
17415 + .vs_ext_stop_y = 0x00000025,
17416 + .avid_start_stop_x = 0x03530083,
17417 + .avid_start_stop_y = 0x026C002E,
17418 + .fid_int_start_x__fid_int_start_y = 0x0001008A,
17419 + .fid_int_offset_y__fid_ext_start_x = 0x002E0138,
17420 + .fid_ext_start_y__fid_ext_offset_y = 0x01380001,
17422 + .tvdetgp_int_start_stop_x = 0x00140001,
17423 + .tvdetgp_int_start_stop_y = 0x00010001,
17424 + .gen_ctrl = 0x00FF0000,
17428 +static const struct venc_config venc_config_ntsc_trm = {
17430 + .vidout_ctrl = 1,
17431 + .sync_ctrl = 0x8040,
17435 + .cc_carr_wss_carr = 0x043F2631,
17440 + .black_level = 0x43,
17441 + .blank_level = 0x38,
17443 + .m_control = 0x1,
17444 + .bstamp_wss_data = 0x38,
17445 + .s_carr = 0x21F07C1F,
17447 + .ln_sel = 0x01310011,
17448 + .l21__wc_ctl = 0x0000F003,
17449 + .htrigger_vtrigger = 0,
17451 + .savid__eavid = 0x069300F4,
17452 + .flen__fal = 0x0016020C,
17453 + .lal__phase_reset = 0x00060107,
17454 + .hs_int_start_stop_x = 0x008E0350,
17455 + .hs_ext_start_stop_x = 0x000F0359,
17456 + .vs_int_start_x = 0x01A00000,
17457 + .vs_int_stop_x__vs_int_start_y = 0x020701A0,
17458 + .vs_int_stop_y__vs_ext_start_x = 0x01AC0024,
17459 + .vs_ext_stop_x__vs_ext_start_y = 0x020D01AC,
17460 + .vs_ext_stop_y = 0x00000006,
17461 + .avid_start_stop_x = 0x03480078,
17462 + .avid_start_stop_y = 0x02060024,
17463 + .fid_int_start_x__fid_int_start_y = 0x0001008A,
17464 + .fid_int_offset_y__fid_ext_start_x = 0x01AC0106,
17465 + .fid_ext_start_y__fid_ext_offset_y = 0x01060006,
17467 + .tvdetgp_int_start_stop_x = 0x00140001,
17468 + .tvdetgp_int_start_stop_y = 0x00010001,
17469 + .gen_ctrl = 0x00F90000,
17472 +static const struct venc_config venc_config_pal_bdghi = {
17474 + .vidout_ctrl = 0,
17480 + .htrigger_vtrigger = 0,
17481 + .tvdetgp_int_start_stop_x = 0x00140001,
17482 + .tvdetgp_int_start_stop_y = 0x00010001,
17483 + .gen_ctrl = 0x00FB0000,
17487 + .cc_carr_wss_carr = 0x2F7625ED,
17492 + .black_level = 0x3e,
17493 + .blank_level = 0x3e,
17494 + .m_control = 0<<2 | 1<<1,
17495 + .bstamp_wss_data = 0x42,
17496 + .s_carr = 0x2a098acb,
17497 + .l21__wc_ctl = 0<<13 | 0x16<<8 | 0<<0,
17498 + .savid__eavid = 0x06A70108,
17499 + .flen__fal = 23<<16 | 624<<0,
17500 + .lal__phase_reset = 2<<17 | 310<<0,
17501 + .hs_int_start_stop_x = 0x00920358,
17502 + .hs_ext_start_stop_x = 0x000F035F,
17503 + .vs_int_start_x = 0x1a7<<16,
17504 + .vs_int_stop_x__vs_int_start_y = 0x000601A7,
17505 + .vs_int_stop_y__vs_ext_start_x = 0x01AF0036,
17506 + .vs_ext_stop_x__vs_ext_start_y = 0x27101af,
17507 + .vs_ext_stop_y = 0x05,
17508 + .avid_start_stop_x = 0x03530082,
17509 + .avid_start_stop_y = 0x0270002E,
17510 + .fid_int_start_x__fid_int_start_y = 0x0005008A,
17511 + .fid_int_offset_y__fid_ext_start_x = 0x002E0138,
17512 + .fid_ext_start_y__fid_ext_offset_y = 0x01380005,
17515 +const struct omap_video_timings omap_dss_pal_timings = {
17518 + .pixel_clock = 13500,
17526 +EXPORT_SYMBOL(omap_dss_pal_timings);
17528 +const struct omap_video_timings omap_dss_ntsc_timings = {
17531 + .pixel_clock = 13500,
17539 +EXPORT_SYMBOL(omap_dss_ntsc_timings);
17542 + void __iomem *base;
17543 + struct mutex venc_lock;
17545 + struct regulator *vdda_dac_reg;
17548 +static inline void venc_write_reg(int idx, u32 val)
17550 + __raw_writel(val, venc.base + idx);
17553 +static inline u32 venc_read_reg(int idx)
17555 + u32 l = __raw_readl(venc.base + idx);
17559 +static void venc_write_config(const struct venc_config *config)
17561 + DSSDBG("write venc conf\n");
17563 + venc_write_reg(VENC_LLEN, config->llen);
17564 + venc_write_reg(VENC_FLENS, config->flens);
17565 + venc_write_reg(VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);
17566 + venc_write_reg(VENC_C_PHASE, config->c_phase);
17567 + venc_write_reg(VENC_GAIN_U, config->gain_u);
17568 + venc_write_reg(VENC_GAIN_V, config->gain_v);
17569 + venc_write_reg(VENC_GAIN_Y, config->gain_y);
17570 + venc_write_reg(VENC_BLACK_LEVEL, config->black_level);
17571 + venc_write_reg(VENC_BLANK_LEVEL, config->blank_level);
17572 + venc_write_reg(VENC_M_CONTROL, config->m_control);
17573 + venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
17575 + venc_write_reg(VENC_S_CARR, config->s_carr);
17576 + venc_write_reg(VENC_L21__WC_CTL, config->l21__wc_ctl);
17577 + venc_write_reg(VENC_SAVID__EAVID, config->savid__eavid);
17578 + venc_write_reg(VENC_FLEN__FAL, config->flen__fal);
17579 + venc_write_reg(VENC_LAL__PHASE_RESET, config->lal__phase_reset);
17580 + venc_write_reg(VENC_HS_INT_START_STOP_X, config->hs_int_start_stop_x);
17581 + venc_write_reg(VENC_HS_EXT_START_STOP_X, config->hs_ext_start_stop_x);
17582 + venc_write_reg(VENC_VS_INT_START_X, config->vs_int_start_x);
17583 + venc_write_reg(VENC_VS_INT_STOP_X__VS_INT_START_Y,
17584 + config->vs_int_stop_x__vs_int_start_y);
17585 + venc_write_reg(VENC_VS_INT_STOP_Y__VS_EXT_START_X,
17586 + config->vs_int_stop_y__vs_ext_start_x);
17587 + venc_write_reg(VENC_VS_EXT_STOP_X__VS_EXT_START_Y,
17588 + config->vs_ext_stop_x__vs_ext_start_y);
17589 + venc_write_reg(VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);
17590 + venc_write_reg(VENC_AVID_START_STOP_X, config->avid_start_stop_x);
17591 + venc_write_reg(VENC_AVID_START_STOP_Y, config->avid_start_stop_y);
17592 + venc_write_reg(VENC_FID_INT_START_X__FID_INT_START_Y,
17593 + config->fid_int_start_x__fid_int_start_y);
17594 + venc_write_reg(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,
17595 + config->fid_int_offset_y__fid_ext_start_x);
17596 + venc_write_reg(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,
17597 + config->fid_ext_start_y__fid_ext_offset_y);
17599 + venc_write_reg(VENC_DAC_B__DAC_C, venc_read_reg(VENC_DAC_B__DAC_C));
17600 + venc_write_reg(VENC_VIDOUT_CTRL, config->vidout_ctrl);
17601 + venc_write_reg(VENC_HFLTR_CTRL, config->hfltr_ctrl);
17602 + venc_write_reg(VENC_X_COLOR, config->x_color);
17603 + venc_write_reg(VENC_LINE21, config->line21);
17604 + venc_write_reg(VENC_LN_SEL, config->ln_sel);
17605 + venc_write_reg(VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);
17606 + venc_write_reg(VENC_TVDETGP_INT_START_STOP_X,
17607 + config->tvdetgp_int_start_stop_x);
17608 + venc_write_reg(VENC_TVDETGP_INT_START_STOP_Y,
17609 + config->tvdetgp_int_start_stop_y);
17610 + venc_write_reg(VENC_GEN_CTRL, config->gen_ctrl);
17611 + venc_write_reg(VENC_F_CONTROL, config->f_control);
17612 + venc_write_reg(VENC_SYNC_CTRL, config->sync_ctrl);
17615 +static void venc_reset(void)
17619 + venc_write_reg(VENC_F_CONTROL, 1<<8);
17620 + while (venc_read_reg(VENC_F_CONTROL) & (1<<8)) {
17622 + DSSERR("Failed to reset venc\n");
17627 + /* the magical sleep that makes things work */
17631 +static void venc_enable_clocks(int enable)
17634 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
17637 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
17641 +static const struct venc_config *venc_timings_to_config(
17642 + struct omap_video_timings *timings)
17644 + if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
17645 + return &venc_config_pal_trm;
17647 + if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
17648 + return &venc_config_ntsc_trm;
17658 +static int venc_panel_probe(struct omap_dss_device *dssdev)
17660 + dssdev->panel.timings = omap_dss_pal_timings;
17665 +static void venc_panel_remove(struct omap_dss_device *dssdev)
17669 +static int venc_panel_enable(struct omap_dss_device *dssdev)
17673 + /* wait couple of vsyncs until enabling the LCD */
17676 + if (dssdev->platform_enable)
17677 + r = dssdev->platform_enable(dssdev);
17682 +static void venc_panel_disable(struct omap_dss_device *dssdev)
17684 + if (dssdev->platform_disable)
17685 + dssdev->platform_disable(dssdev);
17687 + /* wait at least 5 vsyncs after disabling the LCD */
17692 +static int venc_panel_suspend(struct omap_dss_device *dssdev)
17694 + venc_panel_disable(dssdev);
17698 +static int venc_panel_resume(struct omap_dss_device *dssdev)
17700 + return venc_panel_enable(dssdev);
17703 +static struct omap_dss_driver venc_driver = {
17704 + .probe = venc_panel_probe,
17705 + .remove = venc_panel_remove,
17707 + .enable = venc_panel_enable,
17708 + .disable = venc_panel_disable,
17709 + .suspend = venc_panel_suspend,
17710 + .resume = venc_panel_resume,
17714 + .owner = THIS_MODULE,
17721 +int venc_init(struct platform_device *pdev)
17725 + mutex_init(&venc.venc_lock);
17727 + venc.wss_data = 0;
17729 + venc.base = ioremap(VENC_BASE, SZ_1K);
17730 + if (!venc.base) {
17731 + DSSERR("can't ioremap VENC\n");
17735 + venc.vdda_dac_reg = regulator_get(&pdev->dev, "vdda_dac");
17736 + if (IS_ERR(venc.vdda_dac_reg)) {
17737 + iounmap(venc.base);
17738 + DSSERR("can't get VDDA_DAC regulator\n");
17739 + return PTR_ERR(venc.vdda_dac_reg);
17742 + venc_enable_clocks(1);
17744 + rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
17745 + printk(KERN_INFO "OMAP VENC rev %d\n", rev_id);
17747 + venc_enable_clocks(0);
17749 + return omap_dss_register_driver(&venc_driver);
17752 +void venc_exit(void)
17754 + omap_dss_unregister_driver(&venc_driver);
17756 + regulator_put(venc.vdda_dac_reg);
17758 + iounmap(venc.base);
17761 +static void venc_power_on(struct omap_dss_device *dssdev)
17765 + venc_enable_clocks(1);
17768 + venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
17770 + dss_set_venc_output(dssdev->phy.venc.type);
17771 + dss_set_dac_pwrdn_bgz(1);
17775 + if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
17777 + else /* S-Video */
17778 + l |= (1 << 0) | (1 << 2);
17780 + if (dssdev->phy.venc.invert_polarity == false)
17783 + venc_write_reg(VENC_OUTPUT_CONTROL, l);
17785 + dispc_set_digit_size(dssdev->panel.timings.x_res,
17786 + dssdev->panel.timings.y_res/2);
17788 + regulator_enable(venc.vdda_dac_reg);
17790 + if (dssdev->platform_enable)
17791 + dssdev->platform_enable(dssdev);
17793 + dispc_enable_digit_out(1);
17796 +static void venc_power_off(struct omap_dss_device *dssdev)
17798 + venc_write_reg(VENC_OUTPUT_CONTROL, 0);
17799 + dss_set_dac_pwrdn_bgz(0);
17801 + dispc_enable_digit_out(0);
17803 + if (dssdev->platform_disable)
17804 + dssdev->platform_disable(dssdev);
17806 + regulator_disable(venc.vdda_dac_reg);
17808 + venc_enable_clocks(0);
17811 +static int venc_enable_display(struct omap_dss_device *dssdev)
17815 + DSSDBG("venc_enable_display\n");
17817 + mutex_lock(&venc.venc_lock);
17819 + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
17824 + venc_power_on(dssdev);
17826 + venc.wss_data = 0;
17828 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
17830 + mutex_unlock(&venc.venc_lock);
17835 +static void venc_disable_display(struct omap_dss_device *dssdev)
17837 + DSSDBG("venc_disable_display\n");
17839 + mutex_lock(&venc.venc_lock);
17841 + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
17844 + if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
17845 + /* suspended is the same as disabled with venc */
17846 + dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
17850 + venc_power_off(dssdev);
17852 + dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
17854 + mutex_unlock(&venc.venc_lock);
17857 +static int venc_display_suspend(struct omap_dss_device *dssdev)
17861 + DSSDBG("venc_display_suspend\n");
17863 + mutex_lock(&venc.venc_lock);
17865 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
17870 + venc_power_off(dssdev);
17872 + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
17874 + mutex_unlock(&venc.venc_lock);
17879 +static int venc_display_resume(struct omap_dss_device *dssdev)
17883 + DSSDBG("venc_display_resume\n");
17885 + mutex_lock(&venc.venc_lock);
17887 + if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
17892 + venc_power_on(dssdev);
17894 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
17896 + mutex_unlock(&venc.venc_lock);
17901 +static void venc_get_timings(struct omap_dss_device *dssdev,
17902 + struct omap_video_timings *timings)
17904 + *timings = dssdev->panel.timings;
17907 +static void venc_set_timings(struct omap_dss_device *dssdev,
17908 + struct omap_video_timings *timings)
17910 + DSSDBG("venc_set_timings\n");
17912 + /* Reset WSS data when the TV standard changes. */
17913 + if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings)))
17914 + venc.wss_data = 0;
17916 + dssdev->panel.timings = *timings;
17917 + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
17918 + /* turn the venc off and on to get new timings to use */
17919 + venc_disable_display(dssdev);
17920 + venc_enable_display(dssdev);
17924 +static int venc_check_timings(struct omap_dss_device *dssdev,
17925 + struct omap_video_timings *timings)
17927 + DSSDBG("venc_check_timings\n");
17929 + if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
17932 + if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
17938 +static u32 venc_get_wss(struct omap_dss_device *dssdev)
17940 + /* Invert due to VENC_L21_WC_CTL:INV=1 */
17941 + return (venc.wss_data >> 8) ^ 0xfffff;
17944 +static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
17946 + const struct venc_config *config;
17948 + DSSDBG("venc_set_wss\n");
17950 + mutex_lock(&venc.venc_lock);
17952 + config = venc_timings_to_config(&dssdev->panel.timings);
17954 + /* Invert due to VENC_L21_WC_CTL:INV=1 */
17955 + venc.wss_data = (wss ^ 0xfffff) << 8;
17957 + venc_enable_clocks(1);
17959 + venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
17962 + venc_enable_clocks(0);
17964 + mutex_unlock(&venc.venc_lock);
17969 +static enum omap_dss_update_mode venc_display_get_update_mode(
17970 + struct omap_dss_device *dssdev)
17972 + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
17973 + return OMAP_DSS_UPDATE_AUTO;
17975 + return OMAP_DSS_UPDATE_DISABLED;
17978 +int venc_init_display(struct omap_dss_device *dssdev)
17980 + DSSDBG("init_display\n");
17982 + dssdev->enable = venc_enable_display;
17983 + dssdev->disable = venc_disable_display;
17984 + dssdev->suspend = venc_display_suspend;
17985 + dssdev->resume = venc_display_resume;
17986 + dssdev->get_timings = venc_get_timings;
17987 + dssdev->set_timings = venc_set_timings;
17988 + dssdev->check_timings = venc_check_timings;
17989 + dssdev->get_wss = venc_get_wss;
17990 + dssdev->set_wss = venc_set_wss;
17991 + dssdev->get_update_mode = venc_display_get_update_mode;
17996 +void venc_dump_regs(struct seq_file *s)
17998 +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
18000 + venc_enable_clocks(1);
18002 + DUMPREG(VENC_F_CONTROL);
18003 + DUMPREG(VENC_VIDOUT_CTRL);
18004 + DUMPREG(VENC_SYNC_CTRL);
18005 + DUMPREG(VENC_LLEN);
18006 + DUMPREG(VENC_FLENS);
18007 + DUMPREG(VENC_HFLTR_CTRL);
18008 + DUMPREG(VENC_CC_CARR_WSS_CARR);
18009 + DUMPREG(VENC_C_PHASE);
18010 + DUMPREG(VENC_GAIN_U);
18011 + DUMPREG(VENC_GAIN_V);
18012 + DUMPREG(VENC_GAIN_Y);
18013 + DUMPREG(VENC_BLACK_LEVEL);
18014 + DUMPREG(VENC_BLANK_LEVEL);
18015 + DUMPREG(VENC_X_COLOR);
18016 + DUMPREG(VENC_M_CONTROL);
18017 + DUMPREG(VENC_BSTAMP_WSS_DATA);
18018 + DUMPREG(VENC_S_CARR);
18019 + DUMPREG(VENC_LINE21);
18020 + DUMPREG(VENC_LN_SEL);
18021 + DUMPREG(VENC_L21__WC_CTL);
18022 + DUMPREG(VENC_HTRIGGER_VTRIGGER);
18023 + DUMPREG(VENC_SAVID__EAVID);
18024 + DUMPREG(VENC_FLEN__FAL);
18025 + DUMPREG(VENC_LAL__PHASE_RESET);
18026 + DUMPREG(VENC_HS_INT_START_STOP_X);
18027 + DUMPREG(VENC_HS_EXT_START_STOP_X);
18028 + DUMPREG(VENC_VS_INT_START_X);
18029 + DUMPREG(VENC_VS_INT_STOP_X__VS_INT_START_Y);
18030 + DUMPREG(VENC_VS_INT_STOP_Y__VS_EXT_START_X);
18031 + DUMPREG(VENC_VS_EXT_STOP_X__VS_EXT_START_Y);
18032 + DUMPREG(VENC_VS_EXT_STOP_Y);
18033 + DUMPREG(VENC_AVID_START_STOP_X);
18034 + DUMPREG(VENC_AVID_START_STOP_Y);
18035 + DUMPREG(VENC_FID_INT_START_X__FID_INT_START_Y);
18036 + DUMPREG(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);
18037 + DUMPREG(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);
18038 + DUMPREG(VENC_TVDETGP_INT_START_STOP_X);
18039 + DUMPREG(VENC_TVDETGP_INT_START_STOP_Y);
18040 + DUMPREG(VENC_GEN_CTRL);
18041 + DUMPREG(VENC_OUTPUT_CONTROL);
18042 + DUMPREG(VENC_OUTPUT_TEST);
18044 + venc_enable_clocks(0);
18048 diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
18049 new file mode 100644
18050 index 0000000..bb694cc
18052 +++ b/drivers/video/omap2/omapfb/Kconfig
18054 +menuconfig FB_OMAP2
18055 + tristate "OMAP2/3 frame buffer support (EXPERIMENTAL)"
18056 + depends on FB && OMAP2_DSS
18058 + select OMAP2_VRAM
18059 + select OMAP2_VRFB
18060 + select FB_CFB_FILLRECT
18061 + select FB_CFB_COPYAREA
18062 + select FB_CFB_IMAGEBLIT
18064 + Frame buffer driver for OMAP2/3 based boards.
18066 +config FB_OMAP2_DEBUG_SUPPORT
18067 + bool "Debug support for OMAP2/3 FB"
18069 + depends on FB_OMAP2
18071 + Support for debug output. You have to enable the actual printing
18072 + with debug module parameter.
18074 +config FB_OMAP2_FORCE_AUTO_UPDATE
18075 + bool "Force main display to automatic update mode"
18076 + depends on FB_OMAP2
18078 + Forces main display to automatic update mode (if possible),
18079 + and also enables tearsync (if possible). By default
18080 + displays that support manual update are started in manual
18083 +config FB_OMAP2_NUM_FBS
18084 + int "Number of framebuffers"
18087 + depends on FB_OMAP2
18089 + Select the number of framebuffers created. OMAP2/3 has 3 overlays
18090 + so normally this would be 3.
18091 diff --git a/drivers/video/omap2/omapfb/Makefile b/drivers/video/omap2/omapfb/Makefile
18092 new file mode 100644
18093 index 0000000..51c2e00
18095 +++ b/drivers/video/omap2/omapfb/Makefile
18097 +obj-$(CONFIG_FB_OMAP2) += omapfb.o
18098 +omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o
18099 diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
18100 new file mode 100644
18101 index 0000000..70fb64e
18103 +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
18106 + * linux/drivers/video/omap2/omapfb-ioctl.c
18108 + * Copyright (C) 2008 Nokia Corporation
18109 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
18111 + * Some code and ideas taken from drivers/video/omap/ driver
18114 + * This program is free software; you can redistribute it and/or modify it
18115 + * under the terms of the GNU General Public License version 2 as published by
18116 + * the Free Software Foundation.
18118 + * This program is distributed in the hope that it will be useful, but WITHOUT
18119 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18120 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18123 + * You should have received a copy of the GNU General Public License along with
18124 + * this program. If not, see <http://www.gnu.org/licenses/>.
18127 +#include <linux/fb.h>
18128 +#include <linux/device.h>
18129 +#include <linux/uaccess.h>
18130 +#include <linux/platform_device.h>
18131 +#include <linux/mm.h>
18132 +#include <linux/omapfb.h>
18133 +#include <linux/vmalloc.h>
18135 +#include <mach/display.h>
18136 +#include <mach/vrfb.h>
18137 +#include <mach/vram.h>
18139 +#include "omapfb.h"
18141 +static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
18143 + struct omapfb_info *ofbi = FB2OFB(fbi);
18144 + struct omapfb2_device *fbdev = ofbi->fbdev;
18145 + struct omap_dss_device *display = fb2display(fbi);
18146 + struct omap_overlay *ovl;
18147 + struct omap_overlay_info info;
18150 + DBG("omapfb_setup_plane\n");
18152 + if (ofbi->num_overlays != 1) {
18157 + /* XXX uses only the first overlay */
18158 + ovl = ofbi->overlays[0];
18160 + if (pi->enabled && !ofbi->region.size) {
18162 + * This plane's memory was freed, can't enable it
18163 + * until it's reallocated.
18169 + ovl->get_overlay_info(ovl, &info);
18171 + info.pos_x = pi->pos_x;
18172 + info.pos_y = pi->pos_y;
18173 + info.out_width = pi->out_width;
18174 + info.out_height = pi->out_height;
18175 + info.enabled = pi->enabled;
18177 + r = ovl->set_overlay_info(ovl, &info);
18181 + if (ovl->manager) {
18182 + r = ovl->manager->apply(ovl->manager);
18190 + if (display->sync)
18191 + display->sync(display);
18193 + display->get_resolution(display, &w, &h);
18195 + if (display->update)
18196 + display->update(display, 0, 0, w, h);
18201 + dev_err(fbdev->dev, "setup_plane failed\n");
18205 +static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
18207 + struct omapfb_info *ofbi = FB2OFB(fbi);
18209 + if (ofbi->num_overlays != 1) {
18210 + memset(pi, 0, sizeof(*pi));
18212 + struct omap_overlay_info *ovli;
18213 + struct omap_overlay *ovl;
18215 + ovl = ofbi->overlays[0];
18216 + ovli = &ovl->info;
18218 + pi->pos_x = ovli->pos_x;
18219 + pi->pos_y = ovli->pos_y;
18220 + pi->enabled = ovli->enabled;
18221 + pi->channel_out = 0; /* xxx */
18223 + pi->out_width = ovli->out_width;
18224 + pi->out_height = ovli->out_height;
18230 +static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
18232 + struct omapfb_info *ofbi = FB2OFB(fbi);
18233 + struct omapfb2_device *fbdev = ofbi->fbdev;
18234 + struct omapfb2_mem_region *rg;
18238 + if (mi->type > OMAPFB_MEMTYPE_MAX)
18241 + size = PAGE_ALIGN(mi->size);
18243 + rg = &ofbi->region;
18245 + for (i = 0; i < ofbi->num_overlays; i++) {
18246 + if (ofbi->overlays[i]->info.enabled)
18250 + if (rg->size != size || rg->type != mi->type) {
18251 + r = omapfb_realloc_fbmem(fbi, size, mi->type);
18253 + dev_err(fbdev->dev, "realloc fbmem failed\n");
18261 +static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
18263 + struct omapfb_info *ofbi = FB2OFB(fbi);
18264 + struct omapfb2_mem_region *rg;
18266 + rg = &ofbi->region;
18267 + memset(mi, 0, sizeof(*mi));
18269 + mi->size = rg->size;
18270 + mi->type = rg->type;
18275 +static int omapfb_update_window(struct fb_info *fbi,
18276 + u32 x, u32 y, u32 w, u32 h)
18278 + struct omap_dss_device *display = fb2display(fbi);
18284 + if (w == 0 || h == 0)
18287 + display->get_resolution(display, &dw, &dh);
18289 + if (x + w > dw || y + h > dh)
18292 + display->update(display, x, y, w, h);
18297 +static int omapfb_set_update_mode(struct fb_info *fbi,
18298 + enum omapfb_update_mode mode)
18300 + struct omap_dss_device *display = fb2display(fbi);
18301 + enum omap_dss_update_mode um;
18304 + if (!display || !display->set_update_mode)
18308 + case OMAPFB_UPDATE_DISABLED:
18309 + um = OMAP_DSS_UPDATE_DISABLED;
18312 + case OMAPFB_AUTO_UPDATE:
18313 + um = OMAP_DSS_UPDATE_AUTO;
18316 + case OMAPFB_MANUAL_UPDATE:
18317 + um = OMAP_DSS_UPDATE_MANUAL;
18324 + r = display->set_update_mode(display, um);
18329 +static int omapfb_get_update_mode(struct fb_info *fbi,
18330 + enum omapfb_update_mode *mode)
18332 + struct omap_dss_device *display = fb2display(fbi);
18333 + enum omap_dss_update_mode m;
18335 + if (!display || !display->get_update_mode)
18338 + m = display->get_update_mode(display);
18341 + case OMAP_DSS_UPDATE_DISABLED:
18342 + *mode = OMAPFB_UPDATE_DISABLED;
18344 + case OMAP_DSS_UPDATE_AUTO:
18345 + *mode = OMAPFB_AUTO_UPDATE;
18347 + case OMAP_DSS_UPDATE_MANUAL:
18348 + *mode = OMAPFB_MANUAL_UPDATE;
18357 +/* XXX this color key handling is a hack... */
18358 +static struct omapfb_color_key omapfb_color_keys[2];
18360 +static int _omapfb_set_color_key(struct omap_overlay_manager *mgr,
18361 + struct omapfb_color_key *ck)
18363 + struct omap_overlay_manager_info info;
18364 + enum omap_dss_trans_key_type kt;
18367 + mgr->get_manager_info(mgr, &info);
18369 + if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {
18370 + info.trans_enabled = false;
18371 + omapfb_color_keys[mgr->id] = *ck;
18373 + r = mgr->set_manager_info(mgr, &info);
18377 + r = mgr->apply(mgr);
18382 + switch (ck->key_type) {
18383 + case OMAPFB_COLOR_KEY_GFX_DST:
18384 + kt = OMAP_DSS_COLOR_KEY_GFX_DST;
18386 + case OMAPFB_COLOR_KEY_VID_SRC:
18387 + kt = OMAP_DSS_COLOR_KEY_VID_SRC;
18393 + info.default_color = ck->background;
18394 + info.trans_key = ck->trans_key;
18395 + info.trans_key_type = kt;
18396 + info.trans_enabled = true;
18398 + omapfb_color_keys[mgr->id] = *ck;
18400 + r = mgr->set_manager_info(mgr, &info);
18404 + r = mgr->apply(mgr);
18409 +static int omapfb_set_color_key(struct fb_info *fbi,
18410 + struct omapfb_color_key *ck)
18412 + struct omapfb_info *ofbi = FB2OFB(fbi);
18413 + struct omapfb2_device *fbdev = ofbi->fbdev;
18416 + struct omap_overlay_manager *mgr = NULL;
18418 + omapfb_lock(fbdev);
18420 + for (i = 0; i < ofbi->num_overlays; i++) {
18421 + if (ofbi->overlays[i]->manager) {
18422 + mgr = ofbi->overlays[i]->manager;
18432 + r = _omapfb_set_color_key(mgr, ck);
18434 + omapfb_unlock(fbdev);
18439 +static int omapfb_get_color_key(struct fb_info *fbi,
18440 + struct omapfb_color_key *ck)
18442 + struct omapfb_info *ofbi = FB2OFB(fbi);
18443 + struct omapfb2_device *fbdev = ofbi->fbdev;
18444 + struct omap_overlay_manager *mgr = NULL;
18448 + omapfb_lock(fbdev);
18450 + for (i = 0; i < ofbi->num_overlays; i++) {
18451 + if (ofbi->overlays[i]->manager) {
18452 + mgr = ofbi->overlays[i]->manager;
18462 + *ck = omapfb_color_keys[mgr->id];
18464 + omapfb_unlock(fbdev);
18469 +static int omapfb_memory_read(struct fb_info *fbi,
18470 + struct omapfb_memory_read *mr)
18472 + struct omap_dss_device *display = fb2display(fbi);
18476 + if (!display || !display->memory_read)
18479 + if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
18482 + if (mr->w * mr->h * 3 > mr->buffer_size)
18485 + buf = vmalloc(mr->buffer_size);
18487 + DBG("vmalloc failed\n");
18491 + r = display->memory_read(display, buf, mr->buffer_size,
18492 + mr->x, mr->y, mr->w, mr->h);
18495 + if (copy_to_user(mr->buffer, buf, mr->buffer_size))
18504 +static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,
18505 + struct omapfb_ovl_colormode *mode)
18507 + int ovl_idx = mode->overlay_idx;
18508 + int mode_idx = mode->mode_idx;
18509 + struct omap_overlay *ovl;
18510 + enum omap_color_mode supported_modes;
18511 + struct fb_var_screeninfo var;
18514 + if (ovl_idx >= fbdev->num_overlays)
18516 + ovl = fbdev->overlays[ovl_idx];
18517 + supported_modes = ovl->supported_modes;
18519 + mode_idx = mode->mode_idx;
18521 + for (i = 0; i < sizeof(supported_modes) * 8; i++) {
18522 + if (!(supported_modes & (1 << i)))
18525 + * It's possible that the FB doesn't support a mode
18526 + * that is supported by the overlay, so call the
18527 + * following here.
18529 + if (dss_mode_to_fb_mode(1 << i, &var) < 0)
18533 + if (mode_idx < 0)
18537 + if (i == sizeof(supported_modes) * 8)
18540 + mode->bits_per_pixel = var.bits_per_pixel;
18541 + mode->nonstd = var.nonstd;
18542 + mode->red = var.red;
18543 + mode->green = var.green;
18544 + mode->blue = var.blue;
18545 + mode->transp = var.transp;
18550 +static int omapfb_wait_for_go(struct fb_info *fbi)
18552 + struct omapfb_info *ofbi = FB2OFB(fbi);
18556 + for (i = 0; i < ofbi->num_overlays; ++i) {
18557 + struct omap_overlay *ovl = ofbi->overlays[i];
18558 + r = ovl->wait_for_go(ovl);
18566 +int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
18568 + struct omapfb_info *ofbi = FB2OFB(fbi);
18569 + struct omapfb2_device *fbdev = ofbi->fbdev;
18570 + struct omap_dss_device *display = fb2display(fbi);
18573 + struct omapfb_update_window_old uwnd_o;
18574 + struct omapfb_update_window uwnd;
18575 + struct omapfb_plane_info plane_info;
18576 + struct omapfb_caps caps;
18577 + struct omapfb_mem_info mem_info;
18578 + struct omapfb_color_key color_key;
18579 + struct omapfb_ovl_colormode ovl_colormode;
18580 + enum omapfb_update_mode update_mode;
18582 + struct omapfb_memory_read memory_read;
18583 + struct omapfb_vram_info vram_info;
18589 + case OMAPFB_SYNC_GFX:
18590 + DBG("ioctl SYNC_GFX\n");
18591 + if (!display || !display->sync) {
18592 + /* DSS1 never returns an error here, so we neither */
18597 + r = display->sync(display);
18600 + case OMAPFB_UPDATE_WINDOW_OLD:
18601 + DBG("ioctl UPDATE_WINDOW_OLD\n");
18602 + if (!display || !display->update) {
18607 + if (copy_from_user(&p.uwnd_o,
18608 + (void __user *)arg,
18609 + sizeof(p.uwnd_o))) {
18614 + r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y,
18615 + p.uwnd_o.width, p.uwnd_o.height);
18618 + case OMAPFB_UPDATE_WINDOW:
18619 + DBG("ioctl UPDATE_WINDOW\n");
18620 + if (!display || !display->update) {
18625 + if (copy_from_user(&p.uwnd, (void __user *)arg,
18626 + sizeof(p.uwnd))) {
18631 + r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y,
18632 + p.uwnd.width, p.uwnd.height);
18635 + case OMAPFB_SETUP_PLANE:
18636 + DBG("ioctl SETUP_PLANE\n");
18637 + if (copy_from_user(&p.plane_info, (void __user *)arg,
18638 + sizeof(p.plane_info)))
18641 + r = omapfb_setup_plane(fbi, &p.plane_info);
18644 + case OMAPFB_QUERY_PLANE:
18645 + DBG("ioctl QUERY_PLANE\n");
18646 + r = omapfb_query_plane(fbi, &p.plane_info);
18649 + if (copy_to_user((void __user *)arg, &p.plane_info,
18650 + sizeof(p.plane_info)))
18654 + case OMAPFB_SETUP_MEM:
18655 + DBG("ioctl SETUP_MEM\n");
18656 + if (copy_from_user(&p.mem_info, (void __user *)arg,
18657 + sizeof(p.mem_info)))
18660 + r = omapfb_setup_mem(fbi, &p.mem_info);
18663 + case OMAPFB_QUERY_MEM:
18664 + DBG("ioctl QUERY_MEM\n");
18665 + r = omapfb_query_mem(fbi, &p.mem_info);
18668 + if (copy_to_user((void __user *)arg, &p.mem_info,
18669 + sizeof(p.mem_info)))
18673 + case OMAPFB_GET_CAPS:
18674 + DBG("ioctl GET_CAPS\n");
18680 + memset(&p.caps, 0, sizeof(p.caps));
18681 + p.caps.ctrl = display->caps;
18683 + if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
18687 + case OMAPFB_GET_OVERLAY_COLORMODE:
18688 + DBG("ioctl GET_OVERLAY_COLORMODE\n");
18689 + if (copy_from_user(&p.ovl_colormode, (void __user *)arg,
18690 + sizeof(p.ovl_colormode))) {
18694 + r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);
18697 + if (copy_to_user((void __user *)arg, &p.ovl_colormode,
18698 + sizeof(p.ovl_colormode)))
18702 + case OMAPFB_SET_UPDATE_MODE:
18703 + DBG("ioctl SET_UPDATE_MODE\n");
18704 + if (get_user(p.update_mode, (int __user *)arg))
18707 + r = omapfb_set_update_mode(fbi, p.update_mode);
18710 + case OMAPFB_GET_UPDATE_MODE:
18711 + DBG("ioctl GET_UPDATE_MODE\n");
18712 + r = omapfb_get_update_mode(fbi, &p.update_mode);
18715 + if (put_user(p.update_mode,
18716 + (enum omapfb_update_mode __user *)arg))
18720 + case OMAPFB_SET_COLOR_KEY:
18721 + DBG("ioctl SET_COLOR_KEY\n");
18722 + if (copy_from_user(&p.color_key, (void __user *)arg,
18723 + sizeof(p.color_key)))
18726 + r = omapfb_set_color_key(fbi, &p.color_key);
18729 + case OMAPFB_GET_COLOR_KEY:
18730 + DBG("ioctl GET_COLOR_KEY\n");
18731 + r = omapfb_get_color_key(fbi, &p.color_key);
18734 + if (copy_to_user((void __user *)arg, &p.color_key,
18735 + sizeof(p.color_key)))
18739 + case OMAPFB_WAITFORVSYNC:
18740 + DBG("ioctl WAITFORVSYNC\n");
18746 + r = display->wait_vsync(display);
18749 + case OMAPFB_WAITFORGO:
18750 + DBG("ioctl WAITFORGO\n");
18756 + r = omapfb_wait_for_go(fbi);
18759 + /* LCD and CTRL tests do the same thing for backward
18760 + * compatibility */
18761 + case OMAPFB_LCD_TEST:
18762 + DBG("ioctl LCD_TEST\n");
18763 + if (get_user(p.test_num, (int __user *)arg)) {
18767 + if (!display || !display->run_test) {
18772 + r = display->run_test(display, p.test_num);
18776 + case OMAPFB_CTRL_TEST:
18777 + DBG("ioctl CTRL_TEST\n");
18778 + if (get_user(p.test_num, (int __user *)arg)) {
18782 + if (!display || !display->run_test) {
18787 + r = display->run_test(display, p.test_num);
18791 + case OMAPFB_MEMORY_READ:
18792 + DBG("ioctl MEMORY_READ\n");
18794 + if (copy_from_user(&p.memory_read, (void __user *)arg,
18795 + sizeof(p.memory_read))) {
18800 + r = omapfb_memory_read(fbi, &p.memory_read);
18804 + case OMAPFB_GET_VRAM_INFO: {
18805 + unsigned long vram, free, largest;
18807 + DBG("ioctl GET_VRAM_INFO\n");
18809 + omap_vram_get_info(&vram, &free, &largest);
18810 + p.vram_info.total = vram;
18811 + p.vram_info.free = free;
18812 + p.vram_info.largest_free_block = largest;
18814 + if (copy_to_user((void __user *)arg, &p.vram_info,
18815 + sizeof(p.vram_info)))
18821 + dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
18826 + DBG("ioctl failed: %d\n", r);
18832 diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
18833 new file mode 100644
18834 index 0000000..7f5ec3b
18836 +++ b/drivers/video/omap2/omapfb/omapfb-main.c
18839 + * linux/drivers/video/omap2/omapfb-main.c
18841 + * Copyright (C) 2008 Nokia Corporation
18842 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
18844 + * Some code and ideas taken from drivers/video/omap/ driver
18847 + * This program is free software; you can redistribute it and/or modify it
18848 + * under the terms of the GNU General Public License version 2 as published by
18849 + * the Free Software Foundation.
18851 + * This program is distributed in the hope that it will be useful, but WITHOUT
18852 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18853 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18856 + * You should have received a copy of the GNU General Public License along with
18857 + * this program. If not, see <http://www.gnu.org/licenses/>.
18860 +#include <linux/module.h>
18861 +#include <linux/delay.h>
18862 +#include <linux/fb.h>
18863 +#include <linux/dma-mapping.h>
18864 +#include <linux/vmalloc.h>
18865 +#include <linux/device.h>
18866 +#include <linux/platform_device.h>
18867 +#include <linux/omapfb.h>
18869 +#include <mach/display.h>
18870 +#include <mach/vram.h>
18871 +#include <mach/vrfb.h>
18873 +#include "omapfb.h"
18875 +#define MODULE_NAME "omapfb"
18877 +#define OMAPFB_PLANE_XRES_MIN 8
18878 +#define OMAPFB_PLANE_YRES_MIN 8
18880 +static char *def_mode;
18881 +static char *def_vram;
18882 +static int def_vrfb;
18883 +static int def_rotate;
18884 +static int def_mirror;
18887 +unsigned int omapfb_debug;
18888 +module_param_named(debug, omapfb_debug, bool, 0644);
18889 +static unsigned int omapfb_test_pattern;
18890 +module_param_named(test, omapfb_test_pattern, bool, 0644);
18893 +static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
18896 +static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
18898 + struct fb_var_screeninfo *var = &fbi->var;
18899 + struct fb_fix_screeninfo *fix = &fbi->fix;
18900 + void __iomem *addr = fbi->screen_base;
18901 + const unsigned bytespp = var->bits_per_pixel >> 3;
18902 + const unsigned line_len = fix->line_length / bytespp;
18904 + int r = (color >> 16) & 0xff;
18905 + int g = (color >> 8) & 0xff;
18906 + int b = (color >> 0) & 0xff;
18908 + if (var->bits_per_pixel == 16) {
18909 + u16 __iomem *p = (u16 __iomem *)addr;
18910 + p += y * line_len + x;
18912 + r = r * 32 / 256;
18913 + g = g * 64 / 256;
18914 + b = b * 32 / 256;
18916 + __raw_writew((r << 11) | (g << 5) | (b << 0), p);
18917 + } else if (var->bits_per_pixel == 24) {
18918 + u8 __iomem *p = (u8 __iomem *)addr;
18919 + p += (y * line_len + x) * 3;
18921 + __raw_writeb(b, p + 0);
18922 + __raw_writeb(g, p + 1);
18923 + __raw_writeb(r, p + 2);
18924 + } else if (var->bits_per_pixel == 32) {
18925 + u32 __iomem *p = (u32 __iomem *)addr;
18926 + p += y * line_len + x;
18927 + __raw_writel(color, p);
18931 +static void fill_fb(struct fb_info *fbi)
18933 + struct fb_var_screeninfo *var = &fbi->var;
18934 + const short w = var->xres_virtual;
18935 + const short h = var->yres_virtual;
18936 + void __iomem *addr = fbi->screen_base;
18942 + DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);
18944 + for (y = 0; y < h; y++) {
18945 + for (x = 0; x < w; x++) {
18946 + if (x < 20 && y < 20)
18947 + draw_pixel(fbi, x, y, 0xffffff);
18948 + else if (x < 20 && (y > 20 && y < h - 20))
18949 + draw_pixel(fbi, x, y, 0xff);
18950 + else if (y < 20 && (x > 20 && x < w - 20))
18951 + draw_pixel(fbi, x, y, 0xff00);
18952 + else if (x > w - 20 && (y > 20 && y < h - 20))
18953 + draw_pixel(fbi, x, y, 0xff0000);
18954 + else if (y > h - 20 && (x > 20 && x < w - 20))
18955 + draw_pixel(fbi, x, y, 0xffff00);
18956 + else if (x == 20 || x == w - 20 ||
18957 + y == 20 || y == h - 20)
18958 + draw_pixel(fbi, x, y, 0xffffff);
18959 + else if (x == y || w - x == h - y)
18960 + draw_pixel(fbi, x, y, 0xff00ff);
18961 + else if (w - x == y || x == h - y)
18962 + draw_pixel(fbi, x, y, 0x00ffff);
18963 + else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) {
18964 + int t = x * 3 / w;
18965 + unsigned r = 0, g = 0, b = 0;
18967 + if (var->bits_per_pixel == 16) {
18969 + b = (y % 32) * 256 / 32;
18971 + g = (y % 64) * 256 / 64;
18973 + r = (y % 32) * 256 / 32;
18982 + c = (r << 16) | (g << 8) | (b << 0);
18983 + draw_pixel(fbi, x, y, c);
18985 + draw_pixel(fbi, x, y, 0);
18992 +static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot)
18994 + struct vrfb *vrfb = &ofbi->region.vrfb;
18998 + case FB_ROTATE_UR:
19001 + case FB_ROTATE_CW:
19002 + offset = vrfb->yoffset;
19004 + case FB_ROTATE_UD:
19005 + offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;
19007 + case FB_ROTATE_CCW:
19008 + offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;
19014 + offset *= vrfb->bytespp;
19019 +static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi, int rot)
19021 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
19022 + return ofbi->region.vrfb.paddr[rot]
19023 + + omapfb_get_vrfb_offset(ofbi, rot);
19025 + return ofbi->region.paddr;
19029 +static u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)
19031 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
19032 + return ofbi->region.vrfb.paddr[0];
19034 + return ofbi->region.paddr;
19037 +static void __iomem *omapfb_get_region_vaddr(struct omapfb_info *ofbi)
19039 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
19040 + return ofbi->region.vrfb.vaddr[0];
19042 + return ofbi->region.vaddr;
19045 +static struct omapfb_colormode omapfb_colormodes[] = {
19047 + .dssmode = OMAP_DSS_COLOR_UYVY,
19048 + .bits_per_pixel = 16,
19049 + .nonstd = OMAPFB_COLOR_YUV422,
19051 + .dssmode = OMAP_DSS_COLOR_YUV2,
19052 + .bits_per_pixel = 16,
19053 + .nonstd = OMAPFB_COLOR_YUY422,
19055 + .dssmode = OMAP_DSS_COLOR_ARGB16,
19056 + .bits_per_pixel = 16,
19057 + .red = { .length = 4, .offset = 8, .msb_right = 0 },
19058 + .green = { .length = 4, .offset = 4, .msb_right = 0 },
19059 + .blue = { .length = 4, .offset = 0, .msb_right = 0 },
19060 + .transp = { .length = 4, .offset = 12, .msb_right = 0 },
19062 + .dssmode = OMAP_DSS_COLOR_RGB16,
19063 + .bits_per_pixel = 16,
19064 + .red = { .length = 5, .offset = 11, .msb_right = 0 },
19065 + .green = { .length = 6, .offset = 5, .msb_right = 0 },
19066 + .blue = { .length = 5, .offset = 0, .msb_right = 0 },
19067 + .transp = { .length = 0, .offset = 0, .msb_right = 0 },
19069 + .dssmode = OMAP_DSS_COLOR_RGB24P,
19070 + .bits_per_pixel = 24,
19071 + .red = { .length = 8, .offset = 16, .msb_right = 0 },
19072 + .green = { .length = 8, .offset = 8, .msb_right = 0 },
19073 + .blue = { .length = 8, .offset = 0, .msb_right = 0 },
19074 + .transp = { .length = 0, .offset = 0, .msb_right = 0 },
19076 + .dssmode = OMAP_DSS_COLOR_RGB24U,
19077 + .bits_per_pixel = 32,
19078 + .red = { .length = 8, .offset = 16, .msb_right = 0 },
19079 + .green = { .length = 8, .offset = 8, .msb_right = 0 },
19080 + .blue = { .length = 8, .offset = 0, .msb_right = 0 },
19081 + .transp = { .length = 0, .offset = 0, .msb_right = 0 },
19083 + .dssmode = OMAP_DSS_COLOR_ARGB32,
19084 + .bits_per_pixel = 32,
19085 + .red = { .length = 8, .offset = 16, .msb_right = 0 },
19086 + .green = { .length = 8, .offset = 8, .msb_right = 0 },
19087 + .blue = { .length = 8, .offset = 0, .msb_right = 0 },
19088 + .transp = { .length = 8, .offset = 24, .msb_right = 0 },
19090 + .dssmode = OMAP_DSS_COLOR_RGBA32,
19091 + .bits_per_pixel = 32,
19092 + .red = { .length = 8, .offset = 24, .msb_right = 0 },
19093 + .green = { .length = 8, .offset = 16, .msb_right = 0 },
19094 + .blue = { .length = 8, .offset = 8, .msb_right = 0 },
19095 + .transp = { .length = 8, .offset = 0, .msb_right = 0 },
19097 + .dssmode = OMAP_DSS_COLOR_RGBX32,
19098 + .bits_per_pixel = 32,
19099 + .red = { .length = 8, .offset = 24, .msb_right = 0 },
19100 + .green = { .length = 8, .offset = 16, .msb_right = 0 },
19101 + .blue = { .length = 8, .offset = 8, .msb_right = 0 },
19102 + .transp = { .length = 0, .offset = 0, .msb_right = 0 },
19106 +static bool cmp_var_to_colormode(struct fb_var_screeninfo *var,
19107 + struct omapfb_colormode *color)
19109 + bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)
19111 + return f1->length == f2->length &&
19112 + f1->offset == f2->offset &&
19113 + f1->msb_right == f2->msb_right;
19116 + if (var->bits_per_pixel == 0 ||
19117 + var->red.length == 0 ||
19118 + var->blue.length == 0 ||
19119 + var->green.length == 0)
19122 + return var->bits_per_pixel == color->bits_per_pixel &&
19123 + cmp_component(&var->red, &color->red) &&
19124 + cmp_component(&var->green, &color->green) &&
19125 + cmp_component(&var->blue, &color->blue) &&
19126 + cmp_component(&var->transp, &color->transp);
19129 +static void assign_colormode_to_var(struct fb_var_screeninfo *var,
19130 + struct omapfb_colormode *color)
19132 + var->bits_per_pixel = color->bits_per_pixel;
19133 + var->nonstd = color->nonstd;
19134 + var->red = color->red;
19135 + var->green = color->green;
19136 + var->blue = color->blue;
19137 + var->transp = color->transp;
19140 +static enum omap_color_mode fb_mode_to_dss_mode(struct fb_var_screeninfo *var)
19142 + enum omap_color_mode dssmode;
19145 + /* first match with nonstd field */
19146 + if (var->nonstd) {
19147 + for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
19148 + struct omapfb_colormode *mode = &omapfb_colormodes[i];
19149 + if (var->nonstd == mode->nonstd) {
19150 + assign_colormode_to_var(var, mode);
19151 + return mode->dssmode;
19158 + /* then try exact match of bpp and colors */
19159 + for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
19160 + struct omapfb_colormode *mode = &omapfb_colormodes[i];
19161 + if (cmp_var_to_colormode(var, mode)) {
19162 + assign_colormode_to_var(var, mode);
19163 + return mode->dssmode;
19167 + /* match with bpp if user has not filled color fields
19169 + switch (var->bits_per_pixel) {
19171 + dssmode = OMAP_DSS_COLOR_CLUT1;
19174 + dssmode = OMAP_DSS_COLOR_CLUT2;
19177 + dssmode = OMAP_DSS_COLOR_CLUT4;
19180 + dssmode = OMAP_DSS_COLOR_CLUT8;
19183 + dssmode = OMAP_DSS_COLOR_RGB12U;
19186 + dssmode = OMAP_DSS_COLOR_RGB16;
19189 + dssmode = OMAP_DSS_COLOR_RGB24P;
19192 + dssmode = OMAP_DSS_COLOR_RGB24U;
19198 + for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
19199 + struct omapfb_colormode *mode = &omapfb_colormodes[i];
19200 + if (dssmode == mode->dssmode) {
19201 + assign_colormode_to_var(var, mode);
19202 + return mode->dssmode;
19209 +int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
19210 + struct fb_var_screeninfo *var)
19214 + for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
19215 + struct omapfb_colormode *mode = &omapfb_colormodes[i];
19216 + if (dssmode == mode->dssmode) {
19217 + assign_colormode_to_var(var, mode);
19224 +void set_fb_fix(struct fb_info *fbi)
19226 + struct fb_fix_screeninfo *fix = &fbi->fix;
19227 + struct fb_var_screeninfo *var = &fbi->var;
19228 + struct omapfb_info *ofbi = FB2OFB(fbi);
19229 + struct omapfb2_mem_region *rg = &ofbi->region;
19231 + DBG("set_fb_fix\n");
19233 + /* used by open/write in fbmem.c */
19234 + fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
19236 + DBG("changing rotation to %d\n", var->rotate);
19238 + /* used by mmap in fbmem.c */
19239 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
19240 + switch (var->nonstd) {
19241 + case OMAPFB_COLOR_YUV422:
19242 + case OMAPFB_COLOR_YUY422:
19243 + fix->line_length =
19244 + (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
19247 + fix->line_length =
19248 + (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
19252 + fix->line_length =
19253 + (var->xres_virtual * var->bits_per_pixel) >> 3;
19254 + fix->smem_start = omapfb_get_region_paddr(ofbi);
19255 + fix->smem_len = rg->size;
19257 + fix->type = FB_TYPE_PACKED_PIXELS;
19260 + fix->visual = FB_VISUAL_PSEUDOCOLOR;
19262 + switch (var->bits_per_pixel) {
19267 + fix->visual = FB_VISUAL_TRUECOLOR;
19268 + /* 12bpp is stored in 16 bits */
19274 + fix->visual = FB_VISUAL_PSEUDOCOLOR;
19279 + fix->accel = FB_ACCEL_NONE;
19281 + fix->xpanstep = 1;
19282 + fix->ypanstep = 1;
19284 + if (rg->size && ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
19285 + unsigned bytespp;
19287 + enum omap_color_mode mode;
19289 + mode = fb_mode_to_dss_mode(var);
19291 + bytespp = var->bits_per_pixel >> 3;
19293 + if (mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY)
19296 + yuv_mode = false;
19298 + omap_vrfb_setup(&rg->vrfb, rg->paddr,
19299 + var->xres_virtual,
19300 + var->yres_virtual,
19301 + bytespp, yuv_mode);
19305 +/* check new var and possibly modify it to be ok */
19306 +int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
19308 + struct omapfb_info *ofbi = FB2OFB(fbi);
19309 + struct omap_dss_device *display = fb2display(fbi);
19310 + unsigned long max_frame_size;
19311 + unsigned long line_size;
19312 + int xres_min, yres_min;
19313 + int xres_max, yres_max;
19314 + enum omap_color_mode mode = 0;
19318 + DBG("check_fb_var %d\n", ofbi->id);
19320 + if (ofbi->region.size == 0)
19323 + mode = fb_mode_to_dss_mode(var);
19325 + DBG("cannot convert var to omap dss mode\n");
19329 + for (i = 0; i < ofbi->num_overlays; ++i) {
19330 + if ((ofbi->overlays[i]->supported_modes & mode) == 0) {
19331 + DBG("invalid mode\n");
19336 + if (var->rotate < 0 || var->rotate > 3)
19339 + xres_min = OMAPFB_PLANE_XRES_MIN;
19341 + yres_min = OMAPFB_PLANE_YRES_MIN;
19344 + bytespp = var->bits_per_pixel >> 3;
19346 + /* XXX: some applications seem to set virtual res to 0. */
19347 + if (var->xres_virtual == 0)
19348 + var->xres_virtual = var->xres;
19350 + if (var->yres_virtual == 0)
19351 + var->yres_virtual = var->yres;
19353 + if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)
19356 + if (var->xres < xres_min)
19357 + var->xres = xres_min;
19358 + if (var->yres < yres_min)
19359 + var->yres = yres_min;
19360 + if (var->xres > xres_max)
19361 + var->xres = xres_max;
19362 + if (var->yres > yres_max)
19363 + var->yres = yres_max;
19365 + if (var->xres > var->xres_virtual)
19366 + var->xres = var->xres_virtual;
19367 + if (var->yres > var->yres_virtual)
19368 + var->yres = var->yres_virtual;
19370 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
19371 + line_size = OMAP_VRFB_LINE_LEN * bytespp;
19373 + line_size = var->xres_virtual * bytespp;
19375 + max_frame_size = ofbi->region.size;
19377 + DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);
19379 + if (line_size * var->yres_virtual > max_frame_size) {
19380 + DBG("can't fit FB into memory, reducing y\n");
19381 + var->yres_virtual = max_frame_size / line_size;
19383 + if (var->yres_virtual < yres_min)
19384 + var->yres_virtual = yres_min;
19386 + if (var->yres > var->yres_virtual)
19387 + var->yres = var->yres_virtual;
19390 + if (line_size * var->yres_virtual > max_frame_size) {
19391 + DBG("can't fit FB into memory, reducing x\n");
19392 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
19395 + var->xres_virtual = max_frame_size / var->yres_virtual /
19398 + if (var->xres_virtual < xres_min)
19399 + var->xres_virtual = xres_min;
19401 + if (var->xres > var->xres_virtual)
19402 + var->xres = var->xres_virtual;
19404 + line_size = var->xres_virtual * bytespp;
19407 + if (line_size * var->yres_virtual > max_frame_size) {
19408 + DBG("cannot fit FB to memory\n");
19412 + if (var->xres + var->xoffset > var->xres_virtual)
19413 + var->xoffset = var->xres_virtual - var->xres;
19414 + if (var->yres + var->yoffset > var->yres_virtual)
19415 + var->yoffset = var->yres_virtual - var->yres;
19417 + DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n",
19418 + var->xres, var->yres,
19419 + var->xres_virtual, var->yres_virtual);
19421 + var->height = -1;
19423 + var->grayscale = 0;
19425 + if (display && display->get_timings) {
19426 + struct omap_video_timings timings;
19427 + display->get_timings(display, &timings);
19429 + /* pixclock in ps, the rest in pixclock */
19430 + var->pixclock = timings.pixel_clock != 0 ?
19431 + KHZ2PICOS(timings.pixel_clock) :
19433 + var->left_margin = timings.hfp;
19434 + var->right_margin = timings.hbp;
19435 + var->upper_margin = timings.vfp;
19436 + var->lower_margin = timings.vbp;
19437 + var->hsync_len = timings.hsw;
19438 + var->vsync_len = timings.vsw;
19440 + var->pixclock = 0;
19441 + var->left_margin = 0;
19442 + var->right_margin = 0;
19443 + var->upper_margin = 0;
19444 + var->lower_margin = 0;
19445 + var->hsync_len = 0;
19446 + var->vsync_len = 0;
19449 + /* TODO: get these from panel->config */
19450 + var->vmode = FB_VMODE_NONINTERLACED;
19457 + * ---------------------------------------------------------------------------
19458 + * fbdev framework callbacks
19459 + * ---------------------------------------------------------------------------
19461 +static int omapfb_open(struct fb_info *fbi, int user)
19466 +static int omapfb_release(struct fb_info *fbi, int user)
19469 + struct omapfb_info *ofbi = FB2OFB(fbi);
19470 + struct omapfb2_device *fbdev = ofbi->fbdev;
19471 + struct omap_dss_device *display = fb2display(fbi);
19473 + DBG("Closing fb with plane index %d\n", ofbi->id);
19475 + omapfb_lock(fbdev);
19477 + if (display && display->get_update_mode && display->update) {
19478 + /* XXX this update should be removed, I think. But it's
19479 + * good for debugging */
19480 + if (display->get_update_mode(display) ==
19481 + OMAP_DSS_UPDATE_MANUAL) {
19484 + if (display->sync)
19485 + display->sync(display);
19487 + display->get_resolution(display, &w, &h);
19488 + display->update(display, 0, 0, w, h);
19492 + if (display && display->sync)
19493 + display->sync(display);
19495 + omapfb_unlock(fbdev);
19500 +/* setup overlay according to the fb */
19501 +static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
19502 + u16 posx, u16 posy, u16 outw, u16 outh)
19505 + struct omapfb_info *ofbi = FB2OFB(fbi);
19506 + struct fb_var_screeninfo *var = &fbi->var;
19507 + struct fb_fix_screeninfo *fix = &fbi->fix;
19508 + enum omap_color_mode mode = 0;
19510 + u32 data_start_p;
19511 + void __iomem *data_start_v;
19512 + struct omap_overlay_info info;
19514 + int screen_width;
19516 + int rotation = var->rotate;
19519 + for (i = 0; i < ofbi->num_overlays; i++) {
19520 + if (ovl != ofbi->overlays[i])
19523 + rotation = (rotation + ofbi->rotation[i]) % 4;
19527 + DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
19528 + posx, posy, outw, outh);
19530 + if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {
19531 + xres = var->yres;
19532 + yres = var->xres;
19534 + xres = var->xres;
19535 + yres = var->yres;
19538 + offset = ((var->yoffset * var->xres_virtual +
19539 + var->xoffset) * var->bits_per_pixel) >> 3;
19541 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
19542 + data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
19543 + data_start_v = NULL;
19545 + data_start_p = omapfb_get_region_paddr(ofbi);
19546 + data_start_v = omapfb_get_region_vaddr(ofbi);
19549 + data_start_p += offset;
19550 + data_start_v += offset;
19552 + mode = fb_mode_to_dss_mode(var);
19554 + if (mode == -EINVAL) {
19555 + DBG("fb_mode_to_dss_mode failed");
19560 + switch (var->nonstd) {
19561 + case OMAPFB_COLOR_YUV422:
19562 + case OMAPFB_COLOR_YUY422:
19563 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
19564 + screen_width = fix->line_length
19565 + / (var->bits_per_pixel >> 2);
19569 + screen_width = fix->line_length / (var->bits_per_pixel >> 3);
19573 + ovl->get_overlay_info(ovl, &info);
19575 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
19578 + mirror = ofbi->mirror;
19580 + info.paddr = data_start_p;
19581 + info.vaddr = data_start_v;
19582 + info.screen_width = screen_width;
19583 + info.width = xres;
19584 + info.height = yres;
19585 + info.color_mode = mode;
19586 + info.rotation_type = ofbi->rotation_type;
19587 + info.rotation = rotation;
19588 + info.mirror = mirror;
19590 + info.pos_x = posx;
19591 + info.pos_y = posy;
19592 + info.out_width = outw;
19593 + info.out_height = outh;
19595 + r = ovl->set_overlay_info(ovl, &info);
19597 + DBG("ovl->setup_overlay_info failed\n");
19604 + DBG("setup_overlay failed\n");
19608 +/* apply var to the overlay */
19609 +int omapfb_apply_changes(struct fb_info *fbi, int init)
19612 + struct omapfb_info *ofbi = FB2OFB(fbi);
19613 + struct fb_var_screeninfo *var = &fbi->var;
19614 + struct omap_overlay *ovl;
19620 + if (omapfb_test_pattern)
19624 + for (i = 0; i < ofbi->num_overlays; i++) {
19625 + ovl = ofbi->overlays[i];
19627 + DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
19629 + if (ofbi->region.size == 0) {
19630 + /* the fb is not available. disable the overlay */
19631 + omapfb_overlay_enable(ovl, 0);
19632 + if (!init && ovl->manager)
19633 + ovl->manager->apply(ovl->manager);
19637 + if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
19638 + int rotation = (var->rotate + ofbi->rotation[i]) % 4;
19639 + if (rotation == FB_ROTATE_CW ||
19640 + rotation == FB_ROTATE_CCW) {
19641 + outw = var->yres;
19642 + outh = var->xres;
19644 + outw = var->xres;
19645 + outh = var->yres;
19648 + outw = ovl->info.out_width;
19649 + outh = ovl->info.out_height;
19656 + posx = ovl->info.pos_x;
19657 + posy = ovl->info.pos_y;
19660 + r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
19664 + if (!init && ovl->manager)
19665 + ovl->manager->apply(ovl->manager);
19669 + DBG("apply_changes failed\n");
19673 +/* checks var and eventually tweaks it to something supported,
19674 + * DO NOT MODIFY PAR */
19675 +static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
19679 + DBG("check_var(%d)\n", FB2OFB(fbi)->id);
19681 + r = check_fb_var(fbi, var);
19686 +/* set the video mode according to info->var */
19687 +static int omapfb_set_par(struct fb_info *fbi)
19691 + DBG("set_par(%d)\n", FB2OFB(fbi)->id);
19694 + r = omapfb_apply_changes(fbi, 0);
19699 +static int omapfb_pan_display(struct fb_var_screeninfo *var,
19700 + struct fb_info *fbi)
19702 + struct omapfb_info *ofbi = FB2OFB(fbi);
19705 + DBG("pan_display(%d)\n", ofbi->id);
19707 + if (var->xoffset != fbi->var.xoffset ||
19708 + var->yoffset != fbi->var.yoffset) {
19709 + struct fb_var_screeninfo new_var;
19711 + new_var = fbi->var;
19712 + new_var.xoffset = var->xoffset;
19713 + new_var.yoffset = var->yoffset;
19715 + r = check_fb_var(fbi, &new_var);
19718 + fbi->var = new_var;
19720 + r = omapfb_apply_changes(fbi, 0);
19727 +static void mmap_user_open(struct vm_area_struct *vma)
19729 + struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
19731 + atomic_inc(&ofbi->map_count);
19734 +static void mmap_user_close(struct vm_area_struct *vma)
19736 + struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
19738 + atomic_dec(&ofbi->map_count);
19741 +static struct vm_operations_struct mmap_user_ops = {
19742 + .open = mmap_user_open,
19743 + .close = mmap_user_close,
19746 +static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
19748 + struct omapfb_info *ofbi = FB2OFB(fbi);
19749 + struct fb_fix_screeninfo *fix = &fbi->fix;
19750 + unsigned long off;
19751 + unsigned long start;
19754 + if (vma->vm_end - vma->vm_start == 0)
19756 + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
19758 + off = vma->vm_pgoff << PAGE_SHIFT;
19760 + start = omapfb_get_region_paddr(ofbi);
19761 + len = fix->smem_len;
19764 + if ((vma->vm_end - vma->vm_start + off) > len)
19769 + DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
19771 + vma->vm_pgoff = off >> PAGE_SHIFT;
19772 + vma->vm_flags |= VM_IO | VM_RESERVED;
19773 + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
19774 + vma->vm_ops = &mmap_user_ops;
19775 + vma->vm_private_data = ofbi;
19776 + if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
19777 + vma->vm_end - vma->vm_start, vma->vm_page_prot))
19779 + /* vm_ops.open won't be called for mmap itself. */
19780 + atomic_inc(&ofbi->map_count);
19784 +/* Store a single color palette entry into a pseudo palette or the hardware
19785 + * palette if one is available. For now we support only 16bpp and thus store
19786 + * the entry only to the pseudo palette.
19788 +static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
19789 + u_int blue, u_int transp, int update_hw_pal)
19791 + /*struct omapfb_info *ofbi = FB2OFB(fbi);*/
19792 + /*struct omapfb2_device *fbdev = ofbi->fbdev;*/
19793 + struct fb_var_screeninfo *var = &fbi->var;
19796 + enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */
19798 + /*switch (plane->color_mode) {*/
19800 + case OMAPFB_COLOR_YUV422:
19801 + case OMAPFB_COLOR_YUV420:
19802 + case OMAPFB_COLOR_YUY422:
19805 + case OMAPFB_COLOR_CLUT_8BPP:
19806 + case OMAPFB_COLOR_CLUT_4BPP:
19807 + case OMAPFB_COLOR_CLUT_2BPP:
19808 + case OMAPFB_COLOR_CLUT_1BPP:
19810 + if (fbdev->ctrl->setcolreg)
19811 + r = fbdev->ctrl->setcolreg(regno, red, green, blue,
19812 + transp, update_hw_pal);
19814 + /* Fallthrough */
19817 + case OMAPFB_COLOR_RGB565:
19818 + case OMAPFB_COLOR_RGB444:
19819 + case OMAPFB_COLOR_RGB24P:
19820 + case OMAPFB_COLOR_RGB24U:
19829 + if (regno < 16) {
19831 + pal = ((red >> (16 - var->red.length)) <<
19832 + var->red.offset) |
19833 + ((green >> (16 - var->green.length)) <<
19834 + var->green.offset) |
19835 + (blue >> (16 - var->blue.length));
19836 + ((u32 *)(fbi->pseudo_palette))[regno] = pal;
19845 +static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
19846 + u_int transp, struct fb_info *info)
19848 + DBG("setcolreg\n");
19850 + return _setcolreg(info, regno, red, green, blue, transp, 1);
19853 +static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
19855 + int count, index, r;
19856 + u16 *red, *green, *blue, *transp;
19857 + u16 trans = 0xffff;
19859 + DBG("setcmap\n");
19862 + green = cmap->green;
19863 + blue = cmap->blue;
19864 + transp = cmap->transp;
19865 + index = cmap->start;
19867 + for (count = 0; count < cmap->len; count++) {
19869 + trans = *transp++;
19870 + r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
19871 + count == cmap->len - 1);
19879 +static void omapfb_vrfb_suspend_all(struct omapfb2_device *fbdev)
19883 + for (i = 0; i < fbdev->num_fbs; i++) {
19884 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
19886 + if (ofbi->region.vrfb.vaddr[0])
19887 + omap_vrfb_suspend_ctx(&ofbi->region.vrfb);
19891 +static void omapfb_vrfb_resume_all(struct omapfb2_device *fbdev)
19895 + for (i = 0; i < fbdev->num_fbs; i++) {
19896 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
19898 + if (ofbi->region.vrfb.vaddr[0])
19899 + omap_vrfb_resume_ctx(&ofbi->region.vrfb);
19903 +static int omapfb_blank(int blank, struct fb_info *fbi)
19905 + struct omapfb_info *ofbi = FB2OFB(fbi);
19906 + struct omapfb2_device *fbdev = ofbi->fbdev;
19907 + struct omap_dss_device *display = fb2display(fbi);
19908 + int do_update = 0;
19911 + omapfb_lock(fbdev);
19914 + case FB_BLANK_UNBLANK:
19915 + if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
19918 + omapfb_vrfb_resume_all(fbdev);
19920 + if (display->resume)
19921 + r = display->resume(display);
19923 + if (r == 0 && display->get_update_mode &&
19924 + display->get_update_mode(display) ==
19925 + OMAP_DSS_UPDATE_MANUAL)
19930 + case FB_BLANK_NORMAL:
19931 + /* FB_BLANK_NORMAL could be implemented.
19932 + * Needs DSS additions. */
19933 + case FB_BLANK_VSYNC_SUSPEND:
19934 + case FB_BLANK_HSYNC_SUSPEND:
19935 + case FB_BLANK_POWERDOWN:
19936 + if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
19939 + if (display->suspend)
19940 + r = display->suspend(display);
19942 + omapfb_vrfb_suspend_all(fbdev);
19951 + omapfb_unlock(fbdev);
19953 + if (r == 0 && do_update && display->update) {
19955 + display->get_resolution(display, &w, &h);
19957 + r = display->update(display, 0, 0, w, h);
19964 +/* XXX fb_read and fb_write are needed for VRFB */
19965 +ssize_t omapfb_write(struct fb_info *info, const char __user *buf,
19966 + size_t count, loff_t *ppos)
19968 + DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
19969 + /* XXX needed for VRFB */
19974 +static struct fb_ops omapfb_ops = {
19975 + .owner = THIS_MODULE,
19976 + .fb_open = omapfb_open,
19977 + .fb_release = omapfb_release,
19978 + .fb_fillrect = cfb_fillrect,
19979 + .fb_copyarea = cfb_copyarea,
19980 + .fb_imageblit = cfb_imageblit,
19981 + .fb_blank = omapfb_blank,
19982 + .fb_ioctl = omapfb_ioctl,
19983 + .fb_check_var = omapfb_check_var,
19984 + .fb_set_par = omapfb_set_par,
19985 + .fb_pan_display = omapfb_pan_display,
19986 + .fb_mmap = omapfb_mmap,
19987 + .fb_setcolreg = omapfb_setcolreg,
19988 + .fb_setcmap = omapfb_setcmap,
19989 + /*.fb_write = omapfb_write,*/
19992 +static void omapfb_free_fbmem(struct fb_info *fbi)
19994 + struct omapfb_info *ofbi = FB2OFB(fbi);
19995 + struct omapfb2_device *fbdev = ofbi->fbdev;
19996 + struct omapfb2_mem_region *rg;
19998 + rg = &ofbi->region;
20001 + if (omap_vram_free(rg->paddr, rg->size))
20002 + dev_err(fbdev->dev, "VRAM FREE failed\n");
20005 + iounmap(rg->vaddr);
20007 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
20008 + /* unmap the 0 angle rotation */
20009 + if (rg->vrfb.vaddr[0]) {
20010 + iounmap(rg->vrfb.vaddr[0]);
20011 + omap_vrfb_release_ctx(&rg->vrfb);
20015 + rg->vaddr = NULL;
20021 +static void clear_fb_info(struct fb_info *fbi)
20023 + memset(&fbi->var, 0, sizeof(fbi->var));
20024 + memset(&fbi->fix, 0, sizeof(fbi->fix));
20025 + strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
20028 +static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
20032 + DBG("free all fbmem\n");
20034 + for (i = 0; i < fbdev->num_fbs; i++) {
20035 + struct fb_info *fbi = fbdev->fbs[i];
20036 + omapfb_free_fbmem(fbi);
20037 + clear_fb_info(fbi);
20043 +static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
20044 + unsigned long paddr)
20046 + struct omapfb_info *ofbi = FB2OFB(fbi);
20047 + struct omapfb2_device *fbdev = ofbi->fbdev;
20048 + struct omapfb2_mem_region *rg;
20049 + void __iomem *vaddr;
20052 + rg = &ofbi->region;
20053 + memset(rg, 0, sizeof(*rg));
20055 + size = PAGE_ALIGN(size);
20058 + DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
20059 + r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr);
20061 + DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
20063 + r = omap_vram_reserve(paddr, size);
20067 + dev_err(fbdev->dev, "failed to allocate framebuffer\n");
20071 + if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {
20072 + vaddr = ioremap_wc(paddr, size);
20075 + dev_err(fbdev->dev, "failed to ioremap framebuffer\n");
20076 + omap_vram_free(paddr, size);
20080 + DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);
20082 + void __iomem *va;
20084 + r = omap_vrfb_request_ctx(&rg->vrfb);
20086 + dev_err(fbdev->dev, "vrfb create ctx failed\n");
20090 + /* only ioremap the 0 angle view */
20091 + va = ioremap_wc(rg->vrfb.paddr[0], size);
20094 + printk(KERN_ERR "vrfb: ioremap failed\n");
20095 + omap_vrfb_release_ctx(&rg->vrfb);
20099 + DBG("ioremapped vrfb area 0 to %p\n", va);
20101 + rg->vrfb.vaddr[0] = va;
20106 + rg->paddr = paddr;
20107 + rg->vaddr = vaddr;
20114 +/* allocate fbmem using display resolution as reference */
20115 +static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
20116 + unsigned long paddr)
20118 + struct omapfb_info *ofbi = FB2OFB(fbi);
20119 + struct omap_dss_device *display;
20122 + display = fb2display(fbi);
20127 + switch (display->get_recommended_bpp(display)) {
20142 + display->get_resolution(display, &w, &h);
20144 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
20146 + int oldw = w, oldh = h;
20149 + omap_vrfb_adjust_size(&w, &h, bytespp);
20151 + /* Because we change the resolution of the 0 degree
20152 + * view, we need to alloc max(w, h) for height */
20154 + w = OMAP_VRFB_LINE_LEN;
20156 + DBG("adjusting fb mem size for VRFB, %dx%d -> %dx%d\n",
20157 + oldw, oldh, w, h);
20160 + size = w * h * bytespp;
20166 + return omapfb_alloc_fbmem(fbi, size, paddr);
20169 +static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt)
20171 + enum omap_color_mode mode;
20174 + case OMAPFB_COLOR_RGB565:
20175 + mode = OMAP_DSS_COLOR_RGB16;
20177 + case OMAPFB_COLOR_YUV422:
20178 + mode = OMAP_DSS_COLOR_YUV2;
20180 + case OMAPFB_COLOR_CLUT_8BPP:
20181 + mode = OMAP_DSS_COLOR_CLUT8;
20183 + case OMAPFB_COLOR_CLUT_4BPP:
20184 + mode = OMAP_DSS_COLOR_CLUT4;
20186 + case OMAPFB_COLOR_CLUT_2BPP:
20187 + mode = OMAP_DSS_COLOR_CLUT2;
20189 + case OMAPFB_COLOR_CLUT_1BPP:
20190 + mode = OMAP_DSS_COLOR_CLUT1;
20192 + case OMAPFB_COLOR_RGB444:
20193 + mode = OMAP_DSS_COLOR_RGB12U;
20195 + case OMAPFB_COLOR_YUY422:
20196 + mode = OMAP_DSS_COLOR_UYVY;
20198 + case OMAPFB_COLOR_ARGB16:
20199 + mode = OMAP_DSS_COLOR_ARGB16;
20201 + case OMAPFB_COLOR_RGB24U:
20202 + mode = OMAP_DSS_COLOR_RGB24U;
20204 + case OMAPFB_COLOR_RGB24P:
20205 + mode = OMAP_DSS_COLOR_RGB24P;
20207 + case OMAPFB_COLOR_ARGB32:
20208 + mode = OMAP_DSS_COLOR_ARGB32;
20210 + case OMAPFB_COLOR_RGBA32:
20211 + mode = OMAP_DSS_COLOR_RGBA32;
20213 + case OMAPFB_COLOR_RGBX32:
20214 + mode = OMAP_DSS_COLOR_RGBX32;
20223 +static int omapfb_parse_vram_param(const char *param, int max_entries,
20224 + unsigned long *sizes, unsigned long *paddrs)
20227 + unsigned long size;
20228 + unsigned long paddr = 0;
20231 + start = (char *)param;
20236 + fbnum = simple_strtoul(p, &p, 10);
20244 + if (fbnum >= max_entries)
20247 + size = memparse(p + 1, &p);
20255 + paddr = simple_strtoul(p + 1, &p, 16);
20262 + paddrs[fbnum] = paddr;
20263 + sizes[fbnum] = size;
20279 +static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
20282 + unsigned long vram_sizes[10];
20283 + unsigned long vram_paddrs[10];
20285 + memset(&vram_sizes, 0, sizeof(vram_sizes));
20286 + memset(&vram_paddrs, 0, sizeof(vram_paddrs));
20288 + if (def_vram && omapfb_parse_vram_param(def_vram, 10,
20289 + vram_sizes, vram_paddrs)) {
20290 + dev_err(fbdev->dev, "failed to parse vram parameter\n");
20292 + memset(&vram_sizes, 0, sizeof(vram_sizes));
20293 + memset(&vram_paddrs, 0, sizeof(vram_paddrs));
20296 + if (fbdev->dev->platform_data) {
20297 + struct omapfb_platform_data *opd;
20298 + opd = fbdev->dev->platform_data;
20299 + for (i = 0; i < opd->mem_desc.region_cnt; ++i) {
20300 + if (!vram_sizes[i]) {
20301 + unsigned long size;
20302 + unsigned long paddr;
20304 + size = opd->mem_desc.region[i].size;
20305 + paddr = opd->mem_desc.region[i].paddr;
20307 + vram_sizes[i] = size;
20308 + vram_paddrs[i] = paddr;
20313 + for (i = 0; i < fbdev->num_fbs; i++) {
20314 + /* allocate memory automatically only for fb0, or if
20315 + * excplicitly defined with vram or plat data option */
20316 + if (i == 0 || vram_sizes[i] != 0) {
20317 + r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
20318 + vram_sizes[i], vram_paddrs[i]);
20325 + for (i = 0; i < fbdev->num_fbs; i++) {
20326 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
20327 + struct omapfb2_mem_region *rg;
20328 + rg = &ofbi->region;
20330 + DBG("region%d phys %08x virt %p size=%lu\n",
20340 +int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
20342 + struct omapfb_info *ofbi = FB2OFB(fbi);
20343 + struct omapfb2_device *fbdev = ofbi->fbdev;
20344 + struct omap_dss_device *display = fb2display(fbi);
20345 + struct omapfb2_mem_region *rg = &ofbi->region;
20346 + unsigned long old_size = rg->size;
20347 + unsigned long old_paddr = rg->paddr;
20348 + int old_type = rg->type;
20351 + if (type > OMAPFB_MEMTYPE_MAX)
20354 + size = PAGE_ALIGN(size);
20356 + if (old_size == size && old_type == type)
20359 + if (display && display->sync)
20360 + display->sync(display);
20362 + omapfb_free_fbmem(fbi);
20365 + clear_fb_info(fbi);
20369 + r = omapfb_alloc_fbmem(fbi, size, 0);
20373 + omapfb_alloc_fbmem(fbi, old_size, old_paddr);
20375 + if (rg->size == 0)
20376 + clear_fb_info(fbi);
20381 + if (old_size == size)
20384 + if (old_size == 0) {
20385 + DBG("initializing fb %d\n", ofbi->id);
20386 + r = omapfb_fb_init(fbdev, fbi);
20388 + DBG("omapfb_fb_init failed\n");
20391 + r = omapfb_apply_changes(fbi, 1);
20393 + DBG("omapfb_apply_changes failed\n");
20397 + struct fb_var_screeninfo new_var;
20398 + memcpy(&new_var, &fbi->var, sizeof(new_var));
20399 + r = check_fb_var(fbi, &new_var);
20402 + memcpy(&fbi->var, &new_var, sizeof(fbi->var));
20408 + omapfb_free_fbmem(fbi);
20409 + clear_fb_info(fbi);
20413 +/* initialize fb_info, var, fix to something sane based on the display */
20414 +static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
20416 + struct fb_var_screeninfo *var = &fbi->var;
20417 + struct omap_dss_device *display = fb2display(fbi);
20418 + struct omapfb_info *ofbi = FB2OFB(fbi);
20421 + fbi->fbops = &omapfb_ops;
20422 + fbi->flags = FBINFO_FLAG_DEFAULT;
20423 + fbi->pseudo_palette = fbdev->pseudo_palette;
20425 + if (ofbi->region.size == 0) {
20426 + clear_fb_info(fbi);
20431 + var->bits_per_pixel = 0;
20433 + var->rotate = def_rotate;
20436 + * Check if there is a default color format set in the board file,
20437 + * and use this format instead the default deducted from the
20440 + if (fbdev->dev->platform_data) {
20441 + struct omapfb_platform_data *opd;
20442 + int id = ofbi->id;
20444 + opd = fbdev->dev->platform_data;
20445 + if (opd->mem_desc.region[id].format_used) {
20446 + enum omap_color_mode mode;
20447 + enum omapfb_color_format format;
20449 + format = opd->mem_desc.region[id].format;
20450 + mode = fb_format_to_dss_mode(format);
20455 + r = dss_mode_to_fb_mode(mode, var);
20463 + int rotation = (var->rotate + ofbi->rotation[0]) % 4;
20465 + display->get_resolution(display, &w, &h);
20467 + if (rotation == FB_ROTATE_CW ||
20468 + rotation == FB_ROTATE_CCW) {
20476 + var->xres_virtual = var->xres;
20477 + var->yres_virtual = var->yres;
20479 + if (!var->bits_per_pixel) {
20480 + switch (display->get_recommended_bpp(display)) {
20482 + var->bits_per_pixel = 16;
20485 + var->bits_per_pixel = 32;
20488 + dev_err(fbdev->dev, "illegal display "
20494 + /* if there's no display, let's just guess some basic values */
20497 + var->xres_virtual = var->xres;
20498 + var->yres_virtual = var->yres;
20499 + if (!var->bits_per_pixel)
20500 + var->bits_per_pixel = 16;
20503 + r = check_fb_var(fbi, var);
20509 + r = fb_alloc_cmap(&fbi->cmap, 256, 0);
20511 + dev_err(fbdev->dev, "unable to allocate color map memory\n");
20517 +static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
20519 + fb_dealloc_cmap(&fbi->cmap);
20523 +static void omapfb_free_resources(struct omapfb2_device *fbdev)
20527 + DBG("free_resources\n");
20529 + if (fbdev == NULL)
20532 + for (i = 0; i < fbdev->num_fbs; i++)
20533 + unregister_framebuffer(fbdev->fbs[i]);
20535 + /* free the reserved fbmem */
20536 + omapfb_free_all_fbmem(fbdev);
20538 + for (i = 0; i < fbdev->num_fbs; i++) {
20539 + fbinfo_cleanup(fbdev, fbdev->fbs[i]);
20540 + framebuffer_release(fbdev->fbs[i]);
20543 + for (i = 0; i < fbdev->num_displays; i++) {
20544 + if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
20545 + fbdev->displays[i]->disable(fbdev->displays[i]);
20547 + omap_dss_put_device(fbdev->displays[i]);
20550 + dev_set_drvdata(fbdev->dev, NULL);
20554 +static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
20558 + fbdev->num_fbs = 0;
20560 + DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);
20562 + /* allocate fb_infos */
20563 + for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
20564 + struct fb_info *fbi;
20565 + struct omapfb_info *ofbi;
20567 + fbi = framebuffer_alloc(sizeof(struct omapfb_info),
20570 + if (fbi == NULL) {
20571 + dev_err(fbdev->dev,
20572 + "unable to allocate memory for plane info\n");
20576 + clear_fb_info(fbi);
20578 + fbdev->fbs[i] = fbi;
20580 + ofbi = FB2OFB(fbi);
20581 + ofbi->fbdev = fbdev;
20584 + /* assign these early, so that fb alloc can use them */
20585 + ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
20586 + OMAP_DSS_ROT_DMA;
20587 + ofbi->mirror = def_mirror;
20589 + fbdev->num_fbs++;
20592 + DBG("fb_infos allocated\n");
20594 + /* assign overlays for the fbs */
20595 + for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
20596 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
20598 + ofbi->overlays[0] = fbdev->overlays[i];
20599 + ofbi->num_overlays = 1;
20602 + /* allocate fb memories */
20603 + r = omapfb_allocate_all_fbs(fbdev);
20605 + dev_err(fbdev->dev, "failed to allocate fbmem\n");
20609 + DBG("fbmems allocated\n");
20611 + /* setup fb_infos */
20612 + for (i = 0; i < fbdev->num_fbs; i++) {
20613 + r = omapfb_fb_init(fbdev, fbdev->fbs[i]);
20615 + dev_err(fbdev->dev, "failed to setup fb_info\n");
20620 + DBG("fb_infos initialized\n");
20622 + for (i = 0; i < fbdev->num_fbs; i++) {
20623 + r = register_framebuffer(fbdev->fbs[i]);
20625 + dev_err(fbdev->dev,
20626 + "registering framebuffer %d failed\n", i);
20631 + DBG("framebuffers registered\n");
20633 + for (i = 0; i < fbdev->num_fbs; i++) {
20634 + r = omapfb_apply_changes(fbdev->fbs[i], 1);
20636 + dev_err(fbdev->dev, "failed to change mode\n");
20641 + DBG("create sysfs for fbs\n");
20642 + r = omapfb_create_sysfs(fbdev);
20644 + dev_err(fbdev->dev, "failed to create sysfs entries\n");
20649 + if (fbdev->num_fbs > 0) {
20650 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
20652 + if (ofbi->num_overlays > 0) {
20653 + struct omap_overlay *ovl = ofbi->overlays[0];
20655 + r = omapfb_overlay_enable(ovl, 1);
20658 + dev_err(fbdev->dev,
20659 + "failed to enable overlay\n");
20665 + DBG("create_framebuffers done\n");
20670 +static int omapfb_mode_to_timings(const char *mode_str,
20671 + struct omap_video_timings *timings, u8 *bpp)
20673 + struct fb_info fbi;
20674 + struct fb_var_screeninfo var;
20675 + struct fb_ops fbops;
20678 +#ifdef CONFIG_OMAP2_DSS_VENC
20679 + if (strcmp(mode_str, "pal") == 0) {
20680 + *timings = omap_dss_pal_timings;
20683 + } else if (strcmp(mode_str, "ntsc") == 0) {
20684 + *timings = omap_dss_ntsc_timings;
20690 + /* this is quite a hack, but I wanted to use the modedb and for
20691 + * that we need fb_info and var, so we create dummy ones */
20693 + memset(&fbi, 0, sizeof(fbi));
20694 + memset(&var, 0, sizeof(var));
20695 + memset(&fbops, 0, sizeof(fbops));
20696 + fbi.fbops = &fbops;
20698 + r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24);
20701 + timings->pixel_clock = PICOS2KHZ(var.pixclock);
20702 + timings->hfp = var.left_margin;
20703 + timings->hbp = var.right_margin;
20704 + timings->vfp = var.upper_margin;
20705 + timings->vbp = var.lower_margin;
20706 + timings->hsw = var.hsync_len;
20707 + timings->vsw = var.vsync_len;
20708 + timings->x_res = var.xres;
20709 + timings->y_res = var.yres;
20711 + switch (var.bits_per_pixel) {
20728 +static int omapfb_set_def_mode(struct omap_dss_device *display, char *mode_str)
20732 + struct omap_video_timings timings;
20734 + r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
20738 + display->panel.recommended_bpp = bpp;
20740 + if (!display->check_timings || !display->set_timings)
20743 + r = display->check_timings(display, &timings);
20747 + display->set_timings(display, &timings);
20752 +static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
20754 + char *str, *options, *this_opt;
20757 + str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL);
20758 + strcpy(str, def_mode);
20761 + while (!r && (this_opt = strsep(&options, ",")) != NULL) {
20762 + char *p, *display_str, *mode_str;
20763 + struct omap_dss_device *display;
20766 + p = strchr(this_opt, ':');
20773 + display_str = this_opt;
20774 + mode_str = p + 1;
20777 + for (i = 0; i < fbdev->num_displays; ++i) {
20778 + if (strcmp(fbdev->displays[i]->name,
20779 + display_str) == 0) {
20780 + display = fbdev->displays[i];
20790 + r = omapfb_set_def_mode(display, mode_str);
20800 +static int omapfb_probe(struct platform_device *pdev)
20802 + struct omapfb2_device *fbdev = NULL;
20805 + struct omap_overlay *ovl;
20806 + struct omap_dss_device *def_display;
20807 + struct omap_dss_device *dssdev;
20809 + DBG("omapfb_probe\n");
20811 + if (pdev->num_resources != 0) {
20812 + dev_err(&pdev->dev, "probed for an unknown device\n");
20817 + fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL);
20818 + if (fbdev == NULL) {
20823 + mutex_init(&fbdev->mtx);
20825 + fbdev->dev = &pdev->dev;
20826 + platform_set_drvdata(pdev, fbdev);
20828 + fbdev->num_displays = 0;
20830 + for_each_dss_dev(dssdev) {
20831 + omap_dss_get_device(dssdev);
20832 + fbdev->displays[fbdev->num_displays++] = dssdev;
20835 + if (fbdev->num_displays == 0) {
20836 + dev_err(&pdev->dev, "no displays\n");
20841 + fbdev->num_overlays = omap_dss_get_num_overlays();
20842 + for (i = 0; i < fbdev->num_overlays; i++)
20843 + fbdev->overlays[i] = omap_dss_get_overlay(i);
20845 + fbdev->num_managers = omap_dss_get_num_overlay_managers();
20846 + for (i = 0; i < fbdev->num_managers; i++)
20847 + fbdev->managers[i] = omap_dss_get_overlay_manager(i);
20849 + if (def_mode && strlen(def_mode) > 0) {
20850 + if (omapfb_parse_def_modes(fbdev))
20851 + dev_warn(&pdev->dev, "cannot parse default modes\n");
20854 + r = omapfb_create_framebuffers(fbdev);
20858 + for (i = 0; i < fbdev->num_managers; i++) {
20859 + struct omap_overlay_manager *mgr;
20860 + mgr = fbdev->managers[i];
20861 + r = mgr->apply(mgr);
20863 + dev_warn(fbdev->dev, "failed to apply dispc config\n");
20866 + DBG("mgr->apply'ed\n");
20868 + /* gfx overlay should be the default one. find a display
20869 + * connected to that, and use it as default display */
20870 + ovl = omap_dss_get_overlay(0);
20871 + if (ovl->manager && ovl->manager->device) {
20872 + def_display = ovl->manager->device;
20874 + dev_warn(&pdev->dev, "cannot find default display\n");
20875 + def_display = NULL;
20878 + if (def_display) {
20880 + r = def_display->enable(def_display);
20882 + dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
20883 + def_display->name);
20885 + /* set the update mode */
20886 + if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
20887 +#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
20888 + if (def_display->enable_te)
20889 + def_display->enable_te(def_display, 1);
20890 + if (def_display->set_update_mode)
20891 + def_display->set_update_mode(def_display,
20892 + OMAP_DSS_UPDATE_AUTO);
20893 +#else /* MANUAL_UPDATE */
20894 + if (def_display->enable_te)
20895 + def_display->enable_te(def_display, 0);
20896 + if (def_display->set_update_mode)
20897 + def_display->set_update_mode(def_display,
20898 + OMAP_DSS_UPDATE_MANUAL);
20900 + def_display->get_resolution(def_display, &w, &h);
20901 + def_display->update(def_display, 0, 0, w, h);
20904 + if (def_display->set_update_mode)
20905 + def_display->set_update_mode(def_display,
20906 + OMAP_DSS_UPDATE_AUTO);
20913 + omapfb_free_resources(fbdev);
20915 + dev_err(&pdev->dev, "failed to setup omapfb\n");
20919 +static int omapfb_remove(struct platform_device *pdev)
20921 + struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
20923 + /* FIXME: wait till completion of pending events */
20925 + omapfb_remove_sysfs(fbdev);
20927 + omapfb_free_resources(fbdev);
20932 +static struct platform_driver omapfb_driver = {
20933 + .probe = omapfb_probe,
20934 + .remove = omapfb_remove,
20936 + .name = "omapfb",
20937 + .owner = THIS_MODULE,
20941 +static int __init omapfb_init(void)
20943 + DBG("omapfb_init\n");
20945 + if (platform_driver_register(&omapfb_driver)) {
20946 + printk(KERN_ERR "failed to register omapfb driver\n");
20953 +static void __exit omapfb_exit(void)
20955 + DBG("omapfb_exit\n");
20956 + platform_driver_unregister(&omapfb_driver);
20959 +module_param_named(mode, def_mode, charp, 0);
20960 +module_param_named(vram, def_vram, charp, 0);
20961 +module_param_named(rotate, def_rotate, int, 0);
20962 +module_param_named(vrfb, def_vrfb, bool, 0);
20963 +module_param_named(mirror, def_mirror, bool, 0);
20965 +/* late_initcall to let panel/ctrl drivers loaded first.
20966 + * I guess better option would be a more dynamic approach,
20967 + * so that omapfb reacts to new panels when they are loaded */
20968 +late_initcall(omapfb_init);
20969 +/*module_init(omapfb_init);*/
20970 +module_exit(omapfb_exit);
20972 +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
20973 +MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
20974 +MODULE_LICENSE("GPL v2");
20975 diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c
20976 new file mode 100644
20977 index 0000000..ef30e0e
20979 +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
20982 + * linux/drivers/video/omap2/omapfb-sysfs.c
20984 + * Copyright (C) 2008 Nokia Corporation
20985 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
20987 + * Some code and ideas taken from drivers/video/omap/ driver
20990 + * This program is free software; you can redistribute it and/or modify it
20991 + * under the terms of the GNU General Public License version 2 as published by
20992 + * the Free Software Foundation.
20994 + * This program is distributed in the hope that it will be useful, but WITHOUT
20995 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20996 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20999 + * You should have received a copy of the GNU General Public License along with
21000 + * this program. If not, see <http://www.gnu.org/licenses/>.
21003 +#include <linux/fb.h>
21004 +#include <linux/sysfs.h>
21005 +#include <linux/device.h>
21006 +#include <linux/uaccess.h>
21007 +#include <linux/platform_device.h>
21008 +#include <linux/kernel.h>
21009 +#include <linux/mm.h>
21010 +#include <linux/omapfb.h>
21012 +#include <mach/display.h>
21013 +#include <mach/vrfb.h>
21015 +#include "omapfb.h"
21017 +static ssize_t show_rotate_type(struct device *dev,
21018 + struct device_attribute *attr, char *buf)
21020 + struct fb_info *fbi = dev_get_drvdata(dev);
21021 + struct omapfb_info *ofbi = FB2OFB(fbi);
21023 + return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
21026 +static ssize_t store_rotate_type(struct device *dev,
21027 + struct device_attribute *attr,
21028 + const char *buf, size_t count)
21030 + struct fb_info *fbi = dev_get_drvdata(dev);
21031 + struct omapfb_info *ofbi = FB2OFB(fbi);
21032 + enum omap_dss_rotation_type rot_type;
21035 + rot_type = simple_strtoul(buf, NULL, 0);
21037 + if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
21040 + lock_fb_info(fbi);
21043 + if (rot_type == ofbi->rotation_type)
21046 + if (ofbi->region.size) {
21051 + ofbi->rotation_type = rot_type;
21054 + * Since the VRAM for this FB is not allocated at the moment we don't
21055 + * need to do any further parameter checking at this point.
21058 + unlock_fb_info(fbi);
21060 + return r ? r : count;
21064 +static ssize_t show_mirror(struct device *dev,
21065 + struct device_attribute *attr, char *buf)
21067 + struct fb_info *fbi = dev_get_drvdata(dev);
21068 + struct omapfb_info *ofbi = FB2OFB(fbi);
21070 + return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
21073 +static ssize_t store_mirror(struct device *dev,
21074 + struct device_attribute *attr,
21075 + const char *buf, size_t count)
21077 + struct fb_info *fbi = dev_get_drvdata(dev);
21078 + struct omapfb_info *ofbi = FB2OFB(fbi);
21081 + struct fb_var_screeninfo new_var;
21083 + mirror = simple_strtoul(buf, NULL, 0);
21085 + if (mirror != 0 && mirror != 1)
21088 + lock_fb_info(fbi);
21090 + ofbi->mirror = mirror;
21092 + memcpy(&new_var, &fbi->var, sizeof(new_var));
21093 + r = check_fb_var(fbi, &new_var);
21096 + memcpy(&fbi->var, &new_var, sizeof(fbi->var));
21100 + r = omapfb_apply_changes(fbi, 0);
21106 + unlock_fb_info(fbi);
21111 +static ssize_t show_overlays(struct device *dev,
21112 + struct device_attribute *attr, char *buf)
21114 + struct fb_info *fbi = dev_get_drvdata(dev);
21115 + struct omapfb_info *ofbi = FB2OFB(fbi);
21116 + struct omapfb2_device *fbdev = ofbi->fbdev;
21120 + omapfb_lock(fbdev);
21121 + lock_fb_info(fbi);
21123 + for (t = 0; t < ofbi->num_overlays; t++) {
21124 + struct omap_overlay *ovl = ofbi->overlays[t];
21127 + for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
21128 + if (ovl == fbdev->overlays[ovlnum])
21131 + l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
21132 + t == 0 ? "" : ",", ovlnum);
21135 + l += snprintf(buf + l, PAGE_SIZE - l, "\n");
21137 + unlock_fb_info(fbi);
21138 + omapfb_unlock(fbdev);
21143 +static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
21144 + struct omap_overlay *ovl)
21148 + for (i = 0; i < fbdev->num_fbs; i++) {
21149 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
21151 + for (t = 0; t < ofbi->num_overlays; t++) {
21152 + if (ofbi->overlays[t] == ovl)
21160 +static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
21161 + const char *buf, size_t count)
21163 + struct fb_info *fbi = dev_get_drvdata(dev);
21164 + struct omapfb_info *ofbi = FB2OFB(fbi);
21165 + struct omapfb2_device *fbdev = ofbi->fbdev;
21166 + struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
21167 + struct omap_overlay *ovl;
21168 + int num_ovls, r, i;
21170 + bool added = false;
21174 + len = strlen(buf);
21175 + if (buf[len - 1] == '\n')
21178 + omapfb_lock(fbdev);
21179 + lock_fb_info(fbi);
21182 + char *p = (char *)buf;
21185 + while (p < buf + len) {
21187 + if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
21192 + ovlnum = simple_strtoul(p, &p, 0);
21193 + if (ovlnum > fbdev->num_overlays) {
21199 + for (i = 0; i < num_ovls; ++i) {
21200 + if (ovls[i] == fbdev->overlays[ovlnum]) {
21207 + ovls[num_ovls++] = fbdev->overlays[ovlnum];
21213 + for (i = 0; i < num_ovls; ++i) {
21214 + struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
21215 + if (ofbi2 && ofbi2 != ofbi) {
21216 + dev_err(fbdev->dev, "overlay already in use\n");
21222 + /* detach unused overlays */
21223 + for (i = 0; i < ofbi->num_overlays; ++i) {
21226 + ovl = ofbi->overlays[i];
21230 + for (t = 0; t < num_ovls; ++t) {
21231 + if (ovl == ovls[t]) {
21240 + DBG("detaching %d\n", ofbi->overlays[i]->id);
21242 + omapfb_overlay_enable(ovl, 0);
21244 + if (ovl->manager)
21245 + ovl->manager->apply(ovl->manager);
21247 + for (t = i + 1; t < ofbi->num_overlays; t++) {
21248 + ofbi->rotation[t-1] = ofbi->rotation[t];
21249 + ofbi->overlays[t-1] = ofbi->overlays[t];
21252 + ofbi->num_overlays--;
21256 + for (i = 0; i < num_ovls; ++i) {
21263 + for (t = 0; t < ofbi->num_overlays; ++t) {
21264 + if (ovl == ofbi->overlays[t]) {
21272 + ofbi->rotation[ofbi->num_overlays] = 0;
21273 + ofbi->overlays[ofbi->num_overlays++] = ovl;
21279 + r = omapfb_apply_changes(fbi, 0);
21286 + unlock_fb_info(fbi);
21287 + omapfb_unlock(fbdev);
21292 +static ssize_t show_overlays_rotate(struct device *dev,
21293 + struct device_attribute *attr, char *buf)
21295 + struct fb_info *fbi = dev_get_drvdata(dev);
21296 + struct omapfb_info *ofbi = FB2OFB(fbi);
21300 + lock_fb_info(fbi);
21302 + for (t = 0; t < ofbi->num_overlays; t++) {
21303 + l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
21304 + t == 0 ? "" : ",", ofbi->rotation[t]);
21307 + l += snprintf(buf + l, PAGE_SIZE - l, "\n");
21309 + unlock_fb_info(fbi);
21314 +static ssize_t store_overlays_rotate(struct device *dev,
21315 + struct device_attribute *attr, const char *buf, size_t count)
21317 + struct fb_info *fbi = dev_get_drvdata(dev);
21318 + struct omapfb_info *ofbi = FB2OFB(fbi);
21319 + int num_ovls = 0, r, i;
21321 + bool changed = false;
21322 + u8 rotation[OMAPFB_MAX_OVL_PER_FB];
21324 + len = strlen(buf);
21325 + if (buf[len - 1] == '\n')
21328 + lock_fb_info(fbi);
21331 + char *p = (char *)buf;
21333 + while (p < buf + len) {
21336 + if (num_ovls == ofbi->num_overlays) {
21341 + rot = simple_strtoul(p, &p, 0);
21342 + if (rot < 0 || rot > 3) {
21347 + if (ofbi->rotation[num_ovls] != rot)
21350 + rotation[num_ovls++] = rot;
21356 + if (num_ovls != ofbi->num_overlays) {
21362 + for (i = 0; i < num_ovls; ++i)
21363 + ofbi->rotation[i] = rotation[i];
21365 + r = omapfb_apply_changes(fbi, 0);
21369 + /* FIXME error handling? */
21374 + unlock_fb_info(fbi);
21379 +static ssize_t show_size(struct device *dev,
21380 + struct device_attribute *attr, char *buf)
21382 + struct fb_info *fbi = dev_get_drvdata(dev);
21383 + struct omapfb_info *ofbi = FB2OFB(fbi);
21385 + return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size);
21388 +static ssize_t store_size(struct device *dev, struct device_attribute *attr,
21389 + const char *buf, size_t count)
21391 + struct fb_info *fbi = dev_get_drvdata(dev);
21392 + struct omapfb_info *ofbi = FB2OFB(fbi);
21393 + unsigned long size;
21397 + size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
21399 + lock_fb_info(fbi);
21401 + for (i = 0; i < ofbi->num_overlays; i++) {
21402 + if (ofbi->overlays[i]->info.enabled) {
21408 + if (size != ofbi->region.size) {
21409 + r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type);
21411 + dev_err(dev, "realloc fbmem failed\n");
21418 + unlock_fb_info(fbi);
21423 +static ssize_t show_phys(struct device *dev,
21424 + struct device_attribute *attr, char *buf)
21426 + struct fb_info *fbi = dev_get_drvdata(dev);
21427 + struct omapfb_info *ofbi = FB2OFB(fbi);
21429 + return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr);
21432 +static ssize_t show_virt(struct device *dev,
21433 + struct device_attribute *attr, char *buf)
21435 + struct fb_info *fbi = dev_get_drvdata(dev);
21436 + struct omapfb_info *ofbi = FB2OFB(fbi);
21438 + return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr);
21441 +static struct device_attribute omapfb_attrs[] = {
21442 + __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
21443 + store_rotate_type),
21444 + __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
21445 + __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
21446 + __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
21447 + __ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
21448 + store_overlays_rotate),
21449 + __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
21450 + __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
21453 +int omapfb_create_sysfs(struct omapfb2_device *fbdev)
21458 + DBG("create sysfs for fbs\n");
21459 + for (i = 0; i < fbdev->num_fbs; i++) {
21461 + for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
21462 + r = device_create_file(fbdev->fbs[i]->dev,
21463 + &omapfb_attrs[t]);
21466 + dev_err(fbdev->dev, "failed to create sysfs "
21476 +void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
21480 + DBG("remove sysfs for fbs\n");
21481 + for (i = 0; i < fbdev->num_fbs; i++) {
21482 + for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
21483 + device_remove_file(fbdev->fbs[i]->dev,
21484 + &omapfb_attrs[t]);
21488 diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
21489 new file mode 100644
21490 index 0000000..d9ee986
21492 +++ b/drivers/video/omap2/omapfb/omapfb.h
21495 + * linux/drivers/video/omap2/omapfb.h
21497 + * Copyright (C) 2008 Nokia Corporation
21498 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
21500 + * Some code and ideas taken from drivers/video/omap/ driver
21503 + * This program is free software; you can redistribute it and/or modify it
21504 + * under the terms of the GNU General Public License version 2 as published by
21505 + * the Free Software Foundation.
21507 + * This program is distributed in the hope that it will be useful, but WITHOUT
21508 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21509 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
21512 + * You should have received a copy of the GNU General Public License along with
21513 + * this program. If not, see <http://www.gnu.org/licenses/>.
21516 +#ifndef __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
21517 +#define __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
21519 +#ifdef CONFIG_FB_OMAP2_DEBUG_SUPPORT
21523 +#include <mach/display.h>
21526 +extern unsigned int omapfb_debug;
21527 +#define DBG(format, ...) \
21528 + if (omapfb_debug) \
21529 + printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__)
21531 +#define DBG(format, ...)
21534 +#define FB2OFB(fb_info) ((struct omapfb_info *)(fb_info->par))
21536 +/* max number of overlays to which a framebuffer data can be direct */
21537 +#define OMAPFB_MAX_OVL_PER_FB 3
21539 +struct omapfb2_mem_region {
21541 + void __iomem *vaddr;
21542 + struct vrfb vrfb;
21543 + unsigned long size;
21544 + u8 type; /* OMAPFB_PLANE_MEM_* */
21545 + bool alloc; /* allocated by the driver */
21546 + bool map; /* kernel mapped by the driver */
21549 +/* appended to fb_info */
21550 +struct omapfb_info {
21552 + struct omapfb2_mem_region region;
21553 + atomic_t map_count;
21554 + int num_overlays;
21555 + struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB];
21556 + struct omapfb2_device *fbdev;
21557 + enum omap_dss_rotation_type rotation_type;
21558 + u8 rotation[OMAPFB_MAX_OVL_PER_FB];
21562 +struct omapfb2_device {
21563 + struct device *dev;
21564 + struct mutex mtx;
21566 + u32 pseudo_palette[17];
21570 + unsigned num_fbs;
21571 + struct fb_info *fbs[10];
21573 + unsigned num_displays;
21574 + struct omap_dss_device *displays[10];
21575 + unsigned num_overlays;
21576 + struct omap_overlay *overlays[10];
21577 + unsigned num_managers;
21578 + struct omap_overlay_manager *managers[10];
21581 +struct omapfb_colormode {
21582 + enum omap_color_mode dssmode;
21583 + u32 bits_per_pixel;
21585 + struct fb_bitfield red;
21586 + struct fb_bitfield green;
21587 + struct fb_bitfield blue;
21588 + struct fb_bitfield transp;
21591 +void set_fb_fix(struct fb_info *fbi);
21592 +int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var);
21593 +int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type);
21594 +int omapfb_apply_changes(struct fb_info *fbi, int init);
21596 +int omapfb_create_sysfs(struct omapfb2_device *fbdev);
21597 +void omapfb_remove_sysfs(struct omapfb2_device *fbdev);
21599 +int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg);
21601 +int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
21602 + struct fb_var_screeninfo *var);
21604 +/* find the display connected to this fb, if any */
21605 +static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
21607 + struct omapfb_info *ofbi = FB2OFB(fbi);
21610 + /* XXX: returns the display connected to first attached overlay */
21611 + for (i = 0; i < ofbi->num_overlays; i++) {
21612 + if (ofbi->overlays[i]->manager)
21613 + return ofbi->overlays[i]->manager->device;
21619 +static inline void omapfb_lock(struct omapfb2_device *fbdev)
21621 + mutex_lock(&fbdev->mtx);
21624 +static inline void omapfb_unlock(struct omapfb2_device *fbdev)
21626 + mutex_unlock(&fbdev->mtx);
21629 +static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
21632 + struct omap_overlay_info info;
21634 + ovl->get_overlay_info(ovl, &info);
21635 + info.enabled = enable;
21636 + return ovl->set_overlay_info(ovl, &info);
21640 diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c
21641 new file mode 100644
21642 index 0000000..634ce23
21644 +++ b/drivers/video/omap2/vram.c
21647 + * VRAM manager for OMAP
21649 + * Copyright (C) 2009 Nokia Corporation
21650 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
21652 + * This program is free software; you can redistribute it and/or modify
21653 + * it under the terms of the GNU General Public License version 2 as
21654 + * published by the Free Software Foundation.
21656 + * This program is distributed in the hope that it will be useful, but
21657 + * WITHOUT ANY WARRANTY; without even the implied warranty of
21658 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21659 + * General Public License for more details.
21661 + * You should have received a copy of the GNU General Public License along
21662 + * with this program; if not, write to the Free Software Foundation, Inc.,
21663 + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21668 +#include <linux/kernel.h>
21669 +#include <linux/mm.h>
21670 +#include <linux/list.h>
21671 +#include <linux/seq_file.h>
21672 +#include <linux/bootmem.h>
21673 +#include <linux/completion.h>
21674 +#include <linux/debugfs.h>
21675 +#include <linux/jiffies.h>
21676 +#include <linux/module.h>
21678 +#include <asm/setup.h>
21680 +#include <mach/sram.h>
21681 +#include <mach/vram.h>
21682 +#include <mach/dma.h>
21685 +#define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__)
21687 +#define DBG(format, ...)
21690 +#define OMAP2_SRAM_START 0x40200000
21691 +/* Maximum size, in reality this is smaller if SRAM is partially locked. */
21692 +#define OMAP2_SRAM_SIZE 0xa0000 /* 640k */
21694 +/* postponed regions are used to temporarily store region information at boot
21695 + * time when we cannot yet allocate the region list */
21696 +#define MAX_POSTPONED_REGIONS 10
21698 +static bool vram_initialized;
21699 +static int postponed_cnt;
21701 + unsigned long paddr;
21703 +} postponed_regions[MAX_POSTPONED_REGIONS];
21705 +struct vram_alloc {
21706 + struct list_head list;
21707 + unsigned long paddr;
21711 +struct vram_region {
21712 + struct list_head list;
21713 + struct list_head alloc_list;
21714 + unsigned long paddr;
21718 +static DEFINE_MUTEX(region_mutex);
21719 +static LIST_HEAD(region_list);
21721 +static inline int region_mem_type(unsigned long paddr)
21723 + if (paddr >= OMAP2_SRAM_START &&
21724 + paddr < OMAP2_SRAM_START + OMAP2_SRAM_SIZE)
21725 + return OMAP_VRAM_MEMTYPE_SRAM;
21727 + return OMAP_VRAM_MEMTYPE_SDRAM;
21730 +static struct vram_region *omap_vram_create_region(unsigned long paddr,
21733 + struct vram_region *rm;
21735 + rm = kzalloc(sizeof(*rm), GFP_KERNEL);
21738 + INIT_LIST_HEAD(&rm->alloc_list);
21739 + rm->paddr = paddr;
21740 + rm->pages = pages;
21747 +static void omap_vram_free_region(struct vram_region *vr)
21749 + list_del(&vr->list);
21754 +static struct vram_alloc *omap_vram_create_allocation(struct vram_region *vr,
21755 + unsigned long paddr, unsigned pages)
21757 + struct vram_alloc *va;
21758 + struct vram_alloc *new;
21760 + new = kzalloc(sizeof(*va), GFP_KERNEL);
21765 + new->paddr = paddr;
21766 + new->pages = pages;
21768 + list_for_each_entry(va, &vr->alloc_list, list) {
21769 + if (va->paddr > new->paddr)
21773 + list_add_tail(&new->list, &va->list);
21778 +static void omap_vram_free_allocation(struct vram_alloc *va)
21780 + list_del(&va->list);
21784 +int omap_vram_add_region(unsigned long paddr, size_t size)
21786 + struct vram_region *rm;
21789 + if (vram_initialized) {
21790 + DBG("adding region paddr %08lx size %d\n",
21793 + size &= PAGE_MASK;
21794 + pages = size >> PAGE_SHIFT;
21796 + rm = omap_vram_create_region(paddr, pages);
21800 + list_add(&rm->list, ®ion_list);
21802 + if (postponed_cnt == MAX_POSTPONED_REGIONS)
21805 + postponed_regions[postponed_cnt].paddr = paddr;
21806 + postponed_regions[postponed_cnt].size = size;
21813 +int omap_vram_free(unsigned long paddr, size_t size)
21815 + struct vram_region *rm;
21816 + struct vram_alloc *alloc;
21817 + unsigned start, end;
21819 + DBG("free mem paddr %08lx size %d\n", paddr, size);
21821 + size = PAGE_ALIGN(size);
21823 + mutex_lock(®ion_mutex);
21825 + list_for_each_entry(rm, ®ion_list, list) {
21826 + list_for_each_entry(alloc, &rm->alloc_list, list) {
21827 + start = alloc->paddr;
21828 + end = alloc->paddr + (alloc->pages >> PAGE_SHIFT);
21830 + if (start >= paddr && end < paddr + size)
21835 + mutex_unlock(®ion_mutex);
21839 + omap_vram_free_allocation(alloc);
21841 + mutex_unlock(®ion_mutex);
21844 +EXPORT_SYMBOL(omap_vram_free);
21846 +static int _omap_vram_reserve(unsigned long paddr, unsigned pages)
21848 + struct vram_region *rm;
21849 + struct vram_alloc *alloc;
21852 + size = pages << PAGE_SHIFT;
21854 + list_for_each_entry(rm, ®ion_list, list) {
21855 + unsigned long start, end;
21857 + DBG("checking region %lx %d\n", rm->paddr, rm->pages);
21859 + if (region_mem_type(rm->paddr) != region_mem_type(paddr))
21862 + start = rm->paddr;
21863 + end = start + (rm->pages << PAGE_SHIFT) - 1;
21864 + if (start > paddr || end < paddr + size - 1)
21867 + DBG("block ok, checking allocs\n");
21869 + list_for_each_entry(alloc, &rm->alloc_list, list) {
21870 + end = alloc->paddr - 1;
21872 + if (start <= paddr && end >= paddr + size - 1)
21875 + start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
21878 + end = rm->paddr + (rm->pages << PAGE_SHIFT) - 1;
21880 + if (!(start <= paddr && end >= paddr + size - 1))
21883 + DBG("found area start %lx, end %lx\n", start, end);
21885 + if (omap_vram_create_allocation(rm, paddr, pages) == NULL)
21894 +int omap_vram_reserve(unsigned long paddr, size_t size)
21899 + DBG("reserve mem paddr %08lx size %d\n", paddr, size);
21901 + size = PAGE_ALIGN(size);
21902 + pages = size >> PAGE_SHIFT;
21904 + mutex_lock(®ion_mutex);
21906 + r = _omap_vram_reserve(paddr, pages);
21908 + mutex_unlock(®ion_mutex);
21912 +EXPORT_SYMBOL(omap_vram_reserve);
21914 +static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data)
21916 + struct completion *compl = data;
21920 +static int _omap_vram_clear(u32 paddr, unsigned pages)
21922 + struct completion compl;
21923 + unsigned elem_count;
21924 + unsigned frame_count;
21928 + init_completion(&compl);
21930 + r = omap_request_dma(OMAP_DMA_NO_DEVICE, "VRAM DMA",
21931 + _omap_vram_dma_cb,
21934 + pr_err("VRAM: request_dma failed for memory clear\n");
21938 + elem_count = pages * PAGE_SIZE / 4;
21941 + omap_set_dma_transfer_params(lch, OMAP_DMA_DATA_TYPE_S32,
21942 + elem_count, frame_count,
21943 + OMAP_DMA_SYNC_ELEMENT,
21946 + omap_set_dma_dest_params(lch, 0, OMAP_DMA_AMODE_POST_INC,
21949 + omap_set_dma_color_mode(lch, OMAP_DMA_CONSTANT_FILL, 0x000000);
21951 + omap_start_dma(lch);
21953 + if (wait_for_completion_timeout(&compl, msecs_to_jiffies(1000)) == 0) {
21954 + omap_stop_dma(lch);
21955 + pr_err("VRAM: dma timeout while clearing memory\n");
21962 + omap_free_dma(lch);
21967 +static int _omap_vram_alloc(int mtype, unsigned pages, unsigned long *paddr)
21969 + struct vram_region *rm;
21970 + struct vram_alloc *alloc;
21972 + list_for_each_entry(rm, ®ion_list, list) {
21973 + unsigned long start, end;
21975 + DBG("checking region %lx %d\n", rm->paddr, rm->pages);
21977 + if (region_mem_type(rm->paddr) != mtype)
21980 + start = rm->paddr;
21982 + list_for_each_entry(alloc, &rm->alloc_list, list) {
21983 + end = alloc->paddr;
21985 + if (end - start >= pages << PAGE_SHIFT)
21988 + start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
21991 + end = rm->paddr + (rm->pages << PAGE_SHIFT);
21993 + if (end - start < pages << PAGE_SHIFT)
21996 + DBG("found %lx, end %lx\n", start, end);
21998 + alloc = omap_vram_create_allocation(rm, start, pages);
21999 + if (alloc == NULL)
22004 + _omap_vram_clear(start, pages);
22012 +int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr)
22017 + BUG_ON(mtype > OMAP_VRAM_MEMTYPE_MAX || !size);
22019 + DBG("alloc mem type %d size %d\n", mtype, size);
22021 + size = PAGE_ALIGN(size);
22022 + pages = size >> PAGE_SHIFT;
22024 + mutex_lock(®ion_mutex);
22026 + r = _omap_vram_alloc(mtype, pages, paddr);
22028 + mutex_unlock(®ion_mutex);
22032 +EXPORT_SYMBOL(omap_vram_alloc);
22034 +void omap_vram_get_info(unsigned long *vram,
22035 + unsigned long *free_vram,
22036 + unsigned long *largest_free_block)
22038 + struct vram_region *vr;
22039 + struct vram_alloc *va;
22043 + *largest_free_block = 0;
22045 + mutex_lock(®ion_mutex);
22047 + list_for_each_entry(vr, ®ion_list, list) {
22049 + unsigned long pa;
22052 + *vram += vr->pages << PAGE_SHIFT;
22054 + list_for_each_entry(va, &vr->alloc_list, list) {
22055 + free = va->paddr - pa;
22056 + *free_vram += free;
22057 + if (free > *largest_free_block)
22058 + *largest_free_block = free;
22059 + pa = va->paddr + (va->pages << PAGE_SHIFT);
22062 + free = vr->paddr + (vr->pages << PAGE_SHIFT) - pa;
22063 + *free_vram += free;
22064 + if (free > *largest_free_block)
22065 + *largest_free_block = free;
22068 + mutex_unlock(®ion_mutex);
22070 +EXPORT_SYMBOL(omap_vram_get_info);
22072 +#if defined(CONFIG_DEBUG_FS)
22073 +static int vram_debug_show(struct seq_file *s, void *unused)
22075 + struct vram_region *vr;
22076 + struct vram_alloc *va;
22079 + mutex_lock(®ion_mutex);
22081 + list_for_each_entry(vr, ®ion_list, list) {
22082 + size = vr->pages << PAGE_SHIFT;
22083 + seq_printf(s, "%08lx-%08lx (%d bytes)\n",
22084 + vr->paddr, vr->paddr + size - 1,
22087 + list_for_each_entry(va, &vr->alloc_list, list) {
22088 + size = va->pages << PAGE_SHIFT;
22089 + seq_printf(s, " %08lx-%08lx (%d bytes)\n",
22090 + va->paddr, va->paddr + size - 1,
22095 + mutex_unlock(®ion_mutex);
22100 +static int vram_debug_open(struct inode *inode, struct file *file)
22102 + return single_open(file, vram_debug_show, inode->i_private);
22105 +static const struct file_operations vram_debug_fops = {
22106 + .open = vram_debug_open,
22107 + .read = seq_read,
22108 + .llseek = seq_lseek,
22109 + .release = single_release,
22112 +static int __init omap_vram_create_debugfs(void)
22114 + struct dentry *d;
22116 + d = debugfs_create_file("vram", S_IRUGO, NULL,
22117 + NULL, &vram_debug_fops);
22119 + return PTR_ERR(d);
22125 +static __init int omap_vram_init(void)
22129 + vram_initialized = 1;
22131 + for (i = 0; i < postponed_cnt; i++)
22132 + omap_vram_add_region(postponed_regions[i].paddr,
22133 + postponed_regions[i].size);
22135 +#ifdef CONFIG_DEBUG_FS
22136 + if (omap_vram_create_debugfs())
22137 + pr_err("VRAM: Failed to create debugfs file\n");
22143 +arch_initcall(omap_vram_init);
22145 +/* boottime vram alloc stuff */
22147 +/* set from board file */
22148 +static u32 omap_vram_sram_start __initdata;
22149 +static u32 omap_vram_sram_size __initdata;
22151 +/* set from board file */
22152 +static u32 omap_vram_sdram_start __initdata;
22153 +static u32 omap_vram_sdram_size __initdata;
22155 +/* set from kernel cmdline */
22156 +static u32 omap_vram_def_sdram_size __initdata;
22157 +static u32 omap_vram_def_sdram_start __initdata;
22159 +static void __init omap_vram_early_vram(char **p)
22161 + omap_vram_def_sdram_size = memparse(*p, p);
22163 + omap_vram_def_sdram_start = simple_strtoul((*p) + 1, p, 16);
22165 +__early_param("vram=", omap_vram_early_vram);
22168 + * Called from map_io. We need to call to this early enough so that we
22169 + * can reserve the fixed SDRAM regions before VM could get hold of them.
22171 +void __init omap_vram_reserve_sdram(void)
22173 + struct bootmem_data *bdata;
22174 + unsigned long sdram_start, sdram_size;
22178 + /* cmdline arg overrides the board file definition */
22179 + if (omap_vram_def_sdram_size) {
22180 + size = omap_vram_def_sdram_size;
22181 + paddr = omap_vram_def_sdram_start;
22185 + size = omap_vram_sdram_size;
22186 + paddr = omap_vram_sdram_start;
22189 +#ifdef CONFIG_OMAP2_VRAM_SIZE
22191 + size = CONFIG_OMAP2_VRAM_SIZE * 1024 * 1024;
22199 + size = PAGE_ALIGN(size);
22201 + bdata = NODE_DATA(0)->bdata;
22202 + sdram_start = bdata->node_min_pfn << PAGE_SHIFT;
22203 + sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start;
22206 + if ((paddr & ~PAGE_MASK) || paddr < sdram_start ||
22207 + paddr + size > sdram_start + sdram_size) {
22208 + pr_err("Illegal SDRAM region for VRAM\n");
22212 + if (reserve_bootmem(paddr, size, BOOTMEM_EXCLUSIVE) < 0) {
22213 + pr_err("FB: failed to reserve VRAM\n");
22217 + if (size > sdram_size) {
22218 + pr_err("Illegal SDRAM size for VRAM\n");
22222 + paddr = virt_to_phys(alloc_bootmem_pages(size));
22223 + BUG_ON(paddr & ~PAGE_MASK);
22226 + omap_vram_add_region(paddr, size);
22228 + pr_info("Reserving %u bytes SDRAM for VRAM\n", size);
22232 + * Called at sram init time, before anything is pushed to the SRAM stack.
22233 + * Because of the stack scheme, we will allocate everything from the
22234 + * start of the lowest address region to the end of SRAM. This will also
22235 + * include padding for page alignment and possible holes between regions.
22237 + * As opposed to the SDRAM case, we'll also do any dynamic allocations at
22238 + * this point, since the driver built as a module would have problem with
22239 + * freeing / reallocating the regions.
22241 +unsigned long __init omap_vram_reserve_sram(unsigned long sram_pstart,
22242 + unsigned long sram_vstart,
22243 + unsigned long sram_size,
22244 + unsigned long pstart_avail,
22245 + unsigned long size_avail)
22247 + unsigned long pend_avail;
22248 + unsigned long reserved;
22252 + paddr = omap_vram_sram_start;
22253 + size = omap_vram_sram_size;
22259 + pend_avail = pstart_avail + size_avail;
22262 + /* Dynamic allocation */
22263 + if ((size_avail & PAGE_MASK) < size) {
22264 + pr_err("Not enough SRAM for VRAM\n");
22267 + size_avail = (size_avail - size) & PAGE_MASK;
22268 + paddr = pstart_avail + size_avail;
22271 + if (paddr < sram_pstart ||
22272 + paddr + size > sram_pstart + sram_size) {
22273 + pr_err("Illegal SRAM region for VRAM\n");
22277 + /* Reserve everything above the start of the region. */
22278 + if (pend_avail - paddr > reserved)
22279 + reserved = pend_avail - paddr;
22280 + size_avail = pend_avail - reserved - pstart_avail;
22282 + omap_vram_add_region(paddr, size);
22285 + pr_info("Reserving %lu bytes SRAM for VRAM\n", reserved);
22290 +void __init omap_vram_set_sdram_vram(u32 size, u32 start)
22292 + omap_vram_sdram_start = start;
22293 + omap_vram_sdram_size = size;
22296 +void __init omap_vram_set_sram_vram(u32 size, u32 start)
22298 + omap_vram_sram_start = start;
22299 + omap_vram_sram_size = size;
22301 diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c
22302 new file mode 100644
22303 index 0000000..8726689
22305 +++ b/drivers/video/omap2/vrfb.c
22308 + * VRFB Rotation Engine
22310 + * Copyright (C) 2009 Nokia Corporation
22311 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
22313 + * This program is free software; you can redistribute it and/or modify
22314 + * it under the terms of the GNU General Public License version 2 as
22315 + * published by the Free Software Foundation.
22317 + * This program is distributed in the hope that it will be useful, but
22318 + * WITHOUT ANY WARRANTY; without even the implied warranty of
22319 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22320 + * General Public License for more details.
22322 + * You should have received a copy of the GNU General Public License along
22323 + * with this program; if not, write to the Free Software Foundation, Inc.,
22324 + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22327 +#include <linux/kernel.h>
22328 +#include <linux/module.h>
22329 +#include <linux/ioport.h>
22330 +#include <linux/io.h>
22331 +#include <linux/bitops.h>
22332 +#include <linux/mutex.h>
22334 +#include <mach/io.h>
22335 +#include <mach/vrfb.h>
22336 +#include <mach/sdrc.h>
22340 +#define DBG(format, ...) pr_debug("VRFB: " format, ## __VA_ARGS__)
22342 +#define DBG(format, ...)
22345 +#define SMS_ROT_VIRT_BASE(context, rot) \
22346 + (((context >= 4) ? 0xD0000000 : 0x70000000) \
22347 + + (0x4000000 * (context)) \
22348 + + (0x1000000 * (rot)))
22350 +#define OMAP_VRFB_SIZE (2048 * 2048 * 4)
22352 +#define VRFB_PAGE_WIDTH_EXP 5 /* Assuming SDRAM pagesize= 1024 */
22353 +#define VRFB_PAGE_HEIGHT_EXP 5 /* 1024 = 2^5 * 2^5 */
22354 +#define VRFB_PAGE_WIDTH (1 << VRFB_PAGE_WIDTH_EXP)
22355 +#define VRFB_PAGE_HEIGHT (1 << VRFB_PAGE_HEIGHT_EXP)
22356 +#define SMS_IMAGEHEIGHT_OFFSET 16
22357 +#define SMS_IMAGEWIDTH_OFFSET 0
22358 +#define SMS_PH_OFFSET 8
22359 +#define SMS_PW_OFFSET 4
22360 +#define SMS_PS_OFFSET 0
22362 +#define VRFB_NUM_CTXS 12
22363 +/* bitmap of reserved contexts */
22364 +static unsigned long ctx_map;
22365 +/* bitmap of contexts for which we have to keep the HW context valid */
22366 +static unsigned long ctx_map_active;
22368 +static DEFINE_MUTEX(ctx_lock);
22371 + * Access to this happens from client drivers or the PM core after wake-up.
22372 + * For the first case we require locking at the driver level, for the second
22373 + * we don't need locking, since no drivers will run until after the wake-up
22380 +} vrfb_hw_context[VRFB_NUM_CTXS];
22382 +static inline void restore_hw_context(int ctx)
22384 + omap2_sms_write_rot_control(vrfb_hw_context[ctx].control, ctx);
22385 + omap2_sms_write_rot_size(vrfb_hw_context[ctx].size, ctx);
22386 + omap2_sms_write_rot_physical_ba(vrfb_hw_context[ctx].physical_ba, ctx);
22389 +void omap_vrfb_restore_context(void)
22392 + unsigned long map = ctx_map_active;
22394 + for (i = ffs(map); i; i = ffs(map)) {
22397 + map &= ~(1 << i);
22398 + restore_hw_context(i);
22402 +void omap_vrfb_adjust_size(u16 *width, u16 *height,
22405 + *width = ALIGN(*width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
22406 + *height = ALIGN(*height, VRFB_PAGE_HEIGHT);
22408 +EXPORT_SYMBOL(omap_vrfb_adjust_size);
22410 +void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
22411 + u16 width, u16 height,
22412 + unsigned bytespp, bool yuv_mode)
22414 + unsigned pixel_size_exp;
22417 + u8 ctx = vrfb->context;
22421 + DBG("omapfb_set_vrfb(%d, %lx, %dx%d, %d)\n", ctx, paddr,
22422 + width, height, color_mode);
22424 + /* For YUV2 and UYVY modes VRFB needs to handle pixels a bit
22425 + * differently. See TRM. */
22431 + if (bytespp == 4)
22432 + pixel_size_exp = 2;
22433 + else if (bytespp == 2)
22434 + pixel_size_exp = 1;
22438 + vrfb_width = ALIGN(width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
22439 + vrfb_height = ALIGN(height, VRFB_PAGE_HEIGHT);
22441 + DBG("vrfb w %u, h %u bytespp %d\n", vrfb_width, vrfb_height, bytespp);
22443 + size = vrfb_width << SMS_IMAGEWIDTH_OFFSET;
22444 + size |= vrfb_height << SMS_IMAGEHEIGHT_OFFSET;
22446 + control = pixel_size_exp << SMS_PS_OFFSET;
22447 + control |= VRFB_PAGE_WIDTH_EXP << SMS_PW_OFFSET;
22448 + control |= VRFB_PAGE_HEIGHT_EXP << SMS_PH_OFFSET;
22450 + vrfb_hw_context[ctx].physical_ba = paddr;
22451 + vrfb_hw_context[ctx].size = size;
22452 + vrfb_hw_context[ctx].control = control;
22454 + omap2_sms_write_rot_physical_ba(paddr, ctx);
22455 + omap2_sms_write_rot_size(size, ctx);
22456 + omap2_sms_write_rot_control(control, ctx);
22458 + DBG("vrfb offset pixels %d, %d\n",
22459 + vrfb_width - width, vrfb_height - height);
22461 + vrfb->xoffset = vrfb_width - width;
22462 + vrfb->yoffset = vrfb_height - height;
22463 + vrfb->bytespp = bytespp;
22465 +EXPORT_SYMBOL(omap_vrfb_setup);
22467 +void omap_vrfb_release_ctx(struct vrfb *vrfb)
22470 + int ctx = vrfb->context;
22475 + DBG("release ctx %d\n", ctx);
22477 + mutex_lock(&ctx_lock);
22479 + BUG_ON(!(ctx_map & (1 << ctx)));
22481 + clear_bit(ctx, &ctx_map_active);
22482 + clear_bit(ctx, &ctx_map);
22484 + for (rot = 0; rot < 4; ++rot) {
22485 + if (vrfb->paddr[rot]) {
22486 + release_mem_region(vrfb->paddr[rot], OMAP_VRFB_SIZE);
22487 + vrfb->paddr[rot] = 0;
22491 + vrfb->context = 0xff;
22493 + mutex_unlock(&ctx_lock);
22495 +EXPORT_SYMBOL(omap_vrfb_release_ctx);
22497 +int omap_vrfb_request_ctx(struct vrfb *vrfb)
22504 + DBG("request ctx\n");
22506 + mutex_lock(&ctx_lock);
22508 + for (ctx = 0; ctx < VRFB_NUM_CTXS; ++ctx)
22509 + if ((ctx_map & (1 << ctx)) == 0)
22512 + if (ctx == VRFB_NUM_CTXS) {
22513 + pr_err("vrfb: no free contexts\n");
22518 + DBG("found free ctx %d\n", ctx);
22520 + set_bit(ctx, &ctx_map);
22521 + WARN_ON(ctx_map_active & (1 << ctx));
22522 + set_bit(ctx, &ctx_map_active);
22524 + memset(vrfb, 0, sizeof(*vrfb));
22526 + vrfb->context = ctx;
22528 + for (rot = 0; rot < 4; ++rot) {
22529 + paddr = SMS_ROT_VIRT_BASE(ctx, rot);
22530 + if (!request_mem_region(paddr, OMAP_VRFB_SIZE, "vrfb")) {
22531 + pr_err("vrfb: failed to reserve VRFB "
22532 + "area for ctx %d, rotation %d\n",
22534 + omap_vrfb_release_ctx(vrfb);
22539 + vrfb->paddr[rot] = paddr;
22541 + DBG("VRFB %d/%d: %lx\n", ctx, rot*90, vrfb->paddr[rot]);
22546 + mutex_unlock(&ctx_lock);
22549 +EXPORT_SYMBOL(omap_vrfb_request_ctx);
22551 +void omap_vrfb_suspend_ctx(struct vrfb *vrfb)
22553 + DBG("suspend ctx %d\n", vrfb->context);
22554 + mutex_lock(&ctx_lock);
22556 + BUG_ON(vrfb->context >= VRFB_NUM_CTXS);
22557 + BUG_ON(!((1 << vrfb->context) & ctx_map_active));
22559 + clear_bit(vrfb->context, &ctx_map_active);
22560 + mutex_unlock(&ctx_lock);
22562 +EXPORT_SYMBOL(omap_vrfb_suspend_ctx);
22564 +void omap_vrfb_resume_ctx(struct vrfb *vrfb)
22566 + DBG("resume ctx %d\n", vrfb->context);
22567 + mutex_lock(&ctx_lock);
22569 + BUG_ON(vrfb->context >= VRFB_NUM_CTXS);
22570 + BUG_ON((1 << vrfb->context) & ctx_map_active);
22573 + * omap_vrfb_restore_context is normally called by the core domain
22574 + * save / restore logic, but since this VRFB context was suspended
22575 + * those calls didn't actually restore the context and now we might
22576 + * have an invalid context. Do an explicit restore here.
22578 + restore_hw_context(vrfb->context);
22579 + set_bit(vrfb->context, &ctx_map_active);
22580 + mutex_unlock(&ctx_lock);
22582 +EXPORT_SYMBOL(omap_vrfb_resume_ctx);
22584 diff --git a/include/linux/omapfb.h b/include/linux/omapfb.h
22585 new file mode 100644
22586 index 0000000..52e0987
22588 +++ b/include/linux/omapfb.h
22591 + * File: include/linux/omapfb.h
22593 + * Framebuffer driver for TI OMAP boards
22595 + * Copyright (C) 2004 Nokia Corporation
22596 + * Author: Imre Deak <imre.deak@nokia.com>
22598 + * This program is free software; you can redistribute it and/or modify it
22599 + * under the terms of the GNU General Public License as published by the
22600 + * Free Software Foundation; either version 2 of the License, or (at your
22601 + * option) any later version.
22603 + * This program is distributed in the hope that it will be useful, but
22604 + * WITHOUT ANY WARRANTY; without even the implied warranty of
22605 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22606 + * General Public License for more details.
22608 + * You should have received a copy of the GNU General Public License along
22609 + * with this program; if not, write to the Free Software Foundation, Inc.,
22610 + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22613 +#ifndef __LINUX_OMAPFB_H__
22614 +#define __LINUX_OMAPFB_H__
22616 +#include <linux/fb.h>
22617 +#include <linux/ioctl.h>
22618 +#include <linux/types.h>
22620 +/* IOCTL commands. */
22622 +#define OMAP_IOW(num, dtype) _IOW('O', num, dtype)
22623 +#define OMAP_IOR(num, dtype) _IOR('O', num, dtype)
22624 +#define OMAP_IOWR(num, dtype) _IOWR('O', num, dtype)
22625 +#define OMAP_IO(num) _IO('O', num)
22627 +#define OMAPFB_MIRROR OMAP_IOW(31, int)
22628 +#define OMAPFB_SYNC_GFX OMAP_IO(37)
22629 +#define OMAPFB_VSYNC OMAP_IO(38)
22630 +#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int)
22631 +#define OMAPFB_GET_CAPS OMAP_IOR(42, struct omapfb_caps)
22632 +#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int)
22633 +#define OMAPFB_LCD_TEST OMAP_IOW(45, int)
22634 +#define OMAPFB_CTRL_TEST OMAP_IOW(46, int)
22635 +#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(47, struct omapfb_update_window_old)
22636 +#define OMAPFB_SET_COLOR_KEY OMAP_IOW(50, struct omapfb_color_key)
22637 +#define OMAPFB_GET_COLOR_KEY OMAP_IOW(51, struct omapfb_color_key)
22638 +#define OMAPFB_SETUP_PLANE OMAP_IOW(52, struct omapfb_plane_info)
22639 +#define OMAPFB_QUERY_PLANE OMAP_IOW(53, struct omapfb_plane_info)
22640 +#define OMAPFB_UPDATE_WINDOW OMAP_IOW(54, struct omapfb_update_window)
22641 +#define OMAPFB_SETUP_MEM OMAP_IOW(55, struct omapfb_mem_info)
22642 +#define OMAPFB_QUERY_MEM OMAP_IOW(56, struct omapfb_mem_info)
22643 +#define OMAPFB_WAITFORVSYNC OMAP_IO(57)
22644 +#define OMAPFB_MEMORY_READ OMAP_IOR(58, struct omapfb_memory_read)
22645 +#define OMAPFB_GET_OVERLAY_COLORMODE OMAP_IOR(59, struct omapfb_ovl_colormode)
22646 +#define OMAPFB_WAITFORGO OMAP_IO(60)
22647 +#define OMAPFB_GET_VRAM_INFO OMAP_IOR(61, struct omapfb_vram_info)
22649 +#define OMAPFB_CAPS_GENERIC_MASK 0x00000fff
22650 +#define OMAPFB_CAPS_LCDC_MASK 0x00fff000
22651 +#define OMAPFB_CAPS_PANEL_MASK 0xff000000
22653 +#define OMAPFB_CAPS_MANUAL_UPDATE 0x00001000
22654 +#define OMAPFB_CAPS_TEARSYNC 0x00002000
22655 +#define OMAPFB_CAPS_PLANE_RELOCATE_MEM 0x00004000
22656 +#define OMAPFB_CAPS_PLANE_SCALE 0x00008000
22657 +#define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE 0x00010000
22658 +#define OMAPFB_CAPS_WINDOW_SCALE 0x00020000
22659 +#define OMAPFB_CAPS_WINDOW_OVERLAY 0x00040000
22660 +#define OMAPFB_CAPS_WINDOW_ROTATE 0x00080000
22661 +#define OMAPFB_CAPS_SET_BACKLIGHT 0x01000000
22663 +/* Values from DSP must map to lower 16-bits */
22664 +#define OMAPFB_FORMAT_MASK 0x00ff
22665 +#define OMAPFB_FORMAT_FLAG_DOUBLE 0x0100
22666 +#define OMAPFB_FORMAT_FLAG_TEARSYNC 0x0200
22667 +#define OMAPFB_FORMAT_FLAG_FORCE_VSYNC 0x0400
22668 +#define OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY 0x0800
22669 +#define OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY 0x1000
22671 +#define OMAPFB_MEMTYPE_SDRAM 0
22672 +#define OMAPFB_MEMTYPE_SRAM 1
22673 +#define OMAPFB_MEMTYPE_MAX 1
22675 +enum omapfb_color_format {
22676 + OMAPFB_COLOR_RGB565 = 0,
22677 + OMAPFB_COLOR_YUV422,
22678 + OMAPFB_COLOR_YUV420,
22679 + OMAPFB_COLOR_CLUT_8BPP,
22680 + OMAPFB_COLOR_CLUT_4BPP,
22681 + OMAPFB_COLOR_CLUT_2BPP,
22682 + OMAPFB_COLOR_CLUT_1BPP,
22683 + OMAPFB_COLOR_RGB444,
22684 + OMAPFB_COLOR_YUY422,
22686 + OMAPFB_COLOR_ARGB16,
22687 + OMAPFB_COLOR_RGB24U, /* RGB24, 32-bit container */
22688 + OMAPFB_COLOR_RGB24P, /* RGB24, 24-bit container */
22689 + OMAPFB_COLOR_ARGB32,
22690 + OMAPFB_COLOR_RGBA32,
22691 + OMAPFB_COLOR_RGBX32,
22694 +struct omapfb_update_window {
22696 + __u32 width, height;
22698 + __u32 out_x, out_y;
22699 + __u32 out_width, out_height;
22700 + __u32 reserved[8];
22703 +struct omapfb_update_window_old {
22705 + __u32 width, height;
22709 +enum omapfb_plane {
22710 + OMAPFB_PLANE_GFX = 0,
22711 + OMAPFB_PLANE_VID1,
22712 + OMAPFB_PLANE_VID2,
22715 +enum omapfb_channel_out {
22716 + OMAPFB_CHANNEL_OUT_LCD = 0,
22717 + OMAPFB_CHANNEL_OUT_DIGIT,
22720 +struct omapfb_plane_info {
22724 + __u8 channel_out;
22728 + __u32 out_height;
22729 + __u32 reserved2[12];
22732 +struct omapfb_mem_info {
22735 + __u8 reserved[3];
22738 +struct omapfb_caps {
22740 + __u32 plane_color;
22744 +enum omapfb_color_key_type {
22745 + OMAPFB_COLOR_KEY_DISABLED = 0,
22746 + OMAPFB_COLOR_KEY_GFX_DST,
22747 + OMAPFB_COLOR_KEY_VID_SRC,
22750 +struct omapfb_color_key {
22751 + __u8 channel_out;
22752 + __u32 background;
22757 +enum omapfb_update_mode {
22758 + OMAPFB_UPDATE_DISABLED = 0,
22759 + OMAPFB_AUTO_UPDATE,
22760 + OMAPFB_MANUAL_UPDATE
22763 +struct omapfb_memory_read {
22768 + size_t buffer_size;
22769 + void __user *buffer;
22772 +struct omapfb_ovl_colormode {
22773 + __u8 overlay_idx;
22775 + __u32 bits_per_pixel;
22777 + struct fb_bitfield red;
22778 + struct fb_bitfield green;
22779 + struct fb_bitfield blue;
22780 + struct fb_bitfield transp;
22783 +struct omapfb_vram_info {
22786 + __u32 largest_free_block;
22787 + __u32 reserved[5];
22792 +#include <mach/board.h>
22794 +#ifdef CONFIG_ARCH_OMAP1
22795 +#define OMAPFB_PLANE_NUM 1
22797 +#define OMAPFB_PLANE_NUM 3
22800 +struct omapfb_mem_region {
22802 + void __iomem *vaddr;
22803 + unsigned long size;
22804 + u8 type; /* OMAPFB_PLANE_MEM_* */
22805 + enum omapfb_color_format format;/* OMAPFB_COLOR_* */
22806 + unsigned format_used:1; /* Must be set when format is set.
22807 + * Needed b/c of the badly chosen 0
22808 + * base for OMAPFB_COLOR_* values
22810 + unsigned alloc:1; /* allocated by the driver */
22811 + unsigned map:1; /* kernel mapped by the driver */
22814 +struct omapfb_mem_desc {
22816 + struct omapfb_mem_region region[OMAPFB_PLANE_NUM];
22819 +struct omapfb_platform_data {
22820 + struct omap_lcd_config lcd;
22821 + struct omapfb_mem_desc mem_desc;
22822 + void *ctrl_platform_data;
22825 +/* in arch/arm/plat-omap/fb.c */
22826 +extern void omapfb_set_ctrl_platform_data(void *pdata);
22827 +extern void omapfb_reserve_sdram(void);
22831 +#endif /* __OMAPFB_H */